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.
- package/README.md +32 -16
- package/dist/adapters/capabilities.d.ts +34 -0
- package/dist/adapters/pg/bunsql-extra.d.ts +17 -0
- package/dist/adapters/pg/bunsql.d.ts +60 -0
- package/dist/adapters/pg/call.d.ts +2 -12
- package/dist/adapters/pg/nodepostgres-extra.d.ts +18 -0
- package/dist/adapters/pg/nodepostgres.d.ts +57 -0
- package/dist/adapters/pg/postgres-extra.d.ts +50 -1
- package/dist/adapters/pg/postgresjs.d.ts +0 -4
- package/dist/adapters/pg/session.d.ts +94 -0
- package/dist/adapters/pg/watch.d.ts +18 -0
- package/dist/contracts/catalog/object.d.ts +1 -0
- package/dist/contracts/catalog/types.d.ts +15 -8
- package/dist/contracts/connection.d.ts +13 -0
- package/dist/contracts/driver.d.ts +18 -5
- package/dist/contracts/error.d.ts +17 -1
- package/dist/contracts/generator.d.ts +63 -0
- package/dist/contracts/index.d.ts +2 -2
- package/dist/contracts/index.js +1 -1
- package/dist/contracts/internal.js +11 -9
- package/dist/contracts/location.d.ts +24 -0
- package/dist/contracts/rows.d.ts +15 -0
- package/dist/dialects/pg/archive-bind.d.ts +22 -0
- package/dist/dialects/pg/column.d.ts +126 -9
- package/dist/dialects/pg/compile.d.ts +1 -0
- package/dist/dialects/pg/custom.d.ts +6 -0
- package/dist/dialects/pg/filter-parse.d.ts +19 -0
- package/dist/dialects/pg/filters.d.ts +19 -0
- package/dist/dialects/pg/index.d.ts +11 -2
- package/dist/dialects/pg/index.js +159 -1063
- package/dist/dialects/pg/keys.d.ts +19 -3
- package/dist/dialects/pg/model.d.ts +223 -2
- package/dist/dialects/pg/operator-fit.d.ts +86 -0
- package/dist/dialects/pg/operators.d.ts +39 -1
- package/dist/dialects/pg/ops/arr-append.d.ts +9 -0
- package/dist/dialects/pg/ops/arr-ns.d.ts +7 -0
- package/dist/dialects/pg/ops/arr-remove.d.ts +9 -0
- package/dist/dialects/pg/ops/containedBy.d.ts +9 -0
- package/dist/dialects/pg/ops/contains.d.ts +8 -4
- package/dist/dialects/pg/ops/hasAnyKey.d.ts +8 -0
- package/dist/dialects/pg/ops/hasKey.d.ts +8 -0
- package/dist/dialects/pg/ops/json-ns.d.ts +6 -0
- package/dist/dialects/pg/ops/json-set.d.ts +12 -0
- package/dist/dialects/pg/ops/matches.d.ts +16 -0
- package/dist/dialects/pg/ops/overlaps.d.ts +9 -0
- package/dist/dialects/pg/ops/path.d.ts +13 -0
- package/dist/dialects/pg/preset.d.ts +76 -0
- package/dist/dialects/pg/relations.d.ts +59 -2
- package/dist/dialects/pg/schema.d.ts +109 -5
- package/dist/dialects/pg/table.d.ts +130 -11
- package/dist/dialects/pg/temporal.d.ts +9 -7
- package/dist/dialects/pg/tenancy.d.ts +94 -0
- package/dist/dialects/pg/through.d.ts +21 -0
- package/dist/dialects/pg/trait.d.ts +141 -0
- package/dist/dialects/pg/where.d.ts +37 -0
- package/dist/runtime/aggregate.d.ts +25 -0
- package/dist/runtime/archive-handle.d.ts +18 -0
- package/dist/runtime/archive-rules.d.ts +12 -0
- package/dist/runtime/archive.d.ts +73 -0
- package/dist/runtime/batch.d.ts +20 -0
- package/dist/runtime/client.d.ts +114 -5
- package/dist/runtime/conflict.d.ts +2 -1
- package/dist/runtime/exposure.d.ts +27 -0
- package/dist/runtime/hookm.d.ts +39 -0
- package/dist/runtime/ids/index.d.ts +11 -0
- package/dist/runtime/ids/index.js +193 -0
- package/dist/runtime/ids/okid-extended.d.ts +19 -0
- package/dist/runtime/ids/okid-generator.d.ts +21 -0
- package/dist/runtime/ids/okid-shared.d.ts +89 -0
- package/dist/runtime/ids/okid.d.ts +24 -0
- package/dist/runtime/ids/uuid.d.ts +21 -0
- package/dist/runtime/lock.d.ts +22 -0
- package/dist/runtime/operator-sql.d.ts +8 -0
- package/dist/runtime/page.d.ts +25 -0
- package/dist/runtime/pg/bun.d.ts +30 -0
- package/dist/runtime/pg/bun.js +52 -0
- package/dist/runtime/pg/pg.d.ts +29 -0
- package/dist/runtime/pg/pg.js +52 -0
- package/dist/runtime/pg/pglite.js +16 -17
- package/dist/runtime/pg/postgresjs.js +14 -24
- package/dist/runtime/plan.d.ts +146 -7
- package/dist/runtime/preset-stack.d.ts +17 -0
- package/dist/runtime/presets.d.ts +48 -0
- package/dist/runtime/read-stream.d.ts +26 -0
- package/dist/runtime/safety/index.d.ts +159 -0
- package/dist/runtime/safety/index.js +294 -0
- package/dist/runtime/safety-hook.d.ts +42 -0
- package/dist/runtime/server-check.d.ts +34 -0
- package/dist/runtime/tenancy/index.d.ts +37 -0
- package/dist/runtime/tenancy/index.js +365 -0
- package/dist/runtime/trait-read.d.ts +30 -0
- package/dist/runtime/traits/index.d.ts +128 -0
- package/dist/runtime/traits/index.js +509 -0
- package/dist/runtime/transaction.d.ts +19 -0
- package/dist/runtime/tx.d.ts +22 -7
- package/dist/runtime/types.d.ts +376 -27
- package/dist/runtime/validate/bind.d.ts +11 -0
- package/dist/runtime/validate/closed.d.ts +16 -0
- package/dist/runtime/validate/engine.d.ts +41 -0
- package/dist/runtime/validate/hook.d.ts +17 -0
- package/dist/runtime/validate/index.d.ts +21 -0
- package/dist/runtime/validate/index.js +175 -0
- package/dist/runtime/validate/load.d.ts +13 -0
- package/dist/runtime/validate/places.d.ts +41 -0
- package/dist/runtime/validate/rules.d.ts +108 -0
- package/dist/runtime/validate/surface.d.ts +102 -0
- package/dist/runtime/write.d.ts +30 -5
- package/dist/shared/{fgqgsb5z.js → 0qkxbm1f.js} +2 -2
- package/dist/shared/0v1g424p.js +26 -0
- package/dist/shared/10tjenmd.js +210 -0
- package/dist/shared/{xqbhg6cn.js → 1dp5knt7.js} +95 -10
- package/dist/shared/38crxbgn.js +229 -0
- package/dist/shared/3a5ne750.js +158 -0
- package/dist/shared/4b9da9d7.js +138 -0
- package/dist/shared/4e4c6vq2.js +62 -0
- package/dist/shared/{x5x59srr.js → 4jzzghr6.js} +416 -83
- package/dist/shared/{ycwz42az.js → 52szzakm.js} +6 -26
- package/dist/shared/{05w44d8g.js → 5z4q2zda.js} +567 -18
- package/dist/shared/672t5vym.js +12 -0
- package/dist/shared/7m88x3e9.js +45 -0
- package/dist/shared/7mht49yd.js +1091 -0
- package/dist/shared/{mtkwv8wx.js → 7p2wbz7f.js} +1 -1
- package/dist/shared/83eaefwr.js +10 -0
- package/dist/shared/96ps4g1z.js +32 -0
- package/dist/shared/97g2jnrw.js +76 -0
- package/dist/shared/{xy79j5hq.js → 9k6vetvf.js} +25 -36
- package/dist/shared/{w8samvk1.js → a1gdp7j9.js} +1 -1
- package/dist/shared/a5sxz52y.js +13 -0
- package/dist/shared/{dynq16vb.js → b066g80h.js} +8 -6
- package/dist/shared/cstgkzdx.js +154 -0
- package/dist/shared/{523ft3e8.js → d04j53v8.js} +6 -5
- package/dist/shared/{y9m15dfv.js → d2whjz4k.js} +15 -9
- package/dist/shared/dd4f8mnx.js +307 -0
- package/dist/shared/e6wg00wd.js +164 -0
- package/dist/shared/e7a268fy.js +195 -0
- package/dist/shared/{kprcwaha.js → eaxwrgby.js} +4 -3
- package/dist/shared/{dkn3y60a.js → ecdzej21.js} +76 -112
- package/dist/shared/{hadrfb9h.js → edwqqryd.js} +17 -14
- package/dist/shared/{m3ypagh5.js → eqmtn1bj.js} +57 -5
- package/dist/shared/g1b5zzj9.js +75 -0
- package/dist/shared/g9f0zqce.js +376 -0
- package/dist/shared/ge03bfca.js +64 -0
- package/dist/shared/{yd1kzwn2.js → jns2wx4t.js} +55 -12
- package/dist/shared/k3ted12y.js +33 -0
- package/dist/shared/k7dwkhvq.js +31 -0
- package/dist/shared/{hd293j9g.js → kyxb62mc.js} +14 -2
- package/dist/shared/m9tv7xn7.js +404 -0
- package/dist/shared/mrq77sgw.js +55 -0
- package/dist/shared/mxmcdsh5.js +450 -0
- package/dist/shared/n442h54c.js +14 -0
- package/dist/shared/n47rd821.js +442 -0
- package/dist/shared/n4jqhpqz.js +27 -0
- package/dist/shared/{mkjmqjv4.js → nfzc5z0w.js} +2 -104
- package/dist/shared/nsva2a6b.js +42 -0
- package/dist/shared/ps43134h.js +69 -0
- package/dist/shared/{8b04d28c.js → py3nh7jy.js} +2 -2
- package/dist/shared/qa5dsc7z.js +86 -0
- package/dist/shared/{g5fhqmwe.js → qxa0yb9j.js} +6 -4
- package/dist/shared/r6nwkxnt.js +86 -0
- package/dist/shared/{jjb7yht9.js → rtnaqre0.js} +3 -3
- package/dist/shared/rwmrejjz.js +26 -0
- package/dist/shared/{zhc5vmgf.js → s6gqfn5j.js} +2 -2
- package/dist/shared/sacqha1y.js +70 -0
- package/dist/shared/{qk3hxfja.js → sfh4pk75.js} +5 -5
- package/dist/shared/{j5cn2963.js → t4tbsy9h.js} +13 -64
- package/dist/shared/{ngk8gj61.js → tbszx8mz.js} +15 -1
- package/dist/shared/v18jva5b.js +90 -0
- package/dist/shared/x9v1qgeb.js +201 -0
- package/dist/shared/xatfg0gn.js +193 -0
- package/dist/shared/xkz8g6by.js +225 -0
- package/dist/shared/{rgs0st28.js → xrfnq5k8.js} +237 -434
- package/dist/shared/ytg3xf9p.js +149 -0
- package/dist/shared/yw5c610b.js +48 -0
- package/dist/shared/zd93g3rq.js +31 -0
- package/dist/shared/zt8y0wzb.js +132 -0
- package/dist/shared/{p0cbr3g2.js → zwmqxb0g.js} +1 -1
- package/dist/tooling/cli.js +14 -10
- package/dist/tooling/migrate/commands.d.ts +10 -0
- package/dist/tooling/migrate/engine.d.ts +36 -0
- package/package.json +41 -4
- package/dist/shared/gk7cs7sp.js +0 -566
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* UUID keys.
|
|
3
3
|
*/
|
|
4
|
-
import { type
|
|
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
|
-
*
|
|
9
|
+
* Primary key.
|
|
7
10
|
*
|
|
8
|
-
*
|
|
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
|
-
/**
|
|
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,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
|
|
1
|
+
import { type Tagged } from "../operators.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Substring on text, or containment (`@>`) on an array, jsonb, or range.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
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:
|
|
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,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;
|