okmodel 0.0.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +246 -1
- package/dist/adapters/capabilities.d.ts +62 -0
- package/dist/adapters/error.d.ts +91 -0
- package/dist/adapters/failure.d.ts +39 -0
- package/dist/adapters/pg/batch.d.ts +36 -0
- package/dist/adapters/pg/call.d.ts +59 -0
- package/dist/adapters/pg/pglite.d.ts +21 -0
- package/dist/adapters/pg/postgres-extra.d.ts +43 -0
- package/dist/adapters/pg/postgresjs.d.ts +95 -0
- package/dist/adapters/pg/result.d.ts +30 -0
- package/dist/contracts/catalog/build.d.ts +18 -0
- package/dist/contracts/catalog/document.d.ts +79 -0
- package/dist/contracts/catalog/enum.d.ts +35 -0
- package/dist/contracts/catalog/identifier.d.ts +71 -0
- package/dist/contracts/catalog/identity.d.ts +98 -0
- package/dist/contracts/catalog/index.d.ts +11 -0
- package/dist/contracts/catalog/json.d.ts +17 -0
- package/dist/contracts/catalog/object.d.ts +142 -0
- package/dist/contracts/catalog/order.d.ts +43 -0
- package/dist/contracts/catalog/rewrite.d.ts +18 -0
- package/dist/contracts/catalog/types.d.ts +292 -0
- package/dist/contracts/catalog/words.d.ts +13 -0
- package/dist/contracts/connection.d.ts +33 -0
- package/dist/contracts/driver.d.ts +163 -0
- package/dist/contracts/error.d.ts +298 -0
- package/dist/contracts/index.d.ts +11 -0
- package/dist/contracts/index.js +16 -0
- package/dist/contracts/internal.d.ts +15 -0
- package/dist/contracts/internal.js +68 -0
- package/dist/contracts/nearest.d.ts +15 -0
- package/dist/contracts/rows.d.ts +84 -0
- package/dist/contracts/sha256.d.ts +14 -0
- package/dist/contracts/utf8.d.ts +33 -0
- package/dist/dialects/pg/array-literal.d.ts +25 -0
- package/dist/dialects/pg/bool.d.ts +46 -0
- package/dist/dialects/pg/column.d.ts +386 -0
- package/dist/dialects/pg/compile.d.ts +81 -0
- package/dist/dialects/pg/custom.d.ts +21 -0
- package/dist/dialects/pg/ddl.d.ts +70 -0
- package/dist/dialects/pg/decimal.d.ts +62 -0
- package/dist/dialects/pg/declarations.d.ts +34 -0
- package/dist/dialects/pg/emit.d.ts +18 -0
- package/dist/dialects/pg/enum.d.ts +30 -0
- package/dist/dialects/pg/errors.d.ts +30 -0
- package/dist/dialects/pg/finite.d.ts +15 -0
- package/dist/dialects/pg/geometry.d.ts +55 -0
- package/dist/dialects/pg/index.d.ts +45 -0
- package/dist/dialects/pg/index.js +1821 -0
- package/dist/dialects/pg/integer.d.ts +96 -0
- package/dist/dialects/pg/introspect.d.ts +43 -0
- package/dist/dialects/pg/json.d.ts +43 -0
- package/dist/dialects/pg/keys.d.ts +32 -0
- package/dist/dialects/pg/misuse.d.ts +31 -0
- package/dist/dialects/pg/model.d.ts +71 -0
- package/dist/dialects/pg/namespace.d.ts +63 -0
- package/dist/dialects/pg/network.d.ts +28 -0
- package/dist/dialects/pg/operators.d.ts +71 -0
- package/dist/dialects/pg/ops/between.d.ts +10 -0
- package/dist/dialects/pg/ops/contains.d.ts +8 -0
- package/dist/dialects/pg/ops/endsWith.d.ts +8 -0
- package/dist/dialects/pg/ops/eq.d.ts +9 -0
- package/dist/dialects/pg/ops/every.d.ts +9 -0
- package/dist/dialects/pg/ops/gt.d.ts +9 -0
- package/dist/dialects/pg/ops/gte.d.ts +9 -0
- package/dist/dialects/pg/ops/has.d.ts +9 -0
- package/dist/dialects/pg/ops/ilike.d.ts +8 -0
- package/dist/dialects/pg/ops/inList.d.ts +9 -0
- package/dist/dialects/pg/ops/inc.d.ts +13 -0
- package/dist/dialects/pg/ops/like.d.ts +8 -0
- package/dist/dialects/pg/ops/lt.d.ts +9 -0
- package/dist/dialects/pg/ops/lte.d.ts +9 -0
- package/dist/dialects/pg/ops/none.d.ts +9 -0
- package/dist/dialects/pg/ops/not.d.ts +9 -0
- package/dist/dialects/pg/ops/notIn.d.ts +9 -0
- package/dist/dialects/pg/ops/or.d.ts +9 -0
- package/dist/dialects/pg/ops/startsWith.d.ts +8 -0
- package/dist/dialects/pg/quote.d.ts +24 -0
- package/dist/dialects/pg/range.d.ts +50 -0
- package/dist/dialects/pg/relations.d.ts +45 -0
- package/dist/dialects/pg/schema.d.ts +77 -0
- package/dist/dialects/pg/search.d.ts +23 -0
- package/dist/dialects/pg/table.d.ts +201 -0
- package/dist/dialects/pg/temporal.d.ts +211 -0
- package/dist/dialects/pg/text.d.ts +44 -0
- package/dist/dialects/pg/time.d.ts +46 -0
- package/dist/okm.js +2 -0
- package/dist/okmodel.js +2 -0
- package/dist/runtime/client.d.ts +47 -0
- package/dist/runtime/conflict.d.ts +38 -0
- package/dist/runtime/drift-detail.d.ts +32 -0
- package/dist/runtime/drift.d.ts +29 -0
- package/dist/runtime/include.d.ts +15 -0
- package/dist/runtime/pg/pglite.d.ts +25 -0
- package/dist/runtime/pg/pglite.js +48 -0
- package/dist/runtime/pg/postgresjs.d.ts +29 -0
- package/dist/runtime/pg/postgresjs.js +62 -0
- package/dist/runtime/plan.d.ts +167 -0
- package/dist/runtime/tx.d.ts +29 -0
- package/dist/runtime/types.d.ts +385 -0
- package/dist/runtime/write.d.ts +48 -0
- package/dist/shared/05w44d8g.js +1524 -0
- package/dist/shared/523ft3e8.js +171 -0
- package/dist/shared/8b04d28c.js +14 -0
- package/dist/shared/cn0n68ft.js +16 -0
- package/dist/shared/dkn3y60a.js +374 -0
- package/dist/shared/dynq16vb.js +81 -0
- package/dist/shared/fgqgsb5z.js +281 -0
- package/dist/shared/g5fhqmwe.js +188 -0
- package/dist/shared/gk7cs7sp.js +566 -0
- package/dist/shared/hadrfb9h.js +398 -0
- package/dist/shared/hd293j9g.js +98 -0
- package/dist/shared/j5cn2963.js +701 -0
- package/dist/shared/jjb7yht9.js +37 -0
- package/dist/shared/kprcwaha.js +30 -0
- package/dist/shared/m3ypagh5.js +347 -0
- package/dist/shared/mkjmqjv4.js +456 -0
- package/dist/shared/mtkwv8wx.js +18 -0
- package/dist/shared/ngk8gj61.js +40 -0
- package/dist/shared/p0cbr3g2.js +79 -0
- package/dist/shared/qk3hxfja.js +83 -0
- package/dist/shared/rgs0st28.js +1066 -0
- package/dist/shared/w8samvk1.js +18 -0
- package/dist/shared/x5x59srr.js +566 -0
- package/dist/shared/xqbhg6cn.js +119 -0
- package/dist/shared/xy79j5hq.js +177 -0
- package/dist/shared/y9m15dfv.js +888 -0
- package/dist/shared/ycwz42az.js +412 -0
- package/dist/shared/yd1kzwn2.js +148 -0
- package/dist/shared/zhc5vmgf.js +257 -0
- package/dist/tooling/cli.d.ts +1 -0
- package/dist/tooling/cli.js +193 -0
- package/dist/tooling/errors/registry.d.ts +33 -0
- package/dist/tooling/migrate/apply.d.ts +86 -0
- package/dist/tooling/migrate/commands.d.ts +21 -0
- package/dist/tooling/migrate/config.d.ts +48 -0
- package/dist/tooling/migrate/dev.d.ts +16 -0
- package/dist/tooling/migrate/equal.d.ts +15 -0
- package/dist/tooling/migrate/files.d.ts +19 -0
- package/dist/tooling/migrate/index.d.ts +7 -0
- package/dist/tooling/migrate/index.js +7 -0
- package/dist/tooling/migrate/plan.d.ts +76 -0
- package/dist/tooling/migrate/policy.d.ts +78 -0
- package/dist/tooling/migrate/project.d.ts +69 -0
- package/dist/tooling/migrate/status.d.ts +74 -0
- package/dist/tooling/migrate/values.d.ts +29 -0
- package/package.json +109 -7
- package/dist/index.js +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
creationOrder2,
|
|
3
|
+
renameColumn2,
|
|
4
|
+
renameTable2,
|
|
5
|
+
serializeCatalog2,
|
|
6
|
+
catalogHash2,
|
|
7
|
+
loadTrustedCatalog2,
|
|
8
|
+
parseCatalog2
|
|
9
|
+
} from "./y9m15dfv.js";
|
|
10
|
+
export {
|
|
11
|
+
catalogHash2 as catalogHash,
|
|
12
|
+
creationOrder2 as creationOrder,
|
|
13
|
+
loadTrustedCatalog2 as loadTrustedCatalog,
|
|
14
|
+
parseCatalog2 as parseCatalog,
|
|
15
|
+
renameColumn2 as renameColumn,
|
|
16
|
+
renameTable2 as renameTable,
|
|
17
|
+
serializeCatalog2 as serializeCatalog
|
|
18
|
+
};
|
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
import {
|
|
2
|
+
emitWhere,
|
|
3
|
+
selectedColumns,
|
|
4
|
+
rejectKeys,
|
|
5
|
+
projectExpr,
|
|
6
|
+
decodeRow,
|
|
7
|
+
indexes,
|
|
8
|
+
quote,
|
|
9
|
+
isRecord,
|
|
10
|
+
fail
|
|
11
|
+
} from "./rgs0st28.js";
|
|
12
|
+
import {
|
|
13
|
+
isOperator,
|
|
14
|
+
operatorName,
|
|
15
|
+
operatorValue
|
|
16
|
+
} from "./cn0n68ft.js";
|
|
17
|
+
import {
|
|
18
|
+
OkmError2,
|
|
19
|
+
throwNamed2
|
|
20
|
+
} from "./ycwz42az.js";
|
|
21
|
+
|
|
22
|
+
// src/runtime/tx.ts
|
|
23
|
+
async function runWrite(pool, statements, options) {
|
|
24
|
+
if (statements.length === 0)
|
|
25
|
+
return [];
|
|
26
|
+
const first = statements[0];
|
|
27
|
+
if (statements.length === 1 && first !== undefined) {
|
|
28
|
+
return [await pool.execute(first.text, first.params, options)];
|
|
29
|
+
}
|
|
30
|
+
return pool.batch(statements, options);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/runtime/write.ts
|
|
34
|
+
var WRITE_PARAM_BUDGET = 2048;
|
|
35
|
+
var INSERT_OPTIONS = ["expect", "onConflict", "returning", "signal", "timeout"];
|
|
36
|
+
var FILTER_OPTIONS = ["expect", "returning", "signal", "timeout"];
|
|
37
|
+
async function executeWrite(host, op, table, input, options, mods) {
|
|
38
|
+
const planned = await planWrite(host.schema, op, table, input, options, mods);
|
|
39
|
+
if (planned.statements.length === 0)
|
|
40
|
+
return finish([], planned, table);
|
|
41
|
+
const results = await runWrite(host.pool, planned.statements, callOptions(options));
|
|
42
|
+
return finish(results, planned, table);
|
|
43
|
+
}
|
|
44
|
+
async function explainWrite(schema, op, table, input, options, mods) {
|
|
45
|
+
const planned = await planWrite(schema, op, table, input, options, mods);
|
|
46
|
+
return { statements: planned.statements };
|
|
47
|
+
}
|
|
48
|
+
async function planWrite(schema, op, tableName, input, options, mods) {
|
|
49
|
+
const table = indexes(schema).get(tableName);
|
|
50
|
+
if (table === undefined) {
|
|
51
|
+
fail("OKM1120", `Table ${tableName} is not in the schema.`);
|
|
52
|
+
}
|
|
53
|
+
const record = isRecord(options) ? options : {};
|
|
54
|
+
rejectKeys(record, op === "insert" ? INSERT_OPTIONS : FILTER_OPTIONS, op);
|
|
55
|
+
if (op === "insert")
|
|
56
|
+
return planInsert(table, input, record, mods);
|
|
57
|
+
if (op === "update")
|
|
58
|
+
return planUpdate(schema, table, input, record, mods);
|
|
59
|
+
return planDelete(schema, table, input, record, mods);
|
|
60
|
+
}
|
|
61
|
+
async function planInsert(table, input, options, mods) {
|
|
62
|
+
const many = Array.isArray(input);
|
|
63
|
+
const rows = (many ? input : [input]).map((row) => insertRow(table, row));
|
|
64
|
+
const columns = writtenColumns(table, rows);
|
|
65
|
+
const returning = selectedColumns(table, options.returning);
|
|
66
|
+
const outputs = outputsOf(returning);
|
|
67
|
+
const clause = returningClause(returning, undefined);
|
|
68
|
+
const expect = expectOf(options, mods);
|
|
69
|
+
const shape = many ? "rows" : "row";
|
|
70
|
+
if (columns.length === 0) {
|
|
71
|
+
const text = `insert into ${quote(table.model.sql)} default values${clause}`;
|
|
72
|
+
return {
|
|
73
|
+
statements: rows.map(() => ({ text })),
|
|
74
|
+
outputs,
|
|
75
|
+
shape,
|
|
76
|
+
expect,
|
|
77
|
+
keys: undefined,
|
|
78
|
+
keyFields: undefined
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const conflictMod = options.onConflict === undefined || options.onConflict === "error" ? undefined : await import("./yd1kzwn2.js");
|
|
82
|
+
const conflict = conflictMod?.readConflict(table, options.onConflict);
|
|
83
|
+
const chunks = chunkRows(rows.map((row) => cellsFor(table, columns, row)));
|
|
84
|
+
const statements = [];
|
|
85
|
+
const keys = [];
|
|
86
|
+
let offset = 0;
|
|
87
|
+
for (const chunk of chunks) {
|
|
88
|
+
const slice = rows.slice(offset, offset + chunk.length);
|
|
89
|
+
offset += chunk.length;
|
|
90
|
+
const built = insertHead(table, columns, chunk);
|
|
91
|
+
if (conflict === undefined || conflictMod === undefined) {
|
|
92
|
+
statements.push(withParams(`${built.text}${clause}`, built.params));
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const keyRows = conflict.kind === "return" ? slice.map((row) => keyWire(conflict.columns, row)) : [];
|
|
96
|
+
for (const row of keyRows)
|
|
97
|
+
keys.push([...row]);
|
|
98
|
+
statements.push(conflictMod.finishInsert(built.text, clause, built.params ?? [], conflict, table, returning, keyRows));
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
statements,
|
|
102
|
+
outputs,
|
|
103
|
+
shape,
|
|
104
|
+
expect,
|
|
105
|
+
keys: conflict?.kind === "return" ? keys : undefined,
|
|
106
|
+
keyFields: conflict?.kind === "return" ? conflict.columns.map((column) => column.field) : undefined
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function planUpdate(schema, table, input, options, mods) {
|
|
110
|
+
const returning = returningOption(table, options.returning);
|
|
111
|
+
const outputs = outputsOf(returning);
|
|
112
|
+
const expect = expectOf(options, mods);
|
|
113
|
+
if (Array.isArray(input)) {
|
|
114
|
+
const rows = input.map((item) => updateItem(table, item));
|
|
115
|
+
return {
|
|
116
|
+
statements: updateList(schema, table, rows, returning),
|
|
117
|
+
outputs,
|
|
118
|
+
shape: returning === undefined ? "count" : "rows",
|
|
119
|
+
expect,
|
|
120
|
+
keys: undefined,
|
|
121
|
+
keyFields: undefined
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (!isRecord(input))
|
|
125
|
+
fail("OKM1121", "update expects { where, set } or a list of rows.");
|
|
126
|
+
const set = writeSet(table, input.set);
|
|
127
|
+
requireFilter(table, input.where, mods, "update");
|
|
128
|
+
if (Object.keys(set).length === 0)
|
|
129
|
+
fail("OKM1120", "update set is empty.");
|
|
130
|
+
const sql = new Sql;
|
|
131
|
+
sql.text("update ");
|
|
132
|
+
sql.text(quote(table.model.sql));
|
|
133
|
+
sql.text(" as t set ");
|
|
134
|
+
emitSet(sql, table, set, "t");
|
|
135
|
+
emitFilter(schema, table, input.where, sql, "t");
|
|
136
|
+
sql.text(returningClause(returning, "t"));
|
|
137
|
+
return {
|
|
138
|
+
statements: [sql.statement()],
|
|
139
|
+
outputs,
|
|
140
|
+
shape: returning === undefined ? "count" : "rows",
|
|
141
|
+
expect,
|
|
142
|
+
keys: undefined,
|
|
143
|
+
keyFields: undefined
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function planDelete(schema, table, input, options, mods) {
|
|
147
|
+
if (!isRecord(input))
|
|
148
|
+
fail("OKM1121", "delete expects { where }.");
|
|
149
|
+
rejectKeys(input, ["where"], "delete");
|
|
150
|
+
requireFilter(table, input.where, mods, "delete");
|
|
151
|
+
const returning = returningOption(table, options.returning);
|
|
152
|
+
const sql = new Sql;
|
|
153
|
+
sql.text("delete from ");
|
|
154
|
+
sql.text(quote(table.model.sql));
|
|
155
|
+
sql.text(" as t");
|
|
156
|
+
emitFilter(schema, table, input.where, sql, "t");
|
|
157
|
+
sql.text(returningClause(returning, "t"));
|
|
158
|
+
return {
|
|
159
|
+
statements: [sql.statement()],
|
|
160
|
+
outputs: outputsOf(returning),
|
|
161
|
+
shape: returning === undefined ? "count" : "rows",
|
|
162
|
+
expect: expectOf(options, mods),
|
|
163
|
+
keys: undefined,
|
|
164
|
+
keyFields: undefined
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function finish(results, planned, table) {
|
|
168
|
+
if (planned.shape === "count") {
|
|
169
|
+
let count = 0;
|
|
170
|
+
for (const result of results)
|
|
171
|
+
count += result.count;
|
|
172
|
+
checkExpect(count, planned.expect, table, "write");
|
|
173
|
+
return { count };
|
|
174
|
+
}
|
|
175
|
+
const decoded = [];
|
|
176
|
+
for (const result of results) {
|
|
177
|
+
for (const row of result.rows)
|
|
178
|
+
decoded.push(decodeRow(planned.outputs, row));
|
|
179
|
+
}
|
|
180
|
+
const rows = planned.keys === undefined || planned.keyFields === undefined ? decoded : orderByKeys(decoded, planned.keyFields, planned.keys);
|
|
181
|
+
checkExpect(rows.length, planned.expect, table, "insert");
|
|
182
|
+
if (planned.shape === "row")
|
|
183
|
+
return rows[0] ?? null;
|
|
184
|
+
return rows;
|
|
185
|
+
}
|
|
186
|
+
function orderByKeys(rows, fields, keys) {
|
|
187
|
+
const found = new Map;
|
|
188
|
+
for (const row of rows)
|
|
189
|
+
found.set(fields.map((field) => wireKey(row[field])).join("\x00"), row);
|
|
190
|
+
const ordered = [];
|
|
191
|
+
for (const key of keys) {
|
|
192
|
+
const row = found.get(key.map((value) => value ?? "").join("\x00"));
|
|
193
|
+
if (row !== undefined)
|
|
194
|
+
ordered.push(row);
|
|
195
|
+
}
|
|
196
|
+
return ordered;
|
|
197
|
+
}
|
|
198
|
+
function wireKey(value) {
|
|
199
|
+
if (typeof value === "string")
|
|
200
|
+
return value;
|
|
201
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
202
|
+
return String(value);
|
|
203
|
+
}
|
|
204
|
+
return "";
|
|
205
|
+
}
|
|
206
|
+
function insertHead(table, columns, rows) {
|
|
207
|
+
const params = [];
|
|
208
|
+
const lists = [];
|
|
209
|
+
for (const row of rows) {
|
|
210
|
+
const slots = [];
|
|
211
|
+
for (const cell of row) {
|
|
212
|
+
if (cell.kind === "default") {
|
|
213
|
+
slots.push("default");
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
params.push(cell.kind === "null" ? null : cell.wire);
|
|
217
|
+
slots.push(`$${String(params.length)}::${cell.dataType}`);
|
|
218
|
+
}
|
|
219
|
+
lists.push(`(${slots.join(", ")})`);
|
|
220
|
+
}
|
|
221
|
+
const names = columns.map((column) => quote(column.sql)).join(", ");
|
|
222
|
+
return {
|
|
223
|
+
text: `insert into ${quote(table.model.sql)} (${names}) values ${lists.join(", ")}`,
|
|
224
|
+
params
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function updateList(schema, table, rows, returning) {
|
|
228
|
+
if (rows.length === 0)
|
|
229
|
+
return [];
|
|
230
|
+
const width = Math.max(1, Object.keys(rows[0]?.set ?? {}).length + 2);
|
|
231
|
+
const size = Math.max(1, Math.floor(WRITE_PARAM_BUDGET / (width * 2)));
|
|
232
|
+
const statements = [];
|
|
233
|
+
for (let index = 0;index < rows.length; index += size) {
|
|
234
|
+
statements.push(updateSlice(schema, table, rows.slice(index, index + size), returning));
|
|
235
|
+
}
|
|
236
|
+
return statements;
|
|
237
|
+
}
|
|
238
|
+
function updateSlice(schema, table, rows, returning) {
|
|
239
|
+
const fields = [];
|
|
240
|
+
const seen = new Set;
|
|
241
|
+
for (const row of rows) {
|
|
242
|
+
for (const key of Object.keys(row.set)) {
|
|
243
|
+
if (seen.has(key))
|
|
244
|
+
continue;
|
|
245
|
+
seen.add(key);
|
|
246
|
+
const column = table.columns.get(key);
|
|
247
|
+
if (column !== undefined)
|
|
248
|
+
fields.push(column);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (fields.length === 0)
|
|
252
|
+
fail("OKM1120", "update set is empty.");
|
|
253
|
+
const sql = new Sql;
|
|
254
|
+
sql.text("update ");
|
|
255
|
+
sql.text(quote(table.model.sql));
|
|
256
|
+
sql.text(" as t set ");
|
|
257
|
+
for (let field = 0;field < fields.length; field += 1) {
|
|
258
|
+
const column = fields[field];
|
|
259
|
+
if (column === undefined)
|
|
260
|
+
continue;
|
|
261
|
+
if (field > 0)
|
|
262
|
+
sql.text(", ");
|
|
263
|
+
sql.text(quote(column.sql));
|
|
264
|
+
sql.text(" = case");
|
|
265
|
+
for (const row of rows) {
|
|
266
|
+
sql.text(" when ");
|
|
267
|
+
emitBare(schema, table, row.where, sql, "t");
|
|
268
|
+
sql.text(" then ");
|
|
269
|
+
const value = row.set[column.field];
|
|
270
|
+
if (value === undefined)
|
|
271
|
+
sql.text(`t.${quote(column.sql)}`);
|
|
272
|
+
else
|
|
273
|
+
emitValue(sql, column, value, "t");
|
|
274
|
+
}
|
|
275
|
+
sql.text(" else t.");
|
|
276
|
+
sql.text(quote(column.sql));
|
|
277
|
+
sql.text(" end");
|
|
278
|
+
}
|
|
279
|
+
sql.text(" where ");
|
|
280
|
+
for (let index = 0;index < rows.length; index += 1) {
|
|
281
|
+
const row = rows[index];
|
|
282
|
+
if (row === undefined)
|
|
283
|
+
continue;
|
|
284
|
+
if (index > 0)
|
|
285
|
+
sql.text(" or ");
|
|
286
|
+
sql.text("(");
|
|
287
|
+
emitBare(schema, table, row.where, sql, "t");
|
|
288
|
+
sql.text(")");
|
|
289
|
+
}
|
|
290
|
+
sql.text(returningClause(returning, "t"));
|
|
291
|
+
return sql.statement();
|
|
292
|
+
}
|
|
293
|
+
function emitSet(sql, table, set, alias) {
|
|
294
|
+
const keys = Object.keys(set);
|
|
295
|
+
for (let index = 0;index < keys.length; index += 1) {
|
|
296
|
+
const key = keys[index];
|
|
297
|
+
if (key === undefined)
|
|
298
|
+
continue;
|
|
299
|
+
const column = table.columns.get(key);
|
|
300
|
+
if (column === undefined)
|
|
301
|
+
continue;
|
|
302
|
+
if (index > 0)
|
|
303
|
+
sql.text(", ");
|
|
304
|
+
sql.text(quote(column.sql));
|
|
305
|
+
sql.text(" = ");
|
|
306
|
+
emitValue(sql, column, set[key], alias);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function emitValue(sql, column, value, alias) {
|
|
310
|
+
if (isOperator(value)) {
|
|
311
|
+
if (operatorName(value) !== "inc") {
|
|
312
|
+
fail("OKM1121", `Field ${column.field} received an operator. set accepts a value or inc.`);
|
|
313
|
+
}
|
|
314
|
+
const amount = operatorValue(value);
|
|
315
|
+
if (typeof amount === "object" && amount !== null) {
|
|
316
|
+
fail("OKM1121", `inc on ${column.field} needs a value.`);
|
|
317
|
+
}
|
|
318
|
+
sql.text(`${alias}.${quote(column.sql)} + `);
|
|
319
|
+
sql.param(column.encode(amount), column.dataType);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (value === null) {
|
|
323
|
+
sql.text(`null::${column.dataType}`);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (typeof value === "object") {
|
|
327
|
+
fail("OKM1121", `Field ${column.field} received an object. Pass a value or inc.`);
|
|
328
|
+
}
|
|
329
|
+
sql.param(column.encode(value), column.dataType);
|
|
330
|
+
}
|
|
331
|
+
function emitFilter(schema, table, where, sql, alias) {
|
|
332
|
+
emitWhere(schema, table, where, sql.sink(), alias, 0);
|
|
333
|
+
}
|
|
334
|
+
function emitBare(schema, table, where, sql, alias) {
|
|
335
|
+
let dropped = false;
|
|
336
|
+
const sink = {
|
|
337
|
+
text(value) {
|
|
338
|
+
if (!dropped) {
|
|
339
|
+
dropped = true;
|
|
340
|
+
if (value === " where " || value === " and ")
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
sql.text(value);
|
|
344
|
+
},
|
|
345
|
+
param(encoded) {
|
|
346
|
+
sql.param(encoded, "");
|
|
347
|
+
},
|
|
348
|
+
mark() {}
|
|
349
|
+
};
|
|
350
|
+
emitWhere(schema, table, where, sink, alias, 0);
|
|
351
|
+
if (!dropped) {
|
|
352
|
+
fail("OKM1102", `update on ${table.model.name} needs a where for each row.`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
class Sql {
|
|
357
|
+
parts = [];
|
|
358
|
+
params = [];
|
|
359
|
+
text(value) {
|
|
360
|
+
this.parts.push(value);
|
|
361
|
+
}
|
|
362
|
+
param(wire, dataType) {
|
|
363
|
+
this.params.push(wire);
|
|
364
|
+
const slot = `$${String(this.params.length)}`;
|
|
365
|
+
this.parts.push(dataType.length === 0 ? slot : `${slot}::${dataType}`);
|
|
366
|
+
}
|
|
367
|
+
sink() {
|
|
368
|
+
return {
|
|
369
|
+
text: (value) => {
|
|
370
|
+
this.text(value);
|
|
371
|
+
},
|
|
372
|
+
param: (encoded) => {
|
|
373
|
+
this.param(encoded, "");
|
|
374
|
+
},
|
|
375
|
+
mark() {}
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
statement() {
|
|
379
|
+
return this.params.length === 0 ? { text: this.parts.join("") } : { text: this.parts.join(""), params: this.params };
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
function insertRow(table, value) {
|
|
383
|
+
if (!isRecord(value))
|
|
384
|
+
fail("OKM1121", "insert expects an object or a list of objects.");
|
|
385
|
+
const row = {};
|
|
386
|
+
for (const key of Object.keys(value)) {
|
|
387
|
+
const column = table.columns.get(key);
|
|
388
|
+
if (column === undefined)
|
|
389
|
+
continue;
|
|
390
|
+
if (!column.writable)
|
|
391
|
+
refuse(table.model.name, column);
|
|
392
|
+
if (value[key] !== undefined)
|
|
393
|
+
row[key] = value[key];
|
|
394
|
+
}
|
|
395
|
+
return row;
|
|
396
|
+
}
|
|
397
|
+
function cellsFor(table, columns, row) {
|
|
398
|
+
return columns.map((column) => {
|
|
399
|
+
if (!Object.hasOwn(row, column.field))
|
|
400
|
+
return { kind: "default" };
|
|
401
|
+
const value = row[column.field];
|
|
402
|
+
if (value === null)
|
|
403
|
+
return { kind: "null", dataType: column.dataType };
|
|
404
|
+
if (typeof value === "object") {
|
|
405
|
+
fail("OKM1121", `Field ${table.model.name}.${column.field} received an object.`);
|
|
406
|
+
}
|
|
407
|
+
return { kind: "value", wire: column.encode(value), dataType: column.dataType };
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
function writtenColumns(table, rows) {
|
|
411
|
+
const present = new Set;
|
|
412
|
+
for (const row of rows) {
|
|
413
|
+
for (const key of Object.keys(row))
|
|
414
|
+
present.add(key);
|
|
415
|
+
}
|
|
416
|
+
const columns = [];
|
|
417
|
+
for (const column of table.model.columns) {
|
|
418
|
+
if (column.writable && present.has(column.field))
|
|
419
|
+
columns.push(column);
|
|
420
|
+
}
|
|
421
|
+
return columns;
|
|
422
|
+
}
|
|
423
|
+
function writeSet(table, value) {
|
|
424
|
+
if (!isRecord(value))
|
|
425
|
+
fail("OKM1121", "set must be an object of fields.");
|
|
426
|
+
const set = {};
|
|
427
|
+
for (const key of Object.keys(value)) {
|
|
428
|
+
if (value[key] === undefined)
|
|
429
|
+
continue;
|
|
430
|
+
const column = table.columns.get(key);
|
|
431
|
+
if (column === undefined) {
|
|
432
|
+
throwNamed2("OKM1120", key, table.names, `Field ${key} is not on ${table.model.name}. Accepted names: ${table.names.join(", ")}.`);
|
|
433
|
+
}
|
|
434
|
+
if (!column.writable)
|
|
435
|
+
refuse(table.model.name, column);
|
|
436
|
+
set[key] = value[key];
|
|
437
|
+
}
|
|
438
|
+
return set;
|
|
439
|
+
}
|
|
440
|
+
function updateItem(table, value) {
|
|
441
|
+
if (!isRecord(value))
|
|
442
|
+
fail("OKM1121", "update expects { where, set } or a list of rows.");
|
|
443
|
+
const set = writeSet(table, value.set);
|
|
444
|
+
if (value.where !== undefined)
|
|
445
|
+
return { where: value.where, set };
|
|
446
|
+
if (value.id !== undefined)
|
|
447
|
+
return { where: { id: value.id }, set };
|
|
448
|
+
fail("OKM1102", `update on ${table.model.name} needs id or where for each row.`);
|
|
449
|
+
}
|
|
450
|
+
function requireFilter(table, where, mods, op) {
|
|
451
|
+
if (mods.all !== undefined) {
|
|
452
|
+
if (mods.all.trim().length === 0) {
|
|
453
|
+
fail("OKM1102", `${op} on ${table.model.name} needs a where. .all needs a reason.`);
|
|
454
|
+
}
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
if (isOperator(where))
|
|
458
|
+
return;
|
|
459
|
+
if (isRecord(where) && Object.keys(where).length > 0)
|
|
460
|
+
return;
|
|
461
|
+
fail("OKM1102", `${op} on ${table.model.name} needs a where. Pass a filter, or .all(reason).`);
|
|
462
|
+
}
|
|
463
|
+
function chunkRows(rows) {
|
|
464
|
+
const chunks = [];
|
|
465
|
+
let current = [];
|
|
466
|
+
let count = 0;
|
|
467
|
+
for (const row of rows) {
|
|
468
|
+
let cost = 0;
|
|
469
|
+
for (const cell of row)
|
|
470
|
+
if (cell.kind !== "default")
|
|
471
|
+
cost += 1;
|
|
472
|
+
if (current.length > 0 && count + cost > WRITE_PARAM_BUDGET) {
|
|
473
|
+
chunks.push(current);
|
|
474
|
+
current = [];
|
|
475
|
+
count = 0;
|
|
476
|
+
}
|
|
477
|
+
current.push(row);
|
|
478
|
+
count += cost;
|
|
479
|
+
}
|
|
480
|
+
if (current.length > 0)
|
|
481
|
+
chunks.push(current);
|
|
482
|
+
return chunks;
|
|
483
|
+
}
|
|
484
|
+
function withParams(text, params) {
|
|
485
|
+
if (params === undefined || params.length === 0)
|
|
486
|
+
return { text };
|
|
487
|
+
return { text, params };
|
|
488
|
+
}
|
|
489
|
+
function keyWire(columns, row) {
|
|
490
|
+
return columns.map((column) => {
|
|
491
|
+
const value = row[column.field];
|
|
492
|
+
if (value === undefined || value === null)
|
|
493
|
+
return null;
|
|
494
|
+
if (typeof value === "object")
|
|
495
|
+
return null;
|
|
496
|
+
return column.encode(value);
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
function returningOption(table, value) {
|
|
500
|
+
if (value === undefined)
|
|
501
|
+
return;
|
|
502
|
+
return selectedColumns(table, value);
|
|
503
|
+
}
|
|
504
|
+
function returningClause(columns, alias) {
|
|
505
|
+
if (columns === undefined || columns.length === 0)
|
|
506
|
+
return "";
|
|
507
|
+
const parts = columns.map((column) => {
|
|
508
|
+
const sql = alias === undefined ? quote(column.sql) : `${alias}.${quote(column.sql)}`;
|
|
509
|
+
return projectExpr(sql, column.dataType);
|
|
510
|
+
});
|
|
511
|
+
return ` returning ${parts.join(", ")}`;
|
|
512
|
+
}
|
|
513
|
+
function outputsOf(columns) {
|
|
514
|
+
const list = columns ?? [];
|
|
515
|
+
return {
|
|
516
|
+
fields: list.map((column, index) => ({
|
|
517
|
+
key: column.field,
|
|
518
|
+
at: index,
|
|
519
|
+
decode: column.decode
|
|
520
|
+
})),
|
|
521
|
+
includes: []
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
function expectOf(options, mods) {
|
|
525
|
+
const value = mods.expect ?? options.expect;
|
|
526
|
+
if (value === undefined)
|
|
527
|
+
return;
|
|
528
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
529
|
+
throw new OkmError2("invalid", "expect must be an integer from 0 up.", { kind: "invalid" });
|
|
530
|
+
}
|
|
531
|
+
return value;
|
|
532
|
+
}
|
|
533
|
+
function checkExpect(count, expected, table, op) {
|
|
534
|
+
if (expected === undefined || count === expected)
|
|
535
|
+
return;
|
|
536
|
+
throw new OkmError2("not_found", `${op} on ${table} changed ${String(count)} rows. expect was ${String(expected)}.`, {
|
|
537
|
+
kind: "not_found",
|
|
538
|
+
table,
|
|
539
|
+
fix: { summary: "Change the filter, or pass the count this write produced." }
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
function callOptions(options) {
|
|
543
|
+
if (!isRecord(options))
|
|
544
|
+
return;
|
|
545
|
+
const signal = options.signal;
|
|
546
|
+
const timeout = options.timeout;
|
|
547
|
+
const hasSignal = typeof signal === "object" && signal !== null && "aborted" in signal;
|
|
548
|
+
const hasTimeout = typeof timeout === "number";
|
|
549
|
+
if (!hasSignal && !hasTimeout)
|
|
550
|
+
return;
|
|
551
|
+
return {
|
|
552
|
+
...hasSignal ? { signal } : {},
|
|
553
|
+
...hasTimeout ? { timeout } : {}
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
function refuse(table, column) {
|
|
557
|
+
if (column.guarded) {
|
|
558
|
+
fail("OKM1190", `Field ${table}.${column.field} is guarded. Input cannot set it.`);
|
|
559
|
+
}
|
|
560
|
+
fail("OKM1120", `Field ${table}.${column.field} cannot be written.`);
|
|
561
|
+
}
|
|
562
|
+
export {
|
|
563
|
+
WRITE_PARAM_BUDGET,
|
|
564
|
+
executeWrite,
|
|
565
|
+
explainWrite
|
|
566
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PgSession
|
|
3
|
+
} from "./dkn3y60a.js";
|
|
4
|
+
import {
|
|
5
|
+
driverErrors,
|
|
6
|
+
rejectClosed,
|
|
7
|
+
mapFailure,
|
|
8
|
+
runCall,
|
|
9
|
+
rowsFrom
|
|
10
|
+
} from "./xy79j5hq.js";
|
|
11
|
+
|
|
12
|
+
// src/adapters/pg/postgres-extra.ts
|
|
13
|
+
var RESET_ALL = "RESET ALL";
|
|
14
|
+
var UNLOCK = "SELECT pg_advisory_unlock_all()";
|
|
15
|
+
async function checkout(pool) {
|
|
16
|
+
if (pool.isClosed())
|
|
17
|
+
return rejectClosed();
|
|
18
|
+
const reserved = await reserveConnection(pool.sql, pool.acquireMs, pool.counters);
|
|
19
|
+
pool.counters.reserved += 1;
|
|
20
|
+
const local = new Set;
|
|
21
|
+
const session = new PgSession(reserved, pool.counters, "reserved", local, pool.isClosed, pool.poolInflight, pool.notices, pool.named);
|
|
22
|
+
let released = false;
|
|
23
|
+
return {
|
|
24
|
+
execute: (text, params, options) => runCall(pool.isClosed(), options, (watch) => session.query(text, params, watch)),
|
|
25
|
+
batch: (statements, options) => runCall(pool.isClosed(), options, async (watch) => {
|
|
26
|
+
const { runAtomicBatch } = await import("./dynq16vb.js");
|
|
27
|
+
return runAtomicBatch(session, statements, watch);
|
|
28
|
+
}),
|
|
29
|
+
cancel() {
|
|
30
|
+
session.cancel();
|
|
31
|
+
},
|
|
32
|
+
async release() {
|
|
33
|
+
if (released)
|
|
34
|
+
return;
|
|
35
|
+
released = true;
|
|
36
|
+
try {
|
|
37
|
+
await resetConnection(reserved, session.depth());
|
|
38
|
+
} finally {
|
|
39
|
+
pool.counters.reserved = Math.max(0, pool.counters.reserved - 1);
|
|
40
|
+
reserved.release();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async function describe(sql, text, params) {
|
|
46
|
+
const pending = sql.unsafe(text, asParams(params), { prepare: true });
|
|
47
|
+
const described = await pending.describe();
|
|
48
|
+
return {
|
|
49
|
+
columns: described.columns.map((column) => column.name),
|
|
50
|
+
parameterCount: described.types.length
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async function* stream(sql, text, params) {
|
|
54
|
+
const pending = sql.unsafe(text, asParams(params));
|
|
55
|
+
for await (const chunk of pending.cursor(64)) {
|
|
56
|
+
yield rowsFrom(chunk);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function reserveConnection(sql, acquireMs, counters) {
|
|
60
|
+
counters.waiting += 1;
|
|
61
|
+
let settled = false;
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
let timer;
|
|
64
|
+
if (acquireMs !== undefined) {
|
|
65
|
+
timer = setTimeout(() => {
|
|
66
|
+
settled = true;
|
|
67
|
+
counters.waiting = Math.max(0, counters.waiting - 1);
|
|
68
|
+
driverErrors().then((errors) => {
|
|
69
|
+
reject(errors.acquireTimeout());
|
|
70
|
+
});
|
|
71
|
+
}, acquireMs);
|
|
72
|
+
}
|
|
73
|
+
sql.reserve().then((connection) => {
|
|
74
|
+
if (settled) {
|
|
75
|
+
resetConnection(connection, 0).finally(() => {
|
|
76
|
+
connection.release();
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (timer !== undefined)
|
|
81
|
+
clearTimeout(timer);
|
|
82
|
+
counters.waiting = Math.max(0, counters.waiting - 1);
|
|
83
|
+
resolve(connection);
|
|
84
|
+
}, (error) => {
|
|
85
|
+
if (settled)
|
|
86
|
+
return;
|
|
87
|
+
if (timer !== undefined)
|
|
88
|
+
clearTimeout(timer);
|
|
89
|
+
counters.waiting = Math.max(0, counters.waiting - 1);
|
|
90
|
+
mapFailure(error).then(reject);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async function resetConnection(sql, depth) {
|
|
95
|
+
if (depth > 0)
|
|
96
|
+
await sql.unsafe("ROLLBACK").catch(() => {
|
|
97
|
+
return;
|
|
98
|
+
});
|
|
99
|
+
try {
|
|
100
|
+
await sql.unsafe(RESET_ALL);
|
|
101
|
+
await sql.unsafe(UNLOCK);
|
|
102
|
+
} catch {
|
|
103
|
+
await sql.unsafe("ROLLBACK").catch(() => {
|
|
104
|
+
return;
|
|
105
|
+
});
|
|
106
|
+
await sql.unsafe(RESET_ALL);
|
|
107
|
+
await sql.unsafe(UNLOCK);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function asParams(params) {
|
|
111
|
+
if (params === undefined)
|
|
112
|
+
return [];
|
|
113
|
+
return params;
|
|
114
|
+
}
|
|
115
|
+
export {
|
|
116
|
+
checkout,
|
|
117
|
+
describe,
|
|
118
|
+
stream
|
|
119
|
+
};
|