litedbmodel 2.1.0 → 2.2.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.
Files changed (189) hide show
  1. package/README.md +8 -1
  2. package/dist/DBConditions.d.ts.map +1 -1
  3. package/dist/DBConditions.js +16 -1
  4. package/dist/DBConditions.js.map +1 -1
  5. package/dist/DBHandler.d.ts.map +1 -1
  6. package/dist/DBHandler.js +6 -0
  7. package/dist/DBHandler.js.map +1 -1
  8. package/dist/DBModel.d.ts +84 -2
  9. package/dist/DBModel.d.ts.map +1 -1
  10. package/dist/DBModel.js +312 -29
  11. package/dist/DBModel.js.map +1 -1
  12. package/dist/decorators.d.ts +52 -0
  13. package/dist/decorators.d.ts.map +1 -1
  14. package/dist/decorators.js +83 -0
  15. package/dist/decorators.js.map +1 -1
  16. package/dist/drivers/mysql.d.ts.map +1 -1
  17. package/dist/drivers/mysql.js +6 -2
  18. package/dist/drivers/mysql.js.map +1 -1
  19. package/dist/drivers/postgres.d.ts.map +1 -1
  20. package/dist/drivers/postgres.js +6 -2
  21. package/dist/drivers/postgres.js.map +1 -1
  22. package/dist/drivers/sqlite.d.ts.map +1 -1
  23. package/dist/drivers/sqlite.js +12 -2
  24. package/dist/drivers/sqlite.js.map +1 -1
  25. package/dist/index.cjs +10741 -0
  26. package/dist/index.d.cts +1 -0
  27. package/dist/scp/coltype.d.ts +26 -1
  28. package/dist/scp/coltype.d.ts.map +1 -1
  29. package/dist/scp/coltype.js +82 -15
  30. package/dist/scp/coltype.js.map +1 -1
  31. package/dist/scp/connection-routing.d.ts +312 -0
  32. package/dist/scp/connection-routing.d.ts.map +1 -0
  33. package/dist/scp/connection-routing.js +394 -0
  34. package/dist/scp/connection-routing.js.map +1 -0
  35. package/dist/scp/dbmodel-runtime.d.ts +101 -0
  36. package/dist/scp/dbmodel-runtime.d.ts.map +1 -0
  37. package/dist/scp/dbmodel-runtime.js +174 -0
  38. package/dist/scp/dbmodel-runtime.js.map +1 -0
  39. package/dist/scp/decorator-adapter.d.ts +196 -0
  40. package/dist/scp/decorator-adapter.d.ts.map +1 -0
  41. package/dist/scp/decorator-adapter.js +286 -0
  42. package/dist/scp/decorator-adapter.js.map +1 -0
  43. package/dist/scp/emit/emitter.d.ts +108 -0
  44. package/dist/scp/emit/emitter.d.ts.map +1 -0
  45. package/dist/scp/emit/emitter.js +782 -0
  46. package/dist/scp/emit/emitter.js.map +1 -0
  47. package/dist/scp/emit/endpoint.d.ts +248 -0
  48. package/dist/scp/emit/endpoint.d.ts.map +1 -0
  49. package/dist/scp/emit/endpoint.js +20 -0
  50. package/dist/scp/emit/endpoint.js.map +1 -0
  51. package/dist/scp/emit/index.d.ts +11 -0
  52. package/dist/scp/emit/index.d.ts.map +1 -0
  53. package/dist/scp/emit/index.js +13 -0
  54. package/dist/scp/emit/index.js.map +1 -0
  55. package/dist/scp/errors.d.ts +45 -1
  56. package/dist/scp/errors.d.ts.map +1 -1
  57. package/dist/scp/errors.js +47 -1
  58. package/dist/scp/errors.js.map +1 -1
  59. package/dist/scp/exec-context.d.ts +390 -0
  60. package/dist/scp/exec-context.d.ts.map +1 -0
  61. package/dist/scp/exec-context.js +540 -0
  62. package/dist/scp/exec-context.js.map +1 -0
  63. package/dist/scp/grouping.d.ts +32 -0
  64. package/dist/scp/grouping.d.ts.map +1 -0
  65. package/dist/scp/grouping.js +0 -0
  66. package/dist/scp/grouping.js.map +1 -0
  67. package/dist/scp/index.cjs +6814 -15731
  68. package/dist/scp/index.d.cts +1 -0
  69. package/dist/scp/index.d.mts +1 -0
  70. package/dist/scp/index.d.ts +47 -49
  71. package/dist/scp/index.d.ts.map +1 -1
  72. package/dist/scp/index.js +174 -152
  73. package/dist/scp/index.js.map +1 -1
  74. package/dist/scp/index.mjs +5561 -3704
  75. package/dist/scp/leaf-transport.d.ts +50 -0
  76. package/dist/scp/leaf-transport.d.ts.map +1 -0
  77. package/dist/scp/leaf-transport.js +92 -0
  78. package/dist/scp/leaf-transport.js.map +1 -0
  79. package/dist/scp/leaves.d.ts +174 -0
  80. package/dist/scp/leaves.d.ts.map +1 -0
  81. package/dist/scp/leaves.js +287 -0
  82. package/dist/scp/leaves.js.map +1 -0
  83. package/dist/scp/limit-config.d.ts +118 -0
  84. package/dist/scp/limit-config.d.ts.map +1 -0
  85. package/dist/scp/limit-config.js +126 -0
  86. package/dist/scp/limit-config.js.map +1 -0
  87. package/dist/scp/makesql/compile-relation.d.ts +49 -23
  88. package/dist/scp/makesql/compile-relation.d.ts.map +1 -1
  89. package/dist/scp/makesql/compile-relation.js +101 -76
  90. package/dist/scp/makesql/compile-relation.js.map +1 -1
  91. package/dist/scp/makesql/compile-select.d.ts +45 -10
  92. package/dist/scp/makesql/compile-select.d.ts.map +1 -1
  93. package/dist/scp/makesql/compile-select.js +50 -10
  94. package/dist/scp/makesql/compile-select.js.map +1 -1
  95. package/dist/scp/makesql/handler.d.ts +1 -1
  96. package/dist/scp/makesql/handler.d.ts.map +1 -1
  97. package/dist/scp/makesql/index.d.ts +7 -9
  98. package/dist/scp/makesql/index.d.ts.map +1 -1
  99. package/dist/scp/makesql/index.js +17 -28
  100. package/dist/scp/makesql/index.js.map +1 -1
  101. package/dist/scp/makesql/json-array.d.ts +65 -0
  102. package/dist/scp/makesql/json-array.d.ts.map +1 -1
  103. package/dist/scp/makesql/json-array.js +99 -10
  104. package/dist/scp/makesql/json-array.js.map +1 -1
  105. package/dist/scp/makesql/json-batch.d.ts.map +1 -1
  106. package/dist/scp/makesql/json-batch.js +15 -18
  107. package/dist/scp/makesql/json-batch.js.map +1 -1
  108. package/dist/scp/makesql/makesql.d.ts +1 -1
  109. package/dist/scp/makesql/makesql.d.ts.map +1 -1
  110. package/dist/scp/makesql/mysql-returning.d.ts +93 -0
  111. package/dist/scp/makesql/mysql-returning.d.ts.map +1 -0
  112. package/dist/scp/makesql/mysql-returning.js +215 -0
  113. package/dist/scp/makesql/mysql-returning.js.map +1 -0
  114. package/dist/scp/makesql/outtype.d.ts +40 -54
  115. package/dist/scp/makesql/outtype.d.ts.map +1 -1
  116. package/dist/scp/makesql/outtype.js +46 -204
  117. package/dist/scp/makesql/outtype.js.map +1 -1
  118. package/dist/scp/makesql/pool-executor.d.ts +86 -34
  119. package/dist/scp/makesql/pool-executor.d.ts.map +1 -1
  120. package/dist/scp/makesql/pool-executor.js +179 -39
  121. package/dist/scp/makesql/pool-executor.js.map +1 -1
  122. package/dist/scp/makesql/tx.d.ts +107 -22
  123. package/dist/scp/makesql/tx.d.ts.map +1 -1
  124. package/dist/scp/makesql/tx.js +451 -97
  125. package/dist/scp/makesql/tx.js.map +1 -1
  126. package/dist/scp/makesql/writeouttype.d.ts +4 -4
  127. package/dist/scp/makesql/writeouttype.d.ts.map +1 -1
  128. package/dist/scp/makesql/writeouttype.js +5 -3
  129. package/dist/scp/makesql/writeouttype.js.map +1 -1
  130. package/dist/scp/middleware.d.ts +287 -0
  131. package/dist/scp/middleware.d.ts.map +1 -0
  132. package/dist/scp/middleware.js +358 -0
  133. package/dist/scp/middleware.js.map +1 -0
  134. package/dist/scp/relation.d.ts +65 -8
  135. package/dist/scp/relation.d.ts.map +1 -1
  136. package/dist/scp/relation.js +154 -93
  137. package/dist/scp/relation.js.map +1 -1
  138. package/dist/scp/tx-options.d.ts +136 -0
  139. package/dist/scp/tx-options.d.ts.map +1 -0
  140. package/dist/scp/tx-options.js +184 -0
  141. package/dist/scp/tx-options.js.map +1 -0
  142. package/dist/scp/write-bundle.d.ts +131 -0
  143. package/dist/scp/write-bundle.d.ts.map +1 -0
  144. package/dist/scp/write-bundle.js +160 -0
  145. package/dist/scp/write-bundle.js.map +1 -0
  146. package/dist/types.d.ts +7 -0
  147. package/dist/types.d.ts.map +1 -1
  148. package/dist/types.js.map +1 -1
  149. package/docs/BENCHMARK.md +54 -97
  150. package/docs/COMPARISON.md +14 -8
  151. package/docs/benchmark-chart.svg +310 -248
  152. package/docs/design/phase-a-execution-context.md +139 -0
  153. package/package.json +14 -13
  154. package/dist/scp/authoring-sql.d.ts +0 -134
  155. package/dist/scp/authoring-sql.d.ts.map +0 -1
  156. package/dist/scp/authoring-sql.js +0 -191
  157. package/dist/scp/authoring-sql.js.map +0 -1
  158. package/dist/scp/authoring.d.ts +0 -218
  159. package/dist/scp/authoring.d.ts.map +0 -1
  160. package/dist/scp/authoring.js +0 -351
  161. package/dist/scp/authoring.js.map +0 -1
  162. package/dist/scp/catalog.d.ts +0 -95
  163. package/dist/scp/catalog.d.ts.map +0 -1
  164. package/dist/scp/catalog.js +0 -245
  165. package/dist/scp/catalog.js.map +0 -1
  166. package/dist/scp/codegen.d.ts +0 -201
  167. package/dist/scp/codegen.d.ts.map +0 -1
  168. package/dist/scp/codegen.js +0 -605
  169. package/dist/scp/codegen.js.map +0 -1
  170. package/dist/scp/find-filter-guard.d.ts +0 -68
  171. package/dist/scp/find-filter-guard.d.ts.map +0 -1
  172. package/dist/scp/find-filter-guard.js +0 -88
  173. package/dist/scp/find-filter-guard.js.map +0 -1
  174. package/dist/scp/guard.d.ts +0 -43
  175. package/dist/scp/guard.d.ts.map +0 -1
  176. package/dist/scp/guard.js +0 -140
  177. package/dist/scp/guard.js.map +0 -1
  178. package/dist/scp/makesql/authoring-compile.d.ts +0 -90
  179. package/dist/scp/makesql/authoring-compile.d.ts.map +0 -1
  180. package/dist/scp/makesql/authoring-compile.js +0 -505
  181. package/dist/scp/makesql/authoring-compile.js.map +0 -1
  182. package/dist/scp/makesql/static-bundle.d.ts +0 -196
  183. package/dist/scp/makesql/static-bundle.d.ts.map +0 -1
  184. package/dist/scp/makesql/static-bundle.js +0 -1244
  185. package/dist/scp/makesql/static-bundle.js.map +0 -1
  186. package/dist/scp/runtime.d.ts +0 -243
  187. package/dist/scp/runtime.d.ts.map +0 -1
  188. package/dist/scp/runtime.js +0 -422
  189. 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,27 +1,22 @@
1
1
  /**
2
- * litedbmodel v2 SCP — codegen `outType` derivation (spec §4.1; issues #58/#56).
2
+ * litedbmodel v2 SCP — read-row de-box type derivation (spec §4.1; issues #58/#59).
3
3
  *
4
- * bc's TYPED-RAW de-box emitters (`rust-typed-raw` / `go-typed-raw` / `typescript-typed`) require
5
- * each read node to carry an `outType` and the component an `outputType` (bc portable type
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
- * 1. the per-node SELECT projection (`table` + `select` ports) → a row `obj` type, each column's
10
- * bc scalar resolved from its SQL type (the schema/DDL SoT) via {@link sqlTypeToBcScalar};
11
- * 2. the node cardinality (a Select node returns a row LIST → `{arr:rowObj}`; a Count → `int`; a
12
- * `.map` node wraps its per-element handler result → `{arr:<elem>}`);
13
- * 3. the component `output` Φ-expression, walked to compose the `outputType` from the node types
14
- * (`{ref:[nodeId]}` → that node's outType; `{obj:{…}}`/`{arr:…}`/`{opt:…}` recurse).
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
- * no-fallback) — a `*` projection, a computed/aliased column, or a column with no schema type
18
- * THROWS. It is NEVER degraded to a boxed/untyped output; that would silently defeat the de-box.
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 type { Component, ComponentRefNode, MapNode } from '../authoring';
18
+ import type { PortableType } from 'behavior-contracts/runtime';
22
19
  import { type MaterializeClass, 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;
25
20
  /**
26
21
  * A parsed `select`-list entry (issue #59). Either a SCHEMA-COLUMN reference (bare / qualified /
27
22
  * aliased — resolvable to a declared column type + a driver-row output key) OR a COMPUTED expression
@@ -56,44 +51,35 @@ export type ProjectionEntry = {
56
51
  * it. This ONE parser guarantees every shape is classified identically for both paths.
57
52
  */
58
53
  export declare function parseProjectionColumn(col: string, table: string, at: string): ProjectionEntry;
59
- /** The outType of ONE read body node (thin wrapper over {@link nodeTypes} for external callers). */
60
- export declare function nodeOutType(node: RefLike, resolveColumnType: ColumnTypeResolver): PortableType;
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
61
  /**
62
- * PRE-COMPILE node-output type (bc 0.8.0 SA5 / #12): the determined `PortableType` a litedbmodel CRUD
63
- * leaf annotates its authored node with, via bc's `.as(t)` recording API, so `compileBehaviors`'
64
- * all-nodes-typed gate (`UNTYPED_NODE`) passes. Computed from the RAW authored ports (a plain `table`
65
- * string + a plain `select` / `returning` column list — the same projection SoT `deriveReadOutTypes`
66
- * reads post-compile, just moved to authoring time) + the model's inline `static columns` resolver.
67
- *
68
- * - `Select` → the row LIST `{arr:{obj:{outKey:<scalar>,…}}}` from the `select` projection. This is
69
- * the value `.as` takes in BOTH positions: a top-level Select node's `outType` is this list; a
70
- * mapped Select's `.as` records it as the map ELEMENT type (bc convention — the per-parent row list).
71
- * - `Count` → NOT handled here: its output is the static `int` catalog `elemType` (no `.as`).
72
- * - `Insert`/`Update`/`Delete` → the RETURNING row list `{arr:{obj:…}}` from the `returning` port
73
- * (bare-column list). No `returning` → an EMPTY row list `{arr:{obj:{}}}` (the write surfaces rows
74
- * only via RETURNING; a no-RETURNING write yields empty rows — mirrors `writeouttype.ts`).
75
- *
76
- * Schema columns are parsed by the SAME {@link parseProjectionColumn} the read/codegen paths use and
77
- * typed via the resolver (an undeclared column fails closed here at authoring — earlier than the
78
- * post-compile derivation). A COMPUTED projected column (`COUNT(*) as n`, a cast, a literal) is OMITTED
79
- * from the typed row struct — the read path leaves a computed column RAW (#59: "the read path leaves it
80
- * raw; the codegen path rejects it"), so its field is absent from the de-box row type. This keeps the
81
- * node's outType DETERMINED (gate passes) while preserving #59's raw-computed read behavior; the typed
82
- * codegen path independently rejects a computed projection later (it needs every field typed). The
83
- * value is the OUTPUT-row type only; SQL stays opaque text on the makeSQL leaf (types the node OUTPUT,
84
- * never the SQL).
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".
85
75
  */
86
- export declare function crudNodeAsType(component: string, ports: Record<string, unknown>, resolveColumnType: ColumnTypeResolver, at: string): PortableType;
76
+ export declare function deriveReadRow(table: string, projection: readonly string[], resolveColumnType: ColumnTypeResolver, at: string): ReadRow;
87
77
  /**
88
- * Per-node `outType` (keyed by body node id) + the component `outputType`, derived for a READ
89
- * component (spec §4.1). `cond` nodes are skipped for the per-node map but a `cond` at the OUTPUT
90
- * position (a shared-branch merge) would be handled by {@link outputType} if reached — the bench's
91
- * read outputs are ref / obj compositions of Select nodes. Any ambiguity throws (fail-closed).
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.
92
83
  */
93
- export declare function deriveReadOutTypes(component: Component, resolveColumnType: ColumnTypeResolver): {
94
- byNode: Map<string, PortableType>;
95
- outputType: PortableType;
96
- materializersByNode: Map<string, Record<string, MaterializeClass>>;
97
- };
98
- export {};
84
+ export declare function outputType(output: unknown, byNode: Map<string, PortableType>, at: string): PortableType;
99
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;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAsB,MAAM,oBAAoB,CAAC;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAA+D,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAczI,2FAA2F;AAC3F,KAAK,OAAO,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAwC1C;;;;;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;AAuFD,oGAAoG;AACpG,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,GAAG,YAAY,CAE9F;AAwDD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,iBAAiB,EAAE,kBAAkB,EACrC,EAAE,EAAE,MAAM,GACT,YAAY,CAoCd;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,EACpB,iBAAiB,EAAE,kBAAkB,GACpC;IAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAAC,UAAU,EAAE,YAAY,CAAC;IAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAA;CAAE,CAWrI"}
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"}