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.
- package/README.md +237 -19
- 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 +390 -25
- 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/{tb4ze1tr.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/{ckb1p0a4.js → 4jzzghr6.js} +416 -83
- package/dist/shared/{ycwz42az.js → 52szzakm.js} +6 -26
- package/dist/shared/{kynx7vbm.js → 5z4q2zda.js} +604 -21
- 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/{ax16zpvm.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/{vkm3q4x1.js → eaxwrgby.js} +4 -3
- package/dist/shared/{7ck0dtry.js → ecdzej21.js} +160 -81
- package/dist/shared/{px90pf9p.js → edwqqryd.js} +21 -16
- package/dist/shared/{g2v6gnc8.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/{79ggp945.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/{4j72449d.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/{f5thc1s0.js → xrfnq5k8.js} +237 -418
- 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 +56 -4
- package/dist/shared/gk7cs7sp.js +0 -566
package/dist/runtime/types.d.ts
CHANGED
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
* Row shapes are the schema's `~row`. Operators are the tagged helpers.
|
|
5
5
|
* A plain object is not a where value when the column type is an object.
|
|
6
6
|
*/
|
|
7
|
+
import type { DriverTimeouts, Notice } from "../contracts/driver.js";
|
|
7
8
|
import type { SafeResult } from "../contracts/error.js";
|
|
8
9
|
import type { QuerySchema } from "../dialects/pg/model.js";
|
|
9
10
|
import type { Inc } from "../dialects/pg/ops/inc.js";
|
|
10
|
-
import type {
|
|
11
|
+
import type { ArrAppend, ArrRemove, JsonSet, Or, RelationFilter } from "../dialects/pg/operators.js";
|
|
12
|
+
import type { FieldWhere, IsJsonObject } from "../dialects/pg/where.js";
|
|
11
13
|
import type { AppliedRule, ReadOp } from "./plan.js";
|
|
14
|
+
export type { FieldWhere, WhereValue } from "../dialects/pg/where.js";
|
|
12
15
|
/** One row of a table in `S`. */
|
|
13
16
|
export type RowOf<S extends QuerySchema, K extends keyof S["~byName"]> = S["~byName"][K] extends {
|
|
14
17
|
readonly "~row": infer R;
|
|
@@ -17,13 +20,8 @@ export type RowOf<S extends QuerySchema, K extends keyof S["~byName"]> = S["~byN
|
|
|
17
20
|
export type RelationsOf<S extends QuerySchema, K extends keyof S["~byName"]> = S["~byName"][K] extends {
|
|
18
21
|
readonly "~relations": infer R;
|
|
19
22
|
} ? R : Record<string, never>;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export type WhereValue<V> = (IsObject<V> extends true ? never : V) | null | Eq<V> | Compare<"lt", V> | Compare<"lte", V> | Compare<"gt", V> | Compare<"gte", V> | Between<V> | Pattern<"startsWith"> | Pattern<"contains"> | Pattern<"endsWith"> | RawPattern<"like"> | RawPattern<"ilike"> | InList<V> | NotIn<V> | Not<V | null | Pattern<"startsWith"> | Pattern<"contains"> | Pattern<"endsWith"> | InList<V>>;
|
|
23
|
-
/** Field filters. Relation filters are one level, so the type does not cycle. */
|
|
24
|
-
export type FieldWhere<Row> = {
|
|
25
|
-
readonly [K in keyof Row]?: WhereValue<Row[K]> | undefined;
|
|
26
|
-
};
|
|
23
|
+
/** Array and JSON writes the column value type can accept. */
|
|
24
|
+
type WriteOp<V> = [unknown] extends [V] ? JsonSet<unknown> | ArrAppend<unknown> | ArrRemove<unknown> : (V extends readonly (infer E)[] ? ArrAppend<E> | ArrRemove<E> : never) | (IsJsonObject<V> extends true ? JsonSet<unknown> : never);
|
|
27
25
|
/** `has`, `none`, and `every` against the related row. */
|
|
28
26
|
export type RelFilter<S extends QuerySchema, Rel> = Rel extends {
|
|
29
27
|
readonly table: infer T extends string;
|
|
@@ -95,19 +93,36 @@ export type ResultRow<S extends QuerySchema, K extends keyof S["~byName"], O> =
|
|
|
95
93
|
} ? Sel : undefined> & IncludeRows<S, K, O extends {
|
|
96
94
|
readonly include: infer Inc;
|
|
97
95
|
} ? Inc : undefined>>;
|
|
96
|
+
/** Per-call cancellation and deadline (spec §15). */
|
|
97
|
+
export type CallOptions = {
|
|
98
|
+
/** Aborts the call. The statement is cancelled where the driver can, and the call fails as `cancelled`. */
|
|
99
|
+
readonly signal?: AbortSignal;
|
|
100
|
+
/** Milliseconds. The call fails as `timeout` when it runs longer. */
|
|
101
|
+
readonly timeout?: number;
|
|
102
|
+
};
|
|
98
103
|
/** Options shared by reads. */
|
|
99
|
-
export type ReadOptions<S extends QuerySchema, K extends keyof S["~byName"]> = {
|
|
104
|
+
export type ReadOptions<S extends QuerySchema, K extends keyof S["~byName"]> = CallOptions & {
|
|
100
105
|
readonly where?: WhereOf<S, K>;
|
|
101
106
|
readonly select?: readonly (keyof RowOf<S, K> & string)[];
|
|
102
107
|
readonly orderBy?: OrderBy<RowOf<S, K>>;
|
|
103
108
|
readonly include?: IncludeOf<S, K>;
|
|
104
109
|
};
|
|
110
|
+
/**
|
|
111
|
+
* Row locks on `find`. They exist inside `tx()` only (OKM1830 outside one).
|
|
112
|
+
*
|
|
113
|
+
* `wait` says what happens when a row is locked by another transaction: `nowait`
|
|
114
|
+
* fails at once (kind `lock_timeout`) and `skip` leaves that row out.
|
|
115
|
+
*/
|
|
116
|
+
export type LockOptions = {
|
|
117
|
+
readonly lock?: "update" | "share";
|
|
118
|
+
readonly wait?: "nowait" | "skip";
|
|
119
|
+
};
|
|
105
120
|
/** `find` options. `limit` is required unless the caller uses `.all(reason)`. */
|
|
106
121
|
export type FindOptions<S extends QuerySchema, K extends keyof S["~byName"]> = ReadOptions<S, K> & {
|
|
107
122
|
readonly limit?: number;
|
|
108
123
|
};
|
|
109
124
|
/** A query handle. Await it, or inspect it before it runs. */
|
|
110
|
-
export type
|
|
125
|
+
export type Query<T> = Promise<T> & {
|
|
111
126
|
/** Logical intent, rules, plan, SQL, parameters, and the routing decision. */
|
|
112
127
|
inspect(): Inspection | Promise<Inspection>;
|
|
113
128
|
/** Statement text and parameters. */
|
|
@@ -120,6 +135,9 @@ export type Read<T> = Promise<T> & {
|
|
|
120
135
|
}>;
|
|
121
136
|
/** `{ ok, value }` or `{ ok, error }`. */
|
|
122
137
|
safe(): Promise<SafeResult<T>>;
|
|
138
|
+
};
|
|
139
|
+
/** The handle `find`, `one`, `count`, and `exists` return. */
|
|
140
|
+
export type Read<T> = Query<T> & {
|
|
123
141
|
/** Allows `find` or a to-many include without `limit`. */
|
|
124
142
|
all(reason: string): Read<T>;
|
|
125
143
|
/** Turns a null `one()` into `not_found`. */
|
|
@@ -127,6 +145,74 @@ export type Read<T> = Promise<T> & {
|
|
|
127
145
|
/** Streams rows when the driver has `stream`. Otherwise OKM1111. */
|
|
128
146
|
stream(): AsyncIterable<T extends readonly (infer R)[] ? R : T>;
|
|
129
147
|
};
|
|
148
|
+
/** One page: the rows, and the cursor for the next page. `next` is `null` on the last page. */
|
|
149
|
+
export type Page<Row> = {
|
|
150
|
+
readonly items: readonly Row[];
|
|
151
|
+
readonly next: string | null;
|
|
152
|
+
};
|
|
153
|
+
/** `page` options. `after` is the `next` of the page before. */
|
|
154
|
+
export type PageOptions<S extends QuerySchema, K extends keyof S["~byName"]> = ReadOptions<S, K> & {
|
|
155
|
+
/** Rows in the page. At least 1. */
|
|
156
|
+
readonly limit: number;
|
|
157
|
+
/** The `next` of the previous page, made for the same `orderBy`. */
|
|
158
|
+
readonly after?: string | null;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Fields `sum` and `avg` take: those typed `number` or `string`.
|
|
162
|
+
*
|
|
163
|
+
* A `numeric` column is a string by default. The types cannot tell it from a
|
|
164
|
+
* `text` column, so `sum` over `text` is refused when the call runs (OKM1124).
|
|
165
|
+
*/
|
|
166
|
+
type NumericKeys<Row> = {
|
|
167
|
+
readonly [F in keyof Row]-?: [NonNullable<Row[F]>] extends [number | string] ? F : never;
|
|
168
|
+
}[keyof Row] & string;
|
|
169
|
+
/** `aggregate` options. A hidden field is refused at runtime. */
|
|
170
|
+
export type AggregateOptions<S extends QuerySchema, K extends keyof S["~byName"]> = CallOptions & {
|
|
171
|
+
readonly where?: WhereOf<S, K>;
|
|
172
|
+
/** One result row per distinct combination. Needs `limit`, or `.all(reason)`. */
|
|
173
|
+
readonly groupBy?: readonly (keyof RowOf<S, K> & string)[];
|
|
174
|
+
/** Adds `count`, the number of rows in the group. */
|
|
175
|
+
readonly count?: true;
|
|
176
|
+
readonly sum?: readonly NumericKeys<RowOf<S, K>>[];
|
|
177
|
+
readonly avg?: readonly NumericKeys<RowOf<S, K>>[];
|
|
178
|
+
readonly min?: readonly (keyof RowOf<S, K> & string)[];
|
|
179
|
+
readonly max?: readonly (keyof RowOf<S, K> & string)[];
|
|
180
|
+
/** Orders the groups. Only `groupBy` fields. Without it, groups come in `groupBy` order. */
|
|
181
|
+
readonly orderBy?: OrderBy<RowOf<S, K>>;
|
|
182
|
+
readonly limit?: number;
|
|
183
|
+
};
|
|
184
|
+
/** A group: its fields, and the aggregates the call named. */
|
|
185
|
+
export type AggregateRow<Row, O> = Show<(O extends {
|
|
186
|
+
readonly groupBy: readonly (infer G)[];
|
|
187
|
+
} ? Pick<Row, G & keyof Row> : unknown) & (O extends {
|
|
188
|
+
readonly count: true;
|
|
189
|
+
} ? {
|
|
190
|
+
readonly count: number;
|
|
191
|
+
} : unknown) & (O extends {
|
|
192
|
+
readonly sum: readonly (infer F)[];
|
|
193
|
+
} ? {
|
|
194
|
+
readonly sum: {
|
|
195
|
+
readonly [P in F & keyof Row]: NonNullable<Row[P]> | null;
|
|
196
|
+
};
|
|
197
|
+
} : unknown) & (O extends {
|
|
198
|
+
readonly avg: readonly (infer F)[];
|
|
199
|
+
} ? {
|
|
200
|
+
readonly avg: {
|
|
201
|
+
readonly [P in F & keyof Row]: NonNullable<Row[P]> | null;
|
|
202
|
+
};
|
|
203
|
+
} : unknown) & (O extends {
|
|
204
|
+
readonly min: readonly (infer F)[];
|
|
205
|
+
} ? {
|
|
206
|
+
readonly min: {
|
|
207
|
+
readonly [P in F & keyof Row]: NonNullable<Row[P]> | null;
|
|
208
|
+
};
|
|
209
|
+
} : unknown) & (O extends {
|
|
210
|
+
readonly max: readonly (infer F)[];
|
|
211
|
+
} ? {
|
|
212
|
+
readonly max: {
|
|
213
|
+
readonly [P in F & keyof Row]: NonNullable<Row[P]> | null;
|
|
214
|
+
};
|
|
215
|
+
} : unknown)>;
|
|
130
216
|
/** What {@link Read.inspect} returns. */
|
|
131
217
|
export type Inspection = {
|
|
132
218
|
readonly intent: {
|
|
@@ -200,7 +286,7 @@ export type Router = {
|
|
|
200
286
|
*
|
|
201
287
|
* @typeParam T - Insert shape
|
|
202
288
|
*/
|
|
203
|
-
type RequiredInsert<T> = {
|
|
289
|
+
export type RequiredInsert<T> = {
|
|
204
290
|
readonly [K in keyof T as undefined extends T[K] ? never : K]: T[K];
|
|
205
291
|
};
|
|
206
292
|
/**
|
|
@@ -208,7 +294,7 @@ type RequiredInsert<T> = {
|
|
|
208
294
|
*
|
|
209
295
|
* @typeParam T - Insert shape
|
|
210
296
|
*/
|
|
211
|
-
type OptionalInsert<T> = {
|
|
297
|
+
export type OptionalInsert<T> = {
|
|
212
298
|
readonly [K in keyof T as undefined extends T[K] ? K : never]?: T[K];
|
|
213
299
|
};
|
|
214
300
|
/** Insert shape of one table. */
|
|
@@ -219,9 +305,9 @@ export type InsertOf<S extends QuerySchema, K extends keyof S["~byName"]> = S["~
|
|
|
219
305
|
export type UpdateOf<S extends QuerySchema, K extends keyof S["~byName"]> = S["~byName"][K] extends {
|
|
220
306
|
readonly "~update": infer U;
|
|
221
307
|
} ? U : never;
|
|
222
|
-
/** `set` values. `undefined` leaves the field unchanged. `inc` adds to it. */
|
|
308
|
+
/** `set` values. `undefined` leaves the field unchanged. `inc` adds to it. `set` and `arr` write json and arrays. */
|
|
223
309
|
export type UpdateSet<S extends QuerySchema, K extends keyof S["~byName"]> = {
|
|
224
|
-
readonly [F in keyof UpdateOf<S, K>]?: UpdateOf<S, K>[F] | Inc<NonNullable<UpdateOf<S, K>[F]>>;
|
|
310
|
+
readonly [F in keyof UpdateOf<S, K>]?: UpdateOf<S, K>[F] | Inc<NonNullable<UpdateOf<S, K>[F]>> | WriteOp<NonNullable<UpdateOf<S, K>[F]>>;
|
|
225
311
|
};
|
|
226
312
|
/** Conflict handling on `insert` (spec §11). */
|
|
227
313
|
export type OnConflict<S extends QuerySchema, K extends keyof S["~byName"]> = "error" | "ignore" | {
|
|
@@ -235,16 +321,24 @@ export type OnConflict<S extends QuerySchema, K extends keyof S["~byName"]> = "e
|
|
|
235
321
|
export type InsertOptions<S extends QuerySchema, K extends keyof S["~byName"]> = {
|
|
236
322
|
readonly onConflict?: OnConflict<S, K>;
|
|
237
323
|
readonly returning?: readonly (keyof RowOf<S, K> & string)[];
|
|
324
|
+
/** Guarded fields this call may set. */
|
|
325
|
+
readonly allow?: readonly (keyof RowOf<S, K> & string)[];
|
|
238
326
|
readonly expect?: number;
|
|
239
327
|
readonly signal?: AbortSignal;
|
|
240
328
|
readonly timeout?: number;
|
|
329
|
+
/** `false` skips validation for this call. Codecs still run. */
|
|
330
|
+
readonly validate?: boolean;
|
|
241
331
|
};
|
|
242
332
|
/** Options for `update` and `delete`. */
|
|
243
333
|
export type WriteOptions<S extends QuerySchema, K extends keyof S["~byName"]> = {
|
|
244
334
|
readonly returning?: readonly (keyof RowOf<S, K> & string)[];
|
|
335
|
+
/** Guarded fields this call may set. `delete` ignores it. */
|
|
336
|
+
readonly allow?: readonly (keyof RowOf<S, K> & string)[];
|
|
245
337
|
readonly expect?: number;
|
|
246
338
|
readonly signal?: AbortSignal;
|
|
247
339
|
readonly timeout?: number;
|
|
340
|
+
/** `false` skips validation for this call. `delete` ignores it. */
|
|
341
|
+
readonly validate?: boolean;
|
|
248
342
|
};
|
|
249
343
|
/** `{ count }` from an update or delete without `returning`. */
|
|
250
344
|
export type WriteCount = {
|
|
@@ -266,6 +360,17 @@ export type Write<T> = Promise<T> & {
|
|
|
266
360
|
/** Allows `update` or `delete` without `where`. */
|
|
267
361
|
all(reason: string): Write<T>;
|
|
268
362
|
};
|
|
363
|
+
/** `set` plus guarded fields named in `{ allow }`. */
|
|
364
|
+
type AllowedSet<S extends QuerySchema, K extends keyof S["~byName"], Allow extends readonly (keyof RowOf<S, K> & string)[]> = UpdateSet<S, K> & Partial<Pick<RowOf<S, K>, Allow[number]>>;
|
|
365
|
+
/** One update, or a per-row list, when `{ allow }` opens guarded fields. */
|
|
366
|
+
type AllowedUpdate<S extends QuerySchema, K extends keyof S["~byName"], Allow extends readonly (keyof RowOf<S, K> & string)[]> = {
|
|
367
|
+
readonly where?: WhereOf<S, K>;
|
|
368
|
+
readonly set: AllowedSet<S, K, Allow>;
|
|
369
|
+
} | readonly {
|
|
370
|
+
readonly id?: unknown;
|
|
371
|
+
readonly where?: WhereOf<S, K>;
|
|
372
|
+
readonly set: AllowedSet<S, K, Allow>;
|
|
373
|
+
}[];
|
|
269
374
|
/** One update, or a per-row list in one statement. */
|
|
270
375
|
export type UpdateTarget<S extends QuerySchema, K extends keyof S["~byName"]> = {
|
|
271
376
|
readonly where?: WhereOf<S, K>;
|
|
@@ -275,38 +380,230 @@ export type UpdateTarget<S extends QuerySchema, K extends keyof S["~byName"]> =
|
|
|
275
380
|
readonly where?: WhereOf<S, K>;
|
|
276
381
|
readonly set: UpdateSet<S, K>;
|
|
277
382
|
}[];
|
|
383
|
+
/** `{ count, archiveId }` from one `archive()` call. */
|
|
384
|
+
export type ArchiveCount = {
|
|
385
|
+
readonly count: number;
|
|
386
|
+
readonly archiveId: string;
|
|
387
|
+
};
|
|
388
|
+
/** `archive`, `restore`, and the visibility modifiers. Present only on archivable tables. */
|
|
389
|
+
type ArchiveOps<S extends QuerySchema, K extends keyof S["~byName"] & string, L> = {
|
|
390
|
+
/**
|
|
391
|
+
* Archives the active rows that match.
|
|
392
|
+
*
|
|
393
|
+
* One new `archiveId` is shared by the row and its cascaded children.
|
|
394
|
+
* `expect` matches {@link TableApi.update}.
|
|
395
|
+
*/
|
|
396
|
+
archive(target: {
|
|
397
|
+
readonly where?: WhereOf<S, K>;
|
|
398
|
+
}, options?: WriteOptions<S, K>): Write<ArchiveCount>;
|
|
399
|
+
/**
|
|
400
|
+
* Restores archived rows.
|
|
401
|
+
*
|
|
402
|
+
* `where` restores those rows and the children that carry their `archiveId`.
|
|
403
|
+
* `archiveId` restores that whole operation. An archived parent fails.
|
|
404
|
+
*/
|
|
405
|
+
restore(target: {
|
|
406
|
+
readonly where?: WhereOf<S, K>;
|
|
407
|
+
} | {
|
|
408
|
+
readonly archiveId: string;
|
|
409
|
+
}, options?: WriteOptions<S, K>): Write<WriteCount>;
|
|
410
|
+
/** Reads, updates, and deletes include archived rows. */
|
|
411
|
+
withArchived(): TableApi<S, K, L>;
|
|
412
|
+
/** Reads, updates, and deletes target only archived rows. */
|
|
413
|
+
onlyArchived(): TableApi<S, K, L>;
|
|
414
|
+
};
|
|
415
|
+
/**
|
|
416
|
+
* Methods an opt-in feature adds to a table handle.
|
|
417
|
+
*
|
|
418
|
+
* The interface is empty here, so an application that imports no feature
|
|
419
|
+
* pays one empty instantiation per table. A feature's entry point merges its
|
|
420
|
+
* members in with a module augmentation, and its types appear only when that
|
|
421
|
+
* entry point is part of the program.
|
|
422
|
+
*
|
|
423
|
+
* @typeParam S - Connected schema
|
|
424
|
+
* @typeParam K - Table name
|
|
425
|
+
*/
|
|
426
|
+
export interface TableExtras<S extends QuerySchema, K extends keyof S["~byName"] & string> {
|
|
427
|
+
}
|
|
278
428
|
/** Methods on one table. */
|
|
279
|
-
export type TableApi<S extends QuerySchema, K extends keyof S["~byName"] & string> = {
|
|
280
|
-
find<const O extends FindOptions<S, K> & {
|
|
429
|
+
export type TableApi<S extends QuerySchema, K extends keyof S["~byName"] & string, L = unknown> = {
|
|
430
|
+
find<const O extends FindOptions<S, K> & L & {
|
|
281
431
|
readonly limit: number;
|
|
282
432
|
}>(options: O): Read<readonly ResultRow<S, K, O>[]>;
|
|
283
|
-
find<const O extends FindOptions<S, K
|
|
433
|
+
find<const O extends FindOptions<S, K> & L>(options: O): {
|
|
284
434
|
all(reason: string): Read<readonly ResultRow<S, K, O>[]>;
|
|
285
435
|
};
|
|
286
436
|
one<const O extends ReadOptions<S, K>>(options?: O): Read<ResultRow<S, K, O> | null>;
|
|
287
|
-
|
|
437
|
+
/**
|
|
438
|
+
* One page of rows and the cursor for the next.
|
|
439
|
+
*
|
|
440
|
+
* Keyset on `orderBy` plus the primary key, so a page is stable while rows
|
|
441
|
+
* are inserted. Pass `next` back as `after` with the same `orderBy`.
|
|
442
|
+
*/
|
|
443
|
+
page<const O extends PageOptions<S, K>>(options: O): Query<Page<ResultRow<S, K, O>>>;
|
|
444
|
+
/**
|
|
445
|
+
* Counts, sums, averages, and finds extremes, per group.
|
|
446
|
+
*
|
|
447
|
+
* The tenant and active-set rules apply as in `find`.
|
|
448
|
+
*/
|
|
449
|
+
aggregate<const O extends AggregateOptions<S, K> & ({
|
|
450
|
+
readonly limit: number;
|
|
451
|
+
} | {
|
|
452
|
+
readonly groupBy?: undefined;
|
|
453
|
+
})>(options: O): Query<readonly AggregateRow<RowOf<S, K>, O>[]>;
|
|
454
|
+
aggregate<const O extends AggregateOptions<S, K>>(options: O): {
|
|
455
|
+
all(reason: string): Query<readonly AggregateRow<RowOf<S, K>, O>[]>;
|
|
456
|
+
};
|
|
457
|
+
count(options?: CallOptions & {
|
|
288
458
|
readonly where?: WhereOf<S, K>;
|
|
289
459
|
}): Read<number>;
|
|
290
|
-
exists(options?: {
|
|
460
|
+
exists(options?: CallOptions & {
|
|
291
461
|
readonly where?: WhereOf<S, K>;
|
|
292
462
|
}): Read<boolean>;
|
|
293
463
|
/**
|
|
294
|
-
* Inserts one row. Unknown keys are dropped.
|
|
464
|
+
* Inserts one row. Unknown keys are dropped. `{ allow }` may set guarded fields.
|
|
295
465
|
*
|
|
296
466
|
* Optional columns are optional keys, so completion lists the ones not yet written.
|
|
297
467
|
*/
|
|
468
|
+
insert<const Allow extends readonly (keyof RowOf<S, K> & string)[]>(data: RequiredInsert<InsertOf<S, K>> & OptionalInsert<InsertOf<S, K>> & Partial<Pick<RowOf<S, K>, Allow[number]>>, options: InsertOptions<S, K> & {
|
|
469
|
+
readonly allow: Allow;
|
|
470
|
+
}): Write<Show<RowOf<S, K>>>;
|
|
298
471
|
insert(data: RequiredInsert<InsertOf<S, K>> & OptionalInsert<InsertOf<S, K>>, options?: InsertOptions<S, K>): Write<Show<RowOf<S, K>>>;
|
|
299
|
-
/**
|
|
300
|
-
|
|
472
|
+
/**
|
|
473
|
+
* Inserts a list in one transaction. Unknown keys are dropped.
|
|
474
|
+
*
|
|
475
|
+
* Rows may carry different keys. An omitted key or an explicit `undefined` takes the
|
|
476
|
+
* database default for that row; `null` stays NULL.
|
|
477
|
+
*/
|
|
478
|
+
insert(data: readonly (RequiredInsert<InsertOf<S, K>> & OptionalInsert<InsertOf<S, K>>)[], options?: InsertOptions<S, K>): Write<readonly Show<RowOf<S, K>>[]>;
|
|
301
479
|
/** Updates matching rows, or a per-row list in one statement. `where` is required. */
|
|
480
|
+
update<const Allow extends readonly (keyof RowOf<S, K> & string)[]>(target: AllowedUpdate<S, K, Allow>, options: WriteOptions<S, K> & {
|
|
481
|
+
readonly allow: Allow;
|
|
482
|
+
}): Write<WriteCount>;
|
|
302
483
|
update(target: UpdateTarget<S, K>, options?: WriteOptions<S, K>): Write<WriteCount>;
|
|
303
484
|
/** Deletes matching rows. `where` is required. */
|
|
304
485
|
delete(target: {
|
|
305
486
|
readonly where?: WhereOf<S, K>;
|
|
306
487
|
}, options?: WriteOptions<S, K>): Write<WriteCount>;
|
|
488
|
+
} & (S["~byName"][K] extends {
|
|
489
|
+
readonly "~archive": true;
|
|
490
|
+
} ? ArchiveOps<S, K, L> : unknown) & PresetApi<S, K, L> & TableExtras<S, K>;
|
|
491
|
+
/**
|
|
492
|
+
* One method per preset the table or its traits declare.
|
|
493
|
+
*
|
|
494
|
+
* Each takes the preset's own arguments and returns the table handle with the
|
|
495
|
+
* preset applied, so calls chain: `tasks.pending().ownedBy(userId).find({})`.
|
|
496
|
+
* A table without presets adds nothing.
|
|
497
|
+
*/
|
|
498
|
+
type PresetApi<S extends QuerySchema, K extends keyof S["~byName"] & string, L> = S["~byName"][K] extends {
|
|
499
|
+
readonly "~presets": infer P;
|
|
500
|
+
} ? {
|
|
501
|
+
readonly [N in keyof P & string]: P[N] extends (...all: infer All) => unknown ? All extends readonly [unknown, ...infer A] ? (...args: A) => TableApi<S, K, L> : never : never;
|
|
502
|
+
} : unknown;
|
|
503
|
+
/**
|
|
504
|
+
* `[Symbol.asyncDispose]` when `Symbol` defines it.
|
|
505
|
+
*
|
|
506
|
+
* The check stays in the built declaration. A consumer `lib` without
|
|
507
|
+
* `asyncDispose` does not see the method, including with `skipLibCheck` off.
|
|
508
|
+
*/
|
|
509
|
+
type IfAsyncDisposable<S> = S extends {
|
|
510
|
+
readonly asyncDispose: infer D;
|
|
511
|
+
} ? D extends symbol ? {
|
|
512
|
+
[K in D]: () => Promise<void>;
|
|
513
|
+
} : object : object;
|
|
514
|
+
/** Tenant key, when the schema set column tenancy. */
|
|
515
|
+
type TenantKeyOf<S> = S extends {
|
|
516
|
+
readonly tenancy: {
|
|
517
|
+
readonly key: infer K extends string;
|
|
518
|
+
};
|
|
519
|
+
} ? K : never;
|
|
520
|
+
/** Tables that stay off the root client because they carry the tenant key. */
|
|
521
|
+
type ScopedName<S extends QuerySchema> = TenantKeyOf<S> extends never ? never : {
|
|
522
|
+
readonly [K in keyof S["~byName"] & string]: S["~byName"][K] extends {
|
|
523
|
+
readonly "~global": string;
|
|
524
|
+
} ? never : K;
|
|
525
|
+
}[keyof S["~byName"] & string];
|
|
526
|
+
/** Tables on the root client. Global tables stay. Tenant tables need `for()`. */
|
|
527
|
+
type RootName<S extends QuerySchema> = Exclude<keyof S["~byName"] & string, ScopedName<S>>;
|
|
528
|
+
/** Options of `tx()` (spec §15). */
|
|
529
|
+
export type TxOptions = {
|
|
530
|
+
/** Isolation level. The database default when omitted. Only the outermost `tx()` takes it. */
|
|
531
|
+
readonly isolation?: "read committed" | "repeatable read" | "serializable";
|
|
532
|
+
/**
|
|
533
|
+
* How many times to run the callback again after a serialization failure or a
|
|
534
|
+
* deadlock. Each run is a fresh transaction. Other errors, `cancelled` and
|
|
535
|
+
* `outcome_unknown` are never retried. Only the outermost `tx()` takes it.
|
|
536
|
+
*/
|
|
537
|
+
readonly retry?: number;
|
|
538
|
+
/** Milliseconds for the whole transaction, retries included. The call fails as `timeout`. */
|
|
539
|
+
readonly timeout?: number;
|
|
540
|
+
/** Aborts the transaction and rolls it back. The call fails as `cancelled`. */
|
|
541
|
+
readonly signal?: AbortSignal;
|
|
307
542
|
};
|
|
308
|
-
/**
|
|
309
|
-
|
|
543
|
+
/** What the callback of a batch gets back: one result per operation, in order. */
|
|
544
|
+
type BatchResults<Ops extends readonly unknown[]> = {
|
|
545
|
+
-readonly [I in keyof Ops]: Awaited<Ops[I]>;
|
|
546
|
+
};
|
|
547
|
+
/**
|
|
548
|
+
* Tables of a client: the root client leaves tenant tables out. A flag, not a name list,
|
|
549
|
+
* because a name list as a type argument costs one instantiation per table on every
|
|
550
|
+
* use of the client (D176).
|
|
551
|
+
*/
|
|
552
|
+
type TxNames<S extends QuerySchema, Root extends boolean> = Root extends true ? RootName<S> : keyof S["~byName"] & string;
|
|
553
|
+
/**
|
|
554
|
+
* `tx` and `batch`, on the root client, a scoped client, and the client a transaction hands out.
|
|
555
|
+
*
|
|
556
|
+
* @typeParam S - Connected schema
|
|
557
|
+
* @typeParam Root - True on the root client, whose tenant tables need `for()` first
|
|
558
|
+
*/
|
|
559
|
+
type TxApi<S extends QuerySchema, Root extends boolean> = {
|
|
560
|
+
/**
|
|
561
|
+
* Runs `fn` in a transaction on one reserved connection of the primary.
|
|
562
|
+
*
|
|
563
|
+
* The callback gets a client with the same tables, presets, tenancy and archive
|
|
564
|
+
* handling. It commits when `fn` resolves and rolls back when it throws. Inside a
|
|
565
|
+
* transaction this is a savepoint on the same connection.
|
|
566
|
+
*/
|
|
567
|
+
tx<T>(fn: (t: TxClient<S, Root>) => Promise<T>): Promise<T>;
|
|
568
|
+
tx<T>(options: TxOptions, fn: (t: TxClient<S, Root>) => Promise<T>): Promise<T>;
|
|
569
|
+
/**
|
|
570
|
+
* Runs writes as one atomic unit on the primary. Results come back in order.
|
|
571
|
+
*
|
|
572
|
+
* A failure rolls everything back and the error carries `batchIndex`. Inside a
|
|
573
|
+
* transaction it runs on a savepoint, so the transaction survives a failure.
|
|
574
|
+
*/
|
|
575
|
+
batch<const Ops extends readonly Write<unknown>[]>(ops: Ops, options?: CallOptions): Promise<BatchResults<Ops>>;
|
|
576
|
+
};
|
|
577
|
+
/**
|
|
578
|
+
* The client the callback of `tx()` gets.
|
|
579
|
+
*
|
|
580
|
+
* Its tables take row locks on `find`. It has no `close` and no `for()`: scope the
|
|
581
|
+
* client before calling `tx()`.
|
|
582
|
+
*
|
|
583
|
+
* @typeParam S - Connected schema
|
|
584
|
+
* @typeParam Root - True on the root client, whose tenant tables need `for()` first
|
|
585
|
+
*/
|
|
586
|
+
export type TxClient<S extends QuerySchema, Root extends boolean = false> = {
|
|
587
|
+
readonly [K in TxNames<S, Root>]: TableApi<S, K, LockOptions>;
|
|
588
|
+
} & {
|
|
589
|
+
/** Looks up a table by name. An unknown name is OKM1120. */
|
|
590
|
+
table<K extends TxNames<S, Root>>(name: K): TableApi<S, K, LockOptions>;
|
|
591
|
+
/**
|
|
592
|
+
* Runs `fn` after the outermost transaction commits.
|
|
593
|
+
*
|
|
594
|
+
* It never runs on rollback. Callbacks run in order. An error in one is reported to
|
|
595
|
+
* `hookm.onError` and never changes the commit result.
|
|
596
|
+
*/
|
|
597
|
+
afterCommit(fn: () => void | Promise<void>): void;
|
|
598
|
+
/**
|
|
599
|
+
* Takes a transaction-level advisory lock. It is released at commit or rollback.
|
|
600
|
+
*
|
|
601
|
+
* A string is hashed; a number or bigint is the key itself.
|
|
602
|
+
*/
|
|
603
|
+
advisoryLock(key: string | number | bigint, options?: CallOptions): Promise<void>;
|
|
604
|
+
} & TxApi<S, Root>;
|
|
605
|
+
/** A client whose tables are already inside one tenant or an unscoped reason. */
|
|
606
|
+
type ScopedClient<S extends QuerySchema> = {
|
|
310
607
|
readonly [K in keyof S["~byName"] & string]: TableApi<S, K>;
|
|
311
608
|
} & {
|
|
312
609
|
/** Looks up a table by name. An unknown name is OKM1120. */
|
|
@@ -315,7 +612,45 @@ export type Connected<S extends QuerySchema> = {
|
|
|
315
612
|
close(): Promise<void>;
|
|
316
613
|
/** Resolves when the dialect and `requires` checks have finished. */
|
|
317
614
|
readonly connected: Promise<void>;
|
|
615
|
+
} & TxApi<S, false> & IfAsyncDisposable<typeof Symbol>;
|
|
616
|
+
/** `for` and `unscoped` on a schema that set tenancy. */
|
|
617
|
+
type ScopeMethods<S extends QuerySchema> = TenantKeyOf<S> extends never ? object : {
|
|
618
|
+
/**
|
|
619
|
+
* Opens a client bound to one tenant.
|
|
620
|
+
*
|
|
621
|
+
* The value is the scope. Insert fills it. Reads and writes filter on it.
|
|
622
|
+
* Input cannot set it.
|
|
623
|
+
*
|
|
624
|
+
* @param input - The tenant key and its value
|
|
625
|
+
*/
|
|
626
|
+
for(input: {
|
|
627
|
+
readonly [K in TenantKeyOf<S>]: string;
|
|
628
|
+
}): ScopedClient<S>;
|
|
629
|
+
/**
|
|
630
|
+
* Opens a client with no tenant predicate.
|
|
631
|
+
*
|
|
632
|
+
* The reason is stored and shown by `inspect()`. Insert still needs `for()`.
|
|
633
|
+
*
|
|
634
|
+
* @param reason - Why this client leaves the tenant scope
|
|
635
|
+
*/
|
|
636
|
+
unscoped(reason: string): ScopedClient<S>;
|
|
318
637
|
};
|
|
638
|
+
/** A client typed by its own schema. */
|
|
639
|
+
export type Connected<S extends QuerySchema> = {
|
|
640
|
+
readonly [K in RootName<S>]: TableApi<S, K>;
|
|
641
|
+
} & {
|
|
642
|
+
/** Looks up a table by name. A tenant table on the root client is OKM1701. */
|
|
643
|
+
table<K extends RootName<S>>(name: K): TableApi<S, K>;
|
|
644
|
+
/**
|
|
645
|
+
* Closes the pool when this client opened it.
|
|
646
|
+
*
|
|
647
|
+
* A second call waits on the same close. A client that adopted a pool
|
|
648
|
+
* resolves without closing it.
|
|
649
|
+
*/
|
|
650
|
+
close(): Promise<void>;
|
|
651
|
+
/** Resolves when the dialect and `requires` checks have finished. */
|
|
652
|
+
readonly connected: Promise<void>;
|
|
653
|
+
} & TxApi<S, true> & ScopeMethods<S> & IfAsyncDisposable<typeof Symbol>;
|
|
319
654
|
/**
|
|
320
655
|
* A catalog `okm build` wrote.
|
|
321
656
|
*
|
|
@@ -363,7 +698,37 @@ export type ConnectOptions<S extends QuerySchema> = {
|
|
|
363
698
|
* The target name and `NODE_ENV` do not turn it on.
|
|
364
699
|
*/
|
|
365
700
|
readonly requireMeta?: boolean;
|
|
701
|
+
/**
|
|
702
|
+
* Replaces a built-in client generator by name.
|
|
703
|
+
*
|
|
704
|
+
* `uuidv4`, `uuidv7`, and `okid` are the names. A custom function passed to
|
|
705
|
+
* `.default()` is not replaced. Tests use this for deterministic ids.
|
|
706
|
+
*/
|
|
707
|
+
readonly generators?: import("../contracts/generator.js").IdGenerators;
|
|
366
708
|
readonly signal?: AbortSignal;
|
|
367
709
|
readonly timeout?: number;
|
|
710
|
+
/** Ceilings in milliseconds. See {@link Timeouts}. */
|
|
711
|
+
readonly timeouts?: Timeouts;
|
|
712
|
+
/** Observers of notices, transactions and errors. They cannot change a query (spec §18). */
|
|
713
|
+
readonly hookm?: readonly Hookm[];
|
|
714
|
+
};
|
|
715
|
+
/** Ceilings from `connect({ timeouts })`, in milliseconds. Each key is optional. */
|
|
716
|
+
export type Timeouts = DriverTimeouts;
|
|
717
|
+
/** What `hookm.onTransaction` hears. `depth` is 0 for the transaction and 1 and up for savepoints. */
|
|
718
|
+
export type TransactionEvent = {
|
|
719
|
+
readonly phase: "start" | "commit" | "rollback";
|
|
720
|
+
readonly depth: number;
|
|
721
|
+
};
|
|
722
|
+
/**
|
|
723
|
+
* A read-only observer (spec §18).
|
|
724
|
+
*
|
|
725
|
+
* Events only. An error a hook throws is dropped and never reaches the call.
|
|
726
|
+
*/
|
|
727
|
+
export type Hookm = {
|
|
728
|
+
/** A server notice, such as `RAISE NOTICE`. */
|
|
729
|
+
onNotice?(notice: Notice): void;
|
|
730
|
+
/** A transaction or batch starts, commits, or rolls back. */
|
|
731
|
+
onTransaction?(event: TransactionEvent): void;
|
|
732
|
+
/** An error the runtime could not give to a caller, such as one from an `afterCommit` callback. */
|
|
733
|
+
onError?(error: unknown): void;
|
|
368
734
|
};
|
|
369
|
-
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers the validation hook.
|
|
3
|
+
*
|
|
4
|
+
* Called when `okmodel/validate` is imported and again from each `v` rule,
|
|
5
|
+
* so a bundler that drops the module side effect still registers the hook
|
|
6
|
+
* before `schema()` when the app builds a rule first.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Adds the validation hook to schemas compiled after this call.
|
|
10
|
+
*/
|
|
11
|
+
export declare function armValidation(): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OKM1201, thrown when a write would validate and `okmodel/validate` is not registered.
|
|
3
|
+
*
|
|
4
|
+
* The sentences are the registry entry. The write chunk loads this module when
|
|
5
|
+
* it builds the error. The featureless startup graph does not.
|
|
6
|
+
*/
|
|
7
|
+
/** What went wrong. The OKM1201 registry summary is this sentence. */
|
|
8
|
+
export declare const VALIDATION_NOT_IMPORTED = "Validation is enabled but `okmodel/validate` was not imported.";
|
|
9
|
+
/** What to do. The OKM1201 registry fix is this sentence. */
|
|
10
|
+
export declare const VALIDATION_NOT_IMPORTED_FIX = "Import \"okmodel/validate\" before schema().";
|
|
11
|
+
/**
|
|
12
|
+
* Throws OKM1201.
|
|
13
|
+
*
|
|
14
|
+
* The category is `input`. The message and the fix are the registry sentences.
|
|
15
|
+
*/
|
|
16
|
+
export declare function refuseMissingValidation(): never;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation engine.
|
|
3
|
+
*
|
|
4
|
+
* Loaded on the first validated write or standalone call. A failed import
|
|
5
|
+
* rejects that call. Nothing here runs when validation is off.
|
|
6
|
+
*/
|
|
7
|
+
import type { TableModel } from "../../dialects/pg/model.js";
|
|
8
|
+
import type { AnyTable } from "../../dialects/pg/table.js";
|
|
9
|
+
type Op = "insert" | "update";
|
|
10
|
+
/**
|
|
11
|
+
* Validates a write input and returns the transformed rows.
|
|
12
|
+
*
|
|
13
|
+
* Branded values are copied and not checked again. The copy stays mutable so
|
|
14
|
+
* insert can fill a client default.
|
|
15
|
+
*
|
|
16
|
+
* @param model - Table model. The gate is stored here on first use
|
|
17
|
+
* @param source - Table whose stored rules are read
|
|
18
|
+
* @param schemaFlag - The schema `validation` option, as stored
|
|
19
|
+
* @param op - Insert or update
|
|
20
|
+
* @param input - One row, a list, or an update target
|
|
21
|
+
* @returns The input with transforms applied
|
|
22
|
+
*/
|
|
23
|
+
export declare function prepare(model: TableModel, source: AnyTable, schemaFlag: unknown, op: Op, input: unknown): Promise<unknown>;
|
|
24
|
+
/**
|
|
25
|
+
* Standalone `validate` or `check`.
|
|
26
|
+
*
|
|
27
|
+
* `valid` returns a frozen branded value or throws OKM1200. `check` returns
|
|
28
|
+
* the issues and does not throw for a failed check.
|
|
29
|
+
*
|
|
30
|
+
* @param model - Table model. The gate is stored here on first use
|
|
31
|
+
* @param source - Table whose stored rules are read
|
|
32
|
+
* @param schemaFlag - The schema `validation` option, as stored
|
|
33
|
+
* @param op - Insert or update
|
|
34
|
+
* @param body - One row, a list, or an update patch
|
|
35
|
+
* @param mode - Throw, or return issues
|
|
36
|
+
* @param pick - Fields to keep. Omitted, every field is kept
|
|
37
|
+
* @param omit - Fields to drop
|
|
38
|
+
* @returns The branded value, or the issues
|
|
39
|
+
*/
|
|
40
|
+
export declare function stand(model: TableModel, source: AnyTable, schemaFlag: unknown, op: Op, body: unknown, mode: "valid" | "check", pick?: readonly string[], omit?: readonly string[]): Promise<unknown>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table methods validation adds through the shared client hook.
|
|
3
|
+
*
|
|
4
|
+
* Core does not name `insert.validate`. The engine loads on the first call.
|
|
5
|
+
*/
|
|
6
|
+
import type { SchemaHookCtx } from "../../dialects/pg/model.js";
|
|
7
|
+
/**
|
|
8
|
+
* Adds `insert.validate`, `check`, `pick`, `omit`, and the Standard Schema
|
|
9
|
+
* surface when this table's validation is on.
|
|
10
|
+
*
|
|
11
|
+
* A client-level call has no table and does nothing. A table with validation
|
|
12
|
+
* off is left as core built it.
|
|
13
|
+
*
|
|
14
|
+
* @param target - The table handle being built
|
|
15
|
+
* @param ctx - Table name and the session
|
|
16
|
+
*/
|
|
17
|
+
export declare function attachValidation(target: Record<string, unknown>, ctx: SchemaHookCtx): void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation rules (`okmodel/validate`).
|
|
3
|
+
*
|
|
4
|
+
* Importing this module registers the client hook. An application that does
|
|
5
|
+
* not import it does not load the hook or the engine. It also merges the
|
|
6
|
+
* typed surface (`insert.validate`, `check`, `pick`, `omit`, the Standard
|
|
7
|
+
* Schema members, and `update.validate`) into the table type, so a program
|
|
8
|
+
* that does not import it does not see or pay for those types.
|
|
9
|
+
*/
|
|
10
|
+
import type { QuerySchema } from "../../dialects/pg/model.js";
|
|
11
|
+
import type { ValidateInsert, ValidateUpdate } from "./surface.js";
|
|
12
|
+
declare module "../types.js" {
|
|
13
|
+
interface TableExtras<S extends QuerySchema, K extends keyof S["~byName"] & string> {
|
|
14
|
+
/** `insert` plus the validation members when this table validates. */
|
|
15
|
+
readonly insert: ValidateInsert<S, K>;
|
|
16
|
+
/** `update` plus `validate` when this table validates. */
|
|
17
|
+
readonly update: ValidateUpdate<S, K>;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export { v } from "./rules.js";
|
|
21
|
+
export type { Rule } from "./rules.js";
|