okmodel 0.6.0 → 0.7.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 +100 -1131
- package/dist/adapters/capabilities.d.ts +3 -0
- package/dist/adapters/failure.d.ts +13 -2
- package/dist/adapters/lazy-errors.d.ts +22 -0
- package/dist/adapters/pg/bunsql-extra.d.ts +54 -3
- package/dist/adapters/pg/bunsql.d.ts +14 -1
- package/dist/adapters/pg/cursor.d.ts +17 -0
- package/dist/adapters/pg/no-inflight-timeout.d.ts +11 -8
- package/dist/adapters/pg/nodepostgres-extra.d.ts +22 -1
- package/dist/adapters/pg/nodepostgres.d.ts +12 -0
- package/dist/adapters/pg/pglite-wire.d.ts +24 -0
- package/dist/adapters/pg/pglite.d.ts +10 -0
- package/dist/adapters/pg/postgres-extra.d.ts +27 -11
- package/dist/adapters/pg/reserved.d.ts +42 -0
- package/dist/adapters/pg/session.d.ts +0 -18
- package/dist/contracts/connection.d.ts +7 -6
- package/dist/dialects/pg/floor.d.ts +68 -0
- package/dist/dialects/pg/index.d.ts +6 -1
- package/dist/dialects/pg/index.js +49 -159
- package/dist/dialects/pg/keys.d.ts +11 -8
- package/dist/dialects/pg/model.d.ts +40 -0
- package/dist/dialects/pg/morph.d.ts +43 -0
- package/dist/dialects/pg/operator-fit.d.ts +2 -2
- package/dist/dialects/pg/operators.d.ts +14 -7
- package/dist/dialects/pg/ops/bucket.d.ts +65 -0
- package/dist/dialects/pg/ops/inc.d.ts +2 -2
- package/dist/dialects/pg/ops/matches.d.ts +9 -12
- package/dist/dialects/pg/ops/relevance.d.ts +13 -0
- package/dist/dialects/pg/ops/search-query.d.ts +22 -0
- package/dist/dialects/pg/ops/window.d.ts +103 -0
- package/dist/dialects/pg/preset.d.ts +1 -1
- package/dist/dialects/pg/relations.d.ts +100 -3
- package/dist/dialects/pg/schema.d.ts +31 -3
- package/dist/dialects/pg/view/index.js +1 -1
- package/dist/runtime/aggregate.d.ts +8 -2
- package/dist/runtime/bucket-group.d.ts +70 -0
- package/dist/runtime/conflict.d.ts +22 -4
- package/dist/runtime/include.d.ts +0 -8
- package/dist/runtime/inflight.d.ts +1 -1
- package/dist/runtime/page.d.ts +4 -1
- package/dist/runtime/pg/bun.js +12 -6
- package/dist/runtime/pg/pg.js +5 -5
- package/dist/runtime/pg/pglite.d.ts +1 -0
- package/dist/runtime/pg/pglite.js +9 -9
- package/dist/runtime/pg/postgresjs.js +5 -5
- package/dist/runtime/plan.d.ts +95 -5
- package/dist/runtime/read-stream.d.ts +13 -16
- package/dist/runtime/result-name.d.ts +17 -0
- package/dist/runtime/server-check.d.ts +3 -3
- package/dist/runtime/sort-bind.d.ts +21 -0
- package/dist/runtime/sort.d.ts +56 -0
- package/dist/runtime/sync.d.ts +70 -0
- package/dist/runtime/tenancy/index.js +7 -5
- package/dist/runtime/text-search.d.ts +20 -0
- package/dist/runtime/traits/index.d.ts +80 -0
- package/dist/runtime/traits/index.js +175 -11
- package/dist/runtime/tree.d.ts +38 -0
- package/dist/runtime/types.d.ts +218 -22
- package/dist/runtime/validate/index.js +2 -2
- package/dist/runtime/version.d.ts +39 -0
- package/dist/runtime/window.d.ts +21 -0
- package/dist/runtime/write.d.ts +54 -2
- package/dist/shared/{wkme6tep.js → 14vx95q4.js} +8 -16
- package/dist/shared/1est4ezg.js +313 -0
- package/dist/shared/{4az561fn.js → 1qa0qajz.js} +8 -23
- package/dist/shared/{2cg3wnxc.js → 1w508jbr.js} +593 -130
- package/dist/shared/2c13q96h.js +18 -0
- package/dist/shared/{b4v57v3x.js → 2d3xq4ps.js} +2 -2
- package/dist/shared/{1nw1f3vs.js → 2shdbn8q.js} +7 -7
- package/dist/shared/3v7t1yrv.js +208 -0
- package/dist/shared/{x3jc53kg.js → 5e3tf63j.js} +2 -2
- package/dist/shared/5fe3kbsh.js +10 -0
- package/dist/shared/5v3xf80k.js +37 -0
- package/dist/shared/{c58secgj.js → 63qtkrca.js} +38 -4
- package/dist/shared/{2z7wv5tj.js → 67txcrcw.js} +55 -34
- package/dist/shared/79dt02vc.js +12 -0
- package/dist/shared/{8x72s86k.js → 7k9grvf6.js} +10 -4
- package/dist/shared/7kms6fvj.js +20 -0
- package/dist/shared/7mnme5tn.js +8 -0
- package/dist/shared/7n7ddwt4.js +6 -0
- package/dist/shared/{5j36z8dn.js → 81ebdx9p.js} +39 -70
- package/dist/shared/{knmes2kh.js → 8skf0cam.js} +1 -1
- package/dist/shared/9a4ae4p8.js +31 -0
- package/dist/shared/9y3mmmh1.js +436 -0
- package/dist/shared/ab9gmbwy.js +213 -0
- package/dist/shared/{f0f1n281.js → ax7qv55k.js} +2 -2
- package/dist/shared/{g90m9b0g.js → aytqh5y2.js} +6 -5
- package/dist/shared/{vjpnzwjz.js → b5pftnn2.js} +1 -1
- package/dist/shared/{ag4c7516.js → b76b8d95.js} +2 -2
- package/dist/shared/{vmfkhszw.js → bg3rym3g.js} +33 -26
- package/dist/shared/{mb2ycs1p.js → bm22fvzr.js} +15 -15
- package/dist/shared/{q3j1tq7a.js → bz84tkzm.js} +148 -23
- package/dist/shared/{31vm914h.js → cm3w0ywp.js} +15 -16
- package/dist/shared/cn957f8d.js +179 -0
- package/dist/shared/{gwn6v667.js → cnkky55j.js} +25 -14
- package/dist/shared/{ys0xzyaj.js → dkxgzaqd.js} +224 -19
- package/dist/shared/dzj09cye.js +10 -0
- package/dist/shared/exn3sd90.js +359 -0
- package/dist/shared/g6evj1j3.js +66 -0
- package/dist/shared/ga9j92qj.js +25 -0
- package/dist/shared/{t3g0k88x.js → gs74dbj5.js} +16 -12
- package/dist/shared/gzaveazc.js +285 -0
- package/dist/shared/{2jd1sn0e.js → hyh73qk6.js} +1 -1
- package/dist/shared/{r1fdd0f6.js → je4axnm8.js} +5 -2
- package/dist/shared/{1f0xa3cb.js → jvd0mqag.js} +3 -3
- package/dist/shared/jznfax0y.js +155 -0
- package/dist/shared/{cgbamx3e.js → kb2sdhfb.js} +7 -4
- package/dist/shared/{wt5rzv1h.js → kr0jzbw2.js} +5 -5
- package/dist/shared/{p6bjzq9q.js → ktz42yez.js} +12 -4
- package/dist/shared/{p248q79y.js → m6p12kbr.js} +2 -2
- package/dist/shared/{r6nwkxnt.js → m7n9h2a5.js} +4 -4
- package/dist/shared/{672t5vym.js → mss6ctgv.js} +2 -2
- package/dist/shared/{929h19xp.js → mtaszv5a.js} +40 -10
- package/dist/shared/{b3awxn7h.js → n816peh1.js} +1 -1
- package/dist/shared/nbw1z4yd.js +18 -0
- package/dist/shared/{nx9hh281.js → p6qc5gcp.js} +12 -11
- package/dist/shared/{pjr6xrm5.js → pbp1ss85.js} +20 -17
- package/dist/shared/pt94kz7f.js +6 -0
- package/dist/shared/q5c6ngn3.js +13 -0
- package/dist/shared/{xq0mvhts.js → rs73fca9.js} +4 -4
- package/dist/shared/{r11n8grd.js → sfz1ksn6.js} +7 -4
- package/dist/shared/{wynzeggs.js → svncdeh5.js} +6 -6
- package/dist/shared/{j60w0dvr.js → tbrvgw6z.js} +57 -38
- package/dist/shared/te5as7z7.js +622 -0
- package/dist/shared/{ttmg09vd.js → tsvww22q.js} +1 -1
- package/dist/shared/{y2t3jktd.js → ttsqgp4p.js} +19 -12
- package/dist/shared/{x72jb7ad.js → v8g1vgv8.js} +1 -1
- package/dist/shared/{sbdme3vy.js → vb6qfyve.js} +60 -10
- package/dist/shared/{5d8t84hg.js → vczs8gd4.js} +14 -14
- package/dist/shared/{5yv4k6a6.js → vqrjpcqn.js} +144 -2
- package/dist/shared/{3fqwmr09.js → w72kgg4q.js} +4 -4
- package/dist/shared/{1z04fa85.js → w79hsckn.js} +12 -57
- package/dist/shared/{09p049xa.js → wa07eas9.js} +42 -14
- package/dist/shared/{32cnm7kn.js → x933k9a3.js} +74 -38
- package/dist/shared/{n076ydsc.js → xhfsfkgk.js} +62 -28
- package/dist/shared/xjk7hnn5.js +272 -0
- package/dist/shared/{hazqqecq.js → xnxsed62.js} +50 -21
- package/dist/shared/y6njgyda.js +249 -0
- package/dist/shared/{8etn7d8w.js → z7s6fpxv.js} +1 -1
- package/dist/shared/{n7mcc1gk.js → zchaghkf.js} +4 -3
- package/dist/shared/zm0ptry0.js +40 -0
- package/dist/shared/{nsva2a6b.js → znm0bpp5.js} +3 -0
- package/dist/shared/zp9fmend.js +145 -0
- package/dist/tooling/cli.js +11 -11
- package/dist/tooling/migrate/engine.d.ts +3 -2
- package/dist/tooling/migrate/index.js +7 -7
- package/dist/tooling/testing/index.js +1 -1
- package/package.json +4 -2
- package/dist/shared/3qnhc7w5.js +0 -38
- package/dist/shared/7m88x3e9.js +0 -45
- package/dist/shared/8dqhth8c.js +0 -12
- package/dist/shared/d5azex6s.js +0 -6
- package/dist/shared/j3rkk835.js +0 -99
- package/dist/shared/k68eedmy.js +0 -85
- package/dist/shared/venqrjna.js +0 -216
- package/dist/shared/wxr8cwns.js +0 -6
- package/dist/shared/zm0mafk4.js +0 -92
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
UUIDV7_POSTGRES,
|
|
3
|
+
isPostgresMajor,
|
|
4
|
+
parsePostgresFloor,
|
|
5
|
+
formatPostgresFloor,
|
|
6
|
+
minPostgresDefinition,
|
|
7
|
+
uuidv7NeedsPostgres
|
|
8
|
+
} from "./ga9j92qj.js";
|
|
1
9
|
import {
|
|
2
10
|
catalog,
|
|
3
11
|
enumType,
|
|
@@ -5,7 +13,7 @@ import {
|
|
|
5
13
|
} from "./ywspezzx.js";
|
|
6
14
|
import {
|
|
7
15
|
isRelationCall
|
|
8
|
-
} from "./
|
|
16
|
+
} from "./exn3sd90.js";
|
|
9
17
|
import {
|
|
10
18
|
encodeText,
|
|
11
19
|
decodeText
|
|
@@ -149,6 +157,7 @@ var SCHEMA_KNOWN = new Set([
|
|
|
149
157
|
"defaults",
|
|
150
158
|
"extensions",
|
|
151
159
|
"functions",
|
|
160
|
+
"minPostgres",
|
|
152
161
|
"requires",
|
|
153
162
|
"tables",
|
|
154
163
|
"tenancy",
|
|
@@ -178,7 +187,7 @@ function schema2(config) {
|
|
|
178
187
|
const hooks = collectHooks(tenancy, schemaTraits, config.tables, config.views);
|
|
179
188
|
const types = readTypes(config.types);
|
|
180
189
|
const codecs = readCodecs(config.codecs);
|
|
181
|
-
const requires =
|
|
190
|
+
const requires = readFloor(config.minPostgres, config.requires);
|
|
182
191
|
const idDefault = readIdDefault(config.defaults);
|
|
183
192
|
const namespace = staticNamespace2("public");
|
|
184
193
|
const accepted = acceptTables(config.tables);
|
|
@@ -203,8 +212,9 @@ function schema2(config) {
|
|
|
203
212
|
compileForeignKeys(item, byName, accepted, jobs, edges);
|
|
204
213
|
}
|
|
205
214
|
const model = {};
|
|
215
|
+
const scopeFields = tenancy === undefined ? undefined : tenancy.keys !== undefined ? tenancy.keys : [tenancy.key];
|
|
206
216
|
for (const item of prepared) {
|
|
207
|
-
model[item.tsName] = tableModel(item, edges, byName, accepted);
|
|
217
|
+
model[item.tsName] = tableModel(item, edges, byName, accepted, scopeFields);
|
|
208
218
|
}
|
|
209
219
|
bindViews(config.views, model, tenancy, tables, casing);
|
|
210
220
|
let document;
|
|
@@ -502,7 +512,7 @@ function compileTable(item, namespace, casing, codecs, requires, idDefault, jobs
|
|
|
502
512
|
columnPrimary.push(prepared.sqlName);
|
|
503
513
|
}
|
|
504
514
|
if (column.state.defaultSql === "uuidv7()") {
|
|
505
|
-
refuseUuidV7(
|
|
515
|
+
refuseUuidV7(requires);
|
|
506
516
|
}
|
|
507
517
|
const labels = column.state.enumLabels;
|
|
508
518
|
if (labels !== undefined) {
|
|
@@ -858,7 +868,7 @@ function readCodecs(codecs) {
|
|
|
858
868
|
}
|
|
859
869
|
return { bigint, numeric, timestamps };
|
|
860
870
|
}
|
|
861
|
-
function tableModel(item, edges, byName, accepted) {
|
|
871
|
+
function tableModel(item, edges, byName, accepted, scopeFields) {
|
|
862
872
|
const primary = [];
|
|
863
873
|
for (const sqlName of item.primary) {
|
|
864
874
|
const column = item.bySql.get(sqlName);
|
|
@@ -891,7 +901,7 @@ function tableModel(item, edges, byName, accepted) {
|
|
|
891
901
|
primary,
|
|
892
902
|
uniques: item.uniques,
|
|
893
903
|
columns,
|
|
894
|
-
relations: resolveRelations(item, edges, byName, accepted),
|
|
904
|
+
relations: resolveRelations(item, edges, byName, accepted, scopeFields),
|
|
895
905
|
...conceal ? { conceal: true } : {},
|
|
896
906
|
...item.traits !== undefined ? { traits: item.traits } : {},
|
|
897
907
|
...item.provenance.source !== undefined ? { source: item.provenance.source } : {},
|
|
@@ -899,10 +909,11 @@ function tableModel(item, edges, byName, accepted) {
|
|
|
899
909
|
...item.presets !== undefined ? { presets: item.presets } : {}
|
|
900
910
|
};
|
|
901
911
|
}
|
|
902
|
-
function resolveRelations(item, edges, byName, accepted) {
|
|
912
|
+
function resolveRelations(item, edges, byName, accepted, scopeFields) {
|
|
903
913
|
const raw = item.relationOptions;
|
|
904
914
|
if (raw === undefined)
|
|
905
915
|
return [];
|
|
916
|
+
const describe = (table) => byName.get(table);
|
|
906
917
|
const record = raw;
|
|
907
918
|
const names = Object.keys(record);
|
|
908
919
|
const resolved = [];
|
|
@@ -913,11 +924,18 @@ function resolveRelations(item, edges, byName, accepted) {
|
|
|
913
924
|
seen.add(name);
|
|
914
925
|
const call = record[name];
|
|
915
926
|
if (!isRelationCall(call)) {
|
|
916
|
-
unavailable(`Table ${item.tsName} relation ${name} is not
|
|
927
|
+
unavailable(`Table ${item.tsName} relation ${name} is not a relation. one(), many(), manyThrough(), morph(), and morphMany() are accepted.`);
|
|
917
928
|
}
|
|
918
929
|
const own = call.resolve;
|
|
919
930
|
if (own !== undefined) {
|
|
920
|
-
resolved.push(own({
|
|
931
|
+
resolved.push(own({
|
|
932
|
+
owner: item.tsName,
|
|
933
|
+
name,
|
|
934
|
+
edges,
|
|
935
|
+
tables: accepted,
|
|
936
|
+
describe,
|
|
937
|
+
...scopeFields === undefined ? {} : { scopeFields }
|
|
938
|
+
}));
|
|
921
939
|
continue;
|
|
922
940
|
}
|
|
923
941
|
if (!byName.has(call.table)) {
|
|
@@ -1002,21 +1020,32 @@ function readIdDefault(defaults) {
|
|
|
1002
1020
|
return { kind: "client", fill };
|
|
1003
1021
|
definition('schema() defaults.id must be "uuidv7", "uuidv4", or a client generator.');
|
|
1004
1022
|
}
|
|
1005
|
-
function refuseUuidV7(
|
|
1006
|
-
const declared =
|
|
1007
|
-
if (!(declared > 0) || declared >=
|
|
1023
|
+
function refuseUuidV7(requires) {
|
|
1024
|
+
const declared = parsePostgresFloor(requires?.postgres);
|
|
1025
|
+
if (!(declared > 0) || declared >= UUIDV7_POSTGRES)
|
|
1008
1026
|
return;
|
|
1009
|
-
|
|
1027
|
+
const sentence = uuidv7NeedsPostgres();
|
|
1028
|
+
throw new OkmError2("OKM1812", sentence, { fix: { summary: sentence } });
|
|
1010
1029
|
}
|
|
1011
|
-
function
|
|
1012
|
-
if (requires
|
|
1013
|
-
|
|
1014
|
-
}
|
|
1015
|
-
const postgres = requires.postgres;
|
|
1016
|
-
if (postgres !== undefined && postgres.length === 0) {
|
|
1017
|
-
definition("schema() requires.postgres must be a version range such as >=17.");
|
|
1030
|
+
function readFloor(minPostgres, requires) {
|
|
1031
|
+
if (minPostgres !== undefined && requires !== undefined) {
|
|
1032
|
+
definition("minPostgres or requires.postgres, not both.");
|
|
1018
1033
|
}
|
|
1019
|
-
|
|
1034
|
+
if (minPostgres === undefined && requires === undefined)
|
|
1035
|
+
return;
|
|
1036
|
+
let major = minPostgres;
|
|
1037
|
+
if (minPostgres === undefined) {
|
|
1038
|
+
if (typeof requires !== "object" || requires === null || Array.isArray(requires)) {
|
|
1039
|
+
definition(minPostgresDefinition());
|
|
1040
|
+
}
|
|
1041
|
+
const postgres = requires.postgres;
|
|
1042
|
+
if (postgres === undefined)
|
|
1043
|
+
return {};
|
|
1044
|
+
major = typeof postgres === "string" ? parsePostgresFloor(postgres) : NaN;
|
|
1045
|
+
}
|
|
1046
|
+
if (!isPostgresMajor(major))
|
|
1047
|
+
definition(minPostgresDefinition());
|
|
1048
|
+
return { postgres: formatPostgresFloor(major) };
|
|
1020
1049
|
}
|
|
1021
1050
|
function readIndex(tableName, call) {
|
|
1022
1051
|
if (call.columns.length === 0) {
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import {
|
|
2
|
+
stack2
|
|
3
|
+
} from "./mss6ctgv.js";
|
|
4
|
+
import {
|
|
5
|
+
updateSliceBody2,
|
|
6
|
+
rejectDuplicateTargets2,
|
|
7
|
+
emitSet2,
|
|
8
|
+
Sql2,
|
|
9
|
+
writeSet2,
|
|
10
|
+
rejectMixedSets2,
|
|
11
|
+
readClaim2,
|
|
12
|
+
rejectUpdateKeys2,
|
|
13
|
+
requireFilter2,
|
|
14
|
+
returningOption2,
|
|
15
|
+
expectOf2,
|
|
16
|
+
allowSet2,
|
|
17
|
+
noteGuarded2
|
|
18
|
+
} from "./1w508jbr.js";
|
|
19
|
+
import {
|
|
20
|
+
emitWhere,
|
|
21
|
+
projectExpr,
|
|
22
|
+
quote,
|
|
23
|
+
isRecord,
|
|
24
|
+
fail2
|
|
25
|
+
} from "./67txcrcw.js";
|
|
26
|
+
|
|
27
|
+
// src/runtime/version.ts
|
|
28
|
+
function planVersioned(schema, table, input, options, mods) {
|
|
29
|
+
if (mods.all !== undefined) {
|
|
30
|
+
fail2("OKM1120", `update on ${table.model.name} cannot use .all() with versioned().`, "Pass a per-row list with the version you read for each row.");
|
|
31
|
+
}
|
|
32
|
+
const allow = allowSet2(table, options.allow);
|
|
33
|
+
noteGuarded2(table, allow, "update");
|
|
34
|
+
const column = versionColumn(table);
|
|
35
|
+
const returning = returningOption2(table, options.returning);
|
|
36
|
+
const expect = expectOf2(options, mods);
|
|
37
|
+
if (Array.isArray(input) && input.length === 0) {
|
|
38
|
+
return {
|
|
39
|
+
statements: [],
|
|
40
|
+
outputs: outputsOf(undefined),
|
|
41
|
+
shape: "count",
|
|
42
|
+
expect,
|
|
43
|
+
versioned: { fields: [], sent: [] }
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const rows = readRows(schema, table, input, allow, mods, column);
|
|
47
|
+
const fields = writtenFields(rows);
|
|
48
|
+
const sent = rows.map((row) => row.version);
|
|
49
|
+
const claim = Array.isArray(input) ? undefined : isRecord(input) ? readClaim2(input) : undefined;
|
|
50
|
+
const statement = claim !== undefined ? claimStatement(schema, table, rows[0], claim, column, returning) : targetStatement(schema, table, rows, column, returning);
|
|
51
|
+
const width = statement.params?.length ?? 0;
|
|
52
|
+
if (width > 30000) {
|
|
53
|
+
fail2("OKM1120", `update on ${table.model.name} is too large to check version in one statement.`, "Split the list.");
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
statements: [statement],
|
|
57
|
+
outputs: outputsOf(returning),
|
|
58
|
+
shape: returning === undefined ? "count" : "rows",
|
|
59
|
+
expect,
|
|
60
|
+
versioned: { fields, sent }
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function versionColumn(table) {
|
|
64
|
+
const column = table.columns.get("version");
|
|
65
|
+
if (column === undefined) {
|
|
66
|
+
fail2("OKM1120", `Table ${table.model.name} is versioned and has no version column.`);
|
|
67
|
+
}
|
|
68
|
+
return column;
|
|
69
|
+
}
|
|
70
|
+
function readRows(schema, table, input, allow, mods, column) {
|
|
71
|
+
if (Array.isArray(input)) {
|
|
72
|
+
if (input.length === 0)
|
|
73
|
+
fail2("OKM1120", "update set is empty.");
|
|
74
|
+
const rows = input.map((item) => readRow(schema, table, item, allow, mods, column, true));
|
|
75
|
+
rejectDuplicateTargets2(table, rows);
|
|
76
|
+
rejectMixedSets2(rows);
|
|
77
|
+
return rows;
|
|
78
|
+
}
|
|
79
|
+
return [readRow(schema, table, input, allow, mods, column, false)];
|
|
80
|
+
}
|
|
81
|
+
function readRow(schema, table, input, allow, mods, column, row) {
|
|
82
|
+
if (!isRecord(input))
|
|
83
|
+
fail2("OKM1121", "update expects { where, set, version } or a list of rows.");
|
|
84
|
+
rejectUpdateKeys2(input, row);
|
|
85
|
+
if (!Object.hasOwn(input, "version")) {
|
|
86
|
+
fail2("OKM1120", `update on ${table.model.name} needs the version you read.`, "Pass version from the row you read. If this write conflicts, reread and retry.");
|
|
87
|
+
}
|
|
88
|
+
const version = readVersion(input.version, table.model.name, column);
|
|
89
|
+
const set = writeSet2(table, input.set, allow, schema.tenancy);
|
|
90
|
+
if (Object.keys(set).length === 0)
|
|
91
|
+
fail2("OKM1120", "update set is empty.");
|
|
92
|
+
refusePath(schema, table, set);
|
|
93
|
+
const where = input.where !== undefined ? input.where : input.id !== undefined ? { id: input.id } : undefined;
|
|
94
|
+
requireFilter2(table, where, mods, "update");
|
|
95
|
+
return { where: stack2(where, mods.presets), set, version };
|
|
96
|
+
}
|
|
97
|
+
function readVersion(value, table, column) {
|
|
98
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value)) {
|
|
99
|
+
fail2("OKM1121", `version on ${table} must be an integer.`, "Pass the version you read.");
|
|
100
|
+
}
|
|
101
|
+
column.encode(value);
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
function refusePath(schema, table, set) {
|
|
105
|
+
if (schema.tenancy?.isPath?.(table.model.name) !== true)
|
|
106
|
+
return;
|
|
107
|
+
const field = schema.tenancy.pathOf?.(table.model.name)?.[0]?.localField;
|
|
108
|
+
if (field === undefined || !Object.hasOwn(set, field))
|
|
109
|
+
return;
|
|
110
|
+
fail2("OKM1120", `update on ${table.model.name} cannot change ${field} and check version in one write.`, "Point it at a parent in a later update.");
|
|
111
|
+
}
|
|
112
|
+
function writtenFields(rows) {
|
|
113
|
+
const names = [];
|
|
114
|
+
for (const row of rows) {
|
|
115
|
+
for (const key of Object.keys(row.set))
|
|
116
|
+
if (!names.includes(key))
|
|
117
|
+
names.push(key);
|
|
118
|
+
}
|
|
119
|
+
return names;
|
|
120
|
+
}
|
|
121
|
+
function targetStatement(schema, table, rows, column, returning) {
|
|
122
|
+
const sql = new Sql2;
|
|
123
|
+
sql.text("with ");
|
|
124
|
+
for (let index = 0;index < rows.length; index += 1) {
|
|
125
|
+
const row = rows[index];
|
|
126
|
+
if (row === undefined)
|
|
127
|
+
continue;
|
|
128
|
+
if (index > 0)
|
|
129
|
+
sql.text(", ");
|
|
130
|
+
sql.text("m");
|
|
131
|
+
sql.text(String(index));
|
|
132
|
+
sql.text(" as (select s.ctid as tid, s.tableoid as toid, s.");
|
|
133
|
+
sql.text(quote(column.sql));
|
|
134
|
+
sql.text(" as okm_version from ");
|
|
135
|
+
sql.text(quote(table.model.sql));
|
|
136
|
+
sql.text(" as s");
|
|
137
|
+
emitWhere(schema, table, row.where, sql.sink(), "s", 0);
|
|
138
|
+
sql.text(" for update of s)");
|
|
139
|
+
}
|
|
140
|
+
sql.text(", gate as (select count(*)::int as n from (");
|
|
141
|
+
for (let index = 0;index < rows.length; index += 1) {
|
|
142
|
+
const row = rows[index];
|
|
143
|
+
if (row === undefined)
|
|
144
|
+
continue;
|
|
145
|
+
if (index > 0)
|
|
146
|
+
sql.text(" union all ");
|
|
147
|
+
sql.text("select 1 from m");
|
|
148
|
+
sql.text(String(index));
|
|
149
|
+
sql.text(" where okm_version is distinct from ");
|
|
150
|
+
sql.param(column.encode(row.version), column.dataType);
|
|
151
|
+
}
|
|
152
|
+
sql.text(") as okm_diff), updated as (");
|
|
153
|
+
updateSliceBody2(schema, table, rows, sql, true, {
|
|
154
|
+
afterWhere(body, index) {
|
|
155
|
+
const row = rows[index];
|
|
156
|
+
if (row === undefined)
|
|
157
|
+
return;
|
|
158
|
+
body.text(" and t.");
|
|
159
|
+
body.text(quote(column.sql));
|
|
160
|
+
body.text(" = ");
|
|
161
|
+
body.param(column.encode(row.version), column.dataType);
|
|
162
|
+
},
|
|
163
|
+
afterSet(body) {
|
|
164
|
+
bump(body, column);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
sql.text(" and (select n from gate) = 0");
|
|
168
|
+
closeUpdated(sql, returning, "gate");
|
|
169
|
+
return sql.statement();
|
|
170
|
+
}
|
|
171
|
+
function claimStatement(schema, table, row, limit, column, returning) {
|
|
172
|
+
if (row === undefined)
|
|
173
|
+
fail2("OKM1120", "update set is empty.");
|
|
174
|
+
const sql = new Sql2;
|
|
175
|
+
sql.text("with claimed as (select s.tableoid as toid, s.ctid as tid from ");
|
|
176
|
+
sql.text(quote(table.model.sql));
|
|
177
|
+
sql.text(" as s");
|
|
178
|
+
emitWhere(schema, table, row.where, sql.sink(), "s", 0);
|
|
179
|
+
sql.text(" and s.");
|
|
180
|
+
sql.text(quote(column.sql));
|
|
181
|
+
sql.text(" = ");
|
|
182
|
+
sql.param(column.encode(row.version), column.dataType);
|
|
183
|
+
sql.text(" for update of s skip locked limit ");
|
|
184
|
+
sql.param(String(limit), "integer");
|
|
185
|
+
sql.text("), stale_free as (select 1 as hit from ");
|
|
186
|
+
sql.text(quote(table.model.sql));
|
|
187
|
+
sql.text(" as s");
|
|
188
|
+
emitWhere(schema, table, row.where, sql.sink(), "s", 0);
|
|
189
|
+
sql.text(" and s.");
|
|
190
|
+
sql.text(quote(column.sql));
|
|
191
|
+
sql.text(" is distinct from ");
|
|
192
|
+
sql.param(column.encode(row.version), column.dataType);
|
|
193
|
+
sql.text(" for update of s skip locked limit 1), updated as (update ");
|
|
194
|
+
sql.text(quote(table.model.sql));
|
|
195
|
+
sql.text(" as t set ");
|
|
196
|
+
emitSet2(sql, table, row.set, "t");
|
|
197
|
+
bump(sql, column);
|
|
198
|
+
sql.text(" where (t.tableoid, t.ctid) in (select toid, tid from claimed)");
|
|
199
|
+
closeUpdated(sql, returning, "claim");
|
|
200
|
+
return sql.statement();
|
|
201
|
+
}
|
|
202
|
+
function bump(sql, column) {
|
|
203
|
+
sql.text(", ");
|
|
204
|
+
sql.text(quote(column.sql));
|
|
205
|
+
sql.text(" = t.");
|
|
206
|
+
sql.text(quote(column.sql));
|
|
207
|
+
sql.text(" + 1");
|
|
208
|
+
}
|
|
209
|
+
function closeUpdated(sql, returning, source) {
|
|
210
|
+
const stale = source === "gate" ? "(select n from gate)" : "(case when (select count(*) from updated) > 0 then 0 else (select count(*)::int from stale_free) end)";
|
|
211
|
+
if (returning === undefined || returning.length === 0) {
|
|
212
|
+
sql.text(" returning 1) select ");
|
|
213
|
+
sql.text(stale);
|
|
214
|
+
sql.text(", (select count(*)::int from updated)");
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
sql.text(" returning t.ctid as okm_tid");
|
|
218
|
+
for (let index = 0;index < returning.length; index += 1) {
|
|
219
|
+
const column = returning[index];
|
|
220
|
+
if (column === undefined)
|
|
221
|
+
continue;
|
|
222
|
+
sql.text(", ");
|
|
223
|
+
sql.text(projectExpr(`t.${quote(column.sql)}`, column.dataType));
|
|
224
|
+
sql.text(" as okm_");
|
|
225
|
+
sql.text(String(index));
|
|
226
|
+
}
|
|
227
|
+
sql.text(") select ");
|
|
228
|
+
sql.text(stale);
|
|
229
|
+
sql.text(", case when u.okm_tid is null then 0 else 1 end");
|
|
230
|
+
for (let index = 0;index < returning.length; index += 1) {
|
|
231
|
+
sql.text(", u.okm_");
|
|
232
|
+
sql.text(String(index));
|
|
233
|
+
}
|
|
234
|
+
sql.text(" from (select 1) as okm_one left join updated u on true");
|
|
235
|
+
}
|
|
236
|
+
function outputsOf(columns) {
|
|
237
|
+
const list = columns ?? [];
|
|
238
|
+
return {
|
|
239
|
+
fields: list.map((column, index) => ({
|
|
240
|
+
key: column.field,
|
|
241
|
+
at: index + 2,
|
|
242
|
+
decode: column.decode
|
|
243
|
+
})),
|
|
244
|
+
includes: []
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
export {
|
|
248
|
+
planVersioned
|
|
249
|
+
};
|
|
@@ -39,7 +39,7 @@ async function refreshView(session, name, concurrently) {
|
|
|
39
39
|
throw error;
|
|
40
40
|
}
|
|
41
41
|
} catch (error) {
|
|
42
|
-
const { mapPostgresError } = await import("./
|
|
42
|
+
const { mapPostgresError } = await import("./63qtkrca.js");
|
|
43
43
|
const mapped = mapPostgresError(error, {
|
|
44
44
|
...host.http !== undefined ? { http: host.http } : {},
|
|
45
45
|
...host.includeValues === true ? { includeValues: true } : {},
|
|
@@ -18,6 +18,7 @@ var FAMILIES = {
|
|
|
18
18
|
hasAnyKey: ["jsonb"],
|
|
19
19
|
path: ["json", "jsonb"],
|
|
20
20
|
matches: ["tsvector"],
|
|
21
|
+
relevance: ["tsvector"],
|
|
21
22
|
"json.set": ["json", "jsonb"],
|
|
22
23
|
"arr.append": ["array"],
|
|
23
24
|
"arr.remove": ["array"]
|
|
@@ -53,7 +54,7 @@ var ACCEPTED = {
|
|
|
53
54
|
jsonb: ["eq", "not", "contains", "containedBy", "hasKey", "hasAnyKey", "path", "json.set"],
|
|
54
55
|
json: ["eq", "not", "path", "json.set"],
|
|
55
56
|
range: ["eq", "not", "lt", "lte", "gt", "gte", "contains", "containedBy", "overlaps"],
|
|
56
|
-
tsvector: ["eq", "not", "matches"],
|
|
57
|
+
tsvector: ["eq", "not", "matches", "relevance"],
|
|
57
58
|
scalar: ["eq", "not", "lt", "lte", "gt", "gte", "between", "inList", "notIn", "inc"]
|
|
58
59
|
};
|
|
59
60
|
var SAFE_TYPE = /^[A-Za-z_][A-Za-z0-9_]*(\(\d+\))?(\[\])*$/;
|
|
@@ -81,7 +82,7 @@ function assertOperatorFits(column, name) {
|
|
|
81
82
|
if (families.includes(columnFamily(column.dataType)))
|
|
82
83
|
return;
|
|
83
84
|
const accepted = ACCEPTED[columnFamily(column.dataType)];
|
|
84
|
-
const search = name === "matches" && columnFamily(column.dataType) === "text" ? "
|
|
85
|
+
const search = (name === "matches" || name === "relevance") && columnFamily(column.dataType) === "text" ? " Search needs a column built for search, not a plain text column." : "";
|
|
85
86
|
throw new OkmError2("OKM1124", `Operator ${name} does not apply to ${column.dataType} column ${column.field}. Accepted operators: ${accepted.join(", ")}.${search}`, { fix: { summary: `Use one of: ${accepted.join(", ")}.` } });
|
|
86
87
|
}
|
|
87
88
|
function sqlType(dataType, column) {
|
|
@@ -110,7 +111,7 @@ function assertBoundText(value, role) {
|
|
|
110
111
|
}
|
|
111
112
|
function assertRegconfig(config) {
|
|
112
113
|
if (!REGCONFIG.test(config)) {
|
|
113
|
-
throw new OkmError2("OKM1122", `
|
|
114
|
+
throw new OkmError2("OKM1122", `Language ${config} is not a text search language. Pass a name such as english.`, { fix: { summary: "Pass a language name such as english." } });
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
117
|
function textArray(values, role) {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isConnectionLost
|
|
3
|
+
} from "./cnkky55j.js";
|
|
4
|
+
import {
|
|
5
|
+
rejectClosed
|
|
6
|
+
} from "./kb2sdhfb.js";
|
|
7
|
+
|
|
8
|
+
// src/adapters/pg/reserved.ts
|
|
9
|
+
var RESET_ALL = "RESET ALL";
|
|
10
|
+
var UNLOCK = "SELECT pg_advisory_unlock_all()";
|
|
11
|
+
async function resetSession2(depth, run) {
|
|
12
|
+
if (depth > 0)
|
|
13
|
+
await run("ROLLBACK").catch(() => {
|
|
14
|
+
return;
|
|
15
|
+
});
|
|
16
|
+
try {
|
|
17
|
+
await run(RESET_ALL);
|
|
18
|
+
await run(UNLOCK);
|
|
19
|
+
} catch {
|
|
20
|
+
await run("ROLLBACK").catch(() => {
|
|
21
|
+
return;
|
|
22
|
+
});
|
|
23
|
+
await run(RESET_ALL);
|
|
24
|
+
await run(UNLOCK);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function resetQueried2(session) {
|
|
28
|
+
await resetSession2(session.inTransaction() ? 1 : 0, (text) => text === "ROLLBACK" ? session.rollback() : session.query(text, undefined, undefined));
|
|
29
|
+
}
|
|
30
|
+
function refuseWhenLost2(lost, run) {
|
|
31
|
+
if (lost.on)
|
|
32
|
+
return rejectClosed();
|
|
33
|
+
return run().catch((error) => {
|
|
34
|
+
if (isConnectionLost(error))
|
|
35
|
+
lost.on = true;
|
|
36
|
+
throw error;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { resetSession2, resetQueried2, refuseWhenLost2 };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DriverError2
|
|
3
|
+
} from "./cm3w0ywp.js";
|
|
4
|
+
import {
|
|
5
|
+
armDriverError,
|
|
6
|
+
send,
|
|
7
|
+
connectClient
|
|
8
|
+
} from "./w79hsckn.js";
|
|
9
|
+
import {
|
|
10
|
+
resetSession2
|
|
11
|
+
} from "./zm0ptry0.js";
|
|
12
|
+
import {
|
|
13
|
+
cursorStream
|
|
14
|
+
} from "./7kms6fvj.js";
|
|
15
|
+
import {
|
|
16
|
+
isConnectionLost
|
|
17
|
+
} from "./cnkky55j.js";
|
|
18
|
+
import {
|
|
19
|
+
WireSession
|
|
20
|
+
} from "./1qa0qajz.js";
|
|
21
|
+
import {
|
|
22
|
+
rejectClosed,
|
|
23
|
+
runCall
|
|
24
|
+
} from "./kb2sdhfb.js";
|
|
25
|
+
|
|
26
|
+
// src/adapters/pg/nodepostgres-extra.ts
|
|
27
|
+
async function checkout(held) {
|
|
28
|
+
const { pool, counters, named, isClosed } = held;
|
|
29
|
+
if (isClosed())
|
|
30
|
+
return rejectClosed();
|
|
31
|
+
const client = await connectClient(pool, held.acquireMs, counters);
|
|
32
|
+
counters.reserved += 1;
|
|
33
|
+
let lost = false;
|
|
34
|
+
const onError = () => {
|
|
35
|
+
lost = true;
|
|
36
|
+
};
|
|
37
|
+
const events = client;
|
|
38
|
+
events.on("error", onError);
|
|
39
|
+
const local = new Set;
|
|
40
|
+
const session = new WireSession((text, params) => {
|
|
41
|
+
const pending = send(client, text, params, named, client);
|
|
42
|
+
const guarded = pending.catch((error) => {
|
|
43
|
+
if (isConnectionLost(error) || lost) {
|
|
44
|
+
lost = true;
|
|
45
|
+
if (isConnectionLost(error))
|
|
46
|
+
throw error;
|
|
47
|
+
throw Object.assign(new DriverError2("CONNECTION_CLOSED", { cause: error }), {
|
|
48
|
+
code: "CONNECTION_CLOSED"
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
throw error;
|
|
52
|
+
});
|
|
53
|
+
guarded.cancel = () => {
|
|
54
|
+
pending.cancel?.();
|
|
55
|
+
};
|
|
56
|
+
return guarded;
|
|
57
|
+
}, held.notices, isClosed, true, () => {
|
|
58
|
+
counters.reservedBusy += 1;
|
|
59
|
+
}, () => {
|
|
60
|
+
counters.reservedBusy = Math.max(0, counters.reservedBusy - 1);
|
|
61
|
+
}, local);
|
|
62
|
+
const guard = (run) => lost ? rejectClosed() : run();
|
|
63
|
+
let released = false;
|
|
64
|
+
return {
|
|
65
|
+
execute: (text, params, options) => guard(() => runCall(isClosed(), options, (watch) => session.query(text, params, watch))),
|
|
66
|
+
batch: (statements, options) => guard(() => runCall(isClosed(), options, async (watch) => {
|
|
67
|
+
const { runAtomicBatch } = await import("./b76b8d95.js");
|
|
68
|
+
return runAtomicBatch(session, statements, watch);
|
|
69
|
+
})),
|
|
70
|
+
cancel() {
|
|
71
|
+
session.cancel();
|
|
72
|
+
},
|
|
73
|
+
async release() {
|
|
74
|
+
if (released)
|
|
75
|
+
return;
|
|
76
|
+
released = true;
|
|
77
|
+
try {
|
|
78
|
+
if (!lost)
|
|
79
|
+
await reset(session, client);
|
|
80
|
+
} finally {
|
|
81
|
+
counters.reserved = Math.max(0, counters.reserved - 1);
|
|
82
|
+
events.removeListener("error", onError);
|
|
83
|
+
client.release(lost);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async function reset(session, client) {
|
|
89
|
+
await resetSession2(session.depth(), (text) => client.query(text));
|
|
90
|
+
}
|
|
91
|
+
async function listen(held, channel, onNotify) {
|
|
92
|
+
const { pool, counters } = held;
|
|
93
|
+
const client = await connectClient(pool, held.acquireMs, counters);
|
|
94
|
+
counters.reserved += 1;
|
|
95
|
+
const quoted = quoteIdent(channel);
|
|
96
|
+
const onNotification = (message) => {
|
|
97
|
+
if (message.channel === channel)
|
|
98
|
+
onNotify(message.payload ?? "");
|
|
99
|
+
};
|
|
100
|
+
client.on("notification", onNotification);
|
|
101
|
+
let released = false;
|
|
102
|
+
const release = (dead) => {
|
|
103
|
+
if (released)
|
|
104
|
+
return;
|
|
105
|
+
released = true;
|
|
106
|
+
client.removeListener("notification", onNotification);
|
|
107
|
+
client.removeListener("error", release);
|
|
108
|
+
counters.reserved = Math.max(0, counters.reserved - 1);
|
|
109
|
+
client.release(Boolean(dead));
|
|
110
|
+
};
|
|
111
|
+
armDriverError(client, release);
|
|
112
|
+
try {
|
|
113
|
+
await client.query(`LISTEN ${quoted}`);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
release(false);
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
return async () => {
|
|
119
|
+
if (released)
|
|
120
|
+
return;
|
|
121
|
+
try {
|
|
122
|
+
await client.query(`UNLISTEN ${quoted}`);
|
|
123
|
+
} finally {
|
|
124
|
+
release(false);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function streamRows(checkout, text, params) {
|
|
129
|
+
return async function* () {
|
|
130
|
+
const connection = await checkout();
|
|
131
|
+
try {
|
|
132
|
+
yield* cursorStream((statement, values) => connection.execute(statement, values), text, params);
|
|
133
|
+
} finally {
|
|
134
|
+
await connection.release();
|
|
135
|
+
}
|
|
136
|
+
}();
|
|
137
|
+
}
|
|
138
|
+
function quoteIdent(name) {
|
|
139
|
+
return `"${name.replaceAll('"', '""')}"`;
|
|
140
|
+
}
|
|
141
|
+
export {
|
|
142
|
+
checkout,
|
|
143
|
+
listen,
|
|
144
|
+
streamRows
|
|
145
|
+
};
|