okmodel 0.5.0 → 0.6.0
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 +36 -18
- package/dist/adapters/pg/no-inflight-timeout.d.ts +17 -0
- package/dist/adapters/pg/postgres-extra.d.ts +22 -0
- package/dist/contracts/catalog/document.d.ts +19 -5
- package/dist/contracts/catalog/object.d.ts +2 -1
- package/dist/contracts/catalog/policy.d.ts +48 -0
- package/dist/contracts/catalog/types.d.ts +25 -1
- package/dist/contracts/catalog/view.d.ts +2 -0
- package/dist/contracts/internal.js +1 -1
- package/dist/contracts/location.d.ts +10 -0
- package/dist/dialects/pg/column.d.ts +13 -2
- package/dist/dialects/pg/ddl.d.ts +37 -1
- package/dist/dialects/pg/emit.d.ts +19 -1
- package/dist/dialects/pg/errors.d.ts +32 -1
- package/dist/dialects/pg/ext/citext.js +1 -1
- package/dist/dialects/pg/ext/index.js +1 -1
- package/dist/dialects/pg/ext/pg-trgm.js +1 -1
- package/dist/dialects/pg/filter-parse.d.ts +10 -3
- package/dist/dialects/pg/fn/index.js +10 -2
- package/dist/dialects/pg/index.d.ts +2 -1
- package/dist/dialects/pg/index.js +29 -17
- package/dist/dialects/pg/introspect.d.ts +7 -0
- package/dist/dialects/pg/model.d.ts +7 -2
- package/dist/dialects/pg/ops/or.d.ts +1 -1
- package/dist/dialects/pg/owner.d.ts +42 -0
- package/dist/dialects/pg/path-endpoint.d.ts +20 -0
- package/dist/dialects/pg/role/check.d.ts +3 -0
- package/dist/dialects/pg/role/index.d.ts +71 -6
- package/dist/dialects/pg/role/sql.d.ts +11 -0
- package/dist/dialects/pg/schema.d.ts +2 -0
- package/dist/dialects/pg/table.d.ts +25 -3
- package/dist/dialects/pg/temporal.d.ts +5 -76
- package/dist/dialects/pg/tenancy.d.ts +45 -3
- package/dist/dialects/pg/view/client.d.ts +19 -1
- package/dist/dialects/pg/view/index.d.ts +4 -0
- package/dist/dialects/pg/view/index.js +21 -178
- package/dist/dialects/pg/view/refresh.d.ts +24 -0
- package/dist/runtime/batch.d.ts +1 -1
- package/dist/runtime/client.d.ts +6 -1
- package/dist/runtime/conflict.d.ts +2 -1
- package/dist/runtime/drift.d.ts +9 -0
- package/dist/runtime/inflight.d.ts +14 -0
- package/dist/runtime/pg/bun.js +6 -5
- package/dist/runtime/pg/pg.js +5 -5
- package/dist/runtime/pg/pglite.js +6 -5
- package/dist/runtime/pg/postgresjs.js +5 -5
- package/dist/runtime/plan.d.ts +22 -1
- package/dist/runtime/predicate.d.ts +19 -0
- package/dist/runtime/safety/index.js +1 -1
- package/dist/runtime/tenancy/composite.d.ts +26 -0
- package/dist/runtime/tenancy/context.d.ts +16 -0
- package/dist/runtime/tenancy/index.d.ts +9 -5
- package/dist/runtime/tenancy/index.js +1508 -37
- package/dist/runtime/tenancy/path.d.ts +87 -0
- package/dist/runtime/tenancy/rls.d.ts +67 -0
- package/dist/runtime/tenancy/via.d.ts +22 -0
- package/dist/runtime/traits/index.js +17 -11
- package/dist/runtime/types.d.ts +13 -1
- package/dist/runtime/validate/index.js +4 -4
- package/dist/runtime/write.d.ts +1 -1
- package/dist/shared/09p049xa.js +702 -0
- package/dist/shared/{ykv7wh5b.js → 1f0xa3cb.js} +5 -5
- package/dist/shared/1nw1f3vs.js +23 -0
- package/dist/shared/{6p5k20sm.js → 1z04fa85.js} +21 -11
- package/dist/shared/{p7pfx624.js → 2cg3wnxc.js} +314 -65
- package/dist/shared/{dyj86cmj.js → 2jd1sn0e.js} +2 -2
- package/dist/shared/{qgvt8nx1.js → 2z7wv5tj.js} +21 -5
- package/dist/shared/{kyxb62mc.js → 31vm914h.js} +9 -1
- package/dist/shared/{sf8m6tfy.js → 32cnm7kn.js} +8 -3
- package/dist/shared/{t4tbsy9h.js → 358zsv4r.js} +1 -1
- package/dist/shared/{jdgqqx31.js → 3fqwmr09.js} +38 -14
- package/dist/shared/{922qbgnw.js → 3qnhc7w5.js} +16 -9
- package/dist/shared/{zvbjc949.js → 4az561fn.js} +1 -1
- package/dist/shared/{k3ted12y.js → 54tqkxja.js} +20 -2
- package/dist/shared/{k7cc9nzk.js → 5d8t84hg.js} +15 -3
- package/dist/shared/{fa9vt245.js → 5j36z8dn.js} +17 -6
- package/dist/shared/{1g0drakv.js → 5yv4k6a6.js} +1 -1
- package/dist/shared/8dqhth8c.js +12 -0
- package/dist/shared/8etn7d8w.js +62 -0
- package/dist/shared/{g516zdsb.js → 8x72s86k.js} +476 -30
- package/dist/shared/{nkc9sfqb.js → 929h19xp.js} +145 -7
- package/dist/shared/{gjthds9j.js → 9628a9xt.js} +1 -1
- package/dist/shared/{8xsbagad.js → 9s0ypp87.js} +88 -7
- package/dist/shared/{b066g80h.js → ag4c7516.js} +2 -2
- package/dist/shared/b3awxn7h.js +45 -0
- package/dist/shared/b4v57v3x.js +9 -0
- package/dist/shared/bdk4sty6.js +58 -0
- package/dist/shared/{s6gqfn5j.js → c58secgj.js} +125 -8
- package/dist/shared/{rrstp3kb.js → cgbamx3e.js} +2 -2
- package/dist/shared/d5azex6s.js +6 -0
- package/dist/shared/{5fqx9yh4.js → dk8v79p3.js} +3 -1
- package/dist/shared/{4m9fn52z.js → ed0b8k4s.js} +1 -1
- package/dist/shared/{z2rnngj4.js → ek2wt2dz.js} +8 -5
- package/dist/shared/{wxn4b7pp.js → f0f1n281.js} +59 -12
- package/dist/shared/{gdh9mrtp.js → g90m9b0g.js} +3 -2
- package/dist/shared/{tbszx8mz.js → gwn6v667.js} +2 -2
- package/dist/shared/{c8aghh05.js → h15jx9bc.js} +8 -2
- package/dist/shared/{3p4b1fg0.js → hazqqecq.js} +17 -93
- package/dist/shared/{4ef7mmqf.js → j3rkk835.js} +34 -11
- package/dist/shared/{bt9sfq0z.js → j60w0dvr.js} +56 -21
- package/dist/shared/{ycatkxmq.js → jgqj11w4.js} +1 -1
- package/dist/shared/k68eedmy.js +85 -0
- package/dist/shared/{szm0cksa.js → knmes2kh.js} +34 -6
- package/dist/shared/{ckjbyrt9.js → mb2ycs1p.js} +7 -9
- package/dist/shared/{tq9afp8d.js → n076ydsc.js} +1 -1
- package/dist/shared/{xhh1srw3.js → nx9hh281.js} +50 -32
- package/dist/shared/{kdkxh3kb.js → p248q79y.js} +58 -59
- package/dist/shared/{990a291j.js → p6bjzq9q.js} +14 -9
- package/dist/shared/{h4nqvjkp.js → pjr6xrm5.js} +2 -2
- package/dist/shared/pz6rj8ay.js +212 -0
- package/dist/shared/{5vdm4sgp.js → q3j1tq7a.js} +36 -23
- package/dist/shared/{8bwbwy8h.js → qq3899ht.js} +128 -18
- package/dist/shared/{dxjp14rk.js → r11n8grd.js} +2 -2
- package/dist/shared/r1fdd0f6.js +19 -0
- package/dist/shared/{8ktwd3rh.js → r3j8s5y0.js} +1 -1
- package/dist/shared/rhs3xe4k.js +7 -0
- package/dist/shared/{jsd07prz.js → rpycarcr.js} +6 -6
- package/dist/shared/{xsq7v6wp.js → sbdme3vy.js} +14 -2
- package/dist/shared/{xdpj5kkm.js → t3g0k88x.js} +775 -264
- package/dist/shared/{ayz64vzj.js → ttmg09vd.js} +708 -19
- package/dist/shared/{r6pj4fq2.js → venqrjna.js} +8 -4
- package/dist/shared/{fancm5pt.js → vjpnzwjz.js} +138 -15
- package/dist/shared/{9tgmr1gh.js → vmfkhszw.js} +44 -9
- package/dist/shared/{wqem4jed.js → wkme6tep.js} +11 -9
- package/dist/shared/{qy9rdq0g.js → wt5rzv1h.js} +15 -11
- package/dist/shared/wxr8cwns.js +6 -0
- package/dist/shared/{bzsjtd7c.js → wynzeggs.js} +19 -14
- package/dist/shared/x3jc53kg.js +220 -0
- package/dist/shared/{7p2wbz7f.js → x72jb7ad.js} +1 -1
- package/dist/shared/{fyqkk1m0.js → xq0mvhts.js} +10 -9
- package/dist/shared/xqve9598.js +53 -0
- package/dist/shared/{47xzb9fc.js → y2t3jktd.js} +2 -2
- package/dist/shared/{9x25fxhc.js → y34a8714.js} +1 -1
- package/dist/shared/{k7dwkhvq.js → y6jdds7g.js} +4 -1
- package/dist/shared/{h8ne16fq.js → ys0xzyaj.js} +1 -1
- package/dist/shared/{c9z5g0fm.js → ywr8hmey.js} +5 -2
- package/dist/shared/{g7ez901n.js → ywspezzx.js} +1 -1
- package/dist/shared/{9m80mkac.js → ze4hxsmy.js} +1 -1
- package/dist/shared/{fb00y8fp.js → zm0mafk4.js} +12 -6
- package/dist/shared/{y005b761.js → zy8r7qvz.js} +6 -2
- package/dist/tooling/cli.js +97 -24
- package/dist/tooling/migrate/apply.d.ts +14 -0
- package/dist/tooling/migrate/check.d.ts +3 -4
- package/dist/tooling/migrate/classify.d.ts +4 -0
- package/dist/tooling/migrate/commands.d.ts +1 -2
- package/dist/tooling/migrate/config.d.ts +3 -2
- package/dist/tooling/migrate/drift.d.ts +1 -1
- package/dist/tooling/migrate/estimate.d.ts +14 -1
- package/dist/tooling/migrate/files.d.ts +11 -1
- package/dist/tooling/migrate/index.js +17 -16
- package/dist/tooling/migrate/lint.d.ts +4 -4
- package/dist/tooling/migrate/lost.d.ts +28 -0
- package/dist/tooling/migrate/paths.d.ts +14 -0
- package/dist/tooling/migrate/plan.d.ts +10 -3
- package/dist/tooling/migrate/policy.d.ts +11 -0
- package/dist/tooling/migrate/runner.d.ts +25 -0
- package/dist/tooling/migrate/sandbox.d.ts +57 -0
- package/dist/tooling/migrate/sql-lex.d.ts +39 -0
- package/dist/tooling/migrate/text.d.ts +42 -0
- package/dist/tooling/node-version.d.ts +21 -0
- package/dist/tooling/testing/factories.d.ts +10 -0
- package/dist/tooling/testing/facts.d.ts +33 -5
- package/dist/tooling/testing/index.d.ts +1 -1
- package/dist/tooling/testing/index.js +3 -3
- package/dist/tooling/testing/isolation.d.ts +15 -8
- package/package.json +10 -6
- package/dist/shared/0v1g424p.js +0 -26
- package/dist/shared/r73pt594.js +0 -426
- package/dist/shared/rasvvzgz.js +0 -21
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
effectivePredicate
|
|
3
|
+
} from "./b3awxn7h.js";
|
|
1
4
|
import {
|
|
2
5
|
assertOperatorFits,
|
|
3
6
|
textArray,
|
|
@@ -16,10 +19,10 @@ import {
|
|
|
16
19
|
} from "./n4jqhpqz.js";
|
|
17
20
|
import {
|
|
18
21
|
writeWouldValidate
|
|
19
|
-
} from "./
|
|
22
|
+
} from "./ze4hxsmy.js";
|
|
20
23
|
import {
|
|
21
24
|
encodeJson
|
|
22
|
-
} from "./
|
|
25
|
+
} from "./9628a9xt.js";
|
|
23
26
|
import {
|
|
24
27
|
withRowFilters,
|
|
25
28
|
archiveRules,
|
|
@@ -34,7 +37,7 @@ import {
|
|
|
34
37
|
isRecord,
|
|
35
38
|
registerFailFix,
|
|
36
39
|
fail
|
|
37
|
-
} from "./
|
|
40
|
+
} from "./2z7wv5tj.js";
|
|
38
41
|
import {
|
|
39
42
|
safetyInstalled,
|
|
40
43
|
runSafety
|
|
@@ -45,7 +48,8 @@ import {
|
|
|
45
48
|
operatorValue
|
|
46
49
|
} from "./cn0n68ft.js";
|
|
47
50
|
import {
|
|
48
|
-
OkmError2
|
|
51
|
+
OkmError2,
|
|
52
|
+
throwNamed2
|
|
49
53
|
} from "./52szzakm.js";
|
|
50
54
|
|
|
51
55
|
// src/runtime/write.ts
|
|
@@ -98,6 +102,8 @@ var INSERT_OPTIONS = [
|
|
|
98
102
|
"validate"
|
|
99
103
|
];
|
|
100
104
|
var FILTER_OPTIONS = ["allow", "expect", "returning", "signal", "timeout", "validate"];
|
|
105
|
+
var UPDATE_KEYS = ["set", "where"];
|
|
106
|
+
var UPDATE_ROW_KEYS = ["id", "set", "where"];
|
|
101
107
|
var NO_ALLOW = new Set;
|
|
102
108
|
async function executeWrite(host, op, table, input, options, mods, scope, plan) {
|
|
103
109
|
const prepared = await prepareWrite(host, op, table, input, options, mods, scope);
|
|
@@ -114,7 +120,7 @@ async function prepareWrite(host, op, table, input, options, mods, scope) {
|
|
|
114
120
|
return {
|
|
115
121
|
statements: planned.statements,
|
|
116
122
|
options: callOptions(options),
|
|
117
|
-
...planned.expect !== undefined ? { checked: "expect" } : {},
|
|
123
|
+
...planned.parentGuard === true ? { checked: "parent" } : planned.expect !== undefined ? { checked: "expect" } : {},
|
|
118
124
|
finish: (results) => finish(results, planned, table)
|
|
119
125
|
};
|
|
120
126
|
} catch (error) {
|
|
@@ -147,7 +153,7 @@ async function planWrite(schema, generators, op, tableName, input, options, mods
|
|
|
147
153
|
if (op === "update") {
|
|
148
154
|
return withRowFilters(scope, mods.archive, () => {
|
|
149
155
|
noteArchive(table, mods.archive);
|
|
150
|
-
return planUpdate(schema, table, input, record, mods);
|
|
156
|
+
return planUpdate(schema, table, input, record, mods, scope);
|
|
151
157
|
});
|
|
152
158
|
}
|
|
153
159
|
return withRowFilters(scope, mods.archive, () => {
|
|
@@ -162,12 +168,16 @@ async function planInsert(table, input, options, mods, generators, scope, tenanc
|
|
|
162
168
|
const rows = (many ? input : [input]).map((row) => insertRow(table, row, allow, tenancy));
|
|
163
169
|
tenancy?.stamp(table.model.name, rows, scope);
|
|
164
170
|
fillInsert(table, rows, generators);
|
|
165
|
-
const columns = writtenColumns(table, rows, allow, tenancy
|
|
171
|
+
const columns = writtenColumns(table, rows, allow, tenantKeyList(tenancy));
|
|
166
172
|
const returning = selectedColumns(table, options.returning);
|
|
167
173
|
const outputs = outputsOf(returning);
|
|
168
174
|
const clause = returningClause(returning, undefined);
|
|
169
175
|
const expect = expectOf(options, mods);
|
|
170
176
|
const shape = many ? "rows" : "row";
|
|
177
|
+
const path = tenancy?.isPath?.(table.model.name) === true;
|
|
178
|
+
if (path && options.onConflict !== undefined && options.onConflict !== "error") {
|
|
179
|
+
fail("OKM1120", `onConflict on ${table.model.name} is not available. The insert checks the parent.`);
|
|
180
|
+
}
|
|
171
181
|
if (columns.length === 0) {
|
|
172
182
|
const text = `insert into ${quote(table.model.sql)} default values${clause}`;
|
|
173
183
|
return {
|
|
@@ -179,8 +189,8 @@ async function planInsert(table, input, options, mods, generators, scope, tenanc
|
|
|
179
189
|
keyFields: undefined
|
|
180
190
|
};
|
|
181
191
|
}
|
|
182
|
-
const conflictMod = options.onConflict === undefined || options.onConflict === "error" ? undefined : await import("./
|
|
183
|
-
const conflict = conflictMod?.readConflict(table, options.onConflict, allow);
|
|
192
|
+
const conflictMod = options.onConflict === undefined || options.onConflict === "error" ? undefined : await import("./vmfkhszw.js");
|
|
193
|
+
const conflict = conflictMod?.readConflict(table, options.onConflict, allow, tenantKeyList(tenancy));
|
|
184
194
|
const chunks = chunkRows(rows.map((row) => cellsFor(columns, row)));
|
|
185
195
|
const statements = [];
|
|
186
196
|
const keys = [];
|
|
@@ -188,7 +198,7 @@ async function planInsert(table, input, options, mods, generators, scope, tenanc
|
|
|
188
198
|
for (const chunk of chunks) {
|
|
189
199
|
const slice = rows.slice(offset, offset + chunk.length);
|
|
190
200
|
offset += chunk.length;
|
|
191
|
-
const built = insertHead(table, columns, chunk);
|
|
201
|
+
const built = path ? pathInsert(table, columns, chunk, scope, tenancy) : insertHead(table, columns, chunk);
|
|
192
202
|
if (conflict === undefined || conflictMod === undefined) {
|
|
193
203
|
statements.push(withParams(`${built.text}${clause}`, built.params));
|
|
194
204
|
continue;
|
|
@@ -204,10 +214,11 @@ async function planInsert(table, input, options, mods, generators, scope, tenanc
|
|
|
204
214
|
shape,
|
|
205
215
|
expect,
|
|
206
216
|
keys: conflict?.kind === "return" ? keys : undefined,
|
|
207
|
-
keyFields: conflict?.kind === "return" ? conflict.columns.map((column) => column.field) : undefined
|
|
217
|
+
keyFields: conflict?.kind === "return" ? conflict.columns.map((column) => column.field) : undefined,
|
|
218
|
+
...path ? { parent: rows.length } : {}
|
|
208
219
|
};
|
|
209
220
|
}
|
|
210
|
-
function planUpdate(schema, table, input, options, mods) {
|
|
221
|
+
function planUpdate(schema, table, input, options, mods, scope) {
|
|
211
222
|
const allow = allowSet(table, options.allow);
|
|
212
223
|
noteGuarded(table, allow, "update");
|
|
213
224
|
const returning = returningOption(table, options.returning);
|
|
@@ -216,8 +227,22 @@ function planUpdate(schema, table, input, options, mods) {
|
|
|
216
227
|
if (Array.isArray(input)) {
|
|
217
228
|
const rows = input.map((item) => {
|
|
218
229
|
const row = updateItem(table, item, allow, schema.tenancy);
|
|
230
|
+
requireFilter(table, row.where, mods, "update");
|
|
231
|
+
pathAssignment(schema.tenancy, table.model.name, row.set, scope);
|
|
219
232
|
return { ...row, where: stack(row.where, mods.presets) };
|
|
220
233
|
});
|
|
234
|
+
const moves = rows.some((row) => pathField(schema.tenancy, table.model.name, row.set) !== undefined);
|
|
235
|
+
if (moves) {
|
|
236
|
+
return {
|
|
237
|
+
statements: [pathListUpdate(schema, table, rows, scope, returning)],
|
|
238
|
+
outputs: parentOutputs(returning),
|
|
239
|
+
shape: returning === undefined ? "count" : "rows",
|
|
240
|
+
expect,
|
|
241
|
+
keys: undefined,
|
|
242
|
+
keyFields: undefined,
|
|
243
|
+
parentGuard: true
|
|
244
|
+
};
|
|
245
|
+
}
|
|
221
246
|
return {
|
|
222
247
|
statements: updateList(schema, table, rows, returning),
|
|
223
248
|
outputs,
|
|
@@ -229,16 +254,30 @@ function planUpdate(schema, table, input, options, mods) {
|
|
|
229
254
|
}
|
|
230
255
|
if (!isRecord(input))
|
|
231
256
|
fail("OKM1121", "update expects { where, set } or a list of rows.");
|
|
257
|
+
rejectUpdateKeys(input, false);
|
|
232
258
|
const set = writeSet(table, input.set, allow, schema.tenancy);
|
|
233
259
|
requireFilter(table, input.where, mods, "update");
|
|
234
260
|
if (Object.keys(set).length === 0)
|
|
235
261
|
fail("OKM1120", "update set is empty.");
|
|
262
|
+
const where = stack(input.where, mods.presets);
|
|
263
|
+
if (pathAssignment(schema.tenancy, table.model.name, set, scope) !== undefined) {
|
|
264
|
+
return {
|
|
265
|
+
statements: [pathSetUpdate(schema, table, where, set, scope, returning)],
|
|
266
|
+
outputs: parentOutputs(returning),
|
|
267
|
+
shape: returning === undefined ? "count" : "rows",
|
|
268
|
+
expect,
|
|
269
|
+
keys: undefined,
|
|
270
|
+
keyFields: undefined,
|
|
271
|
+
parentGuard: true
|
|
272
|
+
};
|
|
273
|
+
}
|
|
236
274
|
const sql = new Sql;
|
|
237
275
|
sql.text("update ");
|
|
238
276
|
sql.text(quote(table.model.sql));
|
|
239
277
|
sql.text(" as t set ");
|
|
240
278
|
emitSet(sql, table, set, "t");
|
|
241
|
-
emitFilter(schema, table,
|
|
279
|
+
emitFilter(schema, table, where, sql, "t");
|
|
280
|
+
schema.tenancy?.noteParent?.(table.model.name, set, sql.sink(), scope, (field) => table.columns.get(field)?.sql);
|
|
242
281
|
sql.text(returningClause(returning, "t"));
|
|
243
282
|
return {
|
|
244
283
|
statements: [sql.statement()],
|
|
@@ -271,6 +310,8 @@ function planDelete(schema, table, input, options, mods) {
|
|
|
271
310
|
};
|
|
272
311
|
}
|
|
273
312
|
function finish(results, planned, table) {
|
|
313
|
+
if (planned.parentGuard === true)
|
|
314
|
+
return finishParent(results, planned, table);
|
|
274
315
|
if (planned.shape === "count") {
|
|
275
316
|
let count = 0;
|
|
276
317
|
for (const result of results)
|
|
@@ -285,63 +326,164 @@ function finish(results, planned, table) {
|
|
|
285
326
|
}
|
|
286
327
|
const rows = planned.keys === undefined || planned.keyFields === undefined ? decoded : orderByKeys(decoded, planned.keyFields, planned.keys);
|
|
287
328
|
checkExpect(rows.length, planned.expect, table, "insert");
|
|
329
|
+
if (planned.parent !== undefined && rows.length < planned.parent) {
|
|
330
|
+
throw new OkmError2("OKM1705", `Insert on ${table} did not find a parent in this tenant.`, {
|
|
331
|
+
fix: { summary: "Insert under a parent that belongs to this tenant." }
|
|
332
|
+
});
|
|
333
|
+
}
|
|
288
334
|
if (planned.shape === "row")
|
|
289
335
|
return rows[0] ?? null;
|
|
290
336
|
return rows;
|
|
291
337
|
}
|
|
292
|
-
function
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
ordered.push(row);
|
|
338
|
+
function finishParent(results, planned, table) {
|
|
339
|
+
const row = results[0]?.rows[0];
|
|
340
|
+
const matched = countCell(row?.[0]);
|
|
341
|
+
const updated = countCell(row?.[1]);
|
|
342
|
+
if (updated < matched) {
|
|
343
|
+
throw new OkmError2("OKM1705", `Update on ${table} did not find a parent in this tenant.`, {
|
|
344
|
+
fix: { summary: "Point the foreign key at a parent in this tenant." }
|
|
345
|
+
});
|
|
301
346
|
}
|
|
302
|
-
|
|
347
|
+
if (planned.shape === "count") {
|
|
348
|
+
checkExpect(updated, planned.expect, table, "write");
|
|
349
|
+
return { count: updated };
|
|
350
|
+
}
|
|
351
|
+
const decoded = [];
|
|
352
|
+
if (updated > 0) {
|
|
353
|
+
for (const result of results) {
|
|
354
|
+
for (const item of result.rows)
|
|
355
|
+
decoded.push(decodeRow(planned.outputs, item));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
checkExpect(decoded.length, planned.expect, table, "write");
|
|
359
|
+
if (planned.shape === "row")
|
|
360
|
+
return decoded[0] ?? null;
|
|
361
|
+
return decoded;
|
|
303
362
|
}
|
|
304
|
-
function
|
|
305
|
-
if (typeof value === "
|
|
363
|
+
function countCell(value) {
|
|
364
|
+
if (typeof value === "number")
|
|
306
365
|
return value;
|
|
307
|
-
if (typeof value === "
|
|
308
|
-
return
|
|
309
|
-
|
|
310
|
-
|
|
366
|
+
if (typeof value === "bigint")
|
|
367
|
+
return Number(value);
|
|
368
|
+
if (typeof value === "string" && value.length > 0)
|
|
369
|
+
return Number(value);
|
|
370
|
+
return 0;
|
|
311
371
|
}
|
|
312
|
-
function
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
372
|
+
function pathField(tenancy, table, set) {
|
|
373
|
+
if (tenancy?.isPath?.(table) !== true)
|
|
374
|
+
return;
|
|
375
|
+
const field = tenancy.pathOf?.(table)?.[0]?.localField;
|
|
376
|
+
if (field === undefined || !Object.hasOwn(set, field))
|
|
377
|
+
return;
|
|
378
|
+
return field;
|
|
379
|
+
}
|
|
380
|
+
function pathAssignment(tenancy, table, set, scope) {
|
|
381
|
+
const field = pathField(tenancy, table, set);
|
|
382
|
+
if (field === undefined)
|
|
383
|
+
return;
|
|
384
|
+
const value = set[field];
|
|
385
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
386
|
+
throw new OkmError2("OKM1705", `Update on ${table} cannot verify ${field}. Pass the parent id as a string.`, { fix: { summary: "Pass the parent id as a string so the tenant can be checked." } });
|
|
326
387
|
}
|
|
327
|
-
|
|
388
|
+
if (scope === undefined || "unscoped" in scope) {
|
|
389
|
+
throw new OkmError2("OKM1705", `Update on ${table} cannot verify ${field} without a tenant.`, {
|
|
390
|
+
fix: { summary: `Call for({ ... }) so ${field} can be checked.` }
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
return field;
|
|
394
|
+
}
|
|
395
|
+
function parentOutputs(returning) {
|
|
396
|
+
const outputs = outputsOf(returning);
|
|
397
|
+
if (returning === undefined)
|
|
398
|
+
return outputs;
|
|
328
399
|
return {
|
|
329
|
-
|
|
330
|
-
|
|
400
|
+
fields: outputs.fields.map((field) => ({ ...field, at: field.at + 2 })),
|
|
401
|
+
includes: outputs.includes
|
|
331
402
|
};
|
|
332
403
|
}
|
|
333
|
-
function
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
404
|
+
function pathSetUpdate(schema, table, where, set, scope, returning) {
|
|
405
|
+
const sql = new Sql;
|
|
406
|
+
sql.text("with matched as (select t.ctid as tid from ");
|
|
407
|
+
sql.text(quote(table.model.sql));
|
|
408
|
+
sql.text(" as t");
|
|
409
|
+
emitFilter(schema, table, where, sql, "t");
|
|
410
|
+
sql.text("), updated as (update ");
|
|
411
|
+
sql.text(quote(table.model.sql));
|
|
412
|
+
sql.text(" as t set ");
|
|
413
|
+
emitSet(sql, table, set, "t");
|
|
414
|
+
sql.text(" where t.ctid in (select tid from matched)");
|
|
415
|
+
schema.tenancy?.noteParent?.(table.model.name, set, sql.sink(), scope, (field) => table.columns.get(field)?.sql);
|
|
416
|
+
endParent(sql, returning);
|
|
417
|
+
return sql.statement();
|
|
418
|
+
}
|
|
419
|
+
function pathListUpdate(schema, table, rows, scope, returning) {
|
|
420
|
+
const sql = new Sql;
|
|
421
|
+
sql.text("with matched as (");
|
|
422
|
+
for (let index = 0;index < rows.length; index += 1) {
|
|
423
|
+
const row = rows[index];
|
|
424
|
+
if (row === undefined)
|
|
425
|
+
continue;
|
|
426
|
+
if (index > 0)
|
|
427
|
+
sql.text(" union all ");
|
|
428
|
+
sql.text("select t.ctid as tid, ");
|
|
429
|
+
sql.text(String(index));
|
|
430
|
+
sql.text(" as ord from ");
|
|
431
|
+
sql.text(quote(table.model.sql));
|
|
432
|
+
sql.text(" as t where ");
|
|
433
|
+
emitBare(schema, table, row.where, sql, "t");
|
|
341
434
|
}
|
|
342
|
-
|
|
435
|
+
sql.text("), rejected as (");
|
|
436
|
+
let rejected = false;
|
|
437
|
+
for (let index = 0;index < rows.length; index += 1) {
|
|
438
|
+
const row = rows[index];
|
|
439
|
+
if (row === undefined)
|
|
440
|
+
continue;
|
|
441
|
+
if (pathField(schema.tenancy, table.model.name, row.set) === undefined)
|
|
442
|
+
continue;
|
|
443
|
+
if (rejected)
|
|
444
|
+
sql.text(" union all ");
|
|
445
|
+
rejected = true;
|
|
446
|
+
sql.text("select ");
|
|
447
|
+
sql.text(String(index));
|
|
448
|
+
sql.text(" as ord where exists (select 1 from matched where ord = ");
|
|
449
|
+
sql.text(String(index));
|
|
450
|
+
sql.text(")");
|
|
451
|
+
noteParentNot(schema, table, row.set, scope, sql);
|
|
452
|
+
}
|
|
453
|
+
if (!rejected)
|
|
454
|
+
sql.text("select 0 as ord where false");
|
|
455
|
+
sql.text("), updated as (");
|
|
456
|
+
updateSliceBody(schema, table, rows, sql, true);
|
|
457
|
+
sql.text(" and not exists (select 1 from rejected)");
|
|
458
|
+
endParent(sql, returning);
|
|
459
|
+
return sql.statement();
|
|
343
460
|
}
|
|
344
|
-
function
|
|
461
|
+
function noteParentNot(schema, table, set, scope, sql) {
|
|
462
|
+
let first = true;
|
|
463
|
+
schema.tenancy?.noteParent?.(table.model.name, set, {
|
|
464
|
+
text(value) {
|
|
465
|
+
if (first) {
|
|
466
|
+
first = false;
|
|
467
|
+
sql.text(" and not ");
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
sql.text(value);
|
|
471
|
+
},
|
|
472
|
+
param(encoded) {
|
|
473
|
+
sql.param(encoded, "");
|
|
474
|
+
},
|
|
475
|
+
mark() {}
|
|
476
|
+
}, scope, (field) => table.columns.get(field)?.sql);
|
|
477
|
+
}
|
|
478
|
+
function endParent(sql, returning) {
|
|
479
|
+
if (returning === undefined || returning.length === 0) {
|
|
480
|
+
sql.text(" returning 1) select (select count(*)::int from matched), (select count(*)::int from updated)");
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
sql.text(returningClause(returning, "t"));
|
|
484
|
+
sql.text(") select c.matched, c.updated, u.* from (select (select count(*)::int from matched) as matched, (select count(*)::int from updated) as updated) c left join updated u on true");
|
|
485
|
+
}
|
|
486
|
+
function updateSliceBody(schema, table, rows, sql, wrapWhere = false) {
|
|
345
487
|
const fields = [];
|
|
346
488
|
const seen = new Set;
|
|
347
489
|
for (const row of rows) {
|
|
@@ -356,7 +498,6 @@ function updateSlice(schema, table, rows, returning) {
|
|
|
356
498
|
}
|
|
357
499
|
if (fields.length === 0)
|
|
358
500
|
fail("OKM1120", "update set is empty.");
|
|
359
|
-
const sql = new Sql;
|
|
360
501
|
sql.text("update ");
|
|
361
502
|
sql.text(quote(table.model.sql));
|
|
362
503
|
sql.text(" as t set ");
|
|
@@ -383,7 +524,7 @@ function updateSlice(schema, table, rows, returning) {
|
|
|
383
524
|
sql.text(" end");
|
|
384
525
|
}
|
|
385
526
|
emitTouch(sql, table, fields.length > 0);
|
|
386
|
-
sql.text(" where ");
|
|
527
|
+
sql.text(wrapWhere ? " where (" : " where ");
|
|
387
528
|
for (let index = 0;index < rows.length; index += 1) {
|
|
388
529
|
const row = rows[index];
|
|
389
530
|
if (row === undefined)
|
|
@@ -394,6 +535,64 @@ function updateSlice(schema, table, rows, returning) {
|
|
|
394
535
|
emitBare(schema, table, row.where, sql, "t");
|
|
395
536
|
sql.text(")");
|
|
396
537
|
}
|
|
538
|
+
if (wrapWhere)
|
|
539
|
+
sql.text(")");
|
|
540
|
+
}
|
|
541
|
+
function orderByKeys(rows, fields, keys) {
|
|
542
|
+
const found = new Map;
|
|
543
|
+
for (const row of rows)
|
|
544
|
+
found.set(fields.map((field) => wireKey(row[field])).join("\x00"), row);
|
|
545
|
+
const ordered = [];
|
|
546
|
+
for (const key of keys) {
|
|
547
|
+
const row = found.get(key.map((value) => value ?? "").join("\x00"));
|
|
548
|
+
if (row !== undefined)
|
|
549
|
+
ordered.push(row);
|
|
550
|
+
}
|
|
551
|
+
return ordered;
|
|
552
|
+
}
|
|
553
|
+
function wireKey(value) {
|
|
554
|
+
if (typeof value === "string")
|
|
555
|
+
return value;
|
|
556
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
557
|
+
return String(value);
|
|
558
|
+
}
|
|
559
|
+
return "";
|
|
560
|
+
}
|
|
561
|
+
function insertHead(table, columns, rows) {
|
|
562
|
+
const params = [];
|
|
563
|
+
const lists = [];
|
|
564
|
+
for (const row of rows) {
|
|
565
|
+
const slots = [];
|
|
566
|
+
for (const cell of row) {
|
|
567
|
+
if (cell.kind === "default") {
|
|
568
|
+
slots.push("default");
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
params.push(cell.kind === "null" ? null : cell.wire);
|
|
572
|
+
slots.push(`$${String(params.length)}::${cell.dataType}`);
|
|
573
|
+
}
|
|
574
|
+
lists.push(`(${slots.join(", ")})`);
|
|
575
|
+
}
|
|
576
|
+
const names = columns.map((column) => quote(column.sql)).join(", ");
|
|
577
|
+
return {
|
|
578
|
+
text: `insert into ${quote(table.model.sql)} (${names}) values ${lists.join(", ")}`,
|
|
579
|
+
params
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
function updateList(schema, table, rows, returning) {
|
|
583
|
+
if (rows.length === 0)
|
|
584
|
+
return [];
|
|
585
|
+
const width = Math.max(1, Object.keys(rows[0]?.set ?? {}).length + 2);
|
|
586
|
+
const size = Math.max(1, Math.floor(WRITE_PARAM_BUDGET / (width * 2)));
|
|
587
|
+
const statements = [];
|
|
588
|
+
for (let index = 0;index < rows.length; index += size) {
|
|
589
|
+
statements.push(updateSlice(schema, table, rows.slice(index, index + size), returning));
|
|
590
|
+
}
|
|
591
|
+
return statements;
|
|
592
|
+
}
|
|
593
|
+
function updateSlice(schema, table, rows, returning) {
|
|
594
|
+
const sql = new Sql;
|
|
595
|
+
updateSliceBody(schema, table, rows, sql);
|
|
397
596
|
sql.text(returningClause(returning, "t"));
|
|
398
597
|
return sql.statement();
|
|
399
598
|
}
|
|
@@ -603,7 +802,7 @@ function nextFill(fill, generators) {
|
|
|
603
802
|
return generators.okid();
|
|
604
803
|
return fill.call();
|
|
605
804
|
}
|
|
606
|
-
function writtenColumns(table, rows, allow,
|
|
805
|
+
function writtenColumns(table, rows, allow, tenantKeys) {
|
|
607
806
|
const present = new Set;
|
|
608
807
|
for (const row of rows) {
|
|
609
808
|
for (const key of Object.keys(row))
|
|
@@ -611,12 +810,55 @@ function writtenColumns(table, rows, allow, tenantKey) {
|
|
|
611
810
|
}
|
|
612
811
|
const columns = [];
|
|
613
812
|
for (const column of table.model.columns) {
|
|
614
|
-
if (present.has(column.field) && (writable(table, column, allow) || column.fill !== undefined || column.field ===
|
|
813
|
+
if (present.has(column.field) && (writable(table, column, allow) || column.fill !== undefined || tenantKeys?.includes(column.field) === true)) {
|
|
615
814
|
columns.push(column);
|
|
616
815
|
}
|
|
617
816
|
}
|
|
618
817
|
return columns;
|
|
619
818
|
}
|
|
819
|
+
function tenantKeyList(tenancy) {
|
|
820
|
+
if (tenancy === undefined)
|
|
821
|
+
return;
|
|
822
|
+
if (tenancy.keys !== undefined && tenancy.keys.length > 0)
|
|
823
|
+
return tenancy.keys;
|
|
824
|
+
return [tenancy.key];
|
|
825
|
+
}
|
|
826
|
+
function pathInsert(table, columns, rows, scope, tenancy) {
|
|
827
|
+
const sql = new Sql;
|
|
828
|
+
const names = columns.map((column) => quote(column.sql)).join(", ");
|
|
829
|
+
const selected = columns.map((column) => `v.${quote(column.sql)}`).join(", ");
|
|
830
|
+
sql.text(`insert into ${quote(table.model.sql)} (${names}) select ${selected} from (values `);
|
|
831
|
+
for (let row = 0;row < rows.length; row += 1) {
|
|
832
|
+
const cells = rows[row];
|
|
833
|
+
if (cells === undefined)
|
|
834
|
+
continue;
|
|
835
|
+
if (row > 0)
|
|
836
|
+
sql.text(", ");
|
|
837
|
+
sql.text("(");
|
|
838
|
+
for (let index = 0;index < cells.length; index += 1) {
|
|
839
|
+
const cell = cells[index];
|
|
840
|
+
if (index > 0)
|
|
841
|
+
sql.text(", ");
|
|
842
|
+
if (cell === undefined || cell.kind === "default") {
|
|
843
|
+
sql.text("default");
|
|
844
|
+
continue;
|
|
845
|
+
}
|
|
846
|
+
sql.param(cell.kind === "null" ? null : cell.wire, cell.dataType);
|
|
847
|
+
}
|
|
848
|
+
sql.text(")");
|
|
849
|
+
}
|
|
850
|
+
sql.text(`) as v(${names})`);
|
|
851
|
+
tenancy?.lockPredicate?.({
|
|
852
|
+
table: table.model.name,
|
|
853
|
+
fieldSql: (field) => table.columns.get(field)?.sql,
|
|
854
|
+
encode: table.columns.get(tenancy.key)?.encode,
|
|
855
|
+
alias: "v",
|
|
856
|
+
appended: false,
|
|
857
|
+
scope,
|
|
858
|
+
sink: sql.sink()
|
|
859
|
+
});
|
|
860
|
+
return sql.statement();
|
|
861
|
+
}
|
|
620
862
|
function writeSet(table, value, allow, tenancy) {
|
|
621
863
|
if (!isRecord(value))
|
|
622
864
|
fail("OKM1121", "set must be an object of fields.");
|
|
@@ -637,6 +879,7 @@ function writeSet(table, value, allow, tenancy) {
|
|
|
637
879
|
function updateItem(table, value, allow, tenancy) {
|
|
638
880
|
if (!isRecord(value))
|
|
639
881
|
fail("OKM1121", "update expects { where, set } or a list of rows.");
|
|
882
|
+
rejectUpdateKeys(value, true);
|
|
640
883
|
const set = writeSet(table, value.set, allow, tenancy);
|
|
641
884
|
if (value.where !== undefined)
|
|
642
885
|
return { where: value.where, set };
|
|
@@ -644,6 +887,14 @@ function updateItem(table, value, allow, tenancy) {
|
|
|
644
887
|
return { where: { id: value.id }, set };
|
|
645
888
|
fail("OKM1102", `update on ${table.model.name} needs id or where for each row.`);
|
|
646
889
|
}
|
|
890
|
+
function rejectUpdateKeys(input, row) {
|
|
891
|
+
const accepted = row ? UPDATE_ROW_KEYS : UPDATE_KEYS;
|
|
892
|
+
for (const key of Object.keys(input)) {
|
|
893
|
+
if (accepted.includes(key))
|
|
894
|
+
continue;
|
|
895
|
+
throwNamed2("OKM1120", key, [...accepted, ...FILTER_OPTIONS], `Option ${key} is not accepted by update. Accepted options: ${accepted.join(", ")}. timeout and signal go in the second argument.`);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
647
898
|
function requireFilter(table, where, mods, op) {
|
|
648
899
|
if (mods.all !== undefined) {
|
|
649
900
|
if (mods.all.trim().length === 0) {
|
|
@@ -651,11 +902,9 @@ function requireFilter(table, where, mods, op) {
|
|
|
651
902
|
}
|
|
652
903
|
return;
|
|
653
904
|
}
|
|
654
|
-
if (
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
return;
|
|
658
|
-
fail("OKM1102", `${op} on ${table.model.name} needs a where. Pass a filter, or .all(reason).`);
|
|
905
|
+
if (!effectivePredicate(where)) {
|
|
906
|
+
fail("OKM1102", `${op} on ${table.model.name} needs a where. Pass a filter, or .all(reason).`);
|
|
907
|
+
}
|
|
659
908
|
}
|
|
660
909
|
function chunkRows(rows) {
|
|
661
910
|
const chunks = [];
|
|
@@ -416,6 +416,7 @@ function emitPredicate(schema, table, key, value, sink, alias, depth) {
|
|
|
416
416
|
if (column === undefined) {
|
|
417
417
|
throwNamed2("OKM1120", key, table.names, `Field ${key} is not on ${table.model.name}. Accepted names: ${list(table.names)}.`);
|
|
418
418
|
}
|
|
419
|
+
refuseHidden(column);
|
|
419
420
|
sink.mark(`w:${key}`);
|
|
420
421
|
emitOperand(schema, table, column, value, sink, alias, depth);
|
|
421
422
|
}
|
|
@@ -533,7 +534,9 @@ function emitIn(column, ref, name, value, sink) {
|
|
|
533
534
|
sink.text(")");
|
|
534
535
|
}
|
|
535
536
|
function emitOr(schema, table, value, sink, alias, depth) {
|
|
536
|
-
if (!Array.isArray(value)
|
|
537
|
+
if (!Array.isArray(value))
|
|
538
|
+
orFail(false);
|
|
539
|
+
if (value.length === 0) {
|
|
537
540
|
sink.text("false");
|
|
538
541
|
sink.mark(":0");
|
|
539
542
|
return;
|
|
@@ -559,7 +562,7 @@ function emitOr(schema, table, value, sink, alias, depth) {
|
|
|
559
562
|
emitPredicate(schema, table, key, item, sink, alias, depth);
|
|
560
563
|
}
|
|
561
564
|
if (!wrote)
|
|
562
|
-
|
|
565
|
+
orFail(true);
|
|
563
566
|
sink.text(")");
|
|
564
567
|
}
|
|
565
568
|
sink.text(")");
|
|
@@ -612,6 +615,7 @@ function emitOrder(table, orderBy, sink, alias) {
|
|
|
612
615
|
if (column === undefined) {
|
|
613
616
|
throwNamed2("OKM1120", key, table.names, `Field ${key} is not on ${table.model.name}. Accepted names: ${list(table.names)}.`);
|
|
614
617
|
}
|
|
618
|
+
refuseHidden(column);
|
|
615
619
|
const parsed = parseOrder(key, orderBy[key]);
|
|
616
620
|
if (index > 0)
|
|
617
621
|
sink.text(", ");
|
|
@@ -640,6 +644,11 @@ function emitPrimaryOrder(table, sink, alias) {
|
|
|
640
644
|
sink.text(" asc");
|
|
641
645
|
}
|
|
642
646
|
}
|
|
647
|
+
function refuseHidden(column) {
|
|
648
|
+
if (column.hidden !== true)
|
|
649
|
+
return;
|
|
650
|
+
fail("OKM1120", `Field ${column.field} is hidden.`, "Call hidden({ filterable: true }).");
|
|
651
|
+
}
|
|
643
652
|
function emitLimit(call, sink) {
|
|
644
653
|
if (call.op === "one") {
|
|
645
654
|
const ordered = call.orderBy !== undefined && isRecord(call.orderBy) && Object.keys(call.orderBy).length > 0;
|
|
@@ -844,6 +853,13 @@ function list(names) {
|
|
|
844
853
|
function isRecord(value) {
|
|
845
854
|
return typeof value === "object" && value !== null && !Array.isArray(value) && !isOperator(value);
|
|
846
855
|
}
|
|
856
|
+
function orFail(empty) {
|
|
857
|
+
throw new OkmError2("OKM1121", empty ? "or() branch is empty." : "Pass an array: or([a, b]).", {
|
|
858
|
+
fix: {
|
|
859
|
+
summary: empty ? "Give every or() branch a predicate. An empty branch matches every row." : "Pass an array: or([a, b])."
|
|
860
|
+
}
|
|
861
|
+
});
|
|
862
|
+
}
|
|
847
863
|
var FAIL_FIX = {
|
|
848
864
|
OKM1121: "Use eq for an object value, or has, none, or every for a relation.",
|
|
849
865
|
OKM1101: "Pass limit, or call .all(reason)."
|
|
@@ -851,8 +867,8 @@ var FAIL_FIX = {
|
|
|
851
867
|
function registerFailFix(code, summary) {
|
|
852
868
|
FAIL_FIX[code] = summary;
|
|
853
869
|
}
|
|
854
|
-
function fail(code, message) {
|
|
855
|
-
const summary = FAIL_FIX[code];
|
|
870
|
+
function fail(code, message, fix) {
|
|
871
|
+
const summary = fix ?? FAIL_FIX[code];
|
|
856
872
|
throw new OkmError2(code, message, summary === undefined ? undefined : { fix: { summary } });
|
|
857
873
|
}
|
|
858
874
|
function plain(value) {
|
|
@@ -875,4 +891,4 @@ function hasMany(include) {
|
|
|
875
891
|
return Object.keys(include).length > 0;
|
|
876
892
|
}
|
|
877
893
|
|
|
878
|
-
export { withRowFilters, installArchiveInspect, archiveRules, readOptionNames, installOperatorSql, readNeedsOperatorSql, emitRelationFrom, bindCall, compileCall, decodeResult, logicalIntent, appliedRules, emitJoin, emitWhere, emitOrder, emitPrimaryOrder, selectedColumns, parseOrder, rejectKeys, readLimit, takeObject, projectExpr, jsonExpr, decodeRow, cell, indexes, quote, list, isRecord, registerFailFix, fail };
|
|
894
|
+
export { withRowFilters, installArchiveInspect, archiveRules, readOptionNames, installOperatorSql, readNeedsOperatorSql, emitRelationFrom, bindCall, compileCall, decodeResult, logicalIntent, appliedRules, emitJoin, emitWhere, emitOrder, emitPrimaryOrder, refuseHidden, selectedColumns, parseOrder, rejectKeys, readLimit, takeObject, projectExpr, jsonExpr, decodeRow, cell, indexes, quote, list, isRecord, orFail, registerFailFix, fail };
|
|
@@ -75,7 +75,7 @@ function mapDriverError2(error, batchIndex) {
|
|
|
75
75
|
if (error instanceof DriverError2) {
|
|
76
76
|
return batchIndex === undefined ? error : error.at(batchIndex);
|
|
77
77
|
}
|
|
78
|
-
const message = error
|
|
78
|
+
const message = messageOf(error);
|
|
79
79
|
return new DriverError2(message, driverFields({
|
|
80
80
|
sqlstate: sqlstateOf(error),
|
|
81
81
|
constraint: errorField2(error, "constraint_name") ?? errorField2(error, "constraint"),
|
|
@@ -86,6 +86,14 @@ function mapDriverError2(error, batchIndex) {
|
|
|
86
86
|
batchIndex
|
|
87
87
|
}));
|
|
88
88
|
}
|
|
89
|
+
function messageOf(error) {
|
|
90
|
+
if (!(error instanceof Error))
|
|
91
|
+
return "driver error";
|
|
92
|
+
if (error.message.length > 0)
|
|
93
|
+
return error.message;
|
|
94
|
+
const first = error.errors?.[0];
|
|
95
|
+
return first instanceof Error && first.message.length > 0 ? first.message : "driver error";
|
|
96
|
+
}
|
|
89
97
|
function driverFields(input) {
|
|
90
98
|
const fields = {};
|
|
91
99
|
if (input.sqlstate !== undefined)
|