okmodel 0.1.1 → 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 +32 -16
  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 +376 -27
  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/{xqbhg6cn.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/{x5x59srr.js → 4jzzghr6.js} +416 -83
  117. package/dist/shared/{ycwz42az.js → 52szzakm.js} +6 -26
  118. package/dist/shared/{05w44d8g.js → 5z4q2zda.js} +567 -18
  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/{523ft3e8.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/{kprcwaha.js → eaxwrgby.js} +4 -3
  137. package/dist/shared/{dkn3y60a.js → ecdzej21.js} +76 -112
  138. package/dist/shared/{hadrfb9h.js → edwqqryd.js} +17 -14
  139. package/dist/shared/{m3ypagh5.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/{yd1kzwn2.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/{jjb7yht9.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/{rgs0st28.js → xrfnq5k8.js} +237 -434
  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 +41 -4
  181. package/dist/shared/gk7cs7sp.js +0 -566
@@ -1,15 +1,31 @@
1
1
  /**
2
2
  * UUID keys.
3
3
  */
4
- import { type ColumnBuilder, type IdFlags, type PlainFlags } from "./column.js";
4
+ import { type ClientGenerator } from "../../contracts/generator.js";
5
+ import { type ColumnBuilder, type IdFlags, type IdSuppliedFlags, type PlainFlags } from "./column.js";
6
+ /** How {@link id} fills the primary key. */
7
+ export type IdDefault = "uuidv7" | "uuidv4" | "none";
5
8
  /**
6
- * UUID primary key with default `uuidv7()`.
9
+ * Primary key.
7
10
  *
8
- * Insert and update omit it, and it is guarded.
11
+ * With no options, the database default is `uuidv7()` unless
12
+ * `schema({ defaults: { id } })` says otherwise. `uuidv4` stores
13
+ * `gen_random_uuid()` (built in from Postgres 13). `none` takes the id on
14
+ * insert. A client generator (`uuidv4`, `uuidv7`, or `okid(...)` from
15
+ * `okmodel/ids`) is filled on insert and stored with no database default.
16
+ * OKID is `text` with collation `C`. A database default is omitted from
17
+ * insert and update. `none` is required on insert and omitted from update.
9
18
  *
19
+ * @param options - Which default to store. Omitted means the schema default, or `uuidv7()`
10
20
  * @returns An id column
11
21
  */
12
22
  export declare function id(): ColumnBuilder<string, IdFlags>;
23
+ export declare function id(options: {
24
+ readonly default: "none";
25
+ }): ColumnBuilder<string, IdSuppliedFlags>;
26
+ export declare function id(options: {
27
+ readonly default: "uuidv7" | "uuidv4" | ClientGenerator<string>;
28
+ }): ColumnBuilder<string, IdFlags>;
13
29
  /**
14
30
  * UUID text, with no default.
15
31
  *
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * `schema()` fills it once. Query planning does not walk column builders again.
5
5
  */
6
+ import type { ClientFill } from "../../contracts/generator.js";
6
7
  /** One column the planner can filter, select, decode, and write. */
7
8
  export type ColumnModel = {
8
9
  /** Field name. */
@@ -20,12 +21,42 @@ export type ColumnModel = {
20
21
  * call a codec it does not need.
21
22
  */
22
23
  readonly decode: ((wire: string) => unknown) | undefined;
23
- /** Excluded from a default select. Named selects still return it. */
24
+ /** Excluded from a default select. Named selects still return it. Includes never return it. */
24
25
  readonly hidden: boolean;
25
- /** Refused when present in insert or update input. */
26
+ /**
27
+ * Redacted in logs, errors, and `inspect()`.
28
+ *
29
+ * A selected read still returns the value.
30
+ */
31
+ readonly sensitive: boolean;
32
+ /** Refused when present in insert or update input, unless `{ allow }` names it. */
26
33
  readonly guarded: boolean;
27
34
  /** Included in insert and update. Guarded, generated, and omitted columns are not. */
28
35
  readonly writable: boolean;
36
+ /** Refused on update. Insert may still set it. A caller-supplied primary key. */
37
+ readonly guardUpdate: boolean;
38
+ /**
39
+ * Catalog-output label for a client default.
40
+ *
41
+ * The hashed catalog does not store it. Changing the generator does not
42
+ * change the catalog hash.
43
+ */
44
+ readonly clientDefault?: "client";
45
+ /** Called once per inserted row when the field is omitted. */
46
+ readonly fill?: ClientFill;
47
+ /**
48
+ * Encodes one array element.
49
+ *
50
+ * Present on array columns. `arr.append` and `arr.remove` use it.
51
+ */
52
+ readonly elementEncode?: (value: unknown) => string;
53
+ /**
54
+ * Object kinds the codec takes as input, named by `Object.prototype.toString`.
55
+ *
56
+ * Absent when the codec takes only scalars; the planner then rejects every
57
+ * object for the column (OKM1121).
58
+ */
59
+ readonly accepts?: readonly string[] | undefined;
29
60
  };
30
61
  /**
31
62
  * A resolved relation.
@@ -41,6 +72,89 @@ export type RelationModel = {
41
72
  readonly local: readonly string[];
42
73
  /** SQL names on the related table. */
43
74
  readonly remote: readonly string[];
75
+ /**
76
+ * Set on a `manyThrough` relation.
77
+ *
78
+ * `local` and `remote` then join the join table to this table: `remote` names
79
+ * columns of the join table. The pairs below join the join table to `table`.
80
+ */
81
+ readonly through?: {
82
+ /** Join table, by its TypeScript name. */
83
+ readonly table: string;
84
+ /** SQL names on the join table. */
85
+ readonly local: readonly string[];
86
+ /** SQL names on the related table. */
87
+ readonly remote: readonly string[];
88
+ /**
89
+ * Writes the join-table source and its link to the parent.
90
+ *
91
+ * The relation carries its own emitter, so a schema without `manyThrough`
92
+ * does not ship it. The planner passes its helpers in.
93
+ */
94
+ readonly emit: ThroughEmit;
95
+ };
96
+ };
97
+ /** Where a planner writes SQL text and statement marks. */
98
+ export type RelationSink = {
99
+ text(value: string): void;
100
+ param(encoded: string): void;
101
+ mark(token: string): void;
102
+ };
103
+ /** A table with its columns and relations indexed by name, as the planner holds it. */
104
+ export type PlannedTable = {
105
+ readonly model: TableModel;
106
+ readonly columns: ReadonlyMap<string, ColumnModel>;
107
+ readonly relations: ReadonlyMap<string, RelationModel>;
108
+ readonly names: readonly string[];
109
+ };
110
+ /** The planner helpers a relation emitter calls. */
111
+ export type RelationPlanner = {
112
+ /** Writes `child.remote = parent.local` for each key column. */
113
+ readonly join: (sink: RelationSink, parent: string, child: string, relation: RelationModel) => void;
114
+ /** Writes `where` predicates, including tenancy and active-set ones, for a table. */
115
+ readonly where: (schema: QuerySchema, table: PlannedTable, where: unknown, sink: RelationSink, alias: string, depth: number, appended: boolean) => void;
116
+ /** Indexes a schema's tables by TypeScript name. */
117
+ readonly indexes: (schema: QuerySchema) => ReadonlyMap<string, PlannedTable>;
118
+ /** Quotes an identifier. */
119
+ readonly quote: (name: string) => string;
120
+ };
121
+ /**
122
+ * Writes `<join> <alias> join <table> ... where <link to parent>` for a
123
+ * `manyThrough` relation. The caller adds the related table's own predicates.
124
+ */
125
+ export type ThroughEmit = (planner: RelationPlanner, schema: QuerySchema, relation: RelationModel, child: PlannedTable, sink: RelationSink, parent: string, alias: string, depth: number) => void;
126
+ /**
127
+ * One foreign key the archive path follows.
128
+ *
129
+ * `local` and `remote` are SQL names, in the same order. `at` and `id` are
130
+ * the other table's archive columns.
131
+ */
132
+ export type ArchiveLink = {
133
+ readonly table: string;
134
+ readonly sql: string;
135
+ readonly at: string;
136
+ readonly id: string;
137
+ readonly local: readonly string[];
138
+ readonly remote: readonly string[];
139
+ };
140
+ /**
141
+ * Archive columns and the children and parents resolved at schema time.
142
+ *
143
+ * Absent when the table is not archivable, so a normal table does not carry it.
144
+ */
145
+ export type ArchiveModel = {
146
+ /** SQL name of `archivedAt`. */
147
+ readonly at: string;
148
+ /** SQL name of `archiveId`. */
149
+ readonly id: string;
150
+ /** Field name of `archivedAt`. */
151
+ readonly atField: string;
152
+ /** Field name of `archiveId`. */
153
+ readonly idField: string;
154
+ /** Children archived and restored with this row. */
155
+ readonly cascade: readonly ArchiveLink[];
156
+ /** Archivable tables this row references. Restore refuses an archived one. */
157
+ readonly parents: readonly ArchiveLink[];
44
158
  };
45
159
  /** One table, keyed by its TypeScript name on the schema. */
46
160
  export type TableModel = {
@@ -56,7 +170,106 @@ export type TableModel = {
56
170
  readonly uniques: readonly (readonly string[])[];
57
171
  readonly columns: readonly ColumnModel[];
58
172
  readonly relations: readonly RelationModel[];
173
+ /**
174
+ * Traits that apply to this table.
175
+ *
176
+ * Absent when it has none. Writes read `touch` and `sealed` from here.
177
+ */
178
+ readonly traits?: readonly {
179
+ readonly name: string;
180
+ readonly touch?: readonly string[];
181
+ readonly sealed?: readonly string[];
182
+ }[];
183
+ /**
184
+ * A column is hidden or sensitive.
185
+ *
186
+ * Absent when none are, so a normal table does not carry the flag.
187
+ */
188
+ readonly conceal?: true;
189
+ /**
190
+ * `file.ts:line` where the table was defined.
191
+ *
192
+ * Absent on a catalog loaded from a build artifact. Not part of the hash.
193
+ */
194
+ readonly source?: string;
195
+ /**
196
+ * Archive columns, cascade, and parent links.
197
+ *
198
+ * Absent when the table is not archivable.
199
+ */
200
+ readonly archive?: ArchiveModel;
201
+ /**
202
+ * The table's presets by name: its own and its traits', merged.
203
+ *
204
+ * Absent when it has none, so a normal table does not carry the key. The
205
+ * values are the author's functions; the preset module runs them.
206
+ */
207
+ readonly presets?: Readonly<Record<string, unknown>>;
208
+ /**
209
+ * Validation for this table.
210
+ *
211
+ * Absent until the engine fills it on the first validated call. `schema()`
212
+ * does not pack it, so a featureless table never carries it.
213
+ */
214
+ readonly validation?: ValidationModel;
59
215
  };
216
+ /**
217
+ * Rules and derived checks for one table.
218
+ *
219
+ * Field rules and picklists are stored here. Column codecs stay on {@link ColumnModel}.
220
+ */
221
+ export type ValidationModel = {
222
+ /** Run the same checks on read results. Stored for a later step. */
223
+ readonly onRead: boolean;
224
+ /** Cross-field rules from `validate.$row`, in source order. */
225
+ readonly row: readonly unknown[];
226
+ /** Per-field rules. Absent fields have none. */
227
+ readonly fields: Readonly<Record<string, readonly unknown[]>>;
228
+ /** Insert must include these fields. */
229
+ readonly required: readonly string[];
230
+ /** `null` is rejected. Includes columns that have a default. */
231
+ readonly notNull: readonly string[];
232
+ /** Picklist values, keyed by field. Absent fields have no list. */
233
+ readonly pick: Readonly<Record<string, readonly string[]>>;
234
+ };
235
+ /**
236
+ * One opt-in feature attaching methods to the client or a table handle.
237
+ *
238
+ * Tenancy supplies `for()` and `unscoped()`. Archivable supplies `archive()`,
239
+ * `restore()`, `withArchived()`, and `onlyArchived()`. Core only calls the list.
240
+ */
241
+ export type SchemaHook = (target: Record<string, unknown>, ctx: SchemaHookCtx) => void;
242
+ /**
243
+ * What the client passes to a {@link SchemaHook}.
244
+ *
245
+ * A client-level call sets `tables`. A table-level call sets `table`.
246
+ */
247
+ export type SchemaHookCtx = {
248
+ readonly names?: readonly string[];
249
+ readonly tables?: Record<string, unknown>;
250
+ readonly scoped?: boolean;
251
+ readonly open?: (scope: {
252
+ readonly value: string;
253
+ } | {
254
+ readonly unscoped: string;
255
+ }) => unknown;
256
+ readonly table?: string;
257
+ readonly view?: "with" | "only";
258
+ /** The last preset chained on this handle. Absent when none is. */
259
+ readonly uses?: PresetUse | undefined;
260
+ readonly reopen?: (view?: "with" | "only") => Record<string, unknown>;
261
+ readonly session?: object;
262
+ };
263
+ /**
264
+ * One preset call on a table handle: the call before it, its name, and its arguments.
265
+ *
266
+ * A chain is a linked list, newest first, so adding a call allocates one tuple.
267
+ */
268
+ export type PresetUse = readonly [
269
+ before: PresetUse | undefined,
270
+ name: string,
271
+ args: readonly unknown[]
272
+ ];
60
273
  /** Schema fields the read path and `connect()` read. */
61
274
  export type QuerySchema = {
62
275
  readonly "~byName": {
@@ -68,4 +281,12 @@ export type QuerySchema = {
68
281
  readonly requires?: {
69
282
  readonly postgres?: string;
70
283
  } | undefined;
284
+ /** Column tenancy, when the schema set it. The methods live on that object. */
285
+ readonly tenancy?: import("./tenancy.js").ColumnTenancy;
286
+ /**
287
+ * Opt-in methods for the client and table handles.
288
+ *
289
+ * Absent when the schema uses none, so a featureless app does not carry the key.
290
+ */
291
+ readonly hooks?: readonly SchemaHook[];
71
292
  };
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Which operators a column type accepts (spec §10.1).
3
+ *
4
+ * The read and write paths share this check. A mismatch is OKM1124 and names
5
+ * the column type and the operators it accepts. Values stay parameters.
6
+ * A path, key, or regconfig that would be interpolated is checked here first.
7
+ */
8
+ /** Column family the operator table uses. */
9
+ export type OperatorFamily = "text" | "array" | "json" | "jsonb" | "range" | "tsvector" | "scalar";
10
+ /**
11
+ * Classifies a catalog type.
12
+ *
13
+ * @param dataType - Column `dataType`
14
+ * @returns The operator family
15
+ */
16
+ export declare function columnFamily(dataType: string): OperatorFamily;
17
+ /**
18
+ * Rejects an operator the column type does not accept.
19
+ *
20
+ * Operators with no entry in the fit table (equality, comparisons on a scalar)
21
+ * are left to the caller.
22
+ *
23
+ * @param column - Field name and catalog type
24
+ * @param name - Operator name
25
+ */
26
+ export declare function assertOperatorFits(column: {
27
+ readonly field: string;
28
+ readonly dataType: string;
29
+ }, name: string): void;
30
+ /**
31
+ * Returns a catalog type that is safe to place in SQL, or throws.
32
+ *
33
+ * @param dataType - Column type from the catalog
34
+ * @param column - Field name, for the error
35
+ * @returns `dataType` when it matches the type pattern
36
+ */
37
+ export declare function sqlType(dataType: string, column: {
38
+ readonly field: string;
39
+ readonly dataType: string;
40
+ }): string;
41
+ /**
42
+ * Rejects NUL and other control characters.
43
+ *
44
+ * An empty string is allowed. {@link assertBoundText} rejects that too.
45
+ *
46
+ * @param value - Text that will be bound
47
+ * @param role - What the string is, used in the error
48
+ */
49
+ export declare function assertNoControl(value: string, role: string): void;
50
+ /**
51
+ * Rejects an empty string, NUL, and other control characters in a key or path segment.
52
+ *
53
+ * These strings are bound, and a control character still fails before the
54
+ * statement is sent.
55
+ *
56
+ * @param value - Key or segment
57
+ * @param role - What the string is, used in the error
58
+ */
59
+ export declare function assertBoundText(value: string, role: string): void;
60
+ /**
61
+ * Rejects a regconfig name that is not an identifier.
62
+ *
63
+ * @param config - Text search configuration
64
+ */
65
+ export declare function assertRegconfig(config: string): void;
66
+ /**
67
+ * Encodes path segments or keys as a Postgres text-array literal.
68
+ *
69
+ * The literal is a parameter, not SQL text.
70
+ *
71
+ * @param values - Segments or keys
72
+ * @param role - What each string is
73
+ * @returns A `{...}` literal
74
+ */
75
+ export declare function textArray(values: readonly string[], role: string): string;
76
+ /**
77
+ * Element type of an array catalog type, safe to splice into SQL.
78
+ *
79
+ * @param dataType - Array type such as `text[]`
80
+ * @param column - Field name, for the error
81
+ * @returns The type with one `[]` removed
82
+ */
83
+ export declare function arrayElementType(dataType: string, column: {
84
+ readonly field: string;
85
+ readonly dataType: string;
86
+ }): string;
@@ -7,7 +7,7 @@
7
7
  declare const brand: unique symbol;
8
8
  declare const RUNTIME: unique symbol;
9
9
  /** Operator names the read path compiles. */
10
- export type OperatorName = "eq" | "lt" | "lte" | "gt" | "gte" | "between" | "startsWith" | "contains" | "endsWith" | "like" | "ilike" | "inList" | "notIn" | "not" | "or" | "has" | "none" | "every" | "inc";
10
+ export type OperatorName = "eq" | "lt" | "lte" | "gt" | "gte" | "between" | "startsWith" | "contains" | "endsWith" | "like" | "ilike" | "inList" | "notIn" | "not" | "or" | "and" | "has" | "none" | "every" | "inc" | "containedBy" | "overlaps" | "hasKey" | "hasAnyKey" | "path" | "matches" | "json.set" | "arr.append" | "arr.remove";
11
11
  /** A tagged operator. `value` is the operand the helper stored. */
12
12
  export type Tagged<Name extends OperatorName, V> = {
13
13
  readonly [brand]: Name;
@@ -21,6 +21,44 @@ export type Compare<Name extends "lt" | "lte" | "gt" | "gte", V> = Tagged<Name,
21
21
  export type Between<V> = Tagged<"between", readonly [V, V]>;
22
22
  /** A literal pattern. `%`, `_`, and `\` in the value are escaped. */
23
23
  export type Pattern<Name extends "startsWith" | "contains" | "endsWith"> = Tagged<Name, string>;
24
+ /** Array, jsonb, or range containment (`@>` or `<@`). */
25
+ export type Containment<Name extends "contains" | "containedBy", V> = Tagged<Name, V>;
26
+ /** Array or range overlap (`&&`). */
27
+ export type Overlaps<V> = Tagged<"overlaps", V>;
28
+ /** One jsonb key (`jsonb_exists`). */
29
+ export type HasKey = Tagged<"hasKey", string>;
30
+ /** Any of these jsonb keys (`jsonb_exists_any`). */
31
+ export type HasAnyKey = Tagged<"hasAnyKey", readonly string[]>;
32
+ /** A comparison applied to a json path (`#>>`). */
33
+ export type PathCompare<V> = Eq<V> | Compare<"lt" | "lte" | "gt" | "gte", V>;
34
+ /** Path segments and the comparison applied to the extracted text. */
35
+ export type PathValue<V> = {
36
+ readonly segments: readonly string[];
37
+ readonly op: PathCompare<V>;
38
+ };
39
+ /** `col #>> segments` compared with `op`. */
40
+ export type Path<V extends string | number | boolean> = Tagged<"path", PathValue<V>>;
41
+ /** How `matches` turns query text into a tsquery. */
42
+ export type MatchMode = "websearch" | "plain" | "phrase";
43
+ /** Full-text query. `config` is a regconfig name when set. */
44
+ export type MatchValue = {
45
+ readonly query: string;
46
+ readonly mode: MatchMode;
47
+ readonly config: string | undefined;
48
+ };
49
+ /** `@@` against a tsvector column. */
50
+ export type Matches = Tagged<"matches", MatchValue>;
51
+ /** `jsonb_set` path and the new value. */
52
+ export type JsonSetValue<V> = {
53
+ readonly path: readonly string[];
54
+ readonly value: V;
55
+ };
56
+ /** Atomic JSON path write (`json.set`). */
57
+ export type JsonSet<V> = Tagged<"json.set", JsonSetValue<V>>;
58
+ /** `array_append` of one element. */
59
+ export type ArrAppend<V> = Tagged<"arr.append", V>;
60
+ /** `array_remove` of one element. */
61
+ export type ArrRemove<V> = Tagged<"arr.remove", V>;
24
62
  /** A raw `LIKE` or `ILIKE` pattern. The caller owns the wildcards. */
25
63
  export type RawPattern<Name extends "like" | "ilike"> = Tagged<Name, string>;
26
64
  /** Membership. An empty list matches nothing. */
@@ -0,0 +1,9 @@
1
+ import { type ArrAppend } from "../operators.js";
2
+ /**
3
+ * Appends one element (`array_append`).
4
+ *
5
+ * @typeParam V - Element
6
+ * @param value - Element to add
7
+ * @returns A tagged operator
8
+ */
9
+ export declare function append<const V>(value: V): ArrAppend<V>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Atomic array writes.
3
+ *
4
+ * `append` and `remove` live in their own files, so importing one drops the other.
5
+ */
6
+ export { append } from "./arr-append.js";
7
+ export { remove } from "./arr-remove.js";
@@ -0,0 +1,9 @@
1
+ import { type ArrRemove } from "../operators.js";
2
+ /**
3
+ * Removes every equal element (`array_remove`).
4
+ *
5
+ * @typeParam V - Element
6
+ * @param value - Element to remove
7
+ * @returns A tagged operator
8
+ */
9
+ export declare function remove<const V>(value: V): ArrRemove<V>;
@@ -0,0 +1,9 @@
1
+ import { type Containment } from "../operators.js";
2
+ /**
3
+ * Contained by (`<@`) for an array, jsonb, or range column.
4
+ *
5
+ * @typeParam V - Operand
6
+ * @param value - Containing value
7
+ * @returns A tagged operator
8
+ */
9
+ export declare function containedBy<const V>(value: V): Containment<"containedBy", V>;
@@ -1,8 +1,12 @@
1
- import { type Pattern } from "../operators.js";
1
+ import { type Tagged } from "../operators.js";
2
2
  /**
3
- * Case-sensitive substring. `%`, `_`, and `\` in `value` are escaped.
3
+ * Substring on text, or containment (`@>`) on an array, jsonb, or range.
4
4
  *
5
- * @param value - Literal substring
5
+ * On text, `%`, `_`, and `\` in `value` are escaped. On the other types the
6
+ * value is a parameter cast to the column type.
7
+ *
8
+ * @typeParam V - Operand
9
+ * @param value - Substring or contained value
6
10
  * @returns A tagged operator
7
11
  */
8
- export declare function contains(value: string): Pattern<"contains">;
12
+ export declare function contains<const V>(value: V): Tagged<"contains", V>;
@@ -0,0 +1,8 @@
1
+ import { type HasAnyKey } from "../operators.js";
2
+ /**
3
+ * jsonb key existence for any of `keys`. Compiled as `jsonb_exists_any`.
4
+ *
5
+ * @param keys - Object keys
6
+ * @returns A tagged operator
7
+ */
8
+ export declare function hasAnyKey(keys: readonly string[]): HasAnyKey;
@@ -0,0 +1,8 @@
1
+ import { type HasKey } from "../operators.js";
2
+ /**
3
+ * jsonb key existence. Compiled as `jsonb_exists`, so `?` never enters SQL text.
4
+ *
5
+ * @param key - Object key
6
+ * @returns A tagged operator
7
+ */
8
+ export declare function hasKey(key: string): HasKey;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Atomic JSON writes.
3
+ *
4
+ * One export per file, so `set` does not pull array operators.
5
+ */
6
+ export { set } from "./json-set.js";
@@ -0,0 +1,12 @@
1
+ import { type JsonSet } from "../operators.js";
2
+ /**
3
+ * Atomic JSON path write, the `set` member of the `json` namespace (spec §11).
4
+ *
5
+ * The path is bound as `text[]` and the value as jsonb.
6
+ *
7
+ * @typeParam V - New value
8
+ * @param path - Path, one segment per element
9
+ * @param value - Value stored at that path
10
+ * @returns A tagged operator
11
+ */
12
+ export declare function set<const V>(path: readonly string[], value: V): JsonSet<V>;
@@ -0,0 +1,16 @@
1
+ import { type MatchMode, type Matches } from "../operators.js";
2
+ /**
3
+ * Full-text match (`@@`) for a tsvector column.
4
+ *
5
+ * The default mode is `websearch_to_tsquery`, which does not throw on user
6
+ * input. `"plain"` uses `plainto_tsquery` and `"phrase"` uses `phraseto_tsquery`.
7
+ * A text column is not searched here.
8
+ *
9
+ * @param query - Search text
10
+ * @param options - Mode and regconfig name
11
+ * @returns A tagged operator
12
+ */
13
+ export declare function matches(query: string, options?: {
14
+ readonly mode?: MatchMode;
15
+ readonly config?: string;
16
+ }): Matches;
@@ -0,0 +1,9 @@
1
+ import { type Overlaps } from "../operators.js";
2
+ /**
3
+ * Overlap (`&&`) for an array or range column.
4
+ *
5
+ * @typeParam V - Operand
6
+ * @param value - Value that must overlap the column
7
+ * @returns A tagged operator
8
+ */
9
+ export declare function overlaps<const V>(value: V): Overlaps<V>;
@@ -0,0 +1,13 @@
1
+ import { type Path, type PathCompare } from "../operators.js";
2
+ /**
3
+ * Compares the text at `segments` (`#>>`) with `op`.
4
+ *
5
+ * The operand of `op` picks the cast: number to numeric, boolean to boolean,
6
+ * string to text. Segments are bound as `text[]`.
7
+ *
8
+ * @typeParam V - Compared value
9
+ * @param segments - Path, one segment per element
10
+ * @param op - Comparison. `eq`, `lt`, `lte`, `gt`, or `gte`
11
+ * @returns A tagged operator
12
+ */
13
+ export declare function path<const V extends string | number | boolean>(segments: readonly string[], op: PathCompare<V>): Path<V>;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Preset types and the names a preset may not take (spec section 6.2, D41, D125).
3
+ *
4
+ * A preset is a named, typed refinement of a table: `tasks.pending()`. It gets
5
+ * a builder with one additive method, `where`, and returns that builder. The
6
+ * builder has no method that removes or replaces a predicate, so a preset can
7
+ * only narrow what the caller, tenancy, and the active set already allow.
8
+ *
9
+ * Only types and one list live here. The code that runs presets loads on the
10
+ * first call (`runtime/presets.ts`).
11
+ */
12
+ import type { Or } from "./operators.js";
13
+ import type { FieldWhere } from "./where.js";
14
+ /**
15
+ * What a preset receives.
16
+ *
17
+ * Every method adds. There is no method that removes or replaces a predicate
18
+ * (D125, D126), and the tenant and active-set predicates are not in the
19
+ * builder at all: the planner puts them around it.
20
+ *
21
+ * @typeParam Row - The table's row
22
+ */
23
+ export type PresetQuery<Row> = {
24
+ /**
25
+ * Adds a predicate, joined with the others by AND.
26
+ *
27
+ * Earlier predicates stay, whether the caller's, another preset's, or this
28
+ * preset's own.
29
+ *
30
+ * @param filter - Fields and operators, or `or(...)`
31
+ * @returns The same builder
32
+ */
33
+ where(filter: FieldWhere<Row> | Or<FieldWhere<Row>>): PresetQuery<Row>;
34
+ };
35
+ /**
36
+ * One preset: the builder first, then the preset's own typed arguments.
37
+ *
38
+ * @typeParam Row - The table's row
39
+ */
40
+ export type Preset<Row> = (q: PresetQuery<Row>, ...args: never[]) => PresetQuery<Row>;
41
+ /**
42
+ * Names a preset may not take (OKM1040).
43
+ *
44
+ * The first group are client methods. The second is reserved for later
45
+ * releases. `then` would make a table handle look like a promise.
46
+ */
47
+ export type ReservedPreset = "find" | "one" | "page" | "aggregate" | "count" | "exists" | "insert" | "update" | "delete" | "archive" | "restore" | "withArchived" | "onlyArchived" | "then" | "lock" | "watch" | "subscribe" | "stream" | "inspect" | "explain" | "with" | "for" | "as";
48
+ /**
49
+ * The `presets` option. A reserved name is a type error here, and OKM1040 when
50
+ * the schema is used.
51
+ *
52
+ * @typeParam Row - The table's row
53
+ */
54
+ export type PresetMap<Row> = {
55
+ readonly [name: string]: Preset<Row>;
56
+ } & {
57
+ readonly [N in ReservedPreset]?: never;
58
+ };
59
+ /** Names {@link ReservedPreset} lists, for the runtime check. */
60
+ export declare const RESERVED_PRESETS: ReadonlySet<string>;
61
+ /**
62
+ * Throws OKM1040 when a preset name is a client method or reserved.
63
+ *
64
+ * @param names - Preset names from one table or one trait
65
+ * @param where - What defines them, for the message: `table tasks` or `trait softDelete`
66
+ */
67
+ export declare function checkPresetNames(names: Iterable<string>, where: string): void;
68
+ /**
69
+ * Throws OKM1040 for a preset name defined by two sources.
70
+ *
71
+ * @param name - The preset name
72
+ * @param table - Table that ends up with both
73
+ * @param first - What defined it first: `table tasks` or `trait softDelete`
74
+ * @param second - What defines it again
75
+ */
76
+ export declare function duplicatePreset(name: string, table: string, first: string, second: string): never;