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,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `one` and `
|
|
2
|
+
* `one`, `many`, and `manyThrough` relations.
|
|
3
3
|
*
|
|
4
4
|
* They name a table. `schema()` resolves the foreign key. An ambiguous key
|
|
5
|
-
* is OKM1021. `manyThrough`
|
|
5
|
+
* is OKM1021. `manyThrough` names the join table as well and carries its own
|
|
6
|
+
* resolver, so a schema without one does not pay for it. `morph` stays reserved.
|
|
6
7
|
*/
|
|
8
|
+
import type { RelationModel } from "./model.js";
|
|
7
9
|
/** A to-one relation. `field` is the local foreign key when the table has several. */
|
|
8
10
|
export type OneRelation<TTable extends string = string> = {
|
|
9
11
|
readonly kind: "one";
|
|
@@ -16,6 +18,46 @@ export type ManyRelation<TTable extends string = string> = {
|
|
|
16
18
|
readonly table: TTable;
|
|
17
19
|
readonly field: string | undefined;
|
|
18
20
|
};
|
|
21
|
+
/** A foreign key `schema()` resolved, as a relation resolver sees it. */
|
|
22
|
+
export type RelationEdge = {
|
|
23
|
+
readonly fromTable: string;
|
|
24
|
+
readonly fromField: string;
|
|
25
|
+
readonly toTable: string;
|
|
26
|
+
/** Local SQL names, one column or a composite key. */
|
|
27
|
+
readonly local: readonly string[];
|
|
28
|
+
/** Referenced SQL names, in the same order. */
|
|
29
|
+
readonly remote: readonly string[];
|
|
30
|
+
};
|
|
31
|
+
/** What a relation's own resolver reads from `schema()`. */
|
|
32
|
+
export type RelationScope = {
|
|
33
|
+
/** The table that declares the relation. */
|
|
34
|
+
readonly owner: string;
|
|
35
|
+
/** The relation name. */
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly edges: readonly RelationEdge[];
|
|
38
|
+
/** Every table name in the schema, sorted. */
|
|
39
|
+
readonly tables: readonly string[];
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* A to-many relation through a join table.
|
|
43
|
+
*
|
|
44
|
+
* It is a {@link ManyRelation} to the types, so `include`, `has`, `none`, and
|
|
45
|
+
* `every` read it as one. `resolve` is what `schema()` calls in place of the
|
|
46
|
+
* foreign-key search that `many` uses.
|
|
47
|
+
*/
|
|
48
|
+
export type ManyThroughRelation<TTable extends string = string> = ManyRelation<TTable> & {
|
|
49
|
+
/** The join table. */
|
|
50
|
+
readonly through: string;
|
|
51
|
+
/** Turns this declaration into a resolved model. */
|
|
52
|
+
readonly resolve: (scope: RelationScope) => RelationModel;
|
|
53
|
+
};
|
|
54
|
+
/** Join-table foreign keys, named only when more than one points at a table. */
|
|
55
|
+
export type ThroughKeys = {
|
|
56
|
+
/** The join table field that references the declaring table. */
|
|
57
|
+
readonly from?: string;
|
|
58
|
+
/** The join table field that references the related table. */
|
|
59
|
+
readonly to?: string;
|
|
60
|
+
};
|
|
19
61
|
/** A relation `table()` stores. */
|
|
20
62
|
export type RelationCall = OneRelation | ManyRelation;
|
|
21
63
|
/**
|
|
@@ -43,3 +85,18 @@ export declare function many<const TTable extends string>(table: TTable, field?:
|
|
|
43
85
|
* @returns `true` for `one` and `many`
|
|
44
86
|
*/
|
|
45
87
|
export declare function isRelationCall(value: unknown): value is RelationCall;
|
|
88
|
+
/**
|
|
89
|
+
* Declares a to-many relation through a join table.
|
|
90
|
+
*
|
|
91
|
+
* The join table has one foreign key to the declaring table and one to the
|
|
92
|
+
* related table. Name `from` and `to` when a table has more than one. Tenancy
|
|
93
|
+
* and archivable apply to the join rows and to the related rows alike.
|
|
94
|
+
*
|
|
95
|
+
* @typeParam TTable - Related table
|
|
96
|
+
* @param table - Related table name
|
|
97
|
+
* @param options - The join table, and its foreign-key fields when ambiguous
|
|
98
|
+
* @returns The relation `schema()` resolves
|
|
99
|
+
*/
|
|
100
|
+
export declare function manyThrough<const TTable extends string>(table: TTable, options: {
|
|
101
|
+
readonly through: string;
|
|
102
|
+
} & ThroughKeys): ManyThroughRelation<TTable>;
|
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
* Work happens here, not in `table()` and not at import.
|
|
5
5
|
*/
|
|
6
6
|
import type { Catalog } from "../../contracts/catalog/types.js";
|
|
7
|
-
import { type
|
|
8
|
-
import { type
|
|
7
|
+
import { type ClientGenerator } from "../../contracts/generator.js";
|
|
8
|
+
import { type SchemaHook, type TableModel } from "./model.js";
|
|
9
|
+
import type { FieldsOfList, HasArchive, PresetsOfList, Trait } from "./trait.js";
|
|
10
|
+
import { type ColumnTenancy, type TenantFields } from "./tenancy.js";
|
|
11
|
+
import { type AnyTable, type InsertFrom, type RowFrom, type UpdateFrom } from "./table.js";
|
|
9
12
|
/** Codec defaults from spec section 6.6. */
|
|
10
13
|
export type SchemaCodecs = {
|
|
11
14
|
readonly bigint: "string" | "number" | "bigint";
|
|
@@ -33,8 +36,28 @@ export type SchemaInput<TTables extends readonly AnyTable[]> = {
|
|
|
33
36
|
readonly timestamps?: SchemaCodecs["timestamps"];
|
|
34
37
|
};
|
|
35
38
|
readonly types?: "emitted" | "inferred";
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
/**
|
|
40
|
+
* What a bare `t.id()` means.
|
|
41
|
+
*
|
|
42
|
+
* `"uuidv7"` and `"uuidv4"` are database defaults. A client generator is
|
|
43
|
+
* filled on insert and stays out of the catalog. A column option wins.
|
|
44
|
+
*/
|
|
45
|
+
readonly defaults?: {
|
|
46
|
+
readonly id?: "uuidv7" | "uuidv4" | ClientGenerator<string>;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Traits applied to every table.
|
|
50
|
+
*
|
|
51
|
+
* A table opts out with `omitDefaults` and a reason. A table's own `traits`
|
|
52
|
+
* are added as well.
|
|
53
|
+
*/
|
|
54
|
+
readonly traits?: readonly Trait[];
|
|
55
|
+
/**
|
|
56
|
+
* Column tenancy.
|
|
57
|
+
*
|
|
58
|
+
* Every table gains the key unless it passes `global("reason")`.
|
|
59
|
+
*/
|
|
60
|
+
readonly tenancy?: ColumnTenancy;
|
|
38
61
|
readonly validation?: unknown;
|
|
39
62
|
readonly extensions?: unknown;
|
|
40
63
|
readonly functions?: unknown;
|
|
@@ -59,11 +82,68 @@ export type BuiltSchema<TTables extends readonly AnyTable[]> = {
|
|
|
59
82
|
readonly codecs: SchemaCodecs;
|
|
60
83
|
readonly requires: SchemaRequires | undefined;
|
|
61
84
|
readonly tables: TTables;
|
|
85
|
+
/**
|
|
86
|
+
* Schema traits, when the call passed a non-empty list.
|
|
87
|
+
*
|
|
88
|
+
* Omitted otherwise, so a schema that uses no traits does not carry the key.
|
|
89
|
+
*/
|
|
90
|
+
readonly traits?: readonly Trait[];
|
|
91
|
+
/**
|
|
92
|
+
* Column tenancy, when the call passed it.
|
|
93
|
+
*
|
|
94
|
+
* Omitted otherwise, so a schema with no tenancy does not carry the key.
|
|
95
|
+
*/
|
|
96
|
+
readonly tenancy?: ColumnTenancy;
|
|
62
97
|
/** Query model. Built once, beside the catalog document. */
|
|
63
98
|
readonly model: {
|
|
64
99
|
readonly [T in TTables[number] as T["~name"]]: TableModel;
|
|
65
100
|
};
|
|
66
101
|
};
|
|
102
|
+
/**
|
|
103
|
+
* A schema whose tenant tables carry the tenant key on the row.
|
|
104
|
+
*
|
|
105
|
+
* A table marked `~global` keeps its own type. No tenancy leaves the schema
|
|
106
|
+
* type unchanged.
|
|
107
|
+
*
|
|
108
|
+
* @typeParam S - Schema type before tenancy
|
|
109
|
+
* @typeParam TTables - Tables in declaration order
|
|
110
|
+
* @typeParam TTenancy - Column tenancy, or `undefined`
|
|
111
|
+
*/
|
|
112
|
+
export type TenancySchema<S, TTables extends readonly AnyTable[], TTenancy> = TTenancy extends ColumnTenancy ? Omit<S, "~byName"> & {
|
|
113
|
+
readonly tenancy: TTenancy;
|
|
114
|
+
readonly "~byName": {
|
|
115
|
+
readonly [T in TTables[number] as T["~name"]]: T extends {
|
|
116
|
+
readonly "~global": string;
|
|
117
|
+
} ? T : T & {
|
|
118
|
+
readonly "~row": RowFrom<TenantFields<TTenancy["key"]>>;
|
|
119
|
+
readonly "~insert": InsertFrom<TenantFields<TTenancy["key"]>>;
|
|
120
|
+
readonly "~update": UpdateFrom<TenantFields<TTenancy["key"]>>;
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
} : S;
|
|
124
|
+
/**
|
|
125
|
+
* A schema whose default traits are part of every table's row type.
|
|
126
|
+
*
|
|
127
|
+
* A table with `omitDefaults` keeps its own type. An empty trait list does not
|
|
128
|
+
* change the schema type.
|
|
129
|
+
*
|
|
130
|
+
* @typeParam TTables - Tables in declaration order
|
|
131
|
+
* @typeParam TTraits - Schema default traits
|
|
132
|
+
*/
|
|
133
|
+
export type SchemaWithTraits<TTables extends readonly AnyTable[], TTraits extends readonly {
|
|
134
|
+
readonly fields: Readonly<Record<string, object>>;
|
|
135
|
+
}[]> = [keyof FieldsOfList<TTraits> | keyof PresetsOfList<TTraits>] extends [never] ? BuiltSchema<TTables> : Omit<BuiltSchema<TTables>, "~byName"> & {
|
|
136
|
+
readonly "~byName": {
|
|
137
|
+
readonly [T in TTables[number] as T["~name"]]: ApplySchemaTraits<T, FieldsOfList<TTraits>, TTraits>;
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
type ApplySchemaTraits<TTable, TFields, TTraits> = TTable extends {
|
|
141
|
+
readonly "~omitDefaults": true;
|
|
142
|
+
} ? TTable : TTable & {
|
|
143
|
+
readonly "~row": RowFrom<TFields>;
|
|
144
|
+
readonly "~insert": InsertFrom<TFields>;
|
|
145
|
+
readonly "~update": UpdateFrom<TFields>;
|
|
146
|
+
} & HasArchive<TTraits> & PresetsOfList<TTraits>;
|
|
67
147
|
/**
|
|
68
148
|
* Compiles tables into a catalog.
|
|
69
149
|
*
|
|
@@ -74,4 +154,28 @@ export type BuiltSchema<TTables extends readonly AnyTable[]> = {
|
|
|
74
154
|
* @param config - Tables, casing, codecs, and the row-type mode
|
|
75
155
|
* @returns The schema and its catalog
|
|
76
156
|
*/
|
|
77
|
-
export declare function schema<const TTables extends readonly AnyTable[]
|
|
157
|
+
export declare function schema<const TTables extends readonly AnyTable[], const TTraits extends readonly {
|
|
158
|
+
readonly fields: Readonly<Record<string, object>>;
|
|
159
|
+
}[], const TTenancy extends ColumnTenancy | undefined = undefined, const TValidation = undefined>(config: Omit<SchemaInput<TTables>, "traits" | "tenancy" | "validation"> & {
|
|
160
|
+
readonly traits: TTraits;
|
|
161
|
+
readonly tenancy?: TTenancy;
|
|
162
|
+
readonly validation?: TValidation;
|
|
163
|
+
}): [TValidation] extends [undefined] ? TenancySchema<SchemaWithTraits<TTables, TTraits>, TTables, TTenancy> : TenancySchema<SchemaWithTraits<TTables, TTraits>, TTables, TTenancy> & {
|
|
164
|
+
readonly "~validation": TValidation;
|
|
165
|
+
};
|
|
166
|
+
export declare function schema<const TTables extends readonly AnyTable[], const TTenancy extends ColumnTenancy | undefined = undefined, const TValidation = undefined>(config: Omit<SchemaInput<TTables>, "tenancy" | "validation"> & {
|
|
167
|
+
readonly tenancy?: TTenancy;
|
|
168
|
+
readonly validation?: TValidation;
|
|
169
|
+
}): [TValidation] extends [undefined] ? TenancySchema<BuiltSchema<TTables>, TTables, TTenancy> : TenancySchema<BuiltSchema<TTables>, TTables, TTenancy> & {
|
|
170
|
+
readonly "~validation": TValidation;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* Registers a hook from an opt-in module.
|
|
174
|
+
*
|
|
175
|
+
* Core does not import that module. A featureless app never calls this, so
|
|
176
|
+
* the module that loads the validation engine stays out of its graph.
|
|
177
|
+
*
|
|
178
|
+
* @param hook - Called for the client and for each table
|
|
179
|
+
*/
|
|
180
|
+
export declare function addSchemaHook(hook: SchemaHook): void;
|
|
181
|
+
export {};
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { type ColumnInsertOf, type ColumnRowOf, type ColumnUpdateOf } from "./column.js";
|
|
8
8
|
import { type RelationCall } from "./relations.js";
|
|
9
|
+
import type { PresetMap } from "./preset.js";
|
|
10
|
+
import { type FieldsOfList, type HasArchive, type PresetsOfList, type Trait } from "./trait.js";
|
|
9
11
|
/**
|
|
10
12
|
* A column as seen by `indexes` and `checks`.
|
|
11
13
|
*
|
|
@@ -20,6 +22,12 @@ export type ColumnHandle = {
|
|
|
20
22
|
export type IndexCall = {
|
|
21
23
|
readonly columns: readonly string[];
|
|
22
24
|
readonly isUnique: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Partial-index predicate, stored as the catalog wrote it.
|
|
27
|
+
*
|
|
28
|
+
* Absent on an ordinary index.
|
|
29
|
+
*/
|
|
30
|
+
readonly predicate?: string;
|
|
23
31
|
/**
|
|
24
32
|
* Marks the index unique.
|
|
25
33
|
*
|
|
@@ -52,16 +60,50 @@ export type TableOptions<TColumns> = {
|
|
|
52
60
|
readonly unique?: {
|
|
53
61
|
readonly [name: string]: readonly (keyof TColumns & string)[];
|
|
54
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* Composite primary key, in column order.
|
|
65
|
+
*
|
|
66
|
+
* A single-column key can use this or `.primaryKey()` on the column.
|
|
67
|
+
* One table has one primary key.
|
|
68
|
+
*/
|
|
69
|
+
readonly primaryKey?: readonly (keyof TColumns & string)[];
|
|
55
70
|
readonly sqlName?: string;
|
|
56
71
|
readonly renamedFrom?: string;
|
|
57
72
|
readonly comment?: string;
|
|
58
73
|
readonly validate?: unknown;
|
|
59
74
|
readonly validation?: unknown;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Traits added to this table.
|
|
77
|
+
*
|
|
78
|
+
* Schema default traits are added as well, unless `omitDefaults` is set.
|
|
79
|
+
*/
|
|
80
|
+
readonly traits?: readonly Trait[];
|
|
81
|
+
/**
|
|
82
|
+
* Skip schema default traits.
|
|
83
|
+
*
|
|
84
|
+
* The value is the reason. An empty reason is rejected when the schema is built.
|
|
85
|
+
*/
|
|
86
|
+
readonly omitDefaults?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Opts this table out of schema tenancy.
|
|
89
|
+
*
|
|
90
|
+
* `global("reason")` is the opt-out. `{ via }` arrives later.
|
|
91
|
+
*/
|
|
92
|
+
readonly tenancy?: {
|
|
93
|
+
readonly kind: "global";
|
|
94
|
+
readonly reason: string;
|
|
95
|
+
} | {
|
|
96
|
+
readonly via: string;
|
|
97
|
+
};
|
|
63
98
|
readonly computed?: unknown;
|
|
64
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Named, typed refinements called as `tasks.pending()`.
|
|
101
|
+
*
|
|
102
|
+
* A preset gets a builder and its own arguments and returns the builder.
|
|
103
|
+
* The builder only adds predicates. A name that is a client method or is
|
|
104
|
+
* reserved is OKM1040.
|
|
105
|
+
*/
|
|
106
|
+
readonly presets?: PresetMap<RowFrom<TColumns>>;
|
|
65
107
|
readonly policies?: unknown;
|
|
66
108
|
readonly reference?: unknown;
|
|
67
109
|
/** `one` and `many`. Other relation kinds stay reserved. */
|
|
@@ -85,16 +127,39 @@ export type Handles<TColumns> = {
|
|
|
85
127
|
* @typeParam TColumns - Column builders
|
|
86
128
|
* @typeParam TRelations - Relations declared on this table
|
|
87
129
|
*/
|
|
88
|
-
export type Table<TName extends string, TColumns, TRelations extends Readonly<Record<string, RelationCall>> = Readonly<Record<string, never
|
|
130
|
+
export type Table<TName extends string, TColumns, TRelations extends Readonly<Record<string, RelationCall>> = Readonly<Record<string, never>>, TKey extends string = never, TOptions = object> = {
|
|
89
131
|
readonly "~name": TName;
|
|
90
132
|
readonly "~columns": TColumns;
|
|
91
133
|
readonly "~row": RowFrom<TColumns>;
|
|
92
134
|
readonly "~insert": InsertFrom<TColumns>;
|
|
93
|
-
readonly "~update": UpdateFrom<TColumns>;
|
|
135
|
+
readonly "~update": UpdateFrom<TColumns, TKey>;
|
|
94
136
|
readonly "~relations": TRelations;
|
|
95
137
|
readonly name: TName;
|
|
96
138
|
readonly columns: TColumns;
|
|
97
|
-
readonly options?:
|
|
139
|
+
readonly options?: TOptions;
|
|
140
|
+
/**
|
|
141
|
+
* Allowlisted client filters.
|
|
142
|
+
*
|
|
143
|
+
* A hidden field in `allow`, `sort`, or `relations` throws OKM1123 here.
|
|
144
|
+
* `parse` loads the parser on first use.
|
|
145
|
+
*
|
|
146
|
+
* @param spec - Fields, operators, and sorts the caller may send
|
|
147
|
+
* @returns A parser for one request object
|
|
148
|
+
*/
|
|
149
|
+
filters(spec: FilterSpec): {
|
|
150
|
+
parse(query: unknown): Promise<ParsedFilters>;
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
/** What {@link Table.filters} accepts. */
|
|
154
|
+
export type FilterSpec = {
|
|
155
|
+
readonly allow?: Readonly<Record<string, readonly string[]>>;
|
|
156
|
+
readonly sort?: readonly string[];
|
|
157
|
+
readonly relations?: Readonly<Record<string, readonly string[]>>;
|
|
158
|
+
};
|
|
159
|
+
/** `where` and `orderBy` a caller can spread into `find`. */
|
|
160
|
+
export type ParsedFilters = {
|
|
161
|
+
readonly where: Readonly<Record<string, unknown>>;
|
|
162
|
+
readonly orderBy?: Readonly<Record<string, "asc" | "desc">>;
|
|
98
163
|
};
|
|
99
164
|
/**
|
|
100
165
|
* Any table `schema()` can compile.
|
|
@@ -108,6 +173,8 @@ export type AnyTable = {
|
|
|
108
173
|
readonly name: string;
|
|
109
174
|
readonly columns: Readonly<Record<string, object>>;
|
|
110
175
|
readonly options?: object;
|
|
176
|
+
/** `file.ts:line` of the `table()` call. Not part of the catalog hash. */
|
|
177
|
+
readonly source?: string;
|
|
111
178
|
};
|
|
112
179
|
/**
|
|
113
180
|
* Row shape. Hidden columns are omitted.
|
|
@@ -130,8 +197,8 @@ export type InsertFrom<TColumns> = {
|
|
|
130
197
|
*
|
|
131
198
|
* @typeParam TColumns - Column builders
|
|
132
199
|
*/
|
|
133
|
-
export type UpdateFrom<TColumns> = {
|
|
134
|
-
readonly [K in keyof TColumns as ColumnUpdateOf<TColumns[K]> extends never ? never : K]: ColumnUpdateOf<TColumns[K]>;
|
|
200
|
+
export type UpdateFrom<TColumns, TKey extends string = never> = {
|
|
201
|
+
readonly [K in keyof TColumns as K extends TKey ? never : ColumnUpdateOf<TColumns[K]> extends never ? never : K]: ColumnUpdateOf<TColumns[K]>;
|
|
135
202
|
};
|
|
136
203
|
/**
|
|
137
204
|
* Declares a table.
|
|
@@ -145,8 +212,8 @@ export type UpdateFrom<TColumns> = {
|
|
|
145
212
|
* @param options - Indexes, checks, unique constraints, and names
|
|
146
213
|
* @returns The table
|
|
147
214
|
*/
|
|
148
|
-
export declare function table<const TName extends string, const TColumns extends Readonly<Record<string, object>>>(name: TName, columns: TColumns): Table<TName, TColumns, Readonly<Record<string, never
|
|
149
|
-
export declare function table<const TName extends string, const TColumns extends Readonly<Record<string, object>>, const TOptions extends TableOptions<TColumns>>(name: TName, columns: TColumns, options: TOptions):
|
|
215
|
+
export declare function table<const TName extends string, const TColumns extends Readonly<Record<string, object>>>(name: TName, columns: TColumns): Table<TName, TColumns, Readonly<Record<string, never>>, never>;
|
|
216
|
+
export declare function table<const TName extends string, const TColumns extends Readonly<Record<string, object>>, const TOptions extends TableOptions<TColumns>>(name: TName, columns: TColumns, options: TOptions): DeclaredTable<TName, TColumns, TOptions>;
|
|
150
217
|
/**
|
|
151
218
|
* Relation map stored on a table.
|
|
152
219
|
*
|
|
@@ -158,6 +225,58 @@ export declare function table<const TName extends string, const TColumns extends
|
|
|
158
225
|
type RelationsOf<TOptions> = TOptions extends {
|
|
159
226
|
readonly relations: infer R;
|
|
160
227
|
} ? R extends Readonly<Record<string, RelationCall>> ? R : Readonly<Record<string, never>> : Readonly<Record<string, never>>;
|
|
228
|
+
/**
|
|
229
|
+
* Column names listed in a table's `primaryKey` option.
|
|
230
|
+
*
|
|
231
|
+
* Absent when the option is omitted, so a table without it does not change
|
|
232
|
+
* its update shape.
|
|
233
|
+
*
|
|
234
|
+
* @typeParam TOptions - Options argument
|
|
235
|
+
*/
|
|
236
|
+
type PrimaryOf<TOptions> = TOptions extends {
|
|
237
|
+
readonly primaryKey: infer K;
|
|
238
|
+
} ? K extends readonly (infer F)[] ? Extract<F, string> : never : never;
|
|
239
|
+
/**
|
|
240
|
+
* Table type callers see, including trait fields and an opt-out of schema traits.
|
|
241
|
+
*
|
|
242
|
+
* @typeParam TName - Table name
|
|
243
|
+
* @typeParam TColumns - Column builders
|
|
244
|
+
* @typeParam TOptions - Options argument
|
|
245
|
+
*/
|
|
246
|
+
type DeclaredTable<TName extends string, TColumns, TOptions> = Table<TName, TColumns, RelationsOf<TOptions>, PrimaryOf<TOptions>, NoInfer<TOptions>> & TraitShapes<TColumns, TOptions> & ArchiveFlag<TOptions> & PresetFlag<TOptions> & OmitFlag<TOptions> & GlobalFlag<TOptions>;
|
|
247
|
+
type ArchiveFlag<TOptions> = TOptions extends {
|
|
248
|
+
readonly traits: infer TTraits;
|
|
249
|
+
} ? HasArchive<TTraits> : unknown;
|
|
250
|
+
/** `{ "~presets" }` from the table's own `presets` and its traits' presets, when there are any. */
|
|
251
|
+
type PresetFlag<TOptions> = (TOptions extends {
|
|
252
|
+
readonly presets: infer TPresets;
|
|
253
|
+
} ? {
|
|
254
|
+
readonly "~presets": TPresets;
|
|
255
|
+
} : unknown) & (TOptions extends {
|
|
256
|
+
readonly traits: infer TTraits;
|
|
257
|
+
} ? PresetsOfList<TTraits> : unknown);
|
|
258
|
+
type OmitFlag<TOptions> = TOptions extends {
|
|
259
|
+
readonly omitDefaults: string;
|
|
260
|
+
} ? {
|
|
261
|
+
readonly "~omitDefaults": true;
|
|
262
|
+
} : unknown;
|
|
263
|
+
type GlobalFlag<TOptions> = TOptions extends {
|
|
264
|
+
readonly tenancy: {
|
|
265
|
+
readonly kind: "global";
|
|
266
|
+
readonly reason: infer TReason;
|
|
267
|
+
};
|
|
268
|
+
} ? {
|
|
269
|
+
readonly "~global": TReason;
|
|
270
|
+
} : unknown;
|
|
271
|
+
type TraitShapes<TColumns, TOptions> = TOptions extends {
|
|
272
|
+
readonly traits: infer TTraits;
|
|
273
|
+
} ? TTraits extends readonly {
|
|
274
|
+
readonly fields: Readonly<Record<string, object>>;
|
|
275
|
+
}[] ? keyof FieldsOfList<TTraits> extends never ? unknown : {
|
|
276
|
+
readonly "~row": RowFrom<TColumns> & RowFrom<FieldsOfList<TTraits>>;
|
|
277
|
+
readonly "~insert": InsertFrom<TColumns> & InsertFrom<FieldsOfList<TTraits>>;
|
|
278
|
+
readonly "~update": UpdateFrom<TColumns, PrimaryOf<TOptions>> & UpdateFrom<FieldsOfList<TTraits>>;
|
|
279
|
+
} : unknown : unknown;
|
|
161
280
|
/**
|
|
162
281
|
* Declares an index from column handles.
|
|
163
282
|
*
|
|
@@ -86,21 +86,23 @@ export declare function encodeTimeZone(value: TimeWithOffset, precision?: TimePr
|
|
|
86
86
|
/**
|
|
87
87
|
* Decodes a time with offset.
|
|
88
88
|
*
|
|
89
|
-
* @param wire - Time text plus an offset
|
|
90
|
-
* @returns Time and offset
|
|
89
|
+
* @param wire - Time text plus an offset, `±HH` as Postgres sends it or `±HH:MM`
|
|
90
|
+
* @returns Time and offset, the offset as `±HH:MM`
|
|
91
91
|
*/
|
|
92
92
|
export declare function decodeTimeZone(wire: string): TimeWithOffset;
|
|
93
93
|
/**
|
|
94
94
|
* Encodes a duration as an ISO-8601 duration.
|
|
95
95
|
*
|
|
96
96
|
* @param value - Duration
|
|
97
|
-
* @returns ISO-8601 text Postgres accepts for interval
|
|
97
|
+
* @returns ISO-8601 text Postgres accepts for interval, with a sign on each field when negative
|
|
98
98
|
*/
|
|
99
99
|
export declare function encodeDuration(value: Temporal.Duration): string;
|
|
100
100
|
/**
|
|
101
|
-
* Decodes an
|
|
101
|
+
* Decodes an interval as Postgres sends it: `1 year 2 mons 3 days 04:05:06.5`,
|
|
102
|
+
* `01:30:00`, or an ISO-8601 duration. A part may carry a sign. Parts of
|
|
103
|
+
* different signs (`1 day -01:00:00`) cannot be one `Temporal.Duration`.
|
|
102
104
|
*
|
|
103
|
-
* @param wire -
|
|
105
|
+
* @param wire - Interval text
|
|
104
106
|
* @returns A duration
|
|
105
107
|
*/
|
|
106
108
|
export declare function decodeDuration(wire: string): Temporal.Duration;
|
|
@@ -202,10 +204,10 @@ declare global {
|
|
|
202
204
|
};
|
|
203
205
|
readonly Duration: {
|
|
204
206
|
/**
|
|
205
|
-
* @param item - ISO-8601 duration
|
|
207
|
+
* @param item - ISO-8601 duration, or numeric fields
|
|
206
208
|
* @returns A duration
|
|
207
209
|
*/
|
|
208
|
-
from(item: string): Temporal.Duration;
|
|
210
|
+
from(item: string | Readonly<Record<string, number>>): Temporal.Duration;
|
|
209
211
|
};
|
|
210
212
|
};
|
|
211
213
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tenancy object `schema()` calls once.
|
|
3
|
+
*
|
|
4
|
+
* The methods live on the value `columnTenancy()` returns from `okmodel/tenancy`.
|
|
5
|
+
* This file only names them. An application that never imports that subpath
|
|
6
|
+
* does not load them.
|
|
7
|
+
*/
|
|
8
|
+
import type { ColumnBuilder, FlagTrue, PlainFlags } from "./column.js";
|
|
9
|
+
import type { SchemaHookCtx } from "./model.js";
|
|
10
|
+
import type { AnyTable } from "./table.js";
|
|
11
|
+
/**
|
|
12
|
+
* A guarded uuid column, one per tenant table.
|
|
13
|
+
*
|
|
14
|
+
* Insert and update omit it. The client fills it from the scope.
|
|
15
|
+
*/
|
|
16
|
+
export type TenantFields<Key extends string> = {
|
|
17
|
+
readonly [K in Key]: ColumnBuilder<string, FlagTrue<PlainFlags, "guarded">>;
|
|
18
|
+
};
|
|
19
|
+
/** One tenant value, or a reason for leaving the scope. The value is not a cache key. */
|
|
20
|
+
export type TenantCall = {
|
|
21
|
+
readonly value: string;
|
|
22
|
+
} | {
|
|
23
|
+
readonly unscoped: string;
|
|
24
|
+
};
|
|
25
|
+
/** Text the scope predicate writes. The planner's sink has these methods. */
|
|
26
|
+
export type TenancyText = {
|
|
27
|
+
text(value: string): void;
|
|
28
|
+
param(encoded: string): void;
|
|
29
|
+
mark(token: string): void;
|
|
30
|
+
};
|
|
31
|
+
/** `for()` and `unscoped()` plus the table names the root client keeps. */
|
|
32
|
+
export type TenancyClient = {
|
|
33
|
+
readonly names: readonly string[];
|
|
34
|
+
readonly for?: (input: unknown) => unknown;
|
|
35
|
+
readonly unscoped?: (reason: string) => unknown;
|
|
36
|
+
};
|
|
37
|
+
/** One inspect rule the tenancy object recorded. */
|
|
38
|
+
export type TenancyRule = {
|
|
39
|
+
readonly rule: string;
|
|
40
|
+
readonly contribution: string;
|
|
41
|
+
readonly provenance: string;
|
|
42
|
+
readonly source?: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Column tenancy passed to `schema({ tenancy })`.
|
|
46
|
+
*
|
|
47
|
+
* `columnTenancy()` from `okmodel/tenancy` builds it. `rewrite` runs once,
|
|
48
|
+
* before compile. The other methods are the planner and the client.
|
|
49
|
+
*/
|
|
50
|
+
export type ColumnTenancy = {
|
|
51
|
+
readonly key: string;
|
|
52
|
+
readonly type: "uuid";
|
|
53
|
+
readonly strategy: "column";
|
|
54
|
+
/** Tables with the tenant column, widened uniques, and composite references. */
|
|
55
|
+
rewrite(tables: readonly AnyTable[]): readonly AnyTable[];
|
|
56
|
+
/** The guarded uuid column, for emitted row types. */
|
|
57
|
+
column(): object;
|
|
58
|
+
predicate(input: {
|
|
59
|
+
readonly table: string;
|
|
60
|
+
readonly fieldSql: (field: string) => string | undefined;
|
|
61
|
+
readonly encode: ((value: unknown) => string) | undefined;
|
|
62
|
+
readonly alias: string;
|
|
63
|
+
readonly appended: boolean;
|
|
64
|
+
readonly scope: TenantCall | undefined;
|
|
65
|
+
readonly sink: TenancyText;
|
|
66
|
+
}): boolean;
|
|
67
|
+
guard(table: string, field: string, kind: "where" | "insert" | "update"): void;
|
|
68
|
+
stamp(table: string, rows: Record<string, unknown>[], scope: TenantCall | undefined): void;
|
|
69
|
+
client(input: {
|
|
70
|
+
readonly names: readonly string[];
|
|
71
|
+
readonly scoped: boolean;
|
|
72
|
+
readonly open: (scope: TenantCall) => unknown;
|
|
73
|
+
}): TenancyClient;
|
|
74
|
+
rules(table: string, source: string | undefined, scope: TenantCall | undefined): readonly TenancyRule[];
|
|
75
|
+
/**
|
|
76
|
+
* Attaches `for()` and `unscoped()` on the root client.
|
|
77
|
+
*
|
|
78
|
+
* The same hook archivable uses for its table methods.
|
|
79
|
+
*
|
|
80
|
+
* @param target - The client object
|
|
81
|
+
* @param ctx - Names, scope, and the table map
|
|
82
|
+
*/
|
|
83
|
+
hook(target: Record<string, unknown>, ctx: SchemaHookCtx): void;
|
|
84
|
+
missing(table: string): never;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Reads `schema({ tenancy })`.
|
|
88
|
+
*
|
|
89
|
+
* Omitted stays `undefined`. Anything else must be `columnTenancy()`.
|
|
90
|
+
*
|
|
91
|
+
* @param value - The option the caller passed
|
|
92
|
+
* @returns The tenancy object, or `undefined`
|
|
93
|
+
*/
|
|
94
|
+
export declare function readTenancy(value: unknown): ColumnTenancy | undefined;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolver and emitter of a `manyThrough` relation.
|
|
3
|
+
*
|
|
4
|
+
* The relation object carries both. `schema()` calls the resolver, and the
|
|
5
|
+
* planner calls the emitter with its own helpers, so a schema that has no
|
|
6
|
+
* `manyThrough` ships none of this. A join row or target in another tenant or
|
|
7
|
+
* archived never shows: the same planner predicates apply to both tables.
|
|
8
|
+
*/
|
|
9
|
+
import type { RelationScope } from "./relations.js";
|
|
10
|
+
import type { RelationModel } from "./model.js";
|
|
11
|
+
/**
|
|
12
|
+
* Resolves a `manyThrough` declaration against the schema's foreign keys.
|
|
13
|
+
*
|
|
14
|
+
* @param scope - What `schema()` knows
|
|
15
|
+
* @param table - Related table name
|
|
16
|
+
* @param through - Join table name
|
|
17
|
+
* @param from - Join table field that references the declaring table, when ambiguous
|
|
18
|
+
* @param to - Join table field that references the related table, when ambiguous
|
|
19
|
+
* @returns The resolved relation, carrying its emitter
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveThrough(scope: RelationScope, table: string, through: string, from: string | undefined, to: string | undefined): RelationModel;
|