litedbmodel 2.0.2 → 2.2.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 +7 -0
- package/dist/DBConditions.d.ts.map +1 -1
- package/dist/DBConditions.js +16 -1
- package/dist/DBConditions.js.map +1 -1
- package/dist/DBHandler.d.ts.map +1 -1
- package/dist/DBHandler.js +6 -0
- package/dist/DBHandler.js.map +1 -1
- package/dist/DBModel.d.ts +84 -2
- package/dist/DBModel.d.ts.map +1 -1
- package/dist/DBModel.js +312 -29
- package/dist/DBModel.js.map +1 -1
- package/dist/decorators.d.ts +52 -0
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +127 -24
- package/dist/decorators.js.map +1 -1
- package/dist/drivers/mysql.d.ts.map +1 -1
- package/dist/drivers/mysql.js +12 -2
- package/dist/drivers/mysql.js.map +1 -1
- package/dist/drivers/postgres.d.ts.map +1 -1
- package/dist/drivers/postgres.js +13 -2
- package/dist/drivers/postgres.js.map +1 -1
- package/dist/drivers/sqlite.d.ts +2 -0
- package/dist/drivers/sqlite.d.ts.map +1 -1
- package/dist/drivers/sqlite.js +49 -4
- package/dist/drivers/sqlite.js.map +1 -1
- package/dist/index.cjs +10741 -0
- package/dist/index.d.cts +1 -0
- package/dist/scp/coltype.d.ts +108 -0
- package/dist/scp/coltype.d.ts.map +1 -1
- package/dist/scp/coltype.js +293 -6
- package/dist/scp/coltype.js.map +1 -1
- package/dist/scp/connection-routing.d.ts +312 -0
- package/dist/scp/connection-routing.d.ts.map +1 -0
- package/dist/scp/connection-routing.js +394 -0
- package/dist/scp/connection-routing.js.map +1 -0
- package/dist/scp/dbmodel-runtime.d.ts +101 -0
- package/dist/scp/dbmodel-runtime.d.ts.map +1 -0
- package/dist/scp/dbmodel-runtime.js +174 -0
- package/dist/scp/dbmodel-runtime.js.map +1 -0
- package/dist/scp/decorator-adapter.d.ts +196 -0
- package/dist/scp/decorator-adapter.d.ts.map +1 -0
- package/dist/scp/decorator-adapter.js +286 -0
- package/dist/scp/decorator-adapter.js.map +1 -0
- package/dist/scp/emit/emitter.d.ts +108 -0
- package/dist/scp/emit/emitter.d.ts.map +1 -0
- package/dist/scp/emit/emitter.js +782 -0
- package/dist/scp/emit/emitter.js.map +1 -0
- package/dist/scp/emit/endpoint.d.ts +248 -0
- package/dist/scp/emit/endpoint.d.ts.map +1 -0
- package/dist/scp/emit/endpoint.js +20 -0
- package/dist/scp/emit/endpoint.js.map +1 -0
- package/dist/scp/emit/index.d.ts +11 -0
- package/dist/scp/emit/index.d.ts.map +1 -0
- package/dist/scp/emit/index.js +13 -0
- package/dist/scp/emit/index.js.map +1 -0
- package/dist/scp/errors.d.ts +45 -1
- package/dist/scp/errors.d.ts.map +1 -1
- package/dist/scp/errors.js +47 -1
- package/dist/scp/errors.js.map +1 -1
- package/dist/scp/exec-context.d.ts +390 -0
- package/dist/scp/exec-context.d.ts.map +1 -0
- package/dist/scp/exec-context.js +540 -0
- package/dist/scp/exec-context.js.map +1 -0
- package/dist/scp/grouping.d.ts +32 -0
- package/dist/scp/grouping.d.ts.map +1 -0
- package/dist/scp/grouping.js +0 -0
- package/dist/scp/grouping.js.map +1 -0
- package/dist/scp/index.cjs +6432 -17579
- package/dist/scp/index.d.cts +1 -0
- package/dist/scp/index.d.mts +1 -0
- package/dist/scp/index.d.ts +51 -52
- package/dist/scp/index.d.ts.map +1 -1
- package/dist/scp/index.js +189 -152
- package/dist/scp/index.js.map +1 -1
- package/dist/scp/index.mjs +6067 -3659
- package/dist/scp/leaf-transport.d.ts +50 -0
- package/dist/scp/leaf-transport.d.ts.map +1 -0
- package/dist/scp/leaf-transport.js +92 -0
- package/dist/scp/leaf-transport.js.map +1 -0
- package/dist/scp/leaves.d.ts +174 -0
- package/dist/scp/leaves.d.ts.map +1 -0
- package/dist/scp/leaves.js +287 -0
- package/dist/scp/leaves.js.map +1 -0
- package/dist/scp/limit-config.d.ts +118 -0
- package/dist/scp/limit-config.d.ts.map +1 -0
- package/dist/scp/limit-config.js +126 -0
- package/dist/scp/limit-config.js.map +1 -0
- package/dist/scp/makesql/compile-relation.d.ts +49 -23
- package/dist/scp/makesql/compile-relation.d.ts.map +1 -1
- package/dist/scp/makesql/compile-relation.js +101 -76
- package/dist/scp/makesql/compile-relation.js.map +1 -1
- package/dist/scp/makesql/compile-select.d.ts +45 -10
- package/dist/scp/makesql/compile-select.d.ts.map +1 -1
- package/dist/scp/makesql/compile-select.js +50 -10
- package/dist/scp/makesql/compile-select.js.map +1 -1
- package/dist/scp/makesql/handler.d.ts +1 -1
- package/dist/scp/makesql/handler.d.ts.map +1 -1
- package/dist/scp/makesql/index.d.ts +7 -10
- package/dist/scp/makesql/index.d.ts.map +1 -1
- package/dist/scp/makesql/index.js +19 -30
- package/dist/scp/makesql/index.js.map +1 -1
- package/dist/scp/makesql/json-array.d.ts +65 -0
- package/dist/scp/makesql/json-array.d.ts.map +1 -1
- package/dist/scp/makesql/json-array.js +99 -10
- package/dist/scp/makesql/json-array.js.map +1 -1
- package/dist/scp/makesql/json-batch.d.ts.map +1 -1
- package/dist/scp/makesql/json-batch.js +21 -19
- package/dist/scp/makesql/json-batch.js.map +1 -1
- package/dist/scp/makesql/makesql.d.ts +1 -1
- package/dist/scp/makesql/makesql.d.ts.map +1 -1
- package/dist/scp/makesql/mysql-returning.d.ts +93 -0
- package/dist/scp/makesql/mysql-returning.d.ts.map +1 -0
- package/dist/scp/makesql/mysql-returning.js +215 -0
- package/dist/scp/makesql/mysql-returning.js.map +1 -0
- package/dist/scp/makesql/outtype.d.ts +75 -34
- package/dist/scp/makesql/outtype.d.ts.map +1 -1
- package/dist/scp/makesql/outtype.js +91 -118
- package/dist/scp/makesql/outtype.js.map +1 -1
- package/dist/scp/makesql/pool-executor.d.ts +135 -13
- package/dist/scp/makesql/pool-executor.d.ts.map +1 -1
- package/dist/scp/makesql/pool-executor.js +229 -21
- package/dist/scp/makesql/pool-executor.js.map +1 -1
- package/dist/scp/makesql/tx.d.ts +107 -22
- package/dist/scp/makesql/tx.d.ts.map +1 -1
- package/dist/scp/makesql/tx.js +451 -97
- package/dist/scp/makesql/tx.js.map +1 -1
- package/dist/scp/makesql/writeouttype.d.ts +7 -8
- package/dist/scp/makesql/writeouttype.d.ts.map +1 -1
- package/dist/scp/makesql/writeouttype.js +8 -7
- package/dist/scp/makesql/writeouttype.js.map +1 -1
- package/dist/scp/middleware.d.ts +287 -0
- package/dist/scp/middleware.d.ts.map +1 -0
- package/dist/scp/middleware.js +358 -0
- package/dist/scp/middleware.js.map +1 -0
- package/dist/scp/relation.d.ts +80 -9
- package/dist/scp/relation.d.ts.map +1 -1
- package/dist/scp/relation.js +198 -78
- package/dist/scp/relation.js.map +1 -1
- package/dist/scp/tx-options.d.ts +136 -0
- package/dist/scp/tx-options.d.ts.map +1 -0
- package/dist/scp/tx-options.js +184 -0
- package/dist/scp/tx-options.js.map +1 -0
- package/dist/scp/write-bundle.d.ts +131 -0
- package/dist/scp/write-bundle.d.ts.map +1 -0
- package/dist/scp/write-bundle.js +160 -0
- package/dist/scp/write-bundle.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/docs/BENCHMARK.md +58 -56
- package/docs/benchmark-chart.svg +166 -166
- package/docs/design/phase-a-execution-context.md +139 -0
- package/package.json +16 -9
- package/dist/scp/authoring-sql.d.ts +0 -134
- package/dist/scp/authoring-sql.d.ts.map +0 -1
- package/dist/scp/authoring-sql.js +0 -191
- package/dist/scp/authoring-sql.js.map +0 -1
- package/dist/scp/authoring.d.ts +0 -155
- package/dist/scp/authoring.d.ts.map +0 -1
- package/dist/scp/authoring.js +0 -162
- package/dist/scp/authoring.js.map +0 -1
- package/dist/scp/catalog.d.ts +0 -94
- package/dist/scp/catalog.d.ts.map +0 -1
- package/dist/scp/catalog.js +0 -234
- package/dist/scp/catalog.js.map +0 -1
- package/dist/scp/codegen.d.ts +0 -189
- package/dist/scp/codegen.d.ts.map +0 -1
- package/dist/scp/codegen.js +0 -421
- package/dist/scp/codegen.js.map +0 -1
- package/dist/scp/find-filter-guard.d.ts +0 -68
- package/dist/scp/find-filter-guard.d.ts.map +0 -1
- package/dist/scp/find-filter-guard.js +0 -88
- package/dist/scp/find-filter-guard.js.map +0 -1
- package/dist/scp/guard.d.ts +0 -43
- package/dist/scp/guard.d.ts.map +0 -1
- package/dist/scp/guard.js +0 -134
- package/dist/scp/guard.js.map +0 -1
- package/dist/scp/makesql/authoring-compile.d.ts +0 -90
- package/dist/scp/makesql/authoring-compile.d.ts.map +0 -1
- package/dist/scp/makesql/authoring-compile.js +0 -494
- package/dist/scp/makesql/authoring-compile.js.map +0 -1
- package/dist/scp/makesql/ir.d.ts +0 -42
- package/dist/scp/makesql/ir.d.ts.map +0 -1
- package/dist/scp/makesql/ir.js +0 -66
- package/dist/scp/makesql/ir.js.map +0 -1
- package/dist/scp/makesql/static-bundle.d.ts +0 -187
- package/dist/scp/makesql/static-bundle.d.ts.map +0 -1
- package/dist/scp/makesql/static-bundle.js +0 -1113
- package/dist/scp/makesql/static-bundle.js.map +0 -1
- package/dist/scp/runtime.d.ts +0 -242
- package/dist/scp/runtime.d.ts.map +0 -1
- package/dist/scp/runtime.js +0 -400
- package/dist/scp/runtime.js.map +0 -1
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — **MySQL has no `RETURNING`**: the one place that knowledge lives.
|
|
4
|
+
*
|
|
5
|
+
* A write compiled for the `mysql` dialect carries the SAME ` RETURNING <cols>` tail as the PG /
|
|
6
|
+
* SQLite bundles (the compilers are dialect-neutral about it), plus a strip-before-execute
|
|
7
|
+
* `/*scp:pk=…;ai=…[;conflict=…]* /` comment naming the target's REAL primary key. MySQL parses
|
|
8
|
+
* neither, so the driver seam STRIPS both and recovers the written rows with a SELECT keyed on
|
|
9
|
+
* whatever identifies them:
|
|
10
|
+
*
|
|
11
|
+
* | write | the rows are recovered by | when |
|
|
12
|
+
* |------------------|--------------------------------------------------------------------|-----------|
|
|
13
|
+
* | create | the AUTO_INCREMENT range `[LAST_INSERT_ID, +affected)`, or the | after |
|
|
14
|
+
* | | client-supplied PK values pulled from the INSERT params by position | |
|
|
15
|
+
* | createMany | the same AUTO_INCREMENT range (N consecutive ids) | after |
|
|
16
|
+
* | upsert / …Many | the CONFLICT key (MySQL does not report the conflicted-row id, so | after |
|
|
17
|
+
* | | the AUTO_INCREMENT range is wrong when a row was UPDATED) | |
|
|
18
|
+
* | update | the write's OWN WHERE predicate | after |
|
|
19
|
+
* | updateMany | the batch JOIN key, re-bound from the SAME JSON payload | after |
|
|
20
|
+
* | delete/deleteMany| the write's OWN WHERE predicate — **before** the write, since the | BEFORE |
|
|
21
|
+
* | | rows no longer exist once the DELETE has run | |
|
|
22
|
+
*
|
|
23
|
+
* The recovering SELECT runs on the SAME connection as the write, so inside a transaction it sees
|
|
24
|
+
* the not-yet-committed rows — and a `DELETE`'s pre-image SELECT is inside the same transaction as
|
|
25
|
+
* the delete it describes.
|
|
26
|
+
*
|
|
27
|
+
* This module is the TypeScript member of a 5-language SSoT: `rust/litedbmodel_runtime/src/livedb.rs`
|
|
28
|
+
* (`build_mysql_reselect`), `go/litedbmodel_runtime/livedb.go`, `python/litedbmodel_runtime/driver.py`
|
|
29
|
+
* and `php/src/LiveDb.php` derive the identical write/select/bind triple. Both TS execution paths —
|
|
30
|
+
* the generated (codegen) leaf `executeSQL` and the mode-2 transaction plan — reach it through the
|
|
31
|
+
* ONE mysql connection adapter (`pool-executor.mysqlConnection`), so they cannot return different rows.
|
|
32
|
+
*/
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.mysqlPkHint = mysqlPkHint;
|
|
35
|
+
exports.stripMysqlPkHint = stripMysqlPkHint;
|
|
36
|
+
exports.buildMysqlReselect = buildMysqlReselect;
|
|
37
|
+
exports.bindReselect = bindReselect;
|
|
38
|
+
/** The strip-before-execute PK-hint comment marker. */
|
|
39
|
+
const MYSQL_PK_HINT_RE = /\s*\/\*scp:pk=[^*]*\*\//;
|
|
40
|
+
/**
|
|
41
|
+
* Serialize a {@link TxOp.pk} descriptor into a strip-before-execute SQL comment appended to an
|
|
42
|
+
* INSERT…RETURNING op, so the MySQL driver emulation can re-select by the REAL primary key. The
|
|
43
|
+
* comment is STRIPPED (with the RETURNING clause) before the write executes, so the executed SQL
|
|
44
|
+
* stays byte-clean; it is emitted ONLY into the mysql-dialect bundle (PG/SQLite keep native
|
|
45
|
+
* RETURNING and never see it). Format: ` /*scp:pk=col1,col2;ai=<autoIncCol|>[;conflict=<cols>]* /`.
|
|
46
|
+
*
|
|
47
|
+
* `conflict` (the upsert conflict-target column list) is added when the write is an upsert — the mysql
|
|
48
|
+
* driver re-selects the upserted row(s) by that key. Its source is `op.writeMeta.onConflict` (single
|
|
49
|
+
* writes carry it); an ad-hoc TxOp built without writeMeta (the batch createMany/upsertMany path)
|
|
50
|
+
* passes the columns via `onConflict`.
|
|
51
|
+
*/
|
|
52
|
+
function mysqlPkHint(op, onConflict) {
|
|
53
|
+
if (op.pk === undefined)
|
|
54
|
+
return op;
|
|
55
|
+
if (!/\breturning\b/i.test(op.sql))
|
|
56
|
+
return op;
|
|
57
|
+
if (MYSQL_PK_HINT_RE.test(op.sql))
|
|
58
|
+
return op; // idempotent: never append a second hint
|
|
59
|
+
const conflict = onConflict ?? op.writeMeta?.onConflict;
|
|
60
|
+
const conflictPart = conflict !== undefined && conflict.length > 0 ? `;conflict=${conflict}` : '';
|
|
61
|
+
const hint = ` /*scp:pk=${op.pk.columns.join(',')};ai=${op.pk.autoInc ?? ''}${conflictPart}*/`;
|
|
62
|
+
return { ...op, sql: op.sql + hint };
|
|
63
|
+
}
|
|
64
|
+
/** Strip a trailing MySQL PK-hint comment from a rendered SQL (defensive; runtimes strip too). */
|
|
65
|
+
function stripMysqlPkHint(sql) {
|
|
66
|
+
return sql.replace(MYSQL_PK_HINT_RE, '');
|
|
67
|
+
}
|
|
68
|
+
/** The `,`-separated INSERT column list (`INSERT [IGNORE] INTO t (a, b, c)` → `['a','b','c']`). */
|
|
69
|
+
function insertCols(writeSql) {
|
|
70
|
+
const m = /\bINSERT\s+(?:IGNORE\s+)?INTO\s+[A-Za-z0-9_."`]+\s*\(([^)]*)\)/i.exec(writeSql);
|
|
71
|
+
return m === null ? [] : m[1].split(',').map((c) => c.trim());
|
|
72
|
+
}
|
|
73
|
+
/** The target table — the identifier after `INSERT INTO` / `UPDATE` / `DELETE FROM`. */
|
|
74
|
+
function tableOf(writeSql) {
|
|
75
|
+
const m = /\b(?:INSERT\s+(?:IGNORE\s+)?INTO|UPDATE|DELETE\s+FROM)\s+([A-Za-z0-9_."`]+)/i.exec(writeSql);
|
|
76
|
+
return m === null ? null : m[1];
|
|
77
|
+
}
|
|
78
|
+
/** The JOIN key column of an updateMany (`ON <alias>.<col> = JSON_UNQUOTE(…)`). */
|
|
79
|
+
function updateBatchKey(writeSql) {
|
|
80
|
+
const m = /\sON\s+[A-Za-z0-9_]*\.?([A-Za-z0-9_]+)\s*=/i.exec(writeSql);
|
|
81
|
+
return m === null ? null : m[1];
|
|
82
|
+
}
|
|
83
|
+
/** The hint's `pk=` columns + `ai=` AUTO_INCREMENT column (absent hint ⇒ `[]` / `''`). */
|
|
84
|
+
function parsePkHint(hintRegion) {
|
|
85
|
+
const m = /\/\*scp:pk=([^;*]*);ai=([^;*]*)/i.exec(hintRegion);
|
|
86
|
+
if (m === null)
|
|
87
|
+
return { pk: [], autoInc: '' };
|
|
88
|
+
return { pk: m[1].split(',').map((c) => c.trim()).filter((c) => c.length > 0), autoInc: m[2].trim() };
|
|
89
|
+
}
|
|
90
|
+
/** The hint's `conflict=` columns (the upsert conflict target). Empty ⇒ not an upsert. */
|
|
91
|
+
function parseConflictHint(hintRegion) {
|
|
92
|
+
const m = /;conflict=([^*]*)\*\//i.exec(hintRegion);
|
|
93
|
+
if (m === null)
|
|
94
|
+
return [];
|
|
95
|
+
return m[1].split(',').map((c) => c.trim()).filter((c) => c.length > 0);
|
|
96
|
+
}
|
|
97
|
+
/** The `?` count of a SQL fragment (the write's params are positional, so a count IS an index). */
|
|
98
|
+
function placeholders(fragment) {
|
|
99
|
+
return (fragment.match(/\?/g) ?? []).length;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Derive the MySQL RETURNING recovery for `sql`, or `null` when the statement declares no RETURNING
|
|
103
|
+
* (a plain write / a SELECT — the caller runs it unchanged).
|
|
104
|
+
*
|
|
105
|
+
* Fail-closed: a RETURNING write whose key cannot be identified (an upsert with no `conflict=` hint,
|
|
106
|
+
* an INSERT whose declared PK column is not in its column list, an UPDATE/DELETE with no WHERE)
|
|
107
|
+
* THROWS rather than silently returning no rows — returning `[]` for a write the caller asked to
|
|
108
|
+
* describe is exactly the defect this module exists to remove.
|
|
109
|
+
*/
|
|
110
|
+
function buildMysqlReselect(sql) {
|
|
111
|
+
const retPos = sql.toLowerCase().lastIndexOf(' returning ');
|
|
112
|
+
if (retPos < 0)
|
|
113
|
+
return null;
|
|
114
|
+
const hintRegion = sql.slice(retPos);
|
|
115
|
+
const cols = stripMysqlPkHint(sql.slice(retPos + ' returning '.length)).trim();
|
|
116
|
+
const { pk, autoInc } = parsePkHint(hintRegion);
|
|
117
|
+
const conflict = parseConflictHint(hintRegion);
|
|
118
|
+
const writeSql = stripMysqlPkHint(sql.slice(0, retPos)).trim();
|
|
119
|
+
const lower = writeSql.toLowerCase();
|
|
120
|
+
const table = tableOf(writeSql);
|
|
121
|
+
if (table === null)
|
|
122
|
+
throw new Error(`scp write(mysql): cannot parse the target table of '${writeSql.slice(0, 60)}…'`);
|
|
123
|
+
// Order by the DECLARED pk so MySQL matches the pg/sqlite RETURNING order (§10 all-dialect parity).
|
|
124
|
+
const orderBy = pk.length > 0 ? ` ORDER BY ${pk.join(', ')}` : '';
|
|
125
|
+
const isBatch = lower.includes('json_table(');
|
|
126
|
+
const done = (selectSql, binds, before = false) => ({ writeSql, selectSql, binds, before });
|
|
127
|
+
/** Recover a BATCH write's rows by reading its key set back out of the SAME JSON payload it bound. */
|
|
128
|
+
const jsonSelect = (key) => `SELECT ${cols} FROM ${table} WHERE ${key} IN ` +
|
|
129
|
+
`(SELECT JSON_UNQUOTE(jt.${key}) FROM JSON_TABLE(?, '$[*]' COLUMNS(${key} JSON PATH '$.${key}')) jt)${orderBy}`;
|
|
130
|
+
// upsert / upsertMany — by the CONFLICT key. MySQL does not report which row an ON DUPLICATE KEY
|
|
131
|
+
// UPDATE touched, so the AUTO_INCREMENT range is wrong as soon as a row was updated, not inserted.
|
|
132
|
+
if (lower.startsWith('insert') && lower.includes('on duplicate key update')) {
|
|
133
|
+
const key = conflict[0];
|
|
134
|
+
if (key === undefined) {
|
|
135
|
+
throw new Error(`scp write(mysql): an upsert…RETURNING needs its conflict key in the pk hint ('${writeSql.slice(0, 60)}…')`);
|
|
136
|
+
}
|
|
137
|
+
if (isBatch)
|
|
138
|
+
return done(jsonSelect(key), [{ kind: 'json' }]);
|
|
139
|
+
const index = insertCols(writeSql).indexOf(key);
|
|
140
|
+
if (index < 0)
|
|
141
|
+
throw new Error(`scp write(mysql): conflict key '${key}' is not among the INSERT columns of '${writeSql.slice(0, 60)}…'`);
|
|
142
|
+
return done(`SELECT ${cols} FROM ${table} WHERE ${key} = ?${orderBy}`, [{ kind: 'param', index }]);
|
|
143
|
+
}
|
|
144
|
+
// create / createMany — by the AUTO_INCREMENT range [LAST_INSERT_ID, +affected), or by the
|
|
145
|
+
// client-supplied PK values pulled from the INSERT params by column position (UUID / composite).
|
|
146
|
+
if (lower.startsWith('insert')) {
|
|
147
|
+
if (autoInc !== '' && pk.length === 1 && pk[0] === autoInc) {
|
|
148
|
+
return done(`SELECT ${cols} FROM ${table} WHERE ${autoInc} >= ? AND ${autoInc} < ?${orderBy}`, [
|
|
149
|
+
{ kind: 'lastId' },
|
|
150
|
+
{ kind: 'highId' },
|
|
151
|
+
]);
|
|
152
|
+
}
|
|
153
|
+
if (pk.length === 0) {
|
|
154
|
+
throw new Error(`scp write(mysql): an INSERT…RETURNING carries no pk hint, so its written rows cannot be identified ` +
|
|
155
|
+
`('${writeSql.slice(0, 60)}…'). The producer must pass the model's declared primary key.`);
|
|
156
|
+
}
|
|
157
|
+
if (isBatch) {
|
|
158
|
+
// createMany with a CLIENT-supplied key: the statement binds ONE JSON payload, not one param per
|
|
159
|
+
// key, so the keys are read back out of that SAME payload — as the upsertMany arm does. (An
|
|
160
|
+
// AUTO_INCREMENT batch never reaches here; its N consecutive ids are the range above.)
|
|
161
|
+
if (pk.length !== 1) {
|
|
162
|
+
throw new Error(`scp write(mysql): a batch INSERT…RETURNING on the COMPOSITE key (${pk.join(', ')}) cannot be ` +
|
|
163
|
+
`recovered from its JSON payload ('${writeSql.slice(0, 60)}…').`);
|
|
164
|
+
}
|
|
165
|
+
return done(jsonSelect(pk[0]), [{ kind: 'json' }]);
|
|
166
|
+
}
|
|
167
|
+
const cols4 = insertCols(writeSql);
|
|
168
|
+
const binds = [];
|
|
169
|
+
const conds = [];
|
|
170
|
+
for (const c of pk) {
|
|
171
|
+
const index = cols4.indexOf(c);
|
|
172
|
+
if (index < 0)
|
|
173
|
+
throw new Error(`scp write(mysql): PK column '${c}' is not among the INSERT columns of '${writeSql.slice(0, 60)}…'`);
|
|
174
|
+
conds.push(`${c} = ?`);
|
|
175
|
+
binds.push({ kind: 'param', index });
|
|
176
|
+
}
|
|
177
|
+
return done(`SELECT ${cols} FROM ${table} WHERE ${conds.join(' AND ')}${orderBy}`, binds);
|
|
178
|
+
}
|
|
179
|
+
// updateMany — by the batch JOIN key, re-selected from the SAME JSON payload the write bound.
|
|
180
|
+
if (lower.startsWith('update') && isBatch) {
|
|
181
|
+
const key = updateBatchKey(writeSql);
|
|
182
|
+
if (key === null)
|
|
183
|
+
throw new Error(`scp write(mysql): cannot parse the batch JOIN key of '${writeSql.slice(0, 60)}…'`);
|
|
184
|
+
return done(jsonSelect(key), [{ kind: 'json' }]);
|
|
185
|
+
}
|
|
186
|
+
// update / delete — by the write's OWN WHERE predicate, bound from the write's own params. The
|
|
187
|
+
// UPDATE re-selects AFTER the write (the rows carry their new values); the DELETE re-selects
|
|
188
|
+
// BEFORE it (afterwards there is nothing left to describe).
|
|
189
|
+
const wherePos = lower.lastIndexOf(' where ');
|
|
190
|
+
if (wherePos < 0) {
|
|
191
|
+
throw new Error(`scp write(mysql): a ${lower.startsWith('delete') ? 'DELETE' : 'UPDATE'}…RETURNING needs a WHERE to recover its rows ('${writeSql.slice(0, 60)}…')`);
|
|
192
|
+
}
|
|
193
|
+
const whereSql = writeSql.slice(wherePos + ' where '.length).trim();
|
|
194
|
+
const before = placeholders(writeSql.slice(0, wherePos));
|
|
195
|
+
const binds = [];
|
|
196
|
+
for (let i = 0; i < placeholders(whereSql); i++)
|
|
197
|
+
binds.push({ kind: 'param', index: before + i });
|
|
198
|
+
return done(`SELECT ${cols} FROM ${table} WHERE ${whereSql}${orderBy}`, binds, lower.startsWith('delete'));
|
|
199
|
+
}
|
|
200
|
+
/** Bind {@link MysqlReselect.binds} against the write's params + the write's own result. */
|
|
201
|
+
function bindReselect(binds, params, lastInsertId, affected) {
|
|
202
|
+
return binds.map((b) => {
|
|
203
|
+
switch (b.kind) {
|
|
204
|
+
case 'lastId':
|
|
205
|
+
return lastInsertId;
|
|
206
|
+
case 'highId':
|
|
207
|
+
return lastInsertId + Math.max(1, affected);
|
|
208
|
+
case 'json':
|
|
209
|
+
return params[0];
|
|
210
|
+
case 'param':
|
|
211
|
+
return params[b.index];
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=mysql-returning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mysql-returning.js","sourceRoot":"","sources":["../../../src/scp/makesql/mysql-returning.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,44 +1,85 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* litedbmodel v2 SCP —
|
|
2
|
+
* litedbmodel v2 SCP — read-row de-box type derivation (spec §4.1; issues #58/#59).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* notation). WITHOUT them the emitter hard-fails ("nothing to de-box") — the correct fail-closed
|
|
7
|
-
* behavior. This module derives those annotations for a READ component from:
|
|
4
|
+
* The read-column coverage + de-box SSoT for the op-independent leaf path. It resolves a read's
|
|
5
|
+
* projection ONCE into two projections of the SAME column-type resolution:
|
|
8
6
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
7
|
+
* - {@link deriveReadRow} — the read ROW `{arr:{obj:{outputKey: <read-de-boxed scalar>}}}` (the
|
|
8
|
+
* bc `outType` bc's native emitter reads for the typed de-box, #154) PLUS the TS-leaf
|
|
9
|
+
* `materializers` coercion map. Array columns read as `{arr:<element>}` (the SSoT array split
|
|
10
|
+
* {@link import('../coltype').arrayElementType}); the element rides the SAME de-box scalar.
|
|
11
|
+
* - {@link outputType} — composes the component `outputType` by walking the `output` Φ-expression
|
|
12
|
+
* against a `nodeId → outType` map.
|
|
15
13
|
*
|
|
16
|
-
* Spec §4.1 discipline: an ambiguous/unmappable projection is a HARD ERROR (no-assume,
|
|
17
|
-
*
|
|
18
|
-
* THROWS
|
|
14
|
+
* Spec §4.1 discipline: an ambiguous/unmappable projection is a HARD ERROR (no-assume, no-fallback)
|
|
15
|
+
* — a `*` projection, a computed column (typed reads only), or an undeclared/unknown-type column
|
|
16
|
+
* THROWS via {@link parseProjectionColumn} + the coltype SSoT; never a boxed/untyped output.
|
|
19
17
|
*/
|
|
20
|
-
import type { PortableType } from 'behavior-contracts';
|
|
21
|
-
import
|
|
22
|
-
import { type ColumnTypeResolver } from '../coltype';
|
|
23
|
-
/** A body node that is a component ref or a map (a cond node has no SELECT projection). */
|
|
24
|
-
type RefLike = ComponentRefNode | MapNode;
|
|
18
|
+
import type { PortableType } from 'behavior-contracts/runtime';
|
|
19
|
+
import { type MaterializeClass, type ColumnTypeResolver } from '../coltype';
|
|
25
20
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* component throws (typed codegen covers only the SQL read catalog).
|
|
21
|
+
* A parsed `select`-list entry (issue #59). Either a SCHEMA-COLUMN reference (bare / qualified /
|
|
22
|
+
* aliased — resolvable to a declared column type + a driver-row output key) OR a COMPUTED expression
|
|
23
|
+
* (a function / aggregate / literal / cast — no underlying schema column). `*` is neither; it throws
|
|
24
|
+
* (the concrete column list is unknown, so nothing can be typed).
|
|
31
25
|
*/
|
|
32
|
-
export
|
|
26
|
+
export type ProjectionEntry = {
|
|
27
|
+
readonly kind: 'column';
|
|
28
|
+
/** The bare column name (qualifier + alias stripped) — what the type resolver is keyed on. */
|
|
29
|
+
readonly underlying: string;
|
|
30
|
+
/** The property name the driver row carries (the alias, else the bare column). */
|
|
31
|
+
readonly outputKey: string;
|
|
32
|
+
/** The qualifier table if the projection was `qual.col` (a JOIN column), else `undefined` — the
|
|
33
|
+
* column's type resolves against THIS table, not the node's base table. */
|
|
34
|
+
readonly qualifier?: string;
|
|
35
|
+
} | {
|
|
36
|
+
readonly kind: 'computed';
|
|
37
|
+
readonly text: string;
|
|
38
|
+
};
|
|
33
39
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
40
|
+
* The SINGLE projection-column parser (issue #59) — shared by BOTH the codegen `outType` derivation
|
|
41
|
+
* and the TS read-path materializer derivation so the two CANNOT diverge (the recurring source of
|
|
42
|
+
* silent-rounding leaks). Classifies ONE `select`-list entry:
|
|
43
|
+
* - bare `col` → `{ kind:'column', underlying:'col', outputKey:'col' }`.
|
|
44
|
+
* - qualified `t.col` → strip qualifier → `underlying:'col', outputKey:'col'`.
|
|
45
|
+
* - aliased `col AS b` / `t.col AS b` → `underlying:'col', outputKey:'b'` (the driver row key).
|
|
46
|
+
* - computed `COUNT(*)`, `NOW()`, `x::uuid`, `x+1`, aliased or not → `{ kind:'computed', text }`.
|
|
47
|
+
* - `*` / `t.*` → HARD ERROR (the concrete column list is unknown).
|
|
48
|
+
* A SCHEMA-column entry MUST be typed against the declaration (a caller resolves + fail-closes on an
|
|
49
|
+
* undeclared column → never a silent rounded-i64 leak). A COMPUTED entry has no schema column to
|
|
50
|
+
* round: the read path leaves it raw; the codegen path (which needs every struct field typed) rejects
|
|
51
|
+
* it. This ONE parser guarantees every shape is classified identically for both paths.
|
|
38
52
|
*/
|
|
39
|
-
export declare function
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
53
|
+
export declare function parseProjectionColumn(col: string, table: string, at: string): ProjectionEntry;
|
|
54
|
+
/** The read row TYPE (SSoT) + its TS-leaf coercion map — two projections of ONE column resolution. */
|
|
55
|
+
export interface ReadRow {
|
|
56
|
+
/** The read row `{arr:{obj:{outputKey: readScalar}}}` — the SINGLE row-type representation (#141). */
|
|
57
|
+
readonly outType: PortableType;
|
|
58
|
+
/** `outputKey → MaterializeClass` (non-passthrough only) — the TS-leaf coercion derived from the SAME row. */
|
|
59
|
+
readonly materializers: Record<string, MaterializeClass>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Derive the read ROW from a projection (#141 SSoT + #59 op-builder guard). Resolves each projected
|
|
63
|
+
* column ONCE via the SHARED {@link parseProjectionColumn} + the coltype SSoT, producing BOTH:
|
|
64
|
+
* - `outType` — `{arr:{obj:{outputKey: keyArrayElemScalar(sqlType)}}}`, the READ-DE-BOXED scalar
|
|
65
|
+
* (int32→`float`(number) / BIGINT→`string` / BOOLEAN→`bool` / DATE→`string` / text/uuid→`string`).
|
|
66
|
+
* This is the ONE row-type representation: bc's native emitter reads it for the typed de-box
|
|
67
|
+
* (#154), and it is the conform target the TS leaf coercion below produces.
|
|
68
|
+
* - `materializers` — the TS-leaf coercion map ({@link sqlTypeToMaterializeClass}); the leaf coerces
|
|
69
|
+
* each driver cell (BIGINT→exact string / DATE→string / BOOLEAN→boolean) so the row MATCHES `outType`
|
|
70
|
+
* before bc conforms it (bc conform VALIDATES, does not coerce). Derived from the SAME resolution as
|
|
71
|
+
* `outType`, so the coerced JS form always equals the declared read scalar — no second row type.
|
|
72
|
+
* This IS the #59 read-column coverage guard: `*`/`t.*` throws (unknown column list), an undeclared
|
|
73
|
+
* column or unknown SQL type throws. A COMPUTED projection (`COUNT(*)`, cast, literal) is left RAW
|
|
74
|
+
* (omitted from BOTH) — #59: "the read path leaves it raw".
|
|
75
|
+
*/
|
|
76
|
+
export declare function deriveReadRow(table: string, projection: readonly string[], resolveColumnType: ColumnTypeResolver, at: string): ReadRow;
|
|
77
|
+
/**
|
|
78
|
+
* Derive the component `outputType` by walking the `output` Φ-expression against a `nodeId →
|
|
79
|
+
* outType` map. `{ref:[id]}` resolves to that node's outType; `{obj:{k:expr,…}}` /
|
|
80
|
+
* `{arr:expr}` / `{opt:expr}` recurse structurally. A `ref` to an unknown id, or an operator the
|
|
81
|
+
* typed output path does not cover, is a HARD ERROR (no-assume, no-fallback) — the output must be
|
|
82
|
+
* a pure composition of typed node results, never a boxed dynamic tree.
|
|
83
|
+
*/
|
|
84
|
+
export declare function outputType(output: unknown, byNode: Map<string, PortableType>, at: string): PortableType;
|
|
44
85
|
//# sourceMappingURL=outtype.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outtype.d.ts","sourceRoot":"","sources":["../../../src/scp/makesql/outtype.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"outtype.d.ts","sourceRoot":"","sources":["../../../src/scp/makesql/outtype.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAqF,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAW/J;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GACvB;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,8FAA8F;IAC9F,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;gFAC4E;IAC5E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,eAAe,CA8B7F;AAGD,sGAAsG;AACtG,MAAM,WAAW,OAAO;IACtB,sGAAsG;IACtG,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,8GAA8G;IAC9G,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,iBAAiB,EAAE,kBAAkB,EACrC,EAAE,EAAE,MAAM,GACT,OAAO,CAyBT;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,YAAY,CA6CvG"}
|