okmodel 0.1.1 → 0.3.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 +727 -37
- 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/enum.d.ts +31 -4
- package/dist/contracts/catalog/extension.d.ts +61 -0
- package/dist/contracts/catalog/object.d.ts +1 -0
- package/dist/contracts/catalog/privilege.d.ts +64 -0
- package/dist/contracts/catalog/routine.d.ts +56 -0
- package/dist/contracts/catalog/types.d.ts +179 -18
- package/dist/contracts/catalog/view.d.ts +73 -0
- 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 +129 -10
- package/dist/dialects/pg/compile.d.ts +1 -0
- package/dist/dialects/pg/custom.d.ts +6 -0
- package/dist/dialects/pg/ddl.d.ts +65 -1
- package/dist/dialects/pg/enum.d.ts +10 -8
- package/dist/dialects/pg/ext/citext.d.ts +14 -0
- package/dist/dialects/pg/ext/citext.js +11 -0
- package/dist/dialects/pg/ext/index.d.ts +52 -0
- package/dist/dialects/pg/ext/index.js +6 -0
- package/dist/dialects/pg/ext/pg-trgm.d.ts +53 -0
- package/dist/dialects/pg/ext/pg-trgm.js +42 -0
- package/dist/dialects/pg/filter-parse.d.ts +19 -0
- package/dist/dialects/pg/filters.d.ts +19 -0
- package/dist/dialects/pg/fn/index.d.ts +107 -0
- package/dist/dialects/pg/fn/index.js +175 -0
- package/dist/dialects/pg/fn/touch.d.ts +14 -0
- package/dist/dialects/pg/index.d.ts +11 -2
- package/dist/dialects/pg/index.js +243 -1062
- package/dist/dialects/pg/introspect.d.ts +10 -1
- 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 +46 -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/role/check.d.ts +45 -0
- package/dist/dialects/pg/role/index.d.ts +50 -0
- package/dist/dialects/pg/role/sql.d.ts +44 -0
- package/dist/dialects/pg/schema.d.ts +109 -5
- package/dist/dialects/pg/table.d.ts +137 -11
- package/dist/dialects/pg/temporal.d.ts +9 -7
- package/dist/dialects/pg/tenancy.d.ts +103 -0
- package/dist/dialects/pg/through.d.ts +21 -0
- package/dist/dialects/pg/trait.d.ts +141 -0
- package/dist/dialects/pg/view/client.d.ts +30 -0
- package/dist/dialects/pg/view/depend.d.ts +35 -0
- package/dist/dialects/pg/view/index.d.ts +114 -0
- package/dist/dialects/pg/view/index.js +289 -0
- package/dist/dialects/pg/view/scratch.d.ts +21 -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 +368 -0
- package/dist/runtime/trait-read.d.ts +30 -0
- package/dist/runtime/traits/index.d.ts +133 -0
- package/dist/runtime/traits/index.js +646 -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/01yr20s5.js +149 -0
- package/dist/shared/0jc3ffzf.js +154 -0
- package/dist/shared/0v1g424p.js +26 -0
- package/dist/shared/1g0drakv.js +225 -0
- package/dist/shared/{kprcwaha.js → 1tfdfvhh.js} +5 -3
- package/dist/shared/{05w44d8g.js → 2ssqrv66.js} +767 -715
- package/dist/shared/3ekj9x92.js +210 -0
- package/dist/shared/49ypnfwt.js +1122 -0
- package/dist/shared/4e4c6vq2.js +62 -0
- package/dist/shared/4m9fn52z.js +70 -0
- package/dist/shared/{ycwz42az.js → 52szzakm.js} +6 -26
- package/dist/shared/5nmdenb6.js +1229 -0
- package/dist/shared/672t5vym.js +12 -0
- package/dist/shared/6bazvqwm.js +86 -0
- package/dist/shared/6w5j844a.js +201 -0
- package/dist/shared/{fgqgsb5z.js → 75xkjv0t.js} +2 -2
- package/dist/shared/7fvtrkwr.js +84 -0
- package/dist/shared/7m88x3e9.js +45 -0
- package/dist/shared/{mtkwv8wx.js → 7p2wbz7f.js} +1 -1
- package/dist/shared/83eaefwr.js +10 -0
- package/dist/shared/94ez8kzh.js +19 -0
- package/dist/shared/96ps4g1z.js +32 -0
- package/dist/shared/{xqbhg6cn.js → 999ade2q.js} +95 -10
- package/dist/shared/9m80mkac.js +158 -0
- package/dist/shared/9x25fxhc.js +150 -0
- package/dist/shared/a5sxz52y.js +13 -0
- package/dist/shared/axhk06q1.js +156 -0
- package/dist/shared/{dynq16vb.js → b066g80h.js} +8 -6
- package/dist/shared/bqha5cg6.js +229 -0
- package/dist/shared/bryqk9k9.js +31 -0
- package/dist/shared/c8aghh05.js +442 -0
- package/dist/shared/c9z5g0fm.js +309 -0
- package/dist/shared/{m3ypagh5.js → dbjej1tw.js} +124 -15
- package/dist/shared/dyj86cmj.js +69 -0
- package/dist/shared/e6wg00wd.js +164 -0
- package/dist/shared/{hadrfb9h.js → edwqqryd.js} +17 -14
- package/dist/shared/{qk3hxfja.js → fptpmvxp.js} +5 -5
- package/dist/shared/fs0ex00p.js +76 -0
- package/dist/shared/{jjb7yht9.js → g4f5kcx9.js} +3 -3
- package/dist/shared/gjthds9j.js +48 -0
- package/dist/shared/hcmdtwgh.js +102 -0
- package/dist/shared/{g5fhqmwe.js → jkc6ws1p.js} +6 -56
- package/dist/shared/{yd1kzwn2.js → jns2wx4t.js} +55 -12
- package/dist/shared/k34e0xf2.js +450 -0
- package/dist/shared/k3ted12y.js +33 -0
- package/dist/shared/k7dwkhvq.js +31 -0
- package/dist/shared/{8b04d28c.js → kgnc8grt.js} +2 -2
- package/dist/shared/{hd293j9g.js → kyxb62mc.js} +14 -2
- package/dist/shared/m78s7898.js +376 -0
- package/dist/shared/m9tv7xn7.js +404 -0
- package/dist/shared/meck53jv.js +99 -0
- package/dist/shared/mt5wswjz.js +90 -0
- package/dist/shared/n0dgs0pb.js +75 -0
- package/dist/shared/n442h54c.js +14 -0
- package/dist/shared/n4jqhpqz.js +27 -0
- package/dist/shared/n7mcc1gk.js +132 -0
- package/dist/shared/ne02ng5c.js +68 -0
- package/dist/shared/{mkjmqjv4.js → nfzc5z0w.js} +2 -104
- package/dist/shared/nsva2a6b.js +42 -0
- package/dist/shared/p24x2334.js +195 -0
- package/dist/shared/qbxzvwwc.js +88 -0
- package/dist/shared/{w8samvk1.js → qybh48nd.js} +1 -1
- package/dist/shared/r6nwkxnt.js +86 -0
- package/dist/shared/{xy79j5hq.js → rrstp3kb.js} +25 -36
- package/dist/shared/rwmrejjz.js +26 -0
- package/dist/shared/{zhc5vmgf.js → s6gqfn5j.js} +2 -2
- package/dist/shared/{523ft3e8.js → scwxrpx2.js} +7 -5
- package/dist/shared/{j5cn2963.js → t4tbsy9h.js} +13 -64
- package/dist/shared/{y9m15dfv.js → t616ynfn.js} +544 -32
- package/dist/shared/{ngk8gj61.js → tbszx8mz.js} +15 -1
- package/dist/shared/th14ygv2.js +69 -0
- package/dist/shared/tmbdywx0.js +178 -0
- package/dist/shared/ty3v3hfk.js +64 -0
- package/dist/shared/wekze34d.js +246 -0
- package/dist/shared/x6wysh83.js +1132 -0
- package/dist/shared/{rgs0st28.js → xrfnq5k8.js} +237 -434
- package/dist/shared/{x5x59srr.js → xva8v7qk.js} +416 -83
- package/dist/shared/{dkn3y60a.js → xw1d69vd.js} +76 -112
- package/dist/shared/y005b761.js +112 -0
- package/dist/shared/ydaz1sv3.js +55 -0
- package/dist/shared/{p0cbr3g2.js → zwmqxb0g.js} +1 -1
- package/dist/tooling/cli.js +40 -12
- package/dist/tooling/migrate/apply.d.ts +16 -0
- package/dist/tooling/migrate/commands.d.ts +12 -1
- package/dist/tooling/migrate/config.d.ts +8 -0
- package/dist/tooling/migrate/doctor.d.ts +25 -0
- package/dist/tooling/migrate/drift.d.ts +19 -0
- package/dist/tooling/migrate/engine.d.ts +36 -0
- package/dist/tooling/migrate/ext.d.ts +17 -0
- package/dist/tooling/migrate/extensions.d.ts +51 -0
- package/dist/tooling/migrate/managed.d.ts +17 -0
- package/dist/tooling/migrate/plan.d.ts +14 -1
- package/dist/tooling/migrate/project.d.ts +25 -1
- package/dist/tooling/migrate/type-name.d.ts +19 -0
- package/package.json +61 -4
- package/dist/shared/gk7cs7sp.js +0 -566
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runWrite
|
|
3
|
+
} from "./n4jqhpqz.js";
|
|
4
|
+
import {
|
|
5
|
+
stack
|
|
6
|
+
} from "./672t5vym.js";
|
|
7
|
+
import {
|
|
8
|
+
withRowFilters,
|
|
9
|
+
archiveRules,
|
|
10
|
+
emitWhere,
|
|
11
|
+
rejectKeys,
|
|
12
|
+
indexes,
|
|
13
|
+
quote,
|
|
14
|
+
isRecord,
|
|
15
|
+
registerFailFix,
|
|
16
|
+
fail
|
|
17
|
+
} from "./xrfnq5k8.js";
|
|
18
|
+
import {
|
|
19
|
+
safetyInstalled,
|
|
20
|
+
runSafety
|
|
21
|
+
} from "./a5sxz52y.js";
|
|
22
|
+
import {
|
|
23
|
+
isOperator
|
|
24
|
+
} from "./cn0n68ft.js";
|
|
25
|
+
import {
|
|
26
|
+
OkmError2
|
|
27
|
+
} from "./52szzakm.js";
|
|
28
|
+
|
|
29
|
+
// src/runtime/archive.ts
|
|
30
|
+
registerFailFix("OKM1102", "Pass where, or call .all(reason) to match every row.");
|
|
31
|
+
var OPTIONS = ["allow", "expect", "returning", "signal", "timeout"];
|
|
32
|
+
async function executeArchive(host, op, table, input, options, mods, scope) {
|
|
33
|
+
const prepared = prepareArchive(host.schema, op, table, input, options, mods, scope);
|
|
34
|
+
const results = await runWrite(host, prepared.statements, prepared.options);
|
|
35
|
+
return prepared.finish(results);
|
|
36
|
+
}
|
|
37
|
+
function prepareArchive(schema, op, table, input, options, mods, scope) {
|
|
38
|
+
const planned = planArchive(schema, op, table, input, options, mods, scope);
|
|
39
|
+
return {
|
|
40
|
+
statements: [{ text: planned.text, params: planned.params }],
|
|
41
|
+
options: planned.call,
|
|
42
|
+
...op === "restore" ? { checked: "restore" } : planned.expect !== undefined ? { checked: "expect" } : {},
|
|
43
|
+
finish: (results) => finish(op, table, results[0], planned)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function explainArchive(schema, op, table, input, options, mods, scope) {
|
|
47
|
+
const planned = planArchive(schema, op, table, input, options, mods, scope);
|
|
48
|
+
return { statements: [{ text: planned.text, params: planned.params }] };
|
|
49
|
+
}
|
|
50
|
+
function planArchive(schema, op, tableName, input, options, mods, scope) {
|
|
51
|
+
const table = indexes(schema).get(tableName);
|
|
52
|
+
if (table === undefined)
|
|
53
|
+
fail("OKM1120", `Table ${tableName} is not in the schema.`);
|
|
54
|
+
const archive = table.model.archive;
|
|
55
|
+
if (archive === undefined) {
|
|
56
|
+
throw new OkmError2("OKM1052", `Table ${tableName} is not archivable.`, {
|
|
57
|
+
fix: { summary: "Call archive and restore only on an archivable table." }
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const record = isRecord(options) ? options : {};
|
|
61
|
+
rejectKeys(record, OPTIONS, op);
|
|
62
|
+
const expect = expectOf(record.expect ?? mods.expect);
|
|
63
|
+
const read = readTarget(op, table, input, mods);
|
|
64
|
+
const target = { ...read, where: stack(read.where, mods.presets) };
|
|
65
|
+
const view = op === "restore" ? "only" : undefined;
|
|
66
|
+
noteArchive(table, view);
|
|
67
|
+
const statement = withRowFilters(scope, view, () => op === "archive" ? archiveSql(schema, table, target.where) : restoreSql(schema, table, target));
|
|
68
|
+
return {
|
|
69
|
+
text: statement.text,
|
|
70
|
+
params: statement.params,
|
|
71
|
+
expect,
|
|
72
|
+
archiveId: op === "archive" ? statement.archiveId : undefined,
|
|
73
|
+
call: callOptions(record)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function noteArchive(table, view) {
|
|
77
|
+
if (!safetyInstalled())
|
|
78
|
+
return;
|
|
79
|
+
const rules = archiveRules(table.model, view);
|
|
80
|
+
if (rules === undefined)
|
|
81
|
+
return;
|
|
82
|
+
runSafety(rules, undefined);
|
|
83
|
+
}
|
|
84
|
+
function readTarget(op, table, input, mods) {
|
|
85
|
+
if (!isRecord(input))
|
|
86
|
+
fail("OKM1121", `${op} expects { where }.`);
|
|
87
|
+
const keys = Object.keys(input);
|
|
88
|
+
if (op === "restore" && input.archiveId !== undefined) {
|
|
89
|
+
if (input.where !== undefined)
|
|
90
|
+
fail("OKM1120", "restore takes where or archiveId, not both.");
|
|
91
|
+
for (const key of keys) {
|
|
92
|
+
if (key !== "archiveId") {
|
|
93
|
+
fail("OKM1120", "restore accepts where or archiveId.");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (typeof input.archiveId !== "string" || input.archiveId.length === 0) {
|
|
97
|
+
fail("OKM1121", "restore archiveId must be a uuid.");
|
|
98
|
+
}
|
|
99
|
+
const idField = table.model.archive?.idField ?? "archiveId";
|
|
100
|
+
return { where: { [idField]: input.archiveId }, archiveId: input.archiveId };
|
|
101
|
+
}
|
|
102
|
+
for (const key of keys) {
|
|
103
|
+
if (key !== "where")
|
|
104
|
+
fail("OKM1120", `${op} accepts where.`);
|
|
105
|
+
}
|
|
106
|
+
requireFilter(table, input.where, mods, op);
|
|
107
|
+
return { where: input.where, archiveId: undefined };
|
|
108
|
+
}
|
|
109
|
+
function archiveSql(schema, table, where) {
|
|
110
|
+
const archive = table.model.archive;
|
|
111
|
+
if (archive === undefined) {
|
|
112
|
+
throw new OkmError2("OKM1052", `Table ${table.model.name} is not archivable.`);
|
|
113
|
+
}
|
|
114
|
+
const archiveId = globalThis.crypto.randomUUID();
|
|
115
|
+
const sql = new Sql;
|
|
116
|
+
const cascade = archive.cascade;
|
|
117
|
+
if (cascade.length === 0) {
|
|
118
|
+
sql.text("update ");
|
|
119
|
+
sql.text(quote(table.model.sql));
|
|
120
|
+
sql.text(" as t set ");
|
|
121
|
+
sql.text(quote(archive.at));
|
|
122
|
+
sql.text(" = now(), ");
|
|
123
|
+
sql.text(quote(archive.id));
|
|
124
|
+
sql.text(" = ");
|
|
125
|
+
sql.param(archiveId);
|
|
126
|
+
sql.text("::uuid");
|
|
127
|
+
emitWhere(schema, table, where, sql, "t", 0);
|
|
128
|
+
return { text: sql.join(), params: sql.params, archiveId };
|
|
129
|
+
}
|
|
130
|
+
const returned = returnedColumns(table, cascade);
|
|
131
|
+
sql.text("with archived as (update ");
|
|
132
|
+
sql.text(quote(table.model.sql));
|
|
133
|
+
sql.text(" as t set ");
|
|
134
|
+
sql.text(quote(archive.at));
|
|
135
|
+
sql.text(" = now(), ");
|
|
136
|
+
sql.text(quote(archive.id));
|
|
137
|
+
sql.text(" = ");
|
|
138
|
+
sql.param(archiveId);
|
|
139
|
+
sql.text("::uuid");
|
|
140
|
+
emitWhere(schema, table, where, sql, "t", 0);
|
|
141
|
+
sql.text(" returning ");
|
|
142
|
+
sql.text(returned.map((column) => `t.${quote(column)}`).join(", "));
|
|
143
|
+
sql.text(")");
|
|
144
|
+
for (let index = 0;index < cascade.length; index += 1) {
|
|
145
|
+
const child = cascade[index];
|
|
146
|
+
if (child === undefined)
|
|
147
|
+
continue;
|
|
148
|
+
sql.text(", c");
|
|
149
|
+
sql.text(String(index));
|
|
150
|
+
sql.text(" as (");
|
|
151
|
+
childUpdate(schema, sql, child, "archived");
|
|
152
|
+
sql.text(")");
|
|
153
|
+
}
|
|
154
|
+
sql.text(" select count(*)::text from archived");
|
|
155
|
+
return { text: sql.join(), params: sql.params, archiveId };
|
|
156
|
+
}
|
|
157
|
+
function restoreSql(schema, table, target) {
|
|
158
|
+
const archive = table.model.archive;
|
|
159
|
+
if (archive === undefined) {
|
|
160
|
+
throw new OkmError2("OKM1052", `Table ${table.model.name} is not archivable.`);
|
|
161
|
+
}
|
|
162
|
+
const parents = archive.parents;
|
|
163
|
+
const cascade = archive.cascade;
|
|
164
|
+
const sql = new Sql;
|
|
165
|
+
if (parents.length === 0 && cascade.length === 0) {
|
|
166
|
+
sql.text("update ");
|
|
167
|
+
sql.text(quote(table.model.sql));
|
|
168
|
+
sql.text(" as t set ");
|
|
169
|
+
sql.text(quote(archive.at));
|
|
170
|
+
sql.text(" = null, ");
|
|
171
|
+
sql.text(quote(archive.id));
|
|
172
|
+
sql.text(" = null");
|
|
173
|
+
emitWhere(schema, table, target.where, sql, "t", 0);
|
|
174
|
+
return { text: sql.join(), params: sql.params, archiveId: "" };
|
|
175
|
+
}
|
|
176
|
+
const pk = primarySql(table);
|
|
177
|
+
const selected = new Set(pk);
|
|
178
|
+
for (const parent of parents)
|
|
179
|
+
for (const column of parent.local)
|
|
180
|
+
selected.add(column);
|
|
181
|
+
for (const child of cascade)
|
|
182
|
+
for (const column of child.remote)
|
|
183
|
+
selected.add(column);
|
|
184
|
+
selected.delete(archive.id);
|
|
185
|
+
sql.text("with target as (select ");
|
|
186
|
+
sql.text([...selected].map((column) => `t.${quote(column)}`).join(", "));
|
|
187
|
+
sql.text(", t.");
|
|
188
|
+
sql.text(quote(archive.id));
|
|
189
|
+
sql.text(' as "archive_id" from ');
|
|
190
|
+
sql.text(quote(table.model.sql));
|
|
191
|
+
sql.text(" t");
|
|
192
|
+
emitWhere(schema, table, target.where, sql, "t", 0);
|
|
193
|
+
sql.text(")");
|
|
194
|
+
if (parents.length > 0) {
|
|
195
|
+
sql.text(", blocked as (");
|
|
196
|
+
for (let index = 0;index < parents.length; index += 1) {
|
|
197
|
+
const parent = parents[index];
|
|
198
|
+
if (parent === undefined)
|
|
199
|
+
continue;
|
|
200
|
+
if (index > 0)
|
|
201
|
+
sql.text(" union all ");
|
|
202
|
+
sql.text("select ");
|
|
203
|
+
sql.text(quoteLiteral(parent.table));
|
|
204
|
+
sql.text(" as parent from target x join ");
|
|
205
|
+
sql.text(quote(parent.sql));
|
|
206
|
+
sql.text(" p on ");
|
|
207
|
+
sql.text(joinOn("p", parent.remote, "x", parent.local));
|
|
208
|
+
sql.text(" where p.");
|
|
209
|
+
sql.text(quote(parent.at));
|
|
210
|
+
sql.text(" is not null");
|
|
211
|
+
}
|
|
212
|
+
sql.text(")");
|
|
213
|
+
}
|
|
214
|
+
sql.text(", restored as (update ");
|
|
215
|
+
sql.text(quote(table.model.sql));
|
|
216
|
+
sql.text(" as u set ");
|
|
217
|
+
sql.text(quote(archive.at));
|
|
218
|
+
sql.text(" = null, ");
|
|
219
|
+
sql.text(quote(archive.id));
|
|
220
|
+
sql.text(" = null from target x where ");
|
|
221
|
+
sql.text(joinOn("u", pk, "x", pk));
|
|
222
|
+
if (parents.length > 0)
|
|
223
|
+
sql.text(" and not exists (select 1 from blocked)");
|
|
224
|
+
sql.text(" returning ");
|
|
225
|
+
sql.text([...new Set([...pk, ...cascade.flatMap((child) => [...child.remote])])].map((column) => `x.${quote(column)}`).join(", "));
|
|
226
|
+
sql.text(', x."archive_id")');
|
|
227
|
+
for (let index = 0;index < cascade.length; index += 1) {
|
|
228
|
+
const child = cascade[index];
|
|
229
|
+
if (child === undefined)
|
|
230
|
+
continue;
|
|
231
|
+
sql.text(", c");
|
|
232
|
+
sql.text(String(index));
|
|
233
|
+
sql.text(" as (");
|
|
234
|
+
childRestore(sql, child, parents.length > 0);
|
|
235
|
+
sql.text(")");
|
|
236
|
+
}
|
|
237
|
+
if (parents.length > 0) {
|
|
238
|
+
sql.text(" select coalesce((select parent from blocked order by parent limit 1), ''), (select count(*)::text from restored)");
|
|
239
|
+
} else {
|
|
240
|
+
sql.text(" select '', count(*)::text from restored");
|
|
241
|
+
}
|
|
242
|
+
return { text: sql.join(), params: sql.params, archiveId: "" };
|
|
243
|
+
}
|
|
244
|
+
function childUpdate(schema, sql, child, parent) {
|
|
245
|
+
const indexed = indexes(schema).get(child.table);
|
|
246
|
+
sql.text("update ");
|
|
247
|
+
sql.text(quote(child.sql));
|
|
248
|
+
sql.text(" as c set ");
|
|
249
|
+
sql.text(quote(child.at));
|
|
250
|
+
sql.text(" = now(), ");
|
|
251
|
+
sql.text(quote(child.id));
|
|
252
|
+
sql.text(" = $1::uuid from ");
|
|
253
|
+
sql.text(parent);
|
|
254
|
+
sql.text(" a where ");
|
|
255
|
+
sql.text(joinOn("c", child.local, "a", child.remote));
|
|
256
|
+
if (indexed === undefined) {
|
|
257
|
+
sql.text(" and c.");
|
|
258
|
+
sql.text(quote(child.at));
|
|
259
|
+
sql.text(" is null");
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
emitWhere(schema, indexed, undefined, sql, "c", 0, true);
|
|
263
|
+
}
|
|
264
|
+
function childRestore(sql, child, blocked) {
|
|
265
|
+
sql.text("update ");
|
|
266
|
+
sql.text(quote(child.sql));
|
|
267
|
+
sql.text(" as c set ");
|
|
268
|
+
sql.text(quote(child.at));
|
|
269
|
+
sql.text(" = null, ");
|
|
270
|
+
sql.text(quote(child.id));
|
|
271
|
+
sql.text(" = null from restored r where ");
|
|
272
|
+
sql.text(joinOn("c", child.local, "r", child.remote));
|
|
273
|
+
sql.text(" and c.");
|
|
274
|
+
sql.text(quote(child.id));
|
|
275
|
+
sql.text(' = r."archive_id" and c.');
|
|
276
|
+
sql.text(quote(child.at));
|
|
277
|
+
sql.text(" is not null");
|
|
278
|
+
if (blocked)
|
|
279
|
+
sql.text(" and not exists (select 1 from blocked)");
|
|
280
|
+
}
|
|
281
|
+
function returnedColumns(table, cascade) {
|
|
282
|
+
const names = [...primarySql(table)];
|
|
283
|
+
for (const child of cascade) {
|
|
284
|
+
for (const column of child.remote)
|
|
285
|
+
if (!names.includes(column))
|
|
286
|
+
names.push(column);
|
|
287
|
+
}
|
|
288
|
+
return names;
|
|
289
|
+
}
|
|
290
|
+
function primarySql(table) {
|
|
291
|
+
const names = [];
|
|
292
|
+
for (const field of table.model.primary) {
|
|
293
|
+
const column = table.columns.get(field);
|
|
294
|
+
if (column !== undefined)
|
|
295
|
+
names.push(column.sql);
|
|
296
|
+
}
|
|
297
|
+
return names;
|
|
298
|
+
}
|
|
299
|
+
function joinOn(left, leftColumns, right, rightColumns) {
|
|
300
|
+
const parts = [];
|
|
301
|
+
for (let index = 0;index < leftColumns.length; index += 1) {
|
|
302
|
+
const local = leftColumns[index];
|
|
303
|
+
const remote = rightColumns[index];
|
|
304
|
+
if (local === undefined || remote === undefined)
|
|
305
|
+
continue;
|
|
306
|
+
parts.push(`${left}.${quote(local)} = ${right}.${quote(remote)}`);
|
|
307
|
+
}
|
|
308
|
+
return parts.length === 0 ? "true" : parts.join(" and ");
|
|
309
|
+
}
|
|
310
|
+
function finish(op, table, result, planned) {
|
|
311
|
+
if (op === "restore") {
|
|
312
|
+
const parent = result.rows[0]?.[0];
|
|
313
|
+
if (typeof parent === "string" && parent.length > 0) {
|
|
314
|
+
throw new OkmError2("invalid", `restore on ${table} references archived ${parent}. Restore ${parent} first.`, {
|
|
315
|
+
kind: "invalid",
|
|
316
|
+
table,
|
|
317
|
+
fix: { summary: `Restore ${parent} before this row.` }
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
const count = countOf(op, result, planned);
|
|
322
|
+
if (planned.expect !== undefined && count !== planned.expect) {
|
|
323
|
+
throw new OkmError2("not_found", `${op} on ${table} changed ${String(count)} rows. expect was ${String(planned.expect)}.`, {
|
|
324
|
+
kind: "not_found",
|
|
325
|
+
table,
|
|
326
|
+
fix: { summary: "Change the filter, or pass the count this write produced." }
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
if (op === "archive")
|
|
330
|
+
return { count, archiveId: planned.archiveId ?? "" };
|
|
331
|
+
return { count };
|
|
332
|
+
}
|
|
333
|
+
function countOf(op, result, planned) {
|
|
334
|
+
if (op === "restore" && result.rows.length > 0) {
|
|
335
|
+
const cell = result.rows[0]?.[1] ?? result.rows[0]?.[0];
|
|
336
|
+
if (cell !== undefined && cell !== null && result.rows[0]?.length === 2)
|
|
337
|
+
return readCount(cell);
|
|
338
|
+
}
|
|
339
|
+
if (result.rows.length === 1 && result.rows[0]?.length === 1) {
|
|
340
|
+
const cell = result.rows[0][0];
|
|
341
|
+
if (cell !== undefined && cell !== null && planned.text.includes("count(*)"))
|
|
342
|
+
return readCount(cell);
|
|
343
|
+
}
|
|
344
|
+
return result.count;
|
|
345
|
+
}
|
|
346
|
+
function readCount(cell) {
|
|
347
|
+
const count = Number(cell);
|
|
348
|
+
return Number.isInteger(count) ? count : 0;
|
|
349
|
+
}
|
|
350
|
+
function expectOf(value) {
|
|
351
|
+
if (value === undefined)
|
|
352
|
+
return;
|
|
353
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
354
|
+
throw new OkmError2("invalid", "expect must be an integer from 0 up.", { kind: "invalid" });
|
|
355
|
+
}
|
|
356
|
+
return value;
|
|
357
|
+
}
|
|
358
|
+
function requireFilter(table, where, mods, op) {
|
|
359
|
+
if (mods.all !== undefined) {
|
|
360
|
+
if (mods.all.trim().length === 0) {
|
|
361
|
+
fail("OKM1102", `${op} on ${table.model.name} needs a where. .all needs a reason.`);
|
|
362
|
+
}
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (isOperator(where))
|
|
366
|
+
return;
|
|
367
|
+
if (isRecord(where) && Object.keys(where).length > 0)
|
|
368
|
+
return;
|
|
369
|
+
fail("OKM1102", `${op} on ${table.model.name} needs a where. Pass a filter, or .all(reason).`);
|
|
370
|
+
}
|
|
371
|
+
function callOptions(input) {
|
|
372
|
+
const signal = input.signal;
|
|
373
|
+
const timeout = input.timeout;
|
|
374
|
+
if (signal === undefined && timeout === undefined)
|
|
375
|
+
return;
|
|
376
|
+
return {
|
|
377
|
+
...signal !== undefined ? { signal } : {},
|
|
378
|
+
...typeof timeout === "number" ? { timeout } : {}
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function quoteLiteral(value) {
|
|
382
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
class Sql {
|
|
386
|
+
parts = [];
|
|
387
|
+
params = [];
|
|
388
|
+
text(value) {
|
|
389
|
+
this.parts.push(value);
|
|
390
|
+
}
|
|
391
|
+
param(encoded) {
|
|
392
|
+
this.params.push(encoded);
|
|
393
|
+
this.parts.push(`$${String(this.params.length)}`);
|
|
394
|
+
}
|
|
395
|
+
mark() {}
|
|
396
|
+
join() {
|
|
397
|
+
return this.parts.join("");
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
export {
|
|
401
|
+
executeArchive,
|
|
402
|
+
explainArchive,
|
|
403
|
+
prepareArchive
|
|
404
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
open2
|
|
3
|
+
} from "./xw1d69vd.js";
|
|
4
|
+
import"./t616ynfn.js";
|
|
5
|
+
import"./n442h54c.js";
|
|
6
|
+
import {
|
|
7
|
+
assertTargetPolicy,
|
|
8
|
+
selectTarget,
|
|
9
|
+
openProject
|
|
10
|
+
} from "./5nmdenb6.js";
|
|
11
|
+
import"./2ssqrv66.js";
|
|
12
|
+
import {
|
|
13
|
+
isExactVersion,
|
|
14
|
+
compareExtensionVersions
|
|
15
|
+
} from "./th14ygv2.js";
|
|
16
|
+
import {
|
|
17
|
+
OkmError2
|
|
18
|
+
} from "./52szzakm.js";
|
|
19
|
+
|
|
20
|
+
// src/tooling/migrate/ext.ts
|
|
21
|
+
async function extProject(cwd, command, flags) {
|
|
22
|
+
const opened = await openProject(cwd);
|
|
23
|
+
const target = selectTarget(opened.config, flags.target);
|
|
24
|
+
assertTargetPolicy(target, "check", flags.allowProtected);
|
|
25
|
+
const pool = open2({ url: target.url, max: 1 });
|
|
26
|
+
try {
|
|
27
|
+
if (command === "list")
|
|
28
|
+
return formatList(await readExtensions(pool));
|
|
29
|
+
return formatCheck(opened.built.catalog.objects, await readExtensions(pool));
|
|
30
|
+
} finally {
|
|
31
|
+
await pool.close();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
var LIST_SQL = `
|
|
35
|
+
select a.name, a.default_version, e.extversion, n.nspname
|
|
36
|
+
from pg_available_extensions a
|
|
37
|
+
left join pg_extension e on e.extname = a.name
|
|
38
|
+
left join pg_namespace n on n.oid = e.extnamespace
|
|
39
|
+
order by a.name
|
|
40
|
+
`;
|
|
41
|
+
async function readExtensions(pool) {
|
|
42
|
+
const result = await pool.execute(LIST_SQL);
|
|
43
|
+
return result.rows.map((row) => ({
|
|
44
|
+
name: cell(row[0]),
|
|
45
|
+
defaultVersion: cell(row[1]),
|
|
46
|
+
installedVersion: cell(row[2]),
|
|
47
|
+
schema: cell(row[3])
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
function cell(value) {
|
|
51
|
+
return typeof value === "string" ? value : "";
|
|
52
|
+
}
|
|
53
|
+
function formatList(rows) {
|
|
54
|
+
const lines = ["name\tdefault\tinstalled\tschema"];
|
|
55
|
+
for (const row of rows) {
|
|
56
|
+
lines.push([row.name, row.defaultVersion, row.installedVersion, row.schema].join("\t"));
|
|
57
|
+
}
|
|
58
|
+
return `${lines.join(`
|
|
59
|
+
`)}
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
function formatCheck(objects, server) {
|
|
63
|
+
const declared = objects.filter((object) => object.kind === "extension");
|
|
64
|
+
if (declared.length === 0)
|
|
65
|
+
return `no extensions
|
|
66
|
+
`;
|
|
67
|
+
const installed = new Map(server.map((row) => [row.name, row.installedVersion]));
|
|
68
|
+
const lines = ["name\tdeclared\tinstalled"];
|
|
69
|
+
for (const object of [...declared].sort((left, right) => left.identity.name < right.identity.name ? -1 : 1)) {
|
|
70
|
+
const name = object.identity.name;
|
|
71
|
+
const have = installed.get(name) ?? "";
|
|
72
|
+
if (have.length === 0) {
|
|
73
|
+
throw new OkmError2("OKM1811", `Extension ${name} is not installed on the server.`, {
|
|
74
|
+
fix: { summary: "Install the extension, or remove the declaration." }
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const want = object.definition.version;
|
|
78
|
+
if (!versionAccepted(want, have)) {
|
|
79
|
+
throw new OkmError2("OKM1812", `Extension ${name} is ${have} on the server. The schema requires ${want ?? ""}.`, { fix: { summary: "Install a version the declaration accepts, or change the pin." } });
|
|
80
|
+
}
|
|
81
|
+
lines.push([name, want ?? "-", have].join("\t"));
|
|
82
|
+
}
|
|
83
|
+
return `${lines.join(`
|
|
84
|
+
`)}
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
function versionAccepted(declared, installed) {
|
|
88
|
+
if (declared === undefined)
|
|
89
|
+
return true;
|
|
90
|
+
const floor = /^>=(\d+(?:\.\d+)*)$/.exec(declared);
|
|
91
|
+
const minimum = floor?.[1];
|
|
92
|
+
if (minimum !== undefined) {
|
|
93
|
+
return isExactVersion(installed) && compareExtensionVersions(installed, minimum) >= 0;
|
|
94
|
+
}
|
|
95
|
+
return declared === installed;
|
|
96
|
+
}
|
|
97
|
+
export {
|
|
98
|
+
extProject
|
|
99
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runWrite
|
|
3
|
+
} from "./n4jqhpqz.js";
|
|
4
|
+
import {
|
|
5
|
+
withHttp,
|
|
6
|
+
settleCall
|
|
7
|
+
} from "./k34e0xf2.js";
|
|
8
|
+
import {
|
|
9
|
+
rejectKeys,
|
|
10
|
+
isRecord,
|
|
11
|
+
fail
|
|
12
|
+
} from "./xrfnq5k8.js";
|
|
13
|
+
import {
|
|
14
|
+
OkmError2
|
|
15
|
+
} from "./52szzakm.js";
|
|
16
|
+
|
|
17
|
+
// src/runtime/batch.ts
|
|
18
|
+
async function batch(session, ops, options, replica) {
|
|
19
|
+
try {
|
|
20
|
+
if (replica !== undefined) {
|
|
21
|
+
throw new OkmError2("OKM1840", "batch() needs the primary. .replica() is not allowed on a batch.", withHttp(session.http, {
|
|
22
|
+
fix: { summary: "Remove .replica(). A batch always runs on the primary." }
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
if (!Array.isArray(ops))
|
|
26
|
+
fail("OKM1121", "batch expects a list of write operations.");
|
|
27
|
+
const record = options ?? {};
|
|
28
|
+
if (!isRecord(record))
|
|
29
|
+
fail("OKM1121", "batch options must be an object.");
|
|
30
|
+
rejectKeys(record, ["signal", "timeout"], "batch");
|
|
31
|
+
const prepared = [];
|
|
32
|
+
for (const op of ops) {
|
|
33
|
+
const plan = typeof op === "object" && op !== null ? op["~plan"] : undefined;
|
|
34
|
+
if (plan === undefined) {
|
|
35
|
+
fail("OKM1121", "batch takes write operations: insert, update, delete, and archive. Pass them without awaiting.");
|
|
36
|
+
}
|
|
37
|
+
const item = await plan();
|
|
38
|
+
if (item.checked !== undefined) {
|
|
39
|
+
fail("OKM1121", item.checked === "restore" ? "batch does not take restore: it is refused while its parent is archived, and a batch cannot report that after it commits. Use tx()." : "batch does not take a write with expect: the count is checked after the statement ran, and a batch cannot report that after it commits. Use tx().");
|
|
40
|
+
}
|
|
41
|
+
prepared.push(item);
|
|
42
|
+
}
|
|
43
|
+
return await run(session, prepared, record);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return settleCall(session, error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function run(session, prepared, options) {
|
|
49
|
+
await session.connected;
|
|
50
|
+
const statements = [];
|
|
51
|
+
const starts = [];
|
|
52
|
+
for (const item of prepared) {
|
|
53
|
+
starts.push(statements.length);
|
|
54
|
+
statements.push(...item.statements);
|
|
55
|
+
}
|
|
56
|
+
if (statements.length === 0)
|
|
57
|
+
return prepared.map((item) => item.finish([]));
|
|
58
|
+
let results;
|
|
59
|
+
try {
|
|
60
|
+
results = await runWrite(session, statements, call(options), true);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw at(error, starts);
|
|
63
|
+
}
|
|
64
|
+
return prepared.map((item, index) => {
|
|
65
|
+
const from = starts[index] ?? 0;
|
|
66
|
+
return item.finish(results.slice(from, from + item.statements.length));
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function call(options) {
|
|
70
|
+
const { signal, timeout } = options;
|
|
71
|
+
if (signal === undefined && timeout === undefined)
|
|
72
|
+
return;
|
|
73
|
+
return {
|
|
74
|
+
...signal !== undefined ? { signal } : {},
|
|
75
|
+
...typeof timeout === "number" ? { timeout } : {}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function at(error, starts) {
|
|
79
|
+
const failed = error?.batchIndex;
|
|
80
|
+
const move = error?.at;
|
|
81
|
+
if (typeof failed !== "number" || typeof move !== "function")
|
|
82
|
+
return error;
|
|
83
|
+
let index = 0;
|
|
84
|
+
while (index + 1 < starts.length && (starts[index + 1] ?? Infinity) <= failed)
|
|
85
|
+
index += 1;
|
|
86
|
+
return index === failed ? error : move.call(error, index);
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
batch
|
|
90
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
definition,
|
|
3
|
+
unavailable
|
|
4
|
+
} from "./tmbdywx0.js";
|
|
5
|
+
|
|
6
|
+
// src/dialects/pg/trait.ts
|
|
7
|
+
var TRAIT_KEYS = new Set(["fields", "name", "presets", "sealed", "touch"]);
|
|
8
|
+
function checkTrait(value, where) {
|
|
9
|
+
if (!isRecord(value))
|
|
10
|
+
definition(`${where} traits must be a list of traits.`);
|
|
11
|
+
for (const key of Object.keys(value)) {
|
|
12
|
+
if (key === "methods" || key === "requires") {
|
|
13
|
+
unavailable(`Trait option ${key} is not available yet. It arrives in 0.2.`);
|
|
14
|
+
}
|
|
15
|
+
if (!TRAIT_KEYS.has(key)) {
|
|
16
|
+
definition(`${where} trait option ${key} is not supported. Accepted options: fields, name, presets, sealed, touch.`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const name = value.name;
|
|
20
|
+
if (typeof name !== "string" || name.length === 0)
|
|
21
|
+
definition(`${where} trait needs a name.`);
|
|
22
|
+
const fields = value.fields;
|
|
23
|
+
if (!isRecord(fields))
|
|
24
|
+
definition(`Trait ${name} needs a fields object.`);
|
|
25
|
+
const known = Object.keys(fields);
|
|
26
|
+
readNames(value.touch, name, "touch", known);
|
|
27
|
+
readNames(value.sealed, name, "sealed", known);
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
function contributedFields(schemaTraits, options) {
|
|
31
|
+
const chosen = choose(options?.omitDefaults === undefined ? schemaTraits : undefined, options?.traits);
|
|
32
|
+
if (chosen === undefined)
|
|
33
|
+
return [];
|
|
34
|
+
const pairs = [];
|
|
35
|
+
const seen = new Set;
|
|
36
|
+
for (const trait of chosen) {
|
|
37
|
+
for (const field of Object.keys(trait.fields)) {
|
|
38
|
+
if (seen.has(field))
|
|
39
|
+
continue;
|
|
40
|
+
const builder = trait.fields[field];
|
|
41
|
+
if (builder === undefined)
|
|
42
|
+
continue;
|
|
43
|
+
seen.add(field);
|
|
44
|
+
pairs.push([field, builder]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return pairs;
|
|
48
|
+
}
|
|
49
|
+
function choose(schemaTraits, local) {
|
|
50
|
+
const shared = schemaTraits ?? [];
|
|
51
|
+
const own = local ?? [];
|
|
52
|
+
if (shared.length === 0 && own.length === 0)
|
|
53
|
+
return;
|
|
54
|
+
if (own.length === 0)
|
|
55
|
+
return shared;
|
|
56
|
+
if (shared.length === 0)
|
|
57
|
+
return own;
|
|
58
|
+
return [...shared, ...own];
|
|
59
|
+
}
|
|
60
|
+
function readNames(value, traitName, label, known) {
|
|
61
|
+
if (value === undefined)
|
|
62
|
+
return;
|
|
63
|
+
if (!Array.isArray(value))
|
|
64
|
+
definition(`Trait ${traitName} ${label} must be a list of field names.`);
|
|
65
|
+
for (const field of value) {
|
|
66
|
+
if (typeof field === "string" && known.includes(field))
|
|
67
|
+
continue;
|
|
68
|
+
definition(`Trait ${traitName} ${label} names ${String(field)}, which is not one of its fields. Accepted fields: ${known.join(", ")}.`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function isRecord(value) {
|
|
72
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { checkTrait, contributedFields };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OkmError2
|
|
3
|
+
} from "./52szzakm.js";
|
|
4
|
+
|
|
5
|
+
// src/runtime/validate/closed.ts
|
|
6
|
+
var VALIDATION_NOT_IMPORTED2 = "Validation is enabled but `okmodel/validate` was not imported.";
|
|
7
|
+
var VALIDATION_NOT_IMPORTED_FIX2 = 'Import "okmodel/validate" before schema().';
|
|
8
|
+
function refuseMissingValidation2() {
|
|
9
|
+
throw new OkmError2("OKM1201", VALIDATION_NOT_IMPORTED2, {
|
|
10
|
+
fix: { summary: VALIDATION_NOT_IMPORTED_FIX2 }
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { VALIDATION_NOT_IMPORTED2, VALIDATION_NOT_IMPORTED_FIX2, refuseMissingValidation2 };
|