okmodel 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +237 -19
  2. package/dist/adapters/capabilities.d.ts +34 -0
  3. package/dist/adapters/pg/bunsql-extra.d.ts +17 -0
  4. package/dist/adapters/pg/bunsql.d.ts +60 -0
  5. package/dist/adapters/pg/call.d.ts +2 -12
  6. package/dist/adapters/pg/nodepostgres-extra.d.ts +18 -0
  7. package/dist/adapters/pg/nodepostgres.d.ts +57 -0
  8. package/dist/adapters/pg/postgres-extra.d.ts +50 -1
  9. package/dist/adapters/pg/postgresjs.d.ts +0 -4
  10. package/dist/adapters/pg/session.d.ts +94 -0
  11. package/dist/adapters/pg/watch.d.ts +18 -0
  12. package/dist/contracts/catalog/object.d.ts +1 -0
  13. package/dist/contracts/catalog/types.d.ts +15 -8
  14. package/dist/contracts/connection.d.ts +13 -0
  15. package/dist/contracts/driver.d.ts +18 -5
  16. package/dist/contracts/error.d.ts +17 -1
  17. package/dist/contracts/generator.d.ts +63 -0
  18. package/dist/contracts/index.d.ts +2 -2
  19. package/dist/contracts/index.js +1 -1
  20. package/dist/contracts/internal.js +11 -9
  21. package/dist/contracts/location.d.ts +24 -0
  22. package/dist/contracts/rows.d.ts +15 -0
  23. package/dist/dialects/pg/archive-bind.d.ts +22 -0
  24. package/dist/dialects/pg/column.d.ts +126 -9
  25. package/dist/dialects/pg/compile.d.ts +1 -0
  26. package/dist/dialects/pg/custom.d.ts +6 -0
  27. package/dist/dialects/pg/filter-parse.d.ts +19 -0
  28. package/dist/dialects/pg/filters.d.ts +19 -0
  29. package/dist/dialects/pg/index.d.ts +11 -2
  30. package/dist/dialects/pg/index.js +159 -1063
  31. package/dist/dialects/pg/keys.d.ts +19 -3
  32. package/dist/dialects/pg/model.d.ts +223 -2
  33. package/dist/dialects/pg/operator-fit.d.ts +86 -0
  34. package/dist/dialects/pg/operators.d.ts +39 -1
  35. package/dist/dialects/pg/ops/arr-append.d.ts +9 -0
  36. package/dist/dialects/pg/ops/arr-ns.d.ts +7 -0
  37. package/dist/dialects/pg/ops/arr-remove.d.ts +9 -0
  38. package/dist/dialects/pg/ops/containedBy.d.ts +9 -0
  39. package/dist/dialects/pg/ops/contains.d.ts +8 -4
  40. package/dist/dialects/pg/ops/hasAnyKey.d.ts +8 -0
  41. package/dist/dialects/pg/ops/hasKey.d.ts +8 -0
  42. package/dist/dialects/pg/ops/json-ns.d.ts +6 -0
  43. package/dist/dialects/pg/ops/json-set.d.ts +12 -0
  44. package/dist/dialects/pg/ops/matches.d.ts +16 -0
  45. package/dist/dialects/pg/ops/overlaps.d.ts +9 -0
  46. package/dist/dialects/pg/ops/path.d.ts +13 -0
  47. package/dist/dialects/pg/preset.d.ts +76 -0
  48. package/dist/dialects/pg/relations.d.ts +59 -2
  49. package/dist/dialects/pg/schema.d.ts +109 -5
  50. package/dist/dialects/pg/table.d.ts +130 -11
  51. package/dist/dialects/pg/temporal.d.ts +9 -7
  52. package/dist/dialects/pg/tenancy.d.ts +94 -0
  53. package/dist/dialects/pg/through.d.ts +21 -0
  54. package/dist/dialects/pg/trait.d.ts +141 -0
  55. package/dist/dialects/pg/where.d.ts +37 -0
  56. package/dist/runtime/aggregate.d.ts +25 -0
  57. package/dist/runtime/archive-handle.d.ts +18 -0
  58. package/dist/runtime/archive-rules.d.ts +12 -0
  59. package/dist/runtime/archive.d.ts +73 -0
  60. package/dist/runtime/batch.d.ts +20 -0
  61. package/dist/runtime/client.d.ts +114 -5
  62. package/dist/runtime/conflict.d.ts +2 -1
  63. package/dist/runtime/exposure.d.ts +27 -0
  64. package/dist/runtime/hookm.d.ts +39 -0
  65. package/dist/runtime/ids/index.d.ts +11 -0
  66. package/dist/runtime/ids/index.js +193 -0
  67. package/dist/runtime/ids/okid-extended.d.ts +19 -0
  68. package/dist/runtime/ids/okid-generator.d.ts +21 -0
  69. package/dist/runtime/ids/okid-shared.d.ts +89 -0
  70. package/dist/runtime/ids/okid.d.ts +24 -0
  71. package/dist/runtime/ids/uuid.d.ts +21 -0
  72. package/dist/runtime/lock.d.ts +22 -0
  73. package/dist/runtime/operator-sql.d.ts +8 -0
  74. package/dist/runtime/page.d.ts +25 -0
  75. package/dist/runtime/pg/bun.d.ts +30 -0
  76. package/dist/runtime/pg/bun.js +52 -0
  77. package/dist/runtime/pg/pg.d.ts +29 -0
  78. package/dist/runtime/pg/pg.js +52 -0
  79. package/dist/runtime/pg/pglite.js +16 -17
  80. package/dist/runtime/pg/postgresjs.js +14 -24
  81. package/dist/runtime/plan.d.ts +146 -7
  82. package/dist/runtime/preset-stack.d.ts +17 -0
  83. package/dist/runtime/presets.d.ts +48 -0
  84. package/dist/runtime/read-stream.d.ts +26 -0
  85. package/dist/runtime/safety/index.d.ts +159 -0
  86. package/dist/runtime/safety/index.js +294 -0
  87. package/dist/runtime/safety-hook.d.ts +42 -0
  88. package/dist/runtime/server-check.d.ts +34 -0
  89. package/dist/runtime/tenancy/index.d.ts +37 -0
  90. package/dist/runtime/tenancy/index.js +365 -0
  91. package/dist/runtime/trait-read.d.ts +30 -0
  92. package/dist/runtime/traits/index.d.ts +128 -0
  93. package/dist/runtime/traits/index.js +509 -0
  94. package/dist/runtime/transaction.d.ts +19 -0
  95. package/dist/runtime/tx.d.ts +22 -7
  96. package/dist/runtime/types.d.ts +390 -25
  97. package/dist/runtime/validate/bind.d.ts +11 -0
  98. package/dist/runtime/validate/closed.d.ts +16 -0
  99. package/dist/runtime/validate/engine.d.ts +41 -0
  100. package/dist/runtime/validate/hook.d.ts +17 -0
  101. package/dist/runtime/validate/index.d.ts +21 -0
  102. package/dist/runtime/validate/index.js +175 -0
  103. package/dist/runtime/validate/load.d.ts +13 -0
  104. package/dist/runtime/validate/places.d.ts +41 -0
  105. package/dist/runtime/validate/rules.d.ts +108 -0
  106. package/dist/runtime/validate/surface.d.ts +102 -0
  107. package/dist/runtime/write.d.ts +30 -5
  108. package/dist/shared/{fgqgsb5z.js → 0qkxbm1f.js} +2 -2
  109. package/dist/shared/0v1g424p.js +26 -0
  110. package/dist/shared/10tjenmd.js +210 -0
  111. package/dist/shared/{tb4ze1tr.js → 1dp5knt7.js} +95 -10
  112. package/dist/shared/38crxbgn.js +229 -0
  113. package/dist/shared/3a5ne750.js +158 -0
  114. package/dist/shared/4b9da9d7.js +138 -0
  115. package/dist/shared/4e4c6vq2.js +62 -0
  116. package/dist/shared/{ckb1p0a4.js → 4jzzghr6.js} +416 -83
  117. package/dist/shared/{ycwz42az.js → 52szzakm.js} +6 -26
  118. package/dist/shared/{kynx7vbm.js → 5z4q2zda.js} +604 -21
  119. package/dist/shared/672t5vym.js +12 -0
  120. package/dist/shared/7m88x3e9.js +45 -0
  121. package/dist/shared/7mht49yd.js +1091 -0
  122. package/dist/shared/{mtkwv8wx.js → 7p2wbz7f.js} +1 -1
  123. package/dist/shared/83eaefwr.js +10 -0
  124. package/dist/shared/96ps4g1z.js +32 -0
  125. package/dist/shared/97g2jnrw.js +76 -0
  126. package/dist/shared/{xy79j5hq.js → 9k6vetvf.js} +25 -36
  127. package/dist/shared/{w8samvk1.js → a1gdp7j9.js} +1 -1
  128. package/dist/shared/a5sxz52y.js +13 -0
  129. package/dist/shared/{dynq16vb.js → b066g80h.js} +8 -6
  130. package/dist/shared/cstgkzdx.js +154 -0
  131. package/dist/shared/{ax16zpvm.js → d04j53v8.js} +6 -5
  132. package/dist/shared/{y9m15dfv.js → d2whjz4k.js} +15 -9
  133. package/dist/shared/dd4f8mnx.js +307 -0
  134. package/dist/shared/e6wg00wd.js +164 -0
  135. package/dist/shared/e7a268fy.js +195 -0
  136. package/dist/shared/{vkm3q4x1.js → eaxwrgby.js} +4 -3
  137. package/dist/shared/{7ck0dtry.js → ecdzej21.js} +160 -81
  138. package/dist/shared/{px90pf9p.js → edwqqryd.js} +21 -16
  139. package/dist/shared/{g2v6gnc8.js → eqmtn1bj.js} +57 -5
  140. package/dist/shared/g1b5zzj9.js +75 -0
  141. package/dist/shared/g9f0zqce.js +376 -0
  142. package/dist/shared/ge03bfca.js +64 -0
  143. package/dist/shared/{79ggp945.js → jns2wx4t.js} +55 -12
  144. package/dist/shared/k3ted12y.js +33 -0
  145. package/dist/shared/k7dwkhvq.js +31 -0
  146. package/dist/shared/{hd293j9g.js → kyxb62mc.js} +14 -2
  147. package/dist/shared/m9tv7xn7.js +404 -0
  148. package/dist/shared/mrq77sgw.js +55 -0
  149. package/dist/shared/mxmcdsh5.js +450 -0
  150. package/dist/shared/n442h54c.js +14 -0
  151. package/dist/shared/n47rd821.js +442 -0
  152. package/dist/shared/n4jqhpqz.js +27 -0
  153. package/dist/shared/{mkjmqjv4.js → nfzc5z0w.js} +2 -104
  154. package/dist/shared/nsva2a6b.js +42 -0
  155. package/dist/shared/ps43134h.js +69 -0
  156. package/dist/shared/{8b04d28c.js → py3nh7jy.js} +2 -2
  157. package/dist/shared/qa5dsc7z.js +86 -0
  158. package/dist/shared/{g5fhqmwe.js → qxa0yb9j.js} +6 -4
  159. package/dist/shared/r6nwkxnt.js +86 -0
  160. package/dist/shared/{4j72449d.js → rtnaqre0.js} +3 -3
  161. package/dist/shared/rwmrejjz.js +26 -0
  162. package/dist/shared/{zhc5vmgf.js → s6gqfn5j.js} +2 -2
  163. package/dist/shared/sacqha1y.js +70 -0
  164. package/dist/shared/{qk3hxfja.js → sfh4pk75.js} +5 -5
  165. package/dist/shared/{j5cn2963.js → t4tbsy9h.js} +13 -64
  166. package/dist/shared/{ngk8gj61.js → tbszx8mz.js} +15 -1
  167. package/dist/shared/v18jva5b.js +90 -0
  168. package/dist/shared/x9v1qgeb.js +201 -0
  169. package/dist/shared/xatfg0gn.js +193 -0
  170. package/dist/shared/xkz8g6by.js +225 -0
  171. package/dist/shared/{f5thc1s0.js → xrfnq5k8.js} +237 -418
  172. package/dist/shared/ytg3xf9p.js +149 -0
  173. package/dist/shared/yw5c610b.js +48 -0
  174. package/dist/shared/zd93g3rq.js +31 -0
  175. package/dist/shared/zt8y0wzb.js +132 -0
  176. package/dist/shared/{p0cbr3g2.js → zwmqxb0g.js} +1 -1
  177. package/dist/tooling/cli.js +14 -10
  178. package/dist/tooling/migrate/commands.d.ts +10 -0
  179. package/dist/tooling/migrate/engine.d.ts +36 -0
  180. package/package.json +56 -4
  181. package/dist/shared/gk7cs7sp.js +0 -566
@@ -0,0 +1,175 @@
1
+ import {
2
+ validationGate
3
+ } from "../../shared/3a5ne750.js";
4
+ import {
5
+ addSchemaHook
6
+ } from "../../shared/7mht49yd.js";
7
+ import {
8
+ queryHandle
9
+ } from "../../shared/mxmcdsh5.js";
10
+ import {
11
+ OkmError2
12
+ } from "../../shared/52szzakm.js";
13
+
14
+ // src/runtime/validate/load.ts
15
+ var engine;
16
+ function loadEngine() {
17
+ engine ??= import("../../shared/n47rd821.js");
18
+ return engine;
19
+ }
20
+
21
+ // src/runtime/validate/hook.ts
22
+ var VALIDATION_HOOK = 1;
23
+ function attachValidation(target, ctx) {
24
+ if (attachValidation["~v"] !== VALIDATION_HOOK)
25
+ return;
26
+ const name = ctx.table;
27
+ const session = ctx.session;
28
+ const schema = session?.schema;
29
+ if (name === undefined || schema === undefined)
30
+ return;
31
+ const source = schema.tables.find((item) => item.name === name);
32
+ const model = schema.model[name];
33
+ if (source === undefined || model === undefined || validationGate(schema.validation, source) === undefined) {
34
+ return;
35
+ }
36
+ const insert = target.insert;
37
+ const update = target.update;
38
+ if (typeof insert !== "function" || typeof update !== "function")
39
+ return;
40
+ const wrapped = guardWrite(insert, "insert", model, source, schema.validation);
41
+ wrapped.validate = (body) => stand(model, source, schema.validation, "insert", body, "valid");
42
+ wrapped.check = (body) => stand(model, source, schema.validation, "insert", body, "check");
43
+ wrapped.pick = (...keys) => ({
44
+ validate: (body) => stand(model, source, schema.validation, "insert", body, "valid", keys),
45
+ check: (body) => stand(model, source, schema.validation, "insert", body, "check", keys)
46
+ });
47
+ wrapped.omit = (...keys) => ({
48
+ validate: (body) => stand(model, source, schema.validation, "insert", body, "valid", undefined, keys),
49
+ check: (body) => stand(model, source, schema.validation, "insert", body, "check", undefined, keys)
50
+ });
51
+ wrapped["~standard"] = {
52
+ version: 1,
53
+ vendor: "okmodel",
54
+ async validate(value) {
55
+ try {
56
+ return {
57
+ value: await stand(model, source, schema.validation, "insert", value, "valid")
58
+ };
59
+ } catch (error) {
60
+ if (error instanceof OkmError2 && error.issues !== undefined)
61
+ return { issues: error.issues };
62
+ throw error;
63
+ }
64
+ }
65
+ };
66
+ target.insert = wrapped;
67
+ const wrappedUpdate = guardWrite(update, "update", model, source, schema.validation);
68
+ wrappedUpdate.validate = (body) => stand(model, source, schema.validation, "update", body, "valid");
69
+ target.update = wrappedUpdate;
70
+ }
71
+ function stand(model, source, schemaFlag, op, body, mode, pick, omit) {
72
+ return loadEngine().then((mod) => mod.stand(model, source, schemaFlag, op, body, mode, pick, omit));
73
+ }
74
+ function guardWrite(original, op, model, source, schemaFlag) {
75
+ const wrapped = (data, options = {}) => {
76
+ const rest = dropValidate(options);
77
+ if (skipped(options))
78
+ return original(data, rest);
79
+ return chain((ok, fail) => {
80
+ loadEngine().then((mod) => {
81
+ mod.prepare(model, source, schemaFlag, op, data).then((next) => ok(original(next, rest)), fail);
82
+ }, fail);
83
+ });
84
+ };
85
+ return wrapped;
86
+ }
87
+ function chain(start) {
88
+ let slot;
89
+ let pending;
90
+ const ready = () => {
91
+ pending ??= new Promise((resolve, reject) => {
92
+ start((handle) => {
93
+ slot = handle;
94
+ resolve();
95
+ }, reject);
96
+ });
97
+ return pending;
98
+ };
99
+ const taken = () => {
100
+ if (slot === undefined)
101
+ throw new Error("Validation did not produce a write.");
102
+ return slot;
103
+ };
104
+ return queryHandle(() => ready().then(() => taken()), {
105
+ sql: () => ready().then(() => taken().sql()),
106
+ expect(count) {
107
+ return chain((ok, fail) => {
108
+ ready().then(() => ok(taken().expect(count)), fail);
109
+ });
110
+ },
111
+ all(reason) {
112
+ return chain((ok, fail) => {
113
+ ready().then(() => ok(taken().all(reason)), fail);
114
+ });
115
+ }
116
+ });
117
+ }
118
+ attachValidation["~v"] = VALIDATION_HOOK;
119
+ function skipped(options) {
120
+ return options.validate === false;
121
+ }
122
+ function dropValidate(options) {
123
+ if (!("validate" in options))
124
+ return options;
125
+ const record = options;
126
+ const { validate: _drop, ...rest } = record;
127
+ return rest;
128
+ }
129
+
130
+ // src/runtime/validate/bind.ts
131
+ var armed = false;
132
+ function armValidation() {
133
+ if (armed)
134
+ return;
135
+ armed = true;
136
+ addSchemaHook(attachValidation);
137
+ }
138
+
139
+ // src/runtime/validate/rules.ts
140
+ var v = {
141
+ trim() {
142
+ armValidation();
143
+ return { k: "trim" };
144
+ },
145
+ lowercase() {
146
+ armValidation();
147
+ return { k: "lower" };
148
+ },
149
+ email(key) {
150
+ armValidation();
151
+ return { k: "email", key };
152
+ },
153
+ min(n, key) {
154
+ armValidation();
155
+ return { k: "min", n, key };
156
+ },
157
+ rule(fn, path, key) {
158
+ armValidation();
159
+ return { k: "rule", fn, path, key };
160
+ },
161
+ onInsert(rule) {
162
+ armValidation();
163
+ return rule === undefined ? { k: "phase", op: "insert" } : { k: "when", op: "insert", rule };
164
+ },
165
+ onUpdate(rule) {
166
+ armValidation();
167
+ return rule === undefined ? { k: "phase", op: "update" } : { k: "when", op: "update", rule };
168
+ }
169
+ };
170
+
171
+ // src/runtime/validate/index.ts
172
+ armValidation();
173
+ export {
174
+ v
175
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The only static reference to the validation engine.
3
+ *
4
+ * A no-validation app does not import this module, so its total graph does
5
+ * not include the engine chunk. A failed import rejects the call that asked
6
+ * for it, and the same promise is reused so a later call fails the same way.
7
+ */
8
+ /**
9
+ * Loads the validation engine.
10
+ *
11
+ * @returns The engine module
12
+ */
13
+ export declare function loadEngine(): Promise<typeof import("./engine.js")>;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Reads validation rules stored on a schema.
3
+ *
4
+ * `schema()` does not call this. `okm check` does, and the engine does on
5
+ * the first validated call. A field with rules in two places is OKM1030.
6
+ */
7
+ import type { ValidationModel } from "../../dialects/pg/model.js";
8
+ import type { AnyTable } from "../../dialects/pg/table.js";
9
+ /**
10
+ * Reports OKM1030 and a malformed `validate` section.
11
+ *
12
+ * A schema with no tables is left alone. The walk reads stored rules and
13
+ * does not run them.
14
+ *
15
+ * @param schema - A `schema()` result
16
+ */
17
+ export declare function assertValidation(schema: object): void;
18
+ /**
19
+ * Builds one table's validation model from the rules stored on it.
20
+ *
21
+ * Returns `undefined` when validation is off for the table. Throws OKM1030
22
+ * when a field is validated in two places, whether or not validation is on.
23
+ *
24
+ * @param schemaFlag - The schema's `validation` option, stored as given
25
+ * @param table - The table, with its column rules and `validate` section
26
+ * @returns The model, or `undefined` when this table does not validate
27
+ */
28
+ export declare function validationGate(schemaFlag: unknown, table: AnyTable): ValidationModel | undefined;
29
+ /**
30
+ * Reports whether a write on this table would run validation.
31
+ *
32
+ * True when the effective setting is on, or the table stores a `validate`
33
+ * section or an inline `.validate(...)`. A call that passes `{ validate: false }`
34
+ * would not. This does not run the rules and does not report OKM1030.
35
+ *
36
+ * @param schemaFlag - The schema `validation` option, stored as given
37
+ * @param table - The table, with its column rules and `validate` section
38
+ * @param options - Write options. `{ validate: false }` skips the call
39
+ * @returns Whether the write would validate
40
+ */
41
+ export declare function writeWouldValidate(schemaFlag: unknown, table: AnyTable, options: object): boolean;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Rule objects `v` returns.
3
+ *
4
+ * The engine interprets `k`. This module does not import the engine. Each
5
+ * rule registers the client hook so a bundled app still has it when the
6
+ * module side effect is dropped.
7
+ */
8
+ /** Trims a string. Other values are left as they are. */
9
+ export type TrimRule = {
10
+ readonly k: "trim";
11
+ };
12
+ /** Lowercases a string. Other values are left as they are. */
13
+ export type LowerRule = {
14
+ readonly k: "lower";
15
+ };
16
+ /** Rejects a string that is not an email. `key` is the issue message. */
17
+ export type EmailRule = {
18
+ readonly k: "email";
19
+ readonly key: string;
20
+ };
21
+ /** Minimum string length or number. `key` is the issue message. */
22
+ export type MinRule = {
23
+ readonly k: "min";
24
+ readonly n: number;
25
+ readonly key: string;
26
+ };
27
+ /** A caller predicate. `false` records `key` at `path`. */
28
+ export type PredicateRule = {
29
+ readonly k: "rule";
30
+ readonly fn: (value: unknown) => boolean;
31
+ readonly path: string;
32
+ readonly key: string;
33
+ };
34
+ /** Runs the inner rule only on insert or only on update. */
35
+ export type WhenRule = {
36
+ readonly k: "when";
37
+ readonly op: "insert" | "update";
38
+ readonly rule: unknown;
39
+ };
40
+ /** Following rules in the same list run only on this operation, until the next phase. */
41
+ export type PhaseRule = {
42
+ readonly k: "phase";
43
+ readonly op: "insert" | "update";
44
+ };
45
+ /** One object `v` can return. */
46
+ export type Rule = TrimRule | LowerRule | EmailRule | MinRule | PredicateRule | WhenRule | PhaseRule;
47
+ /**
48
+ * Validation rules.
49
+ *
50
+ * Transforms (`trim`, `lowercase`) run before checks. `onInsert()` and
51
+ * `onUpdate()` with no argument scope the rules that follow them in the same
52
+ * list. Passed a rule, they scope that rule only.
53
+ */
54
+ export declare const v: {
55
+ /**
56
+ * Removes leading and trailing whitespace from a string.
57
+ *
58
+ * @returns A transform rule
59
+ */
60
+ trim(): TrimRule;
61
+ /**
62
+ * Lowercases a string.
63
+ *
64
+ * @returns A transform rule
65
+ */
66
+ lowercase(): LowerRule;
67
+ /**
68
+ * Requires an email address.
69
+ *
70
+ * @param key - Issue message key
71
+ * @returns A check rule
72
+ */
73
+ email(key: string): EmailRule;
74
+ /**
75
+ * Requires a string at least `n` characters long, or a number at least `n`.
76
+ *
77
+ * @param n - Minimum length or value
78
+ * @param key - Issue message key
79
+ * @returns A check rule
80
+ */
81
+ min(n: number, key: string): MinRule;
82
+ /**
83
+ * Records `key` at `path` when `fn` returns false.
84
+ *
85
+ * On a field, `fn` receives the field value. In `$row`, it receives the row
86
+ * after field transforms.
87
+ *
88
+ * @param fn - Predicate. `true` accepts the value
89
+ * @param path - Issue path segment
90
+ * @param key - Issue message key
91
+ * @returns A check rule
92
+ */
93
+ rule<T>(fn: (value: T) => boolean, path: string, key: string): PredicateRule;
94
+ /**
95
+ * Limits a rule, or the rules that follow, to insert.
96
+ *
97
+ * @param rule - One rule. Omitted, the rules after this marker are limited
98
+ * @returns A phase marker or a wrapped rule
99
+ */
100
+ onInsert(rule?: unknown): PhaseRule | WhenRule;
101
+ /**
102
+ * Limits a rule, or the rules that follow, to update.
103
+ *
104
+ * @param rule - One rule. Omitted, the rules after this marker are limited
105
+ * @returns A phase marker or a wrapped rule
106
+ */
107
+ onUpdate(rule?: unknown): PhaseRule | WhenRule;
108
+ };
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Types `okmodel/validate` adds to a table handle.
3
+ *
4
+ * Nothing here exists at runtime. `index.ts` merges these members into
5
+ * `TableExtras` with a module augmentation, so a program that never imports
6
+ * `okmodel/validate` does not see them and does not pay for them.
7
+ */
8
+ import type { ValidationIssue } from "../../contracts/error.js";
9
+ import type { InputMark } from "../../contracts/rows.js";
10
+ import type { QuerySchema } from "../../dialects/pg/model.js";
11
+ import type { InsertOf, OptionalInsert, RequiredInsert, UpdateOf } from "../types.js";
12
+ /**
13
+ * Reads one stored `validation` option: a boolean or `{ enabled, onRead, style }`.
14
+ *
15
+ * An object without `enabled` is on, as it is at runtime.
16
+ *
17
+ * @typeParam V - The option as the caller wrote it, or `undefined`
18
+ */
19
+ type Enabled<V> = V extends true ? true : V extends {
20
+ readonly enabled: infer E;
21
+ } ? E extends true ? true : false : V extends object ? true : false;
22
+ /** The `validation` option a table's own `options` carry, or `never` when it sets none. */
23
+ type TableOption<T> = T extends {
24
+ readonly options?: infer O;
25
+ } ? O extends {
26
+ readonly validation: infer V;
27
+ } ? V : never : never;
28
+ /**
29
+ * The effective setting for one table: its own option, else the schema's.
30
+ *
31
+ * @typeParam S - Connected schema
32
+ * @typeParam K - Table name
33
+ */
34
+ export type ValidationOn<S extends QuerySchema, K extends keyof S["~byName"]> = Enabled<[
35
+ TableOption<S["~byName"][K]>
36
+ ] extends [never] ? S extends {
37
+ readonly "~validation": infer V;
38
+ } ? V : undefined : TableOption<S["~byName"][K]>>;
39
+ /** Insert shape plus {@link InputMark}. */
40
+ type Marked<S extends QuerySchema, K extends keyof S["~byName"]> = InsertOf<S, K> & InputMark;
41
+ /**
42
+ * One insert body, with optional columns left optional and the input mark.
43
+ *
44
+ * Guarded fields and the tenant key are already absent from the shape.
45
+ *
46
+ * @typeParam S - Connected schema
47
+ * @typeParam K - Table name
48
+ */
49
+ export type InputBody<S extends QuerySchema, K extends keyof S["~byName"]> = RequiredInsert<Marked<S, K>> & OptionalInsert<Marked<S, K>>;
50
+ /** What `validate()` accepts: one body, or a list. */
51
+ type Bodies<S extends QuerySchema, K extends keyof S["~byName"]> = InputBody<S, K> | readonly Marked<S, K>[];
52
+ /**
53
+ * Members `insert` gains when this table validates.
54
+ *
55
+ * @typeParam S - Connected schema
56
+ * @typeParam K - Table name
57
+ */
58
+ export type ValidateInsert<S extends QuerySchema, K extends keyof S["~byName"]> = ValidationOn<S, K> extends true ? {
59
+ /**
60
+ * Checks one row or a list and returns it frozen.
61
+ *
62
+ * A later insert of that value skips these rules.
63
+ */
64
+ validate<const T extends Bodies<S, K>>(body: T): Promise<T>;
65
+ /** The same checks. Issues come back instead of OKM1200. */
66
+ check(body: unknown): Promise<readonly ValidationIssue[]>;
67
+ /** Validates only these fields. */
68
+ pick<const F extends readonly (keyof InsertOf<S, K> & string)[]>(...fields: F): {
69
+ validate(body: unknown): Promise<Pick<InsertOf<S, K>, F[number]> & InputMark>;
70
+ check(body: unknown): Promise<readonly ValidationIssue[]>;
71
+ };
72
+ /** Validates every field except these. */
73
+ omit<const F extends readonly (keyof InsertOf<S, K> & string)[]>(...fields: F): {
74
+ validate(body: unknown): Promise<Omit<InsertOf<S, K>, F[number]> & InputMark>;
75
+ check(body: unknown): Promise<readonly ValidationIssue[]>;
76
+ };
77
+ /** Standard Schema. Issues are returned. Other errors still throw. */
78
+ readonly "~standard": {
79
+ readonly version: 1;
80
+ readonly vendor: "okmodel";
81
+ validate(value: unknown): Promise<{
82
+ readonly value: unknown;
83
+ } | {
84
+ readonly issues: readonly ValidationIssue[];
85
+ }>;
86
+ };
87
+ } : unknown;
88
+ /** A patch: any subset of the update shape, plus {@link InputMark}. */
89
+ type Patch<S extends QuerySchema, K extends keyof S["~byName"]> = Partial<UpdateOf<S, K>> & InputMark;
90
+ /**
91
+ * Members `update` gains when this table validates.
92
+ *
93
+ * @typeParam S - Connected schema
94
+ * @typeParam K - Table name
95
+ */
96
+ export type ValidateUpdate<S extends QuerySchema, K extends keyof S["~byName"]> = ValidationOn<S, K> extends true ? {
97
+ /** Checks a patch. A `{ set }` body checks `set`. */
98
+ validate<const T extends Patch<S, K> | {
99
+ readonly set: Patch<S, K>;
100
+ }>(body: T): Promise<T>;
101
+ } : unknown;
102
+ export {};
@@ -4,8 +4,12 @@
4
4
  * Loaded on the first write. Conflict SQL loads only when `onConflict` is not
5
5
  * `"error"`. Chunked writes go through the internal transaction runner.
6
6
  */
7
- import type { DriverPool, Statement } from "../contracts/driver.js";
7
+ import type { ExecuteOptions, ExecuteResult, Statement } from "../contracts/driver.js";
8
+ import type { IdGenerators } from "../contracts/generator.js";
9
+ import type { PresetUse } from "../dialects/pg/model.js";
8
10
  import type { QuerySchema } from "../dialects/pg/model.js";
11
+ import { type ArchiveView, type CallScope } from "./plan.js";
12
+ import { type RunHost } from "./tx.js";
9
13
  /** Statements in one insert stay under this many parameters. The protocol limit is 65535. */
10
14
  export declare const WRITE_PARAM_BUDGET = 2048;
11
15
  /** A write the caller asked for. */
@@ -14,11 +18,29 @@ export type WriteOp = "insert" | "update" | "delete";
14
18
  export type WriteMods = {
15
19
  readonly all?: string;
16
20
  readonly expect?: number;
21
+ readonly archive?: ArchiveView | undefined;
22
+ /** Presets chained on the handle. `planWrite` resolves them into `presets`. */
23
+ readonly uses?: PresetUse | undefined;
24
+ /** Filters the chained presets added. Joined after each `where` with AND. */
25
+ readonly presets?: readonly unknown[];
17
26
  };
18
27
  /** Pool and schema for one client. The client maps driver errors. */
19
- export type WriteHost = {
28
+ export type WriteHost = RunHost & {
20
29
  readonly schema: QuerySchema;
21
- readonly pool: DriverPool;
30
+ readonly generators?: IdGenerators | undefined;
31
+ };
32
+ /**
33
+ * A planned write: its statements, and what turns their results into the value.
34
+ *
35
+ * `batch` flattens the statements of many operations into one atomic unit and
36
+ * gives each operation back its own slice of the results.
37
+ */
38
+ export type PreparedWrite = {
39
+ readonly statements: readonly Statement[];
40
+ readonly options: ExecuteOptions | undefined;
41
+ /** Set when `finish` can refuse a statement that already ran. `batch` refuses such a write (D183). */
42
+ readonly checked?: "restore" | "expect";
43
+ finish(results: readonly ExecuteResult[]): unknown;
22
44
  };
23
45
  /**
24
46
  * Runs a write and decodes it.
@@ -29,9 +51,11 @@ export type WriteHost = {
29
51
  * @param input - Rows, or the update or delete target
30
52
  * @param options - Returning, conflict, expect, signal, timeout
31
53
  * @param mods - `.all` and `.expect`
54
+ * @param scope - Tenant scope of the client
55
+ * @param plan - Return the {@link PreparedWrite} without running it, for `batch`
32
56
  * @returns Rows, one row, or `{ count }`
33
57
  */
34
- export declare function executeWrite(host: WriteHost, op: WriteOp, table: string, input: unknown, options: object, mods: WriteMods): Promise<unknown>;
58
+ export declare function executeWrite(host: WriteHost, op: WriteOp, table: string, input: unknown, options: object, mods: WriteMods, scope?: CallScope, plan?: true): Promise<unknown>;
35
59
  /**
36
60
  * Plans a write and does not run it.
37
61
  *
@@ -41,8 +65,9 @@ export declare function executeWrite(host: WriteHost, op: WriteOp, table: string
41
65
  * @param input - Rows, or the update or delete target
42
66
  * @param options - Returning, conflict, expect, signal, timeout
43
67
  * @param mods - `.all` and `.expect`
68
+ * @param generators - Built-in replacements. Omitted uses the functions stored on the columns
44
69
  * @returns The statements in order
45
70
  */
46
- export declare function explainWrite(schema: QuerySchema, op: WriteOp, table: string, input: unknown, options: object, mods: WriteMods): Promise<{
71
+ export declare function explainWrite(schema: QuerySchema, op: WriteOp, table: string, input: unknown, options: object, mods: WriteMods, generators?: IdGenerators, scope?: CallScope): Promise<{
47
72
  readonly statements: readonly Statement[];
48
73
  }>;
@@ -9,7 +9,7 @@ import {
9
9
  runCall,
10
10
  EMPTY_NOTICES,
11
11
  resultFrom
12
- } from "./xy79j5hq.js";
12
+ } from "./9k6vetvf.js";
13
13
 
14
14
  // src/adapters/pg/pglite.ts
15
15
  import { PGlite } from "@electric-sql/pglite";
@@ -48,7 +48,7 @@ async function open3(config = {}) {
48
48
  return {
49
49
  execute: (text, params, options) => runCall(closed, options, (watch) => session.query(text, params, watch)),
50
50
  batch: (statements, options) => runCall(closed, options, async (watch) => {
51
- const { runAtomicBatch } = await import("./dynq16vb.js");
51
+ const { runAtomicBatch } = await import("./b066g80h.js");
52
52
  return runAtomicBatch(session, statements, watch);
53
53
  }),
54
54
  async release() {
@@ -0,0 +1,26 @@
1
+ import {
2
+ OkmError2
3
+ } from "./52szzakm.js";
4
+
5
+ // src/dialects/pg/filter-parse.ts
6
+ function parseQuery(allow, sort, query) {
7
+ if (typeof query !== "object" || query === null || Array.isArray(query)) {
8
+ throw new OkmError2("OKM1121", "filters parse expects an object of fields.");
9
+ }
10
+ const where = {};
11
+ let orderBy;
12
+ for (const key of Object.keys(query)) {
13
+ const value = query[key];
14
+ if (key === "sort" && typeof value === "string" && sort.includes(value)) {
15
+ orderBy = { [value]: "asc" };
16
+ continue;
17
+ }
18
+ if (allow[key]?.includes("eq") === true && (value === null || typeof value !== "object")) {
19
+ where[key] = value;
20
+ }
21
+ }
22
+ return orderBy === undefined ? { where } : { where, orderBy };
23
+ }
24
+ export {
25
+ parseQuery
26
+ };