litedbmodel 2.0.0 → 2.0.2

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 (163) hide show
  1. package/dist/scp/authoring-sql.d.ts +78 -0
  2. package/dist/scp/authoring-sql.d.ts.map +1 -1
  3. package/dist/scp/authoring-sql.js +110 -2
  4. package/dist/scp/authoring-sql.js.map +1 -1
  5. package/dist/scp/catalog.d.ts +5 -2
  6. package/dist/scp/catalog.d.ts.map +1 -1
  7. package/dist/scp/catalog.js +32 -1
  8. package/dist/scp/catalog.js.map +1 -1
  9. package/dist/scp/codegen.d.ts +143 -85
  10. package/dist/scp/codegen.d.ts.map +1 -1
  11. package/dist/scp/codegen.js +374 -90
  12. package/dist/scp/codegen.js.map +1 -1
  13. package/dist/scp/coltype.d.ts +41 -0
  14. package/dist/scp/coltype.d.ts.map +1 -0
  15. package/dist/scp/coltype.js +188 -0
  16. package/dist/scp/coltype.js.map +1 -0
  17. package/dist/scp/dialect.d.ts +12 -3
  18. package/dist/scp/dialect.d.ts.map +1 -1
  19. package/dist/scp/dialect.js +12 -3
  20. package/dist/scp/dialect.js.map +1 -1
  21. package/dist/scp/find-filter-guard.d.ts +68 -0
  22. package/dist/scp/find-filter-guard.d.ts.map +1 -0
  23. package/dist/scp/find-filter-guard.js +88 -0
  24. package/dist/scp/find-filter-guard.js.map +1 -0
  25. package/dist/scp/fragment/assemble.d.ts +61 -0
  26. package/dist/scp/fragment/assemble.d.ts.map +1 -0
  27. package/dist/scp/fragment/assemble.js +156 -0
  28. package/dist/scp/fragment/assemble.js.map +1 -0
  29. package/dist/scp/fragment/compile-pg.d.ts +107 -0
  30. package/dist/scp/fragment/compile-pg.d.ts.map +1 -0
  31. package/dist/scp/fragment/compile-pg.js +142 -0
  32. package/dist/scp/fragment/compile-pg.js.map +1 -0
  33. package/dist/scp/fragment/index.d.ts +16 -0
  34. package/dist/scp/fragment/index.d.ts.map +1 -0
  35. package/dist/scp/fragment/index.js +34 -0
  36. package/dist/scp/fragment/index.js.map +1 -0
  37. package/dist/scp/fragment/model.d.ts +119 -0
  38. package/dist/scp/fragment/model.d.ts.map +1 -0
  39. package/dist/scp/fragment/model.js +66 -0
  40. package/dist/scp/fragment/model.js.map +1 -0
  41. package/dist/scp/fragment/pg-array-type.d.ts +13 -0
  42. package/dist/scp/fragment/pg-array-type.d.ts.map +1 -0
  43. package/dist/scp/fragment/pg-array-type.js +34 -0
  44. package/dist/scp/fragment/pg-array-type.js.map +1 -0
  45. package/dist/scp/guard.d.ts +2 -6
  46. package/dist/scp/guard.d.ts.map +1 -1
  47. package/dist/scp/guard.js +19 -22
  48. package/dist/scp/guard.js.map +1 -1
  49. package/dist/scp/index.cjs +18695 -3921
  50. package/dist/scp/index.d.ts +41 -24
  51. package/dist/scp/index.d.ts.map +1 -1
  52. package/dist/scp/index.js +134 -49
  53. package/dist/scp/index.js.map +1 -1
  54. package/dist/scp/index.mjs +4830 -1432
  55. package/dist/scp/makesql/authoring-compile.d.ts +90 -0
  56. package/dist/scp/makesql/authoring-compile.d.ts.map +1 -0
  57. package/dist/scp/makesql/authoring-compile.js +494 -0
  58. package/dist/scp/makesql/authoring-compile.js.map +1 -0
  59. package/dist/scp/makesql/compile-crud.d.ts +133 -0
  60. package/dist/scp/makesql/compile-crud.d.ts.map +1 -0
  61. package/dist/scp/makesql/compile-crud.js +288 -0
  62. package/dist/scp/makesql/compile-crud.js.map +1 -0
  63. package/dist/scp/makesql/compile-relation.d.ts +157 -0
  64. package/dist/scp/makesql/compile-relation.d.ts.map +1 -0
  65. package/dist/scp/makesql/compile-relation.js +425 -0
  66. package/dist/scp/makesql/compile-relation.js.map +1 -0
  67. package/dist/scp/makesql/compile-select.d.ts +52 -0
  68. package/dist/scp/makesql/compile-select.d.ts.map +1 -0
  69. package/dist/scp/makesql/compile-select.js +58 -0
  70. package/dist/scp/makesql/compile-select.js.map +1 -0
  71. package/dist/scp/makesql/compile.d.ts +63 -0
  72. package/dist/scp/makesql/compile.d.ts.map +1 -0
  73. package/dist/scp/makesql/compile.js +99 -0
  74. package/dist/scp/makesql/compile.js.map +1 -0
  75. package/dist/scp/makesql/handler.d.ts +58 -0
  76. package/dist/scp/makesql/handler.d.ts.map +1 -0
  77. package/dist/scp/makesql/handler.js +113 -0
  78. package/dist/scp/makesql/handler.js.map +1 -0
  79. package/dist/scp/makesql/index.d.ts +33 -0
  80. package/dist/scp/makesql/index.d.ts.map +1 -0
  81. package/dist/scp/makesql/index.js +114 -0
  82. package/dist/scp/makesql/index.js.map +1 -0
  83. package/dist/scp/makesql/ir.d.ts +42 -0
  84. package/dist/scp/makesql/ir.d.ts.map +1 -0
  85. package/dist/scp/makesql/ir.js +66 -0
  86. package/dist/scp/makesql/ir.js.map +1 -0
  87. package/dist/scp/makesql/json-array.d.ts +84 -0
  88. package/dist/scp/makesql/json-array.d.ts.map +1 -0
  89. package/dist/scp/makesql/json-array.js +118 -0
  90. package/dist/scp/makesql/json-array.js.map +1 -0
  91. package/dist/scp/makesql/json-batch.d.ts +102 -0
  92. package/dist/scp/makesql/json-batch.d.ts.map +1 -0
  93. package/dist/scp/makesql/json-batch.js +269 -0
  94. package/dist/scp/makesql/json-batch.js.map +1 -0
  95. package/dist/scp/makesql/makesql.d.ts +99 -0
  96. package/dist/scp/makesql/makesql.d.ts.map +1 -0
  97. package/dist/scp/makesql/makesql.js +122 -0
  98. package/dist/scp/makesql/makesql.js.map +1 -0
  99. package/dist/scp/makesql/outtype.d.ts +44 -0
  100. package/dist/scp/makesql/outtype.d.ts.map +1 -0
  101. package/dist/scp/makesql/outtype.js +197 -0
  102. package/dist/scp/makesql/outtype.js.map +1 -0
  103. package/dist/scp/makesql/pool-executor.d.ts +47 -0
  104. package/dist/scp/makesql/pool-executor.d.ts.map +1 -0
  105. package/dist/scp/makesql/pool-executor.js +50 -0
  106. package/dist/scp/makesql/pool-executor.js.map +1 -0
  107. package/dist/scp/makesql/static-bundle.d.ts +187 -0
  108. package/dist/scp/makesql/static-bundle.d.ts.map +1 -0
  109. package/dist/scp/makesql/static-bundle.js +1113 -0
  110. package/dist/scp/makesql/static-bundle.js.map +1 -0
  111. package/dist/scp/makesql/tx.d.ts +216 -0
  112. package/dist/scp/makesql/tx.d.ts.map +1 -0
  113. package/dist/scp/makesql/tx.js +788 -0
  114. package/dist/scp/makesql/tx.js.map +1 -0
  115. package/dist/scp/makesql/writeouttype.d.ts +66 -0
  116. package/dist/scp/makesql/writeouttype.d.ts.map +1 -0
  117. package/dist/scp/makesql/writeouttype.js +195 -0
  118. package/dist/scp/makesql/writeouttype.js.map +1 -0
  119. package/dist/scp/relation.d.ts +86 -74
  120. package/dist/scp/relation.d.ts.map +1 -1
  121. package/dist/scp/relation.js +186 -120
  122. package/dist/scp/relation.js.map +1 -1
  123. package/dist/scp/runtime.d.ts +158 -211
  124. package/dist/scp/runtime.d.ts.map +1 -1
  125. package/dist/scp/runtime.js +250 -515
  126. package/dist/scp/runtime.js.map +1 -1
  127. package/dist/scp/typed-object.d.ts +12 -1
  128. package/dist/scp/typed-object.d.ts.map +1 -1
  129. package/dist/scp/typed-object.js +25 -4
  130. package/dist/scp/typed-object.js.map +1 -1
  131. package/docs/proposal/litedbmodel-v2-scp-architecture.md +51 -0
  132. package/docs/proposal/v0-coverage-matrix.md +157 -0
  133. package/docs/proposal/v2-completeness-plan.md +90 -0
  134. package/docs/proposal/v2-sql-parity-checklist.md +162 -0
  135. package/package.json +3 -3
  136. package/dist/scp/bridge.d.ts +0 -64
  137. package/dist/scp/bridge.d.ts.map +0 -1
  138. package/dist/scp/bridge.js +0 -329
  139. package/dist/scp/bridge.js.map +0 -1
  140. package/dist/scp/compile-dialect.d.ts +0 -39
  141. package/dist/scp/compile-dialect.d.ts.map +0 -1
  142. package/dist/scp/compile-dialect.js +0 -62
  143. package/dist/scp/compile-dialect.js.map +0 -1
  144. package/dist/scp/compile-sqlite.d.ts +0 -114
  145. package/dist/scp/compile-sqlite.d.ts.map +0 -1
  146. package/dist/scp/compile-sqlite.js +0 -149
  147. package/dist/scp/compile-sqlite.js.map +0 -1
  148. package/dist/scp/ir.d.ts +0 -92
  149. package/dist/scp/ir.d.ts.map +0 -1
  150. package/dist/scp/ir.js +0 -28
  151. package/dist/scp/ir.js.map +0 -1
  152. package/dist/scp/render.d.ts +0 -40
  153. package/dist/scp/render.d.ts.map +0 -1
  154. package/dist/scp/render.js +0 -170
  155. package/dist/scp/render.js.map +0 -1
  156. package/dist/scp/write-plan.d.ts +0 -161
  157. package/dist/scp/write-plan.d.ts.map +0 -1
  158. package/dist/scp/write-plan.js +0 -528
  159. package/dist/scp/write-plan.js.map +0 -1
  160. package/dist/scp/write-runtime.d.ts +0 -80
  161. package/dist/scp/write-runtime.d.ts.map +0 -1
  162. package/dist/scp/write-runtime.js +0 -167
  163. package/dist/scp/write-runtime.js.map +0 -1
@@ -1,170 +0,0 @@
1
- "use strict";
2
- /**
3
- * litedbmodel v2 SCP — fragment-tree render + param assembly (WS1, #21).
4
- *
5
- * The NORMATIVE reference implementation of `docs/proposal/sql-dynamic-expansion-spec.md`.
6
- * Given a compiled operation and a bound input scope, it deterministically produces the
7
- * final SQLite SQL text (`?` placeholders) and the flat params array. Every multi-language
8
- * runtime (WS3) must reproduce this byte-for-byte; this TS implementation is the golden
9
- * reference the conformance harness pins.
10
- *
11
- * The three moving parts (dynamic-expansion spec):
12
- * §2 SKIP → fragment existence: a fragment with `when` is present iff `when` evaluates
13
- * to a present (non-null / true) binding; an absent fragment contributes NO SQL and
14
- * NO params.
15
- * §3 empty-WHERE degeneration: if no fragment is present the whole `{where}` splice
16
- * (including the ` WHERE ` keyword) collapses to the empty string.
17
- * §4 AND/OR structure + parenthesization: a nested tree renders `(… <connector> …)`.
18
- * §5 IN-list array expansion: a fragment slot marked `expand` turns its `(?)` into
19
- * `(?, ?, …)` for each element of the bound array (0 elements → the `1 = 0`
20
- * always-false degeneration, byte-identical to litedbmodel v1's empty-IN handling).
21
- */
22
- Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.renderOperation = renderOperation;
24
- const behavior_contracts_1 = require("behavior-contracts");
25
- const ir_1 = require("./ir");
26
- const dialect_1 = require("./dialect");
27
- /** A fragment tree carries a `connector`; a fragment carries `sql`. */
28
- function isTree(node) {
29
- return 'connector' in node;
30
- }
31
- /**
32
- * SKIP existence rule (dynamic-expansion spec §2): a fragment is present iff it is
33
- * `always`, or its `when` Expression evaluates to a PRESENT binding — `null` and `false`
34
- * are absent; everything else (including `0`, `""`) is present. This mirrors bc's
35
- * strict-bool discipline: `when` is expected to be an explicit presence/bool Expression
36
- * (e.g. `{ne:[{refOpt:["status"]}, null]}` in bc's flat scope), evaluated fail-closed by
37
- * evaluateExpression.
38
- */
39
- function fragmentPresent(f, scope) {
40
- if (f.always === true)
41
- return true;
42
- if (f.when === undefined)
43
- return false; // fail-closed: neither always nor when
44
- const v = (0, behavior_contracts_1.evaluateExpression)(f.when, scope);
45
- return v !== null && v !== false;
46
- }
47
- /**
48
- * Render one leaf fragment's SQL + params into the accumulators. Handles IN-list
49
- * expansion (spec §5): the slot at `expand` is an array; its `(?)` in `sql` becomes
50
- * `(?, ?, …)` and each element is pushed as its own param.
51
- */
52
- function renderFragment(f, scope, params) {
53
- if (f.expand === undefined) {
54
- for (const slot of f.params)
55
- params.push((0, behavior_contracts_1.evaluateExpression)(slot, scope));
56
- return f.sql;
57
- }
58
- // IN-list expansion. Evaluate all slots; the `expand` slot must be an array.
59
- let sql = f.sql;
60
- for (let i = 0; i < f.params.length; i++) {
61
- const v = (0, behavior_contracts_1.evaluateExpression)(f.params[i], scope);
62
- if (i === f.expand) {
63
- if (!Array.isArray(v)) {
64
- throw new Error(`IN-list expansion slot ${i} did not bind to an array (got ${v === null ? 'null' : typeof v})`);
65
- }
66
- if (v.length === 0) {
67
- // Empty-array degeneration (dynamic-expansion spec §5): the whole `col IN (?)`
68
- // fragment collapses to the always-false sentinel `1 = 0` — byte-identical to
69
- // litedbmodel v1's DBConditions (an empty IN pushes NO params). The `col IN`
70
- // prefix and the `(?)` slot are BOTH replaced.
71
- sql = '1 = 0';
72
- // no params pushed for this slot
73
- }
74
- else {
75
- // Replace the single `(?)` with `(?, ?, …)` sized to the array; push each element.
76
- sql = sql.replace('(?)', `(${v.map(() => '?').join(', ')})`);
77
- for (const el of v)
78
- params.push(el);
79
- }
80
- }
81
- else {
82
- params.push(v);
83
- }
84
- }
85
- return sql;
86
- }
87
- /**
88
- * Render a fragment tree into a WHERE clause body (no leading ` WHERE ` keyword).
89
- * Present fragments are joined by ` <connector> `; a nested tree is parenthesized
90
- * (spec §4). Returns the empty string when NO fragment is present (degeneration, §3).
91
- *
92
- * Each fragment's `sql` already carries its own leading connector prefix when authored as
93
- * a chained condition (e.g. `" AND status = ?"`), so this function STRIPS the accumulated
94
- * connector from the first present fragment to avoid a dangling leading `AND`/`OR`, then
95
- * joins the rest as-authored. To keep the golden output identical to litedbmodel v1 (which
96
- * builds `parts.join(' AND ')` with no leading connector), fragment `sql` at the top level
97
- * is authored WITHOUT a leading connector and joined here.
98
- */
99
- function renderTree(tree, scope, params) {
100
- const parts = [];
101
- for (const node of tree.fragments) {
102
- if (isTree(node)) {
103
- const inner = renderTree(node, scope, params);
104
- if (inner !== '')
105
- parts.push(`(${inner})`);
106
- }
107
- else if (fragmentPresent(node, scope)) {
108
- parts.push(renderFragment(node, scope, params));
109
- }
110
- }
111
- if (parts.length === 0)
112
- return '';
113
- return parts.join(` ${tree.connector} `);
114
- }
115
- /**
116
- * Render a compiled operation to final SQLite SQL + params for a bound input scope.
117
- *
118
- * Param order (matches SQL text order, dynamic-expansion spec §6): the compiled `sql`
119
- * splices the WHERE tree at `{where}`; static params before the marker are emitted first,
120
- * then the fragment params in tree order, then static params after the marker. WS1's CRUD
121
- * shapes place all pre-WHERE statics (Insert values, Update SET) before `{where}` and all
122
- * post-WHERE statics (LIMIT / OFFSET) after — so a single left-to-right walk of the
123
- * spliced SQL yields the canonical `?` order.
124
- */
125
- function renderOperation(op, input, dialect = dialect_1.SQLITE) {
126
- const params = [];
127
- const markerIdx = op.sql.indexOf(ir_1.WHERE_SLOT);
128
- if (markerIdx === -1) {
129
- // No dynamic WHERE: all params are static, in position order.
130
- for (const slot of op.params)
131
- params.push((0, behavior_contracts_1.evaluateExpression)(slot, input));
132
- return { sql: finalize(op.sql, dialect), params };
133
- }
134
- const before = op.sql.slice(0, markerIdx);
135
- const after = op.sql.slice(markerIdx + ir_1.WHERE_SLOT.length);
136
- // Static params are partitioned by whether their `?` sits before or after the marker.
137
- const beforeQ = countPlaceholders(before);
138
- const preStatics = op.params.slice(0, beforeQ);
139
- const postStatics = op.params.slice(beforeQ);
140
- for (const slot of preStatics)
141
- params.push((0, behavior_contracts_1.evaluateExpression)(slot, input));
142
- let whereSql = '';
143
- if (op.where !== null) {
144
- const body = renderTree(op.where, input, params);
145
- if (body !== '')
146
- whereSql = ` WHERE ${body}`; // degeneration §3: drop keyword when empty
147
- }
148
- for (const slot of postStatics)
149
- params.push((0, behavior_contracts_1.evaluateExpression)(slot, input));
150
- return { sql: finalize(before + whereSql + after, dialect), params };
151
- }
152
- /**
153
- * Apply the dialect's final placeholder pass over the FULLY-assembled SQL text (spec §8): for
154
- * Postgres this converts `?`→`$1,$2,…` in ONE left-to-right pass (the number-reassignment
155
- * problem is designed out — it runs once, after IN-list expansion + fragment splicing are all
156
- * done); for SQLite/MySQL it is identity. This is the single place the `?`→`$N` conversion
157
- * happens, so `params` order (already position-ordered by the walk above) matches `$N` order.
158
- */
159
- function finalize(sql, dialect) {
160
- return dialect.finalizePlaceholders(sql);
161
- }
162
- /** Count `?` placeholders in a static SQL segment (no fragment markers present). */
163
- function countPlaceholders(sql) {
164
- let n = 0;
165
- for (const ch of sql)
166
- if (ch === '?')
167
- n++;
168
- return n;
169
- }
170
- //# sourceMappingURL=render.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/scp/render.ts"],"names":[],"mappings":"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"}
@@ -1,161 +0,0 @@
1
- /**
2
- * litedbmodel v2 SCP — write-time relations → ordered SQL transaction plan (WS5, #25; spec §6).
3
- *
4
- * Derives a declarative {@link LifecycleContract} (the §6 effect arrays) + a base write op
5
- * (the Command's `Insert`/`Update`/`Delete`, e.g. `Insert(Post, {onWrite: Post.writes.create})`)
6
- * into ONE ordered, gate-first multi-statement transaction plan — exactly the §6 example:
7
- *
8
- * ```
9
- * BEGIN;
10
- * -- Gate First (short-circuit + ROLLBACK before any body write)
11
- * requires: SELECT 1 FROM users WHERE id = :author_id; -- absent ⇒ fail
12
- * idempotency: INSERT INTO idem(token) VALUES(:request_id); -- duplicate ⇒ short-circuit
13
- * unique: INSERT INTO uniq(...) ON CONFLICT DO NOTHING; … -- collision ⇒ fail
14
- * -- Body
15
- * INSERT INTO posts(author_id,title) VALUES(:author_id,:title) RETURNING id;
16
- * derive: UPDATE users SET post_count = post_count + 1 WHERE id = :author_id;
17
- * edges: … (M:N intermediate INSERT/DELETE or 1:N FK UPDATE) …
18
- * emits: INSERT INTO outbox(type,payload) VALUES('PostCreated', :payload);
19
- * COMMIT;
20
- * ```
21
- *
22
- * The plan is PURE JSON (each statement is a WS1 {@link CompiledOperation} rendered by the
23
- * SAME {@link import('./render').renderOperation}), so it serializes into the §8 bundle and a
24
- * thin per-language runtime honors the SAME ordering + gate-first (no re-derivation, spec §6:
25
- * "多言語 runtime は同一計画を honor"). `Transaction` は公開仕様にしない — this plan is DERIVED
26
- * from the Command's declared intent, never authored.
27
- *
28
- * ## Gate-first is a real execution behavior, not a text ordering (spec §6 "Gate First")
29
- *
30
- * Each gate statement carries a {@link GateRule} the runtime evaluates AFTER executing it: a
31
- * failing gate short-circuits — the remaining statements (body + derive + edges + emits) never
32
- * execute and the transaction ROLLBACKs. This is semantically-invariant early termination
33
- * ({@link import('./write-runtime').executeTransaction} proves it with real query counts + DB state).
34
- *
35
- * ## Path lowering (spec §6) — `$.input.*` / `$.entity.*` → closed-set Expression IR
36
- *
37
- * A `$.input.<field>` value lowers to `{ref:['<field>']}` (bc flat input scope); a
38
- * `$.entity.<field>` value lowers to `{ref:['__entity','<field>']}` (the body write's
39
- * RETURNING row, exposed to the derive/edges/emits stages under {@link ENTITY_ROOT}). Only
40
- * bc's closed operator set (`ref`) is emitted — no invented opcode (hard rule).
41
- *
42
- * ## Transaction derivation (spec §6 / §14) — tx-DAG + gate-first
43
- *
44
- * A Command carries one or more named base writes, each with its §6 effects. Statements form a
45
- * data-dependency DAG (`$.ref.<writeName>.<field>` consumes an earlier write's RETURNING row,
46
- * exposed via `TxStatement.binds`), with a gate-first constraint (every gate precedes every
47
- * body/derive/edge/emit). The DAG is topologically ordered (Kahn, stable ascending declaration
48
- * `seq` tie-break) into a single-transaction statement plan. Underivable shapes (dependency
49
- * cycle, dangling `$.ref`, referenced write without RETURNING, duplicate bind, composite
50
- * `$.entity`) are LOUD rejects — never a silently mis-ordered plan.
51
- */
52
- import type { CompiledOperation } from './ir';
53
- import { type Dialect } from './dialect';
54
- import { type LifecycleContract, type LifecycleEffects, type WriteLifecyclePhase } from './writes';
55
- /** The role a transaction statement plays (drives the runtime's gate-first interpretation). */
56
- export type StatementRole = 'gate:requires' | 'gate:idempotency' | 'gate:unique' | 'body' | 'derive' | 'edge' | 'emit';
57
- /**
58
- * The gate rule the runtime evaluates on a gate statement's result to decide short-circuit
59
- * (spec §6 "Gate First"):
60
- * - `existsElseRollback` — the statement is a `SELECT 1 …` existence probe; ZERO rows ⇒
61
- * the required row is absent ⇒ short-circuit + ROLLBACK (`requires`).
62
- * - `insertedElseRollback` — the statement is a guard `INSERT … ON CONFLICT DO NOTHING`;
63
- * ZERO affected rows ⇒ a collision ⇒ short-circuit + ROLLBACK (`unique`).
64
- * - `insertedElseNoop` — the statement is an idempotency-token `INSERT … ON CONFLICT DO
65
- * NOTHING`; ZERO affected rows ⇒ a DUPLICATE request ⇒ short-circuit WITHOUT error
66
- * (idempotent: the prior write already happened; the tx commits the no-op / rolls back
67
- * the empty body per {@link TransactionPlan.onIdempotentHit}).
68
- */
69
- export type GateRule = 'existsElseRollback' | 'insertedElseRollback' | 'insertedElseNoop';
70
- /** One ordered statement of a transaction plan (pure JSON — a WS1 compiled op + its role). */
71
- export interface TxStatement {
72
- /** Stable statement id (ordering key + diagnostics). */
73
- readonly id: string;
74
- /** The statement's role in the §6 derivation order. */
75
- readonly role: StatementRole;
76
- /** The compiled SQL op (rendered by the normative {@link import('./render').renderOperation}). */
77
- readonly op: CompiledOperation;
78
- /** For a gate statement: the short-circuit rule. Absent for body/derive/edge/emit. */
79
- readonly gate?: GateRule;
80
- /**
81
- * For a composite (multi-write) body statement: the scope binding under which THIS statement's
82
- * RETURNING row is exposed to LATER statements — a downstream `$.ref.<binds>.<field>` resolves
83
- * to `scope[<binds>][<field>]` (spec §6 nested write). This is the DAG's data-dependency edge,
84
- * self-describing so the 5 runtimes just bind the row and continue (no re-derivation). Absent for
85
- * a statement no later statement depends on; the WS5 single-base write additionally exposes its
86
- * row under {@link TransactionPlan.entityFrom} / {@link ENTITY_ROOT} for `$.entity.*` back-compat.
87
- */
88
- readonly binds?: string;
89
- /** Human label (diagnostics; e.g. `requires users`, `derive users.post_count`). */
90
- readonly label: string;
91
- }
92
- /** How the runtime resolves an idempotency short-circuit hit (a duplicate request). */
93
- export type IdempotentHitPolicy = 'rollback';
94
- /**
95
- * A derived write-time-relations transaction plan (spec §6 / §8 `transaction plan`). Pure JSON:
96
- * ordered statements + gate-first rules + the body-write's `entity` exposure. Serializes into
97
- * the §8 bundle so a WS7 runtime executes the SAME plan.
98
- */
99
- export interface TransactionPlan {
100
- /** The lifecycle phase this plan realizes (`create` / `update` / `remove`). */
101
- readonly phase: WriteLifecyclePhase;
102
- /**
103
- * The statement id whose RETURNING row is exposed to later stages under `$.entity.*`
104
- * ({@link ENTITY_ROOT}). Always the body write. `null` when the body has no RETURNING
105
- * (then no later stage may reference `$.entity.*` — validated at derivation time).
106
- */
107
- readonly entityFrom: string | null;
108
- /** The ordered statements (gate-first, then body, then derive/edges/emits). */
109
- readonly statements: readonly TxStatement[];
110
- /** What a duplicate-idempotency-token short-circuit does (α: rollback the empty tx). */
111
- readonly onIdempotentHit: IdempotentHitPolicy;
112
- }
113
- /**
114
- * The base write op the Command declares (`Insert`/`Update`/`Delete` with `onWrite`). This is
115
- * the Command body statement the plan wraps in a transaction. A Command may declare ONE base
116
- * write (WS5 single-statement scope) OR several (WS8a composite / nested write, spec §6:
117
- * "多対多や nested write(親作成と同時に子作成)は edges/追加 write で表現し、同一 tx にまとめる").
118
- */
119
- export interface BaseWrite {
120
- /** The compiled base write op (from the bridge, e.g. `compileNode` of the Insert node). */
121
- readonly op: CompiledOperation;
122
- /** The body statement's role (always `body`). */
123
- readonly label: string;
124
- /**
125
- * The write's stable NAME (WS8a composite scope) — later statements reference its RETURNING row
126
- * as `$.ref.<name>.<field>`, and the derived body statement `binds` this name. Omitted for the
127
- * WS5 single-base write (its row is addressed as `$.entity.*` under {@link ENTITY_ROOT}).
128
- */
129
- readonly name?: string;
130
- /**
131
- * The write's OWN save-contract effects (WS8a composite scope): its gates/derive/edges/emits.
132
- * For the WS5 single-base write, the lifecycle is passed as the top-level `lifecycle` arg and
133
- * this is omitted. When a base write carries `effects`, the derivation treats it as one DAG
134
- * node group (its gates → its body → its after-effects), then topologically orders ALL groups.
135
- */
136
- readonly effects?: LifecycleEffects;
137
- }
138
- /**
139
- * Derive the ORDERED, gate-first {@link TransactionPlan} from a Command's base write(s) + its
140
- * lifecycle save contract (spec §6 / §14).
141
- *
142
- * ## Single base write (WS5 scope)
143
- *
144
- * One base write + a top-level `lifecycle`; the order is the fixed §6 group
145
- * (requires → idempotency → unique → BODY → derive → edges → emits). `$.entity.*` references in
146
- * derive/edges/emits require the body write to RETURN the entity row (else a loud build error).
147
- *
148
- * ## Composite / nested write (WS8a scope) — real DAG derivation
149
- *
150
- * Multiple base writes, each carrying its OWN {@link BaseWrite.effects} and a `name`. A later
151
- * write references an earlier write's RETURNING row via `$.ref.<name>.<field>` (e.g. a child
152
- * INSERT keyed by the parent's returned id). The derivation builds the data-dependency graph
153
- * (statement → the writes it references) + the gate-first constraint, TOPOLOGICALLY orders it
154
- * (deterministic, stable tie-break), and emits ONE ordered gate-first transaction plan. A cycle
155
- * or dangling reference is ESCALATED (no silent mis-derivation).
156
- *
157
- * @throws if a `$.entity.*` reference lacks a RETURNING body, a `$.ref.*` is dangling, two writes
158
- * bind the same name, or the dependency graph has a cycle.
159
- */
160
- export declare function deriveTransactionPlan(phase: WriteLifecyclePhase, bases: readonly BaseWrite[], lifecycle: LifecycleContract, dialect?: Dialect): TransactionPlan;
161
- //# sourceMappingURL=write-plan.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"write-plan.d.ts","sourceRoot":"","sources":["../../src/scp/write-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAY,MAAM,MAAM,CAAC;AAGxD,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAOL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EAGrB,KAAK,mBAAmB,EACzB,MAAM,UAAU,CAAC;AAElB,+FAA+F;AAC/F,MAAM,MAAM,aAAa,GACrB,eAAe,GACf,kBAAkB,GAClB,aAAa,GACb,MAAM,GACN,QAAQ,GACR,MAAM,GACN,MAAM,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,QAAQ,GAAG,oBAAoB,GAAG,sBAAsB,GAAG,kBAAkB,CAAC;AAE1F,8FAA8F;AAC9F,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,kGAAkG;IAClG,QAAQ,CAAC,EAAE,EAAE,iBAAiB,CAAC;IAC/B,sFAAsF;IACtF,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IACzB;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,uFAAuF;AACvF,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,EAAE,SAAS,WAAW,EAAE,CAAC;IAC5C,wFAAwF;IACxF,QAAQ,CAAC,eAAe,EAAE,mBAAmB,CAAC;CAC/C;AAiMD;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,EAAE,iBAAiB,CAAC;IAC/B,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAuJD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,SAAS,EAAE,iBAAiB,EAC5B,OAAO,GAAE,OAAgB,GACxB,eAAe,CA2DjB"}