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
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import {
|
|
2
|
+
definition,
|
|
3
|
+
rejected,
|
|
4
|
+
quoteLiteral,
|
|
5
|
+
writeArray,
|
|
6
|
+
readArray
|
|
7
|
+
} from "./xatfg0gn.js";
|
|
8
|
+
import {
|
|
9
|
+
REFERENTIAL_ACTIONS,
|
|
10
|
+
referentialAction
|
|
11
|
+
} from "./4e4c6vq2.js";
|
|
12
|
+
import {
|
|
13
|
+
readClientGenerator
|
|
14
|
+
} from "./rwmrejjz.js";
|
|
15
|
+
|
|
16
|
+
// src/dialects/pg/column.ts
|
|
17
|
+
class ColumnBuilder2 {
|
|
18
|
+
state;
|
|
19
|
+
constructor(state) {
|
|
20
|
+
this.state = state;
|
|
21
|
+
}
|
|
22
|
+
encode(value) {
|
|
23
|
+
return this.state.encode(value);
|
|
24
|
+
}
|
|
25
|
+
decode(wire) {
|
|
26
|
+
return this.state.decode(wire);
|
|
27
|
+
}
|
|
28
|
+
nullable() {
|
|
29
|
+
return rebuild(this.state, { nullable: true });
|
|
30
|
+
}
|
|
31
|
+
default(value) {
|
|
32
|
+
const clientDefault = readClientGenerator(value);
|
|
33
|
+
if (clientDefault !== undefined) {
|
|
34
|
+
return rebuild(this.state, {
|
|
35
|
+
hasDefault: true,
|
|
36
|
+
defaultSql: undefined,
|
|
37
|
+
defaultValue: undefined,
|
|
38
|
+
clientDefault,
|
|
39
|
+
generated: undefined
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (value === null && this.state.nullable === false) {
|
|
43
|
+
definition("A null default is only accepted on a nullable column. Call .nullable() first.");
|
|
44
|
+
}
|
|
45
|
+
if (this.state.picklist !== undefined && value !== null) {
|
|
46
|
+
const text = String(value);
|
|
47
|
+
if (!this.state.picklist.values.includes(text)) {
|
|
48
|
+
definition(`Default ${text} is not in the picklist ${this.state.picklist.values.join(", ")}.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return rebuild(this.state, {
|
|
52
|
+
hasDefault: true,
|
|
53
|
+
defaultSql: value === null ? "NULL" : sqlOf(this.state, value),
|
|
54
|
+
defaultValue: value,
|
|
55
|
+
clientDefault: undefined,
|
|
56
|
+
generated: undefined
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
defaultSql(expression) {
|
|
60
|
+
if (expression.length === 0) {
|
|
61
|
+
definition("defaultSql must be a non-empty SQL expression.");
|
|
62
|
+
}
|
|
63
|
+
return rebuild(this.state, {
|
|
64
|
+
hasDefault: true,
|
|
65
|
+
defaultSql: expression,
|
|
66
|
+
defaultValue: undefined,
|
|
67
|
+
clientDefault: undefined,
|
|
68
|
+
generated: undefined
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
primaryKey() {
|
|
72
|
+
return rebuild(this.state, {
|
|
73
|
+
primaryKey: true,
|
|
74
|
+
omitUpdate: true
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
unique(options) {
|
|
78
|
+
const marker = options?.global;
|
|
79
|
+
if (typeof marker === "string" && marker.trim().length === 0) {
|
|
80
|
+
definition("unique() global needs a reason.");
|
|
81
|
+
}
|
|
82
|
+
const named = typeof marker === "string" ? marker.trim() : undefined;
|
|
83
|
+
const globalFlag = typeof marker === "string" ? true : marker;
|
|
84
|
+
return rebuild(this.state, {
|
|
85
|
+
unique: {
|
|
86
|
+
reason: named ?? options?.reason,
|
|
87
|
+
global: globalFlag
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
picklist(values, options) {
|
|
92
|
+
if (values.length === 0) {
|
|
93
|
+
definition("A picklist must contain at least one value.");
|
|
94
|
+
}
|
|
95
|
+
const allowed = new Set;
|
|
96
|
+
for (const value of values) {
|
|
97
|
+
if (value.length === 0) {
|
|
98
|
+
definition("Picklist values must be non-empty strings.");
|
|
99
|
+
}
|
|
100
|
+
if (allowed.has(value)) {
|
|
101
|
+
definition(`Picklist value ${value} is repeated. Each value is accepted once.`);
|
|
102
|
+
}
|
|
103
|
+
allowed.add(value);
|
|
104
|
+
}
|
|
105
|
+
if (typeof this.state.defaultValue === "string" && !allowed.has(this.state.defaultValue)) {
|
|
106
|
+
definition(`Default ${this.state.defaultValue} is not in the picklist ${values.join(", ")}.`);
|
|
107
|
+
}
|
|
108
|
+
const previous = this.state.elementEncode;
|
|
109
|
+
const elementEncode = (value) => {
|
|
110
|
+
if (typeof value !== "string" || !allowed.has(value)) {
|
|
111
|
+
rejected(`Picklist rejected ${String(value)}. Accepted values: ${[...allowed].join(", ")}.`);
|
|
112
|
+
}
|
|
113
|
+
return previous(value);
|
|
114
|
+
};
|
|
115
|
+
return rebuild(this.state, {
|
|
116
|
+
picklist: { values: values.slice(), check: options?.check !== false },
|
|
117
|
+
elementEncode,
|
|
118
|
+
encode: elementEncode
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
generated(expression, options) {
|
|
122
|
+
if (expression.length === 0) {
|
|
123
|
+
definition("generated() must be a non-empty SQL expression.");
|
|
124
|
+
}
|
|
125
|
+
return rebuild(this.state, {
|
|
126
|
+
generated: { stored: options?.stored !== false, expression },
|
|
127
|
+
hasDefault: true,
|
|
128
|
+
defaultSql: undefined,
|
|
129
|
+
defaultValue: undefined,
|
|
130
|
+
clientDefault: undefined
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
guarded() {
|
|
134
|
+
return rebuild(this.state, { guarded: true });
|
|
135
|
+
}
|
|
136
|
+
hidden() {
|
|
137
|
+
return rebuild(this.state, { hidden: true });
|
|
138
|
+
}
|
|
139
|
+
sensitive() {
|
|
140
|
+
return rebuild(this.state, { sensitive: true });
|
|
141
|
+
}
|
|
142
|
+
validate(rules) {
|
|
143
|
+
const list = Array.isArray(rules) ? rules : [rules];
|
|
144
|
+
return rebuild(this.state, { validate: { rules: list } });
|
|
145
|
+
}
|
|
146
|
+
references(table, options) {
|
|
147
|
+
if (table.length === 0) {
|
|
148
|
+
definition("references() needs a table name.");
|
|
149
|
+
}
|
|
150
|
+
const onDelete = readAction(options?.onDelete, "onDelete");
|
|
151
|
+
const onUpdate = readAction(options?.onUpdate, "onUpdate");
|
|
152
|
+
const columns = readReferenceColumns(options?.columns);
|
|
153
|
+
return rebuild(this.state, {
|
|
154
|
+
references: {
|
|
155
|
+
table,
|
|
156
|
+
...onDelete !== undefined ? { onDelete } : {},
|
|
157
|
+
...onUpdate !== undefined ? { onUpdate } : {},
|
|
158
|
+
...columns !== undefined ? { columns } : {}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
renamedFrom(name) {
|
|
163
|
+
if (name.length === 0) {
|
|
164
|
+
definition("renamedFrom must be a non-empty previous column name.");
|
|
165
|
+
}
|
|
166
|
+
return rebuild(this.state, { renamedFrom: name });
|
|
167
|
+
}
|
|
168
|
+
sqlName(name) {
|
|
169
|
+
if (name.length === 0) {
|
|
170
|
+
definition("sqlName must be a non-empty SQL identifier.");
|
|
171
|
+
}
|
|
172
|
+
return rebuild(this.state, { sqlName: name });
|
|
173
|
+
}
|
|
174
|
+
comment(text) {
|
|
175
|
+
return rebuild(this.state, { comment: text });
|
|
176
|
+
}
|
|
177
|
+
array(options) {
|
|
178
|
+
if (this.state.dims !== 0) {
|
|
179
|
+
definition("array() accepts a scalar column. This column is already an array.");
|
|
180
|
+
}
|
|
181
|
+
const dims = options?.dims ?? 1;
|
|
182
|
+
if (!Number.isInteger(dims) || dims < 1 || dims > 6) {
|
|
183
|
+
definition(`Array dims ${String(dims)} must be an integer from 1 to 6.`);
|
|
184
|
+
}
|
|
185
|
+
const elementEncode = this.state.elementEncode;
|
|
186
|
+
const elementDecode = this.state.elementDecode;
|
|
187
|
+
const raw = this.state.sqlForm === "raw";
|
|
188
|
+
return rebuild(this.state, {
|
|
189
|
+
dims,
|
|
190
|
+
accepts: ["Array"],
|
|
191
|
+
encode: (value) => writeArray(value, dims, elementEncode, raw),
|
|
192
|
+
decode: (wire) => readArray(wire, dims, elementDecode)
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function required(body) {
|
|
197
|
+
return openColumn({
|
|
198
|
+
nullable: false,
|
|
199
|
+
hasDefault: false,
|
|
200
|
+
generated: false,
|
|
201
|
+
guarded: false,
|
|
202
|
+
hidden: false,
|
|
203
|
+
omitWrite: false,
|
|
204
|
+
...body
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function openColumn(input) {
|
|
208
|
+
const elementEncode = input.encode;
|
|
209
|
+
const elementDecode = input.decode;
|
|
210
|
+
return new ColumnBuilder2({
|
|
211
|
+
baseType: input.baseType,
|
|
212
|
+
dims: 0,
|
|
213
|
+
nullable: input.nullable,
|
|
214
|
+
hasDefault: input.hasDefault,
|
|
215
|
+
defaultSql: input.defaultSql,
|
|
216
|
+
defaultValue: undefined,
|
|
217
|
+
clientDefault: input.clientDefault,
|
|
218
|
+
collation: input.collation,
|
|
219
|
+
idSource: input.idSource,
|
|
220
|
+
identity: input.identity,
|
|
221
|
+
generated: undefined,
|
|
222
|
+
unique: undefined,
|
|
223
|
+
picklist: undefined,
|
|
224
|
+
guarded: input.guarded,
|
|
225
|
+
hidden: input.hidden,
|
|
226
|
+
sensitive: false,
|
|
227
|
+
omitWrite: input.omitWrite,
|
|
228
|
+
omitUpdate: input.omitUpdate === true,
|
|
229
|
+
renamedFrom: undefined,
|
|
230
|
+
sqlName: undefined,
|
|
231
|
+
comment: undefined,
|
|
232
|
+
extension: input.extension,
|
|
233
|
+
typeDependency: input.typeDependency,
|
|
234
|
+
enumLabels: input.enumLabels,
|
|
235
|
+
domain: input.domain,
|
|
236
|
+
primaryKey: input.primaryKey === true,
|
|
237
|
+
typeLabel: input.typeLabel,
|
|
238
|
+
references: undefined,
|
|
239
|
+
validate: undefined,
|
|
240
|
+
sqlForm: input.sqlForm,
|
|
241
|
+
encode: input.encode,
|
|
242
|
+
decode: input.decode,
|
|
243
|
+
elementEncode,
|
|
244
|
+
elementDecode,
|
|
245
|
+
accepts: input.accepts
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
function formatType(baseType, dims) {
|
|
249
|
+
if (dims === 0) {
|
|
250
|
+
return baseType;
|
|
251
|
+
}
|
|
252
|
+
return baseType + "[]".repeat(dims);
|
|
253
|
+
}
|
|
254
|
+
function sqlOf(state, value) {
|
|
255
|
+
const encoded = state.encode(value);
|
|
256
|
+
const typed = formatType(state.baseType, state.dims);
|
|
257
|
+
if (state.sqlForm === "cast") {
|
|
258
|
+
return `${quoteLiteral(encoded)}::${typed}`;
|
|
259
|
+
}
|
|
260
|
+
if (state.sqlForm === "json") {
|
|
261
|
+
return `${quoteLiteral(encoded)}::json`;
|
|
262
|
+
}
|
|
263
|
+
if (state.sqlForm === "jsonb") {
|
|
264
|
+
return `${quoteLiteral(encoded)}::jsonb`;
|
|
265
|
+
}
|
|
266
|
+
if (state.dims > 0 || state.sqlForm === "quote") {
|
|
267
|
+
return quoteLiteral(encoded);
|
|
268
|
+
}
|
|
269
|
+
return encoded;
|
|
270
|
+
}
|
|
271
|
+
function readAction(action, role) {
|
|
272
|
+
if (action === undefined) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (referentialAction(action) === undefined) {
|
|
276
|
+
definition(`references() ${role} ${action} is not a referential action. Accepted actions: ${REFERENTIAL_ACTIONS.join(", ")}.`);
|
|
277
|
+
}
|
|
278
|
+
return action;
|
|
279
|
+
}
|
|
280
|
+
function readReferenceColumns(columns) {
|
|
281
|
+
if (columns === undefined) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (columns.length === 0) {
|
|
285
|
+
definition("references() columns must name at least one target column.");
|
|
286
|
+
}
|
|
287
|
+
const copy = [];
|
|
288
|
+
for (const name of columns) {
|
|
289
|
+
if (name.length === 0) {
|
|
290
|
+
definition("references() columns must be non-empty names.");
|
|
291
|
+
}
|
|
292
|
+
copy.push(name);
|
|
293
|
+
}
|
|
294
|
+
return copy;
|
|
295
|
+
}
|
|
296
|
+
function retarget(column, patch) {
|
|
297
|
+
return rebuild(column.state, {
|
|
298
|
+
...patch.dropUnique === true ? { unique: undefined } : {},
|
|
299
|
+
...patch.dropPrimary === true ? { primaryKey: false } : {},
|
|
300
|
+
...patch.references !== undefined ? { references: patch.references } : {}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
function rebuild(state, patch) {
|
|
304
|
+
return new ColumnBuilder2({ ...state, ...patch });
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export { ColumnBuilder2, required, openColumn, formatType, retarget };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import {
|
|
2
|
+
safetyInstalled,
|
|
3
|
+
runSafety
|
|
4
|
+
} from "./a5sxz52y.js";
|
|
5
|
+
import {
|
|
6
|
+
isOperator,
|
|
7
|
+
operatorValue
|
|
8
|
+
} from "./cn0n68ft.js";
|
|
9
|
+
import {
|
|
10
|
+
OkmError2
|
|
11
|
+
} from "./52szzakm.js";
|
|
12
|
+
|
|
13
|
+
// src/runtime/exposure.ts
|
|
14
|
+
var REDACTED = "[redacted]";
|
|
15
|
+
var namesOf = new WeakMap;
|
|
16
|
+
function redactView(schema, view, call) {
|
|
17
|
+
const names = concealedNames(schema);
|
|
18
|
+
const secrets = new Set;
|
|
19
|
+
harvest(schema, call.where, names, undefined, secrets);
|
|
20
|
+
harvest(schema, call.include, names, undefined, secrets);
|
|
21
|
+
const model = schema.model[call.table];
|
|
22
|
+
const rules = model === undefined ? view.rules : [...view.rules, ...exposureRules(model, call)];
|
|
23
|
+
if (safetyInstalled())
|
|
24
|
+
runSafety(rules, undefined);
|
|
25
|
+
return {
|
|
26
|
+
...view,
|
|
27
|
+
intent: {
|
|
28
|
+
...view.intent,
|
|
29
|
+
where: walk(view.intent.where, names),
|
|
30
|
+
include: walk(view.intent.include, names)
|
|
31
|
+
},
|
|
32
|
+
rules,
|
|
33
|
+
sql: {
|
|
34
|
+
...view.sql,
|
|
35
|
+
params: view.sql.params.map((value) => value !== null && secrets.has(value) ? REDACTED : value)
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function scrubCall(error, schema, call) {
|
|
40
|
+
const names = concealedNames(schema);
|
|
41
|
+
const secrets = new Set;
|
|
42
|
+
harvest(schema, call.where, names, undefined, secrets);
|
|
43
|
+
harvest(schema, call.include, names, undefined, secrets);
|
|
44
|
+
let message = error.message;
|
|
45
|
+
for (const secret of secrets) {
|
|
46
|
+
if (secret.length < 4 || !message.includes(secret))
|
|
47
|
+
continue;
|
|
48
|
+
message = message.replaceAll(secret, REDACTED);
|
|
49
|
+
}
|
|
50
|
+
if (message === error.message)
|
|
51
|
+
return error;
|
|
52
|
+
return new OkmError2(error.code, message, {
|
|
53
|
+
kind: error.kind,
|
|
54
|
+
...error.table !== undefined ? { table: error.table } : {},
|
|
55
|
+
...error.columns.length > 0 ? { columns: error.columns } : {},
|
|
56
|
+
fix: error.fix
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function concealedNames(schema) {
|
|
60
|
+
const cached = namesOf.get(schema);
|
|
61
|
+
if (cached !== undefined)
|
|
62
|
+
return cached;
|
|
63
|
+
const names = new Set;
|
|
64
|
+
for (const model of Object.values(schema.model)) {
|
|
65
|
+
if (model.conceal !== true)
|
|
66
|
+
continue;
|
|
67
|
+
for (const column of model.columns) {
|
|
68
|
+
if (column.hidden || column.sensitive)
|
|
69
|
+
names.add(column.field);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
namesOf.set(schema, names);
|
|
73
|
+
return names;
|
|
74
|
+
}
|
|
75
|
+
function exposureRules(model, call) {
|
|
76
|
+
const named = namedSelect(call.select);
|
|
77
|
+
const source = model.source;
|
|
78
|
+
const rules = [];
|
|
79
|
+
for (const column of model.columns) {
|
|
80
|
+
if (column.hidden && (named === undefined || !named.has(column.field))) {
|
|
81
|
+
rules.push({
|
|
82
|
+
rule: "hidden",
|
|
83
|
+
contribution: `hidden ${model.name}.${column.field} excluded`,
|
|
84
|
+
provenance: "catalog",
|
|
85
|
+
...source !== undefined ? { source } : {}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (column.sensitive) {
|
|
89
|
+
rules.push({
|
|
90
|
+
rule: "sensitive",
|
|
91
|
+
contribution: `sensitive ${model.name}.${column.field} redacted`,
|
|
92
|
+
provenance: "catalog",
|
|
93
|
+
...source !== undefined ? { source } : {}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return rules;
|
|
98
|
+
}
|
|
99
|
+
function namedSelect(select) {
|
|
100
|
+
if (!Array.isArray(select))
|
|
101
|
+
return;
|
|
102
|
+
const names = new Set;
|
|
103
|
+
for (const name of select) {
|
|
104
|
+
if (typeof name === "string")
|
|
105
|
+
names.add(name);
|
|
106
|
+
}
|
|
107
|
+
return names;
|
|
108
|
+
}
|
|
109
|
+
function harvest(schema, value, names, key, into) {
|
|
110
|
+
if (Array.isArray(value)) {
|
|
111
|
+
for (const item of value)
|
|
112
|
+
harvest(schema, item, names, key, into);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (isOperator(value)) {
|
|
116
|
+
harvest(schema, operatorValue(value), names, key, into);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (typeof value === "object" && value !== null) {
|
|
120
|
+
const record = value;
|
|
121
|
+
for (const child of Object.keys(record))
|
|
122
|
+
harvest(schema, record[child], names, child, into);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (key === undefined || !names.has(key))
|
|
126
|
+
return;
|
|
127
|
+
const encode = encodeOf(schema, key);
|
|
128
|
+
if (encode === undefined)
|
|
129
|
+
return;
|
|
130
|
+
try {
|
|
131
|
+
into.add(encode(value));
|
|
132
|
+
} catch {}
|
|
133
|
+
}
|
|
134
|
+
function encodeOf(schema, field) {
|
|
135
|
+
for (const model of Object.values(schema.model)) {
|
|
136
|
+
for (const column of model.columns) {
|
|
137
|
+
if (column.field === field && (column.hidden || column.sensitive)) {
|
|
138
|
+
return column.encode;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
function walk(value, names, key) {
|
|
145
|
+
if (Array.isArray(value))
|
|
146
|
+
return value.map((item) => walk(item, names, key));
|
|
147
|
+
if (typeof value === "object" && value !== null) {
|
|
148
|
+
const record = value;
|
|
149
|
+
if (typeof record.op === "string" && "value" in record) {
|
|
150
|
+
return { op: record.op, value: walk(record.value, names, key) };
|
|
151
|
+
}
|
|
152
|
+
const out = {};
|
|
153
|
+
for (const child of Object.keys(record))
|
|
154
|
+
out[child] = walk(record[child], names, child);
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
if (key !== undefined && names.has(key))
|
|
158
|
+
return REDACTED;
|
|
159
|
+
return value;
|
|
160
|
+
}
|
|
161
|
+
export {
|
|
162
|
+
redactView,
|
|
163
|
+
scrubCall
|
|
164
|
+
};
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import {
|
|
2
|
+
decodeRows,
|
|
3
|
+
readHandle,
|
|
4
|
+
readCall,
|
|
5
|
+
attachHttp
|
|
6
|
+
} from "./mxmcdsh5.js";
|
|
7
|
+
import {
|
|
8
|
+
selectedColumns,
|
|
9
|
+
parseOrder,
|
|
10
|
+
rejectKeys,
|
|
11
|
+
readLimit,
|
|
12
|
+
indexes,
|
|
13
|
+
quote,
|
|
14
|
+
list,
|
|
15
|
+
isRecord,
|
|
16
|
+
registerFailFix,
|
|
17
|
+
fail
|
|
18
|
+
} from "./xrfnq5k8.js";
|
|
19
|
+
import {
|
|
20
|
+
OkmError2,
|
|
21
|
+
throwNamed2
|
|
22
|
+
} from "./52szzakm.js";
|
|
23
|
+
|
|
24
|
+
// src/runtime/page.ts
|
|
25
|
+
registerFailFix("OKM1130", "Request the next page with the same orderBy and the exact next value the previous page returned. The cursor encodes that order.");
|
|
26
|
+
var OPTIONS = [
|
|
27
|
+
"where",
|
|
28
|
+
"select",
|
|
29
|
+
"orderBy",
|
|
30
|
+
"limit",
|
|
31
|
+
"include",
|
|
32
|
+
"after",
|
|
33
|
+
"signal",
|
|
34
|
+
"timeout"
|
|
35
|
+
];
|
|
36
|
+
function build(session, table, options, mods, view) {
|
|
37
|
+
try {
|
|
38
|
+
return plan(session, table, options, mods, view);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
throw error instanceof OkmError2 ? attachHttp(session.http, error) : error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function plan(session, table, options, mods, view) {
|
|
44
|
+
const record = isRecord(options) ? options : {};
|
|
45
|
+
rejectKeys(record, OPTIONS, "page");
|
|
46
|
+
const indexed = indexes(session.schema).get(table);
|
|
47
|
+
if (indexed === undefined)
|
|
48
|
+
fail("OKM1120", `Table ${table} is not in the schema.`);
|
|
49
|
+
if (record.limit === undefined)
|
|
50
|
+
fail("OKM1101", "page() needs a limit.");
|
|
51
|
+
const size = readLimit(record.limit);
|
|
52
|
+
if (size < 1) {
|
|
53
|
+
throw new OkmError2("invalid", "page() limit must be at least 1.", { kind: "invalid" });
|
|
54
|
+
}
|
|
55
|
+
const keys = orderKeys(indexed, record.orderBy);
|
|
56
|
+
const signature = `${table}:${keys.map((key) => `${key.column.field}.${key.dir}.${key.nulls}`).join(",")}`;
|
|
57
|
+
const after = record.after === undefined || record.after === null ? undefined : keyset(keys, signature, record.after);
|
|
58
|
+
const wanted = selectedColumns(indexed, record.select);
|
|
59
|
+
const extra = keys.filter((key) => !wanted.includes(key.column)).map((key) => key.column.field);
|
|
60
|
+
const select = extra.length === 0 ? record.select : [...wanted.map((column) => column.field), ...extra];
|
|
61
|
+
const orderBy = {};
|
|
62
|
+
for (const key of keys)
|
|
63
|
+
orderBy[key.column.field] = { dir: key.dir, nulls: key.nulls };
|
|
64
|
+
const call = {
|
|
65
|
+
...readCall("find", table, {
|
|
66
|
+
where: record.where,
|
|
67
|
+
select,
|
|
68
|
+
orderBy,
|
|
69
|
+
limit: size + 1,
|
|
70
|
+
include: record.include,
|
|
71
|
+
signal: record.signal,
|
|
72
|
+
timeout: record.timeout
|
|
73
|
+
}, undefined, session.scope, session.schema.model[table], session.schema, view),
|
|
74
|
+
...after !== undefined ? { after } : {}
|
|
75
|
+
};
|
|
76
|
+
return readHandle(session, table, call, mods, async (compiled, rows) => {
|
|
77
|
+
const items = await decodeRows(compiled, rows, table);
|
|
78
|
+
const more = items.length > size;
|
|
79
|
+
const kept = more ? items.slice(0, size) : items;
|
|
80
|
+
const last = rows[size - 1];
|
|
81
|
+
const next = more && last !== undefined ? makeCursor(compiled, last, keys, signature) : null;
|
|
82
|
+
if (extra.length > 0) {
|
|
83
|
+
for (const item of kept) {
|
|
84
|
+
for (const field of extra)
|
|
85
|
+
delete item[field];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { items: kept, next };
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function orderKeys(table, orderBy) {
|
|
92
|
+
if (orderBy !== undefined && !isRecord(orderBy)) {
|
|
93
|
+
fail("OKM1120", "orderBy must be an object of fields.");
|
|
94
|
+
}
|
|
95
|
+
const keys = [];
|
|
96
|
+
for (const field of Object.keys(orderBy ?? {})) {
|
|
97
|
+
const column = table.columns.get(field);
|
|
98
|
+
if (column === undefined) {
|
|
99
|
+
throwNamed2("OKM1120", field, table.names, `Field ${field} is not on ${table.model.name}. Accepted names: ${list(table.names)}.`);
|
|
100
|
+
}
|
|
101
|
+
keys.push({ column, ...parseOrder(field, orderBy?.[field]) });
|
|
102
|
+
}
|
|
103
|
+
if (table.model.primary.length === 0) {
|
|
104
|
+
fail("OKM1120", `page() needs a primary key on ${table.model.name} to break ties.`);
|
|
105
|
+
}
|
|
106
|
+
for (const field of table.model.primary) {
|
|
107
|
+
const column = table.columns.get(field);
|
|
108
|
+
if (column === undefined || keys.some((key) => key.column === column))
|
|
109
|
+
continue;
|
|
110
|
+
keys.push({ column, dir: "asc", nulls: "last" });
|
|
111
|
+
}
|
|
112
|
+
return keys;
|
|
113
|
+
}
|
|
114
|
+
function keyset(keys, signature, token) {
|
|
115
|
+
const values = readCursor(token, signature, keys.length);
|
|
116
|
+
return (sink, alias) => {
|
|
117
|
+
sink.mark(`k:${signature}:${values.map((value) => value === null ? "n" : "v").join("")}`);
|
|
118
|
+
let wrote = false;
|
|
119
|
+
for (let index = 0;index < keys.length; index += 1) {
|
|
120
|
+
const key = keys[index];
|
|
121
|
+
const value = values[index];
|
|
122
|
+
if (key === undefined || value === undefined)
|
|
123
|
+
continue;
|
|
124
|
+
if (value === null && key.nulls === "last")
|
|
125
|
+
continue;
|
|
126
|
+
sink.text(wrote ? " or (" : "(");
|
|
127
|
+
wrote = true;
|
|
128
|
+
for (let before = 0;before < index; before += 1) {
|
|
129
|
+
const prior = keys[before];
|
|
130
|
+
const held = values[before];
|
|
131
|
+
if (prior === undefined || held === undefined)
|
|
132
|
+
continue;
|
|
133
|
+
const ref = `${alias}.${quote(prior.column.sql)}`;
|
|
134
|
+
if (held === null) {
|
|
135
|
+
sink.text(`${ref} is null and `);
|
|
136
|
+
} else {
|
|
137
|
+
sink.text(`${ref} = `);
|
|
138
|
+
sink.param(held);
|
|
139
|
+
sink.text(" and ");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const ref = `${alias}.${quote(key.column.sql)}`;
|
|
143
|
+
if (value === null) {
|
|
144
|
+
sink.text(`${ref} is not null`);
|
|
145
|
+
} else {
|
|
146
|
+
sink.text(key.nulls === "last" ? `(${ref} ${compare(key)} ` : `${ref} ${compare(key)} `);
|
|
147
|
+
sink.param(value);
|
|
148
|
+
sink.text(key.nulls === "last" ? ` or ${ref} is null)` : "");
|
|
149
|
+
}
|
|
150
|
+
sink.text(")");
|
|
151
|
+
}
|
|
152
|
+
if (!wrote)
|
|
153
|
+
sink.text("false");
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function compare(key) {
|
|
157
|
+
return key.dir === "asc" ? ">" : "<";
|
|
158
|
+
}
|
|
159
|
+
function makeCursor(plan, row, keys, signature) {
|
|
160
|
+
const values = keys.map((key) => {
|
|
161
|
+
const at = plan.outputs.fields.find((field) => field.key === key.column.field)?.at;
|
|
162
|
+
return at === undefined ? null : row[at] ?? null;
|
|
163
|
+
});
|
|
164
|
+
const bytes = new TextEncoder().encode(JSON.stringify([signature, ...values]));
|
|
165
|
+
let binary = "";
|
|
166
|
+
for (const byte of bytes)
|
|
167
|
+
binary += String.fromCharCode(byte);
|
|
168
|
+
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
|
|
169
|
+
}
|
|
170
|
+
function readCursor(token, signature, count) {
|
|
171
|
+
let parsed;
|
|
172
|
+
if (typeof token === "string") {
|
|
173
|
+
try {
|
|
174
|
+
const binary = atob(token.replaceAll("-", "+").replaceAll("_", "/"));
|
|
175
|
+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
176
|
+
parsed = JSON.parse(new TextDecoder().decode(bytes));
|
|
177
|
+
} catch {
|
|
178
|
+
parsed = undefined;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (!Array.isArray(parsed) || typeof parsed[0] !== "string") {
|
|
182
|
+
fail("OKM1130", "after is not a cursor that page() returned.");
|
|
183
|
+
}
|
|
184
|
+
if (parsed[0] !== signature) {
|
|
185
|
+
fail("OKM1130", `The cursor was made for another order: ${parsed[0]}. This page orders by ${signature}.`);
|
|
186
|
+
}
|
|
187
|
+
const values = parsed.slice(1);
|
|
188
|
+
if (values.length !== count || !values.every((value) => value === null || typeof value === "string")) {
|
|
189
|
+
fail("OKM1130", "after is not a cursor that page() returned.");
|
|
190
|
+
}
|
|
191
|
+
return values;
|
|
192
|
+
}
|
|
193
|
+
export {
|
|
194
|
+
build
|
|
195
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import"./
|
|
1
|
+
import"./d2whjz4k.js";
|
|
2
|
+
import"./n442h54c.js";
|
|
2
3
|
import {
|
|
3
4
|
listTargets,
|
|
4
5
|
loadConfig
|
|
5
|
-
} from "./
|
|
6
|
+
} from "./5z4q2zda.js";
|
|
6
7
|
|
|
7
8
|
// src/tooling/migrate/dev.ts
|
|
8
9
|
import { mkdirSync } from "node:fs";
|
|
@@ -15,7 +16,7 @@ async function devProject(cwd) {
|
|
|
15
16
|
`;
|
|
16
17
|
const directory = join(cwd, config.out ?? ".okm", "dev-db");
|
|
17
18
|
mkdirSync(directory, { recursive: true });
|
|
18
|
-
const { open } = await import("./
|
|
19
|
+
const { open } = await import("./py3nh7jy.js");
|
|
19
20
|
const pool = await open({ dataDir: directory });
|
|
20
21
|
try {
|
|
21
22
|
await pool.execute("select 1");
|