litedbmodel 2.2.2 → 2.2.4

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 (180) hide show
  1. package/README.md +2 -1
  2. package/dist/DBModel.d.ts.map +1 -1
  3. package/dist/DBModel.js +3 -0
  4. package/dist/DBModel.js.map +1 -1
  5. package/dist/Middleware.d.ts +19 -2
  6. package/dist/Middleware.d.ts.map +1 -1
  7. package/dist/Middleware.js +1 -0
  8. package/dist/Middleware.js.map +1 -1
  9. package/dist/decorators.d.ts.map +1 -1
  10. package/dist/decorators.js +8 -0
  11. package/dist/decorators.js.map +1 -1
  12. package/dist/drivers/MysqlHelper.d.ts +1 -1
  13. package/dist/drivers/MysqlHelper.d.ts.map +1 -1
  14. package/dist/drivers/MysqlHelper.js.map +1 -1
  15. package/dist/drivers/PostgresHelper.d.ts +1 -1
  16. package/dist/drivers/PostgresHelper.d.ts.map +1 -1
  17. package/dist/drivers/PostgresHelper.js.map +1 -1
  18. package/dist/drivers/SqliteHelper.d.ts +1 -1
  19. package/dist/drivers/SqliteHelper.d.ts.map +1 -1
  20. package/dist/drivers/SqliteHelper.js.map +1 -1
  21. package/dist/index.cjs +105 -74
  22. package/dist/scp/connection-routing.d.ts +38 -1
  23. package/dist/scp/connection-routing.d.ts.map +1 -1
  24. package/dist/scp/connection-routing.js +64 -5
  25. package/dist/scp/connection-routing.js.map +1 -1
  26. package/dist/scp/dbmodel-runtime.d.ts +2 -1
  27. package/dist/scp/dbmodel-runtime.d.ts.map +1 -1
  28. package/dist/scp/dbmodel-runtime.js +2 -1
  29. package/dist/scp/dbmodel-runtime.js.map +1 -1
  30. package/dist/scp/decorator-adapter.d.ts +22 -0
  31. package/dist/scp/decorator-adapter.d.ts.map +1 -1
  32. package/dist/scp/decorator-adapter.js +26 -0
  33. package/dist/scp/decorator-adapter.js.map +1 -1
  34. package/dist/scp/emit/emitter.d.ts +21 -10
  35. package/dist/scp/emit/emitter.d.ts.map +1 -1
  36. package/dist/scp/emit/emitter.js +119 -51
  37. package/dist/scp/emit/emitter.js.map +1 -1
  38. package/dist/scp/emit/endpoint.d.ts +3 -8
  39. package/dist/scp/emit/endpoint.d.ts.map +1 -1
  40. package/dist/scp/exec-context.d.ts +39 -17
  41. package/dist/scp/exec-context.d.ts.map +1 -1
  42. package/dist/scp/exec-context.js +69 -35
  43. package/dist/scp/exec-context.js.map +1 -1
  44. package/dist/scp/grouping.d.ts.map +1 -1
  45. package/dist/scp/grouping.js +0 -0
  46. package/dist/scp/grouping.js.map +1 -1
  47. package/dist/scp/index.cjs +257 -670
  48. package/dist/scp/index.d.ts +6 -11
  49. package/dist/scp/index.d.ts.map +1 -1
  50. package/dist/scp/index.js +10 -28
  51. package/dist/scp/index.js.map +1 -1
  52. package/dist/scp/index.mjs +257 -658
  53. package/dist/scp/leaf-transport.d.ts +127 -39
  54. package/dist/scp/leaf-transport.d.ts.map +1 -1
  55. package/dist/scp/leaf-transport.js +30 -24
  56. package/dist/scp/leaf-transport.js.map +1 -1
  57. package/dist/scp/leaves.d.ts +57 -20
  58. package/dist/scp/leaves.d.ts.map +1 -1
  59. package/dist/scp/leaves.js +224 -65
  60. package/dist/scp/leaves.js.map +1 -1
  61. package/dist/scp/makesql/compile-select.d.ts +28 -1
  62. package/dist/scp/makesql/compile-select.d.ts.map +1 -1
  63. package/dist/scp/makesql/compile-select.js +19 -17
  64. package/dist/scp/makesql/compile-select.js.map +1 -1
  65. package/dist/scp/makesql/index.d.ts +2 -2
  66. package/dist/scp/makesql/index.d.ts.map +1 -1
  67. package/dist/scp/makesql/index.js +4 -6
  68. package/dist/scp/makesql/index.js.map +1 -1
  69. package/dist/scp/makesql/tx.d.ts +43 -89
  70. package/dist/scp/makesql/tx.d.ts.map +1 -1
  71. package/dist/scp/makesql/tx.js +45 -496
  72. package/dist/scp/makesql/tx.js.map +1 -1
  73. package/dist/scp/makesql/writeouttype.d.ts +5 -7
  74. package/dist/scp/makesql/writeouttype.d.ts.map +1 -1
  75. package/dist/scp/makesql/writeouttype.js +13 -19
  76. package/dist/scp/makesql/writeouttype.js.map +1 -1
  77. package/dist/scp/middleware.d.ts +4 -4
  78. package/dist/scp/middleware.d.ts.map +1 -1
  79. package/dist/scp/middleware.js +2 -2
  80. package/dist/scp/middleware.js.map +1 -1
  81. package/dist/scp/relation.d.ts +31 -12
  82. package/dist/scp/relation.d.ts.map +1 -1
  83. package/dist/scp/relation.js +16 -6
  84. package/dist/scp/relation.js.map +1 -1
  85. package/dist/scp/typed-object.d.ts +23 -19
  86. package/dist/scp/typed-object.d.ts.map +1 -1
  87. package/dist/scp/typed-object.js +24 -30
  88. package/dist/scp/typed-object.js.map +1 -1
  89. package/dist/scp/write-bundle.d.ts +21 -70
  90. package/dist/scp/write-bundle.d.ts.map +1 -1
  91. package/dist/scp/write-bundle.js +16 -80
  92. package/dist/scp/write-bundle.js.map +1 -1
  93. package/dist/types.d.ts +12 -0
  94. package/dist/types.d.ts.map +1 -1
  95. package/dist/types.js.map +1 -1
  96. package/docs/BENCHMARK.md +26 -22
  97. package/docs/COMPARISON.md +8 -4
  98. package/docs/api/README.md +1 -1
  99. package/docs/api/classes/Conditions.md +10 -10
  100. package/docs/api/classes/DBHandler.md +17 -17
  101. package/docs/api/classes/DBModel.md +111 -104
  102. package/docs/api/classes/LimitExceededError.md +8 -8
  103. package/docs/api/classes/Middleware.md +18 -18
  104. package/docs/api/classes/SqlRaw.md +6 -6
  105. package/docs/api/classes/SqlRef.md +7 -7
  106. package/docs/api/classes/Values.md +6 -6
  107. package/docs/api/classes/WriteInReadOnlyContextError.md +5 -5
  108. package/docs/api/classes/WriteOutsideTransactionError.md +5 -5
  109. package/docs/api/functions/belongsTo.md +2 -2
  110. package/docs/api/functions/closeAllPools.md +2 -2
  111. package/docs/api/functions/condsToRecord.md +2 -2
  112. package/docs/api/functions/createMiddleware.md +2 -2
  113. package/docs/api/functions/createPostgresDriver.md +2 -2
  114. package/docs/api/functions/createSqliteDriver.md +2 -2
  115. package/docs/api/functions/dbCast.md +3 -3
  116. package/docs/api/functions/dbCastIn.md +2 -2
  117. package/docs/api/functions/dbDynamic.md +3 -3
  118. package/docs/api/functions/dbFalse.md +2 -2
  119. package/docs/api/functions/dbImmediate.md +2 -2
  120. package/docs/api/functions/dbIn.md +2 -2
  121. package/docs/api/functions/dbNotNull.md +2 -2
  122. package/docs/api/functions/dbNow.md +2 -2
  123. package/docs/api/functions/dbNull.md +2 -2
  124. package/docs/api/functions/dbRaw.md +2 -2
  125. package/docs/api/functions/dbTrue.md +2 -2
  126. package/docs/api/functions/dbUuid.md +3 -3
  127. package/docs/api/functions/dbUuidIn.md +2 -2
  128. package/docs/api/functions/formatLocalDate.md +25 -0
  129. package/docs/api/functions/formatUTCDate.md +25 -0
  130. package/docs/api/functions/getDBConfig.md +2 -2
  131. package/docs/api/functions/getDBHandler.md +2 -2
  132. package/docs/api/functions/getTransactionConnection.md +2 -2
  133. package/docs/api/functions/getTransactionContext.md +2 -2
  134. package/docs/api/functions/hasMany.md +2 -2
  135. package/docs/api/functions/hasOne.md +2 -2
  136. package/docs/api/functions/initDBHandler.md +2 -2
  137. package/docs/api/functions/isAnySqlFragment.md +2 -2
  138. package/docs/api/functions/isConnectionError.md +26 -0
  139. package/docs/api/functions/isSqlCondition.md +2 -2
  140. package/docs/api/functions/isSqlFragment.md +2 -2
  141. package/docs/api/functions/isSqlRaw.md +2 -2
  142. package/docs/api/functions/isSqlRef.md +2 -2
  143. package/docs/api/functions/isSqlTypedFragment.md +2 -2
  144. package/docs/api/functions/model.md +6 -42
  145. package/docs/api/functions/parentRef.md +2 -2
  146. package/docs/api/functions/sql.md +7 -7
  147. package/docs/api/globals.md +57 -22
  148. package/docs/api/interfaces/Column.md +31 -31
  149. package/docs/api/interfaces/ColumnOptions.md +5 -4
  150. package/docs/api/interfaces/CreatedMiddlewareClass.md +7 -7
  151. package/docs/api/interfaces/DBConfig.md +13 -11
  152. package/docs/api/interfaces/DBConfigOptions.md +8 -8
  153. package/docs/api/interfaces/DeleteOptions.md +4 -4
  154. package/docs/api/interfaces/InsertOptions.md +8 -8
  155. package/docs/api/interfaces/LimitConfig.md +4 -4
  156. package/docs/api/interfaces/MiddlewareConfig.md +15 -15
  157. package/docs/api/interfaces/ModelOptions.md +8 -7
  158. package/docs/api/interfaces/PkeyResult.md +4 -4
  159. package/docs/api/interfaces/SelectOptions.md +17 -16
  160. package/docs/api/interfaces/SqlCondition.md +6 -6
  161. package/docs/api/interfaces/SqlFragment.md +5 -5
  162. package/docs/api/interfaces/SqlTypedFragment.md +7 -7
  163. package/docs/api/interfaces/TransactionOptions.md +7 -7
  164. package/docs/api/interfaces/UpdateManyOptions.md +4 -4
  165. package/docs/api/interfaces/UpdateOptions.md +4 -4
  166. package/docs/architecture.md +452 -0
  167. package/docs/benchmark-chart.svg +225 -249
  168. package/docs/design/phase-a-execution-context.md +2 -0
  169. package/package.json +20 -5
  170. package/dist/scp/writes.d.ts +0 -251
  171. package/dist/scp/writes.d.ts.map +0 -1
  172. package/dist/scp/writes.js +0 -176
  173. package/dist/scp/writes.js.map +0 -1
  174. package/docs/proposal/contracts-architecture-feasibility.md +0 -328
  175. package/docs/proposal/contracts-architecture.md +0 -579
  176. package/docs/proposal/litedbmodel-v2-scp-architecture.md +0 -433
  177. package/docs/proposal/sql-dynamic-expansion-spec.md +0 -175
  178. package/docs/proposal/v0-coverage-matrix.md +0 -157
  179. package/docs/proposal/v2-completeness-plan.md +0 -90
  180. package/docs/proposal/v2-sql-parity-checklist.md +0 -162
@@ -20,45 +20,76 @@
20
20
  * type. A relation op therefore runs `executeSQL → pluck → executeSQL → … → group` entirely on the
21
21
  * wire plane and materializes the whole nested typed graph exactly once, at the end.
22
22
  *
23
- * The two CONTROL ports — {@link DynamicWherePlan} (`whereDynamic`) and {@link CapGuard} (`guard`) —
24
- * are CONCRETE STRUCTS the emitter CONSTRUCTS at the call site from the endpoint's own parameters (not
25
- * leaf→leaf wire values), so a native-codegen emitter builds them as typed structs. They are OPTIONAL:
26
- * only a read with a SKIP predicate carries `whereDynamic`, only a guarded relation child carries
27
- * `guard` — a bounded read, a write, and an uncapped fetch OMIT them (native-clean, CLAUDE.md §2 "only
28
- * actually-optional predicates accumulate a plan"). bc typed-native lowers a NON-NULL struct into an
29
- * `opt<named>` port via `optSome` (bc#275), so a concrete optional port is native — no boxing, and no
30
- * empty plan carried on every statement. The fragment vocabulary is CLAUDE.md §2's: SQL + params + a
31
- * SKIP FLAG (a homogeneous `{skipped, sql, params}` struct), assembled by the leaf at run — never a
32
- * `cond`-to-null variant element (which the native-codegen emitters reject).
23
+ * Everything a statement carries BESIDES its text and its bound values rides in ONE optional CONTROL
24
+ * struct, {@link ExecOptions} (`opts`): WHICH database it runs on (`db`), how to run it (`write` /
25
+ * `returning`) and the two CONCRETE control structs — {@link DynamicWherePlan} (`whereDynamic`) and
26
+ * {@link CapGuard} (`guard`) — the
27
+ * emitter CONSTRUCTS at the call site from the endpoint's own parameters (not leaf→leaf wire values),
28
+ * so a native-codegen emitter builds them as typed structs. It is ONE argument because a mode flag is a
29
+ * NAMED FIELD there: a positional list grows a new slot per fact and every call site's remaining
30
+ * arguments shift (#193), and a trailing optional port can only be reached by passing a filler for the
31
+ * one before it. A PLAIN READ omits `opts` entirely (native-clean — the payload carries `sql`/`params`
32
+ * and nothing else); every other statement spells the whole record, so absence is `null` (a fact) and
33
+ * never a stand-in value. bc typed-native lowers a NON-NULL struct into an `opt<named>` port via
34
+ * `optSome` (bc#275), so a concrete optional port is native — no boxing. The fragment vocabulary is
35
+ * CLAUDE.md §2's: SQL + params + a SKIP FLAG (a homogeneous `{skipped, sql, params}` struct), assembled
36
+ * by the leaf at run — never a `cond`-to-null variant element (which the native-codegen emitters reject).
33
37
  */
34
38
  import { type Int, type WireValue } from 'behavior-contracts';
35
39
  /**
36
- * ONE dynamic-WHERE fragment: the fragment's SQL text and its bound `params`, plus a SKIP FLAG. The
37
- * fragment vocabulary CLAUDE.md §2 fixes — "SQL text + params + SKIP flag" and nothing else. `skipped`
38
- * carries the per-call SKIP decision as DATA (a bounded predicate is always `false`; an optional one is
39
- * `param === null`), so every element of a plan is the SAME struct — never a `cond`-to-null variant,
40
- * which the native-codegen emitters reject. `params` rides opaque (`WireValue[]`) exactly like the base
41
- * `params` port; the leaf binds them in order. The runtime side ({@link import('./leaves')}) READS this
42
- * struct — it never constructs one — so the one definition serves both the emitter's authored literal
43
- * and the leaf's runtime assembly.
40
+ * ONE dynamic-WHERE fragment — always an OPTIONAL predicate's, never a bounded one's (a bounded
41
+ * predicate is lowered into the statement's static WHERE at emit, CLAUDE.md §2). The fragment
42
+ * vocabulary that §2 fixes: the fragment's SQL text, its bound `params`, and a SKIP FLAG — nothing
43
+ * else. `skipped` carries the per-call SKIP decision as DATA (`param === null`), so every element of a
44
+ * plan is the SAME struct — never a `cond`-to-null variant, which the native-codegen emitters reject.
45
+ * `params` rides opaque (`WireValue[]`) exactly like the base `params` port; the leaf binds them in
46
+ * order. The runtime side ({@link import('./leaves')}) READS this struct — it never constructs one — so
47
+ * the one definition serves both the emitter's authored literal and the leaf's runtime assembly.
44
48
  */
45
49
  export interface DynamicWhereFrag {
46
50
  readonly skipped: boolean;
47
51
  readonly sql: string;
48
52
  /**
49
- * The fragment's bound params (`WireValue`), the SAME order the fragment's `?`s appear. An OPTIONAL
50
- * predicate binds its own parameter, which is `null` exactly when the predicate is SKIPPED — so the
51
- * element is `WireValue | null`; a skipped fragment's params are never bound (the leaf drops it), so
52
- * the null is inert. A bounded predicate's params are non-null.
53
+ * The fragment's bound params (`WireValue`), the SAME order the fragment's `?`s appear. The predicate
54
+ * binds its own parameter, which is `null` exactly when the fragment is SKIPPED — so the element is
55
+ * `WireValue | null`; a skipped fragment's params are never bound (the leaf drops it), so the null is
56
+ * inert.
53
57
  */
54
58
  readonly params: (WireValue | null)[];
55
59
  }
56
60
  /**
57
- * The dynamic-WHERE plan a SKIP read carries (OPTIONAL — a bounded read omits it): a HOMOGENEOUS
58
- * fragment list the leaf assembles at run, dropping the `skipped` fragments.
61
+ * The dynamic-WHERE plan a SKIP read carries (OPTIONAL — a read with no optional predicate omits it): a
62
+ * HOMOGENEOUS fragment list the leaf assembles at run, dropping the `skipped` fragments and continuing
63
+ * the statement's static WHERE with the survivors.
64
+ *
65
+ * When a plan is present the statement's `sql`/`params` ports carry only its HEAD — the text up to the
66
+ * end of its WHERE region — and the plan carries everything needed to finish it. That split comes from
67
+ * the emitter's own SELECT builder ({@link import('./makesql/compile-select').SelectBundle}), which knows
68
+ * the boundary because it is the code that puts the WHERE there. The leaf therefore CONCATENATES
69
+ * (`head` + the survivors + `tail`) and never SCANS: a scan of the finished statement mistakes a nested
70
+ * statement's tail keyword for the outer one's (#198) and counts a quoted `?` the placeholder render
71
+ * skips (#202), and a scan-derived byte OFFSET is not even the same number in five languages.
59
72
  */
60
73
  export interface DynamicWherePlan {
61
74
  readonly frags: readonly DynamicWhereFrag[];
75
+ /**
76
+ * How the FIRST surviving fragment joins the head: `'AND'` when the head ends in a static WHERE (its
77
+ * BOUNDED predicates, lowered at emit — CLAUDE.md §2), `'WHERE'` when it carries none. Further
78
+ * survivors always join with `AND`, which is the leaf's own separator.
79
+ */
80
+ readonly lead: string;
81
+ /**
82
+ * The statement text that follows the WHERE region — ` GROUP BY …` / ` ORDER BY …` / the page / the
83
+ * row lock / a raw append tail, `''` when the statement ends at its WHERE. Appended VERBATIM after the
84
+ * assembled clause.
85
+ */
86
+ readonly tail: string;
87
+ /**
88
+ * The params `tail`'s own placeholders bind (a bound ` LIMIT ?` then ` OFFSET ?`), which are therefore
89
+ * the LAST values of the effective statement — after the head's and the survivors'. Carrying them
90
+ * separately is what removes the `?`-counting arithmetic: there is no position to compute.
91
+ */
92
+ readonly tailParams: WireValue[];
62
93
  }
63
94
  /**
64
95
  * The relation runaway cap a GUARDED child fetch carries — the bc wire-construction twin of the runtime
@@ -67,13 +98,68 @@ export interface DynamicWherePlan {
67
98
  * SEPARATE type on purpose: `limit` is bc's `Int` brand so the native struct field is an integer (a
68
99
  * plain `number` would emit as a float and the wire int-probe would miss it), whereas the runtime
69
100
  * `RelationGuard` is `number`-typed because it is CONSTRUCTED from `resolveHasManyHardLimit`'s plain
70
- * numbers — the two cannot be one type. `model` is optional exactly as `LimitExceededError.model` is.
101
+ * numbers — the two cannot be one type. `model` names the capped relation's target table, the identity
102
+ * `LimitExceededError` reports. On the WIRE its key is always spelled — bc types a port by the literal
103
+ * wired into it and rejects a partial struct — so "no model" rides as `null`, and every language
104
+ * transport reads the key fail-closed rather than defaulting an absent one.
71
105
  */
72
106
  export interface CapGuard {
73
107
  readonly limit: Int;
74
- readonly model?: string;
108
+ readonly model: string | null;
75
109
  readonly relation: string;
76
110
  }
111
+ /**
112
+ * EVERYTHING a statement carries besides its text and its bound values — the ONE optional control
113
+ * argument of {@link Db.executeSQL}. A plain read OMITS it; every other statement spells the WHOLE
114
+ * record, because bc types a port by the literal wired into it and rejects a partial one
115
+ * (`the value wired into it has type obj{…}` — an omitted field is a different type, not a default).
116
+ * That is the point: absence is the `null` VALUE of a NAMED field, so no call site ever passes a
117
+ * stand-in value to reach the field after it.
118
+ *
119
+ * `write` describes the STATEMENT, not the transport's branch, and it carries its OWN `returning`
120
+ * ({@link WriteMode}) rather than sitting beside a sibling flag: a statement is a read (`null`) or a
121
+ * write, and only a write can say whether it yields rows. A flag PAIR would encode four states for
122
+ * three meanings, and the fourth — "returns rows but is not a write" — has no meaning to reject at
123
+ * run time in five languages; as a nested struct it does not exist to be rejected.
124
+ */
125
+ export interface ExecOptions {
126
+ /**
127
+ * The NAME of the connection (database) this statement runs on — the multi-DB routing key. `null` ⇒
128
+ * the DEFAULT connection, which is every single-DB deployment.
129
+ *
130
+ * It is a STATIC field, not a per-call value: which database a statement belongs to is a property of
131
+ * its MODEL (v1 gives the model that authority through its `createDBBase` handler, and loads a
132
+ * relation on the TARGET model's — `LazyRelation.ts:236`), so the emitter resolves it at emit time
133
+ * from {@link import('./decorator-adapter').connectionOf} and bakes the name in. The transport puts
134
+ * it on the statement's {@link import('./exec-context').StatementIntent}, which is the ONE input
135
+ * `connectionFor` → {@link import('./connection-routing').resolvePool} routes on: the named
136
+ * connection's reader/writer pair is selected FIRST, then the tx-pin / writer-sticky / reader-writer
137
+ * split apply within it. An unregistered name is LOUD — never a silent run against another database,
138
+ * which is exactly what a dropped name did.
139
+ */
140
+ readonly db: string | null;
141
+ /**
142
+ * How the statement RUNS: `null` ⇒ a READ (the `execute` seam, read intent); a {@link WriteMode} ⇒
143
+ * an INSERT/UPDATE/DELETE (the write seam + the write intent), carrying whether it yields rows.
144
+ */
145
+ readonly write: WriteMode | null;
146
+ /** The DYNAMIC (SKIP) WHERE plan — `null` unless the read declares an OPTIONAL predicate. */
147
+ readonly whereDynamic: DynamicWherePlan | null;
148
+ /** The RELATION runaway cap — `null` unless this is a GUARDED relation child fetch. */
149
+ readonly guard: CapGuard | null;
150
+ }
151
+ /**
152
+ * A WRITE statement's own shape — the value of {@link ExecOptions.write} (its absence, `null`, is what
153
+ * makes a statement a read). `returning` is nested HERE because it is only meaningful under a write:
154
+ * a RETURNING write stays on the ROW path, a plain write yields the one-row
155
+ * `[{changes, lastInsertRowid}]` summary instead, which is what keeps the leaf's output shape uniform.
156
+ * bc lowers this exactly as it lowers {@link CapGuard} — an optional concrete struct, native in go and
157
+ * rust with no boxing — so the three statement shapes are three values of ONE field.
158
+ */
159
+ export interface WriteMode {
160
+ /** The write yields ROWS (a RETURNING write) rather than the affected-rows summary. */
161
+ readonly returning: boolean;
162
+ }
77
163
  /**
78
164
  * The three OP-AGNOSTIC leaf transports. The bodies are declaration stubs — `bc generate --from`
79
165
  * reads this source and derives the catalog from the signatures; the executable side is the handler
@@ -82,21 +168,23 @@ export interface CapGuard {
82
168
  */
83
169
  export declare class Db {
84
170
  /**
85
- * The SOLE SQL transport: bind `params` and run `sql` through the central execute/run seam.
86
- * `write` selects `run` (INSERT/UPDATE/DELETE) vs `execute` (SELECT / RETURNING); `returning` keeps
87
- * a RETURNING write on the row path; `bigint` runs the read in exact-integer mode. A non-returning
88
- * write yields the one-row `[{changes, lastInsertRowid}]` summary so the output shape is uniform.
171
+ * The SOLE SQL transport: bind `params` and run `sql` through the central execute/run seam. Its
172
+ * whole control surface is the OPTIONAL {@link ExecOptions} record: `opts.write` is the statement's
173
+ * RUN MODE — `null` selects `execute` (a read), a {@link WriteMode} selects `run`
174
+ * (INSERT/UPDATE/DELETE), and its own `opts.write.returning` keeps a RETURNING write on the row path
175
+ * (`execute`) instead. A non-returning write yields the one-row `[{changes, lastInsertRowid}]`
176
+ * summary so the output shape is uniform. `opts.guard` is the RELATION runaway cap
177
+ * ({@link CapGuard}, the compiled op's own resolved cap) a guarded relation child fetch carries: the
178
+ * transport asserts the fetched row count against it and raises `LimitExceededError` when the batch
179
+ * overruns. It rides HERE because this is where the RAW child rows exist — past `group` the graph is
180
+ * already nested — and because SCP has no throw. `opts.whereDynamic` is the SKIP plan of a read that
181
+ * declares an optional predicate (CLAUDE.md §2 "only actually-optional predicates accumulate a plan").
89
182
  *
90
- * `guard` is the RELATION runaway cap ({@link CapGuard}, the compiled op's own resolved cap) a
91
- * guarded relation child fetch carries: the transport asserts the fetched row count against it and
92
- * raises `LimitExceededError` when the batch overruns. It rides HERE because this is where the RAW
93
- * child rows exist — past `group` the graph is already nested — and because SCP has no throw. Both
94
- * control ports are OPTIONAL: a bounded read, a write, and an uncapped fetch OMIT them (native-clean,
95
- * CLAUDE.md §2 "only actually-optional predicates accumulate a plan") — `whereDynamic` is present only
96
- * on a read with a SKIP predicate, `guard` only on a guarded relation child. bc typed-native lowers an
97
- * `opt<named>` port fed a non-null struct via `optSome` (bc#275), so a concrete OPTIONAL port is native.
183
+ * A PLAIN READ omits `opts` (native-clean: the payload is `sql` + `params`); bc typed-native lowers a
184
+ * non-null struct into the `opt<named>` port via `optSome` (bc#275), so the record is a native struct
185
+ * literal in go / rust with no boxing.
98
186
  */
99
- static executeSQL(sql: string, params: WireValue[], write: boolean, returning: boolean, bigint: boolean, whereDynamic?: DynamicWherePlan | null, guard?: CapGuard | null): WireValue[];
187
+ static executeSQL(sql: string, params: WireValue[], opts?: ExecOptions | null): WireValue[];
100
188
  /** Relation key extraction: the deduped, non-null key set over the ordered key-column tuple `col`. */
101
189
  static pluck(rows: WireValue[], col: string[]): WireValue[];
102
190
  /** Relation shaping: nest `children` under each parent's `into`, matching `child[fk]` to `parent[pk]`. */
@@ -1 +1 @@
1
- {"version":3,"file":"leaf-transport.d.ts","sourceRoot":"","sources":["../../src/scp/leaf-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAQ,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAkBpE;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC;CACvC;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC7C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC;IACpB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,qBAAa,EAAE;IACb;;;;;;;;;;;;;;OAcG;IACG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,gBAAgB,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,EAAE;IAE5L,sGAAsG;IAChG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE;IAEjE,0GAA0G;IACpG,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE;CACxI"}
1
+ {"version":3,"file":"leaf-transport.d.ts","sourceRoot":"","sources":["../../src/scp/leaf-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAQ,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAkBpE;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC;CACvC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,EAAE,CAAC;CAClC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACjC,6FAA6F;IAC7F,QAAQ,CAAC,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC/C,uFAAuF;IACvF,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,uFAAuF;IACvF,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;GAKG;AACH,qBAAa,EAAE;IACb;;;;;;;;;;;;;;;;OAgBG;IACG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EAAE;IAEjG,sGAAsG;IAChG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE;IAEjE,0GAA0G;IACpG,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE;CACxI"}
@@ -21,16 +21,20 @@
21
21
  * type. A relation op therefore runs `executeSQL → pluck → executeSQL → … → group` entirely on the
22
22
  * wire plane and materializes the whole nested typed graph exactly once, at the end.
23
23
  *
24
- * The two CONTROL ports — {@link DynamicWherePlan} (`whereDynamic`) and {@link CapGuard} (`guard`) —
25
- * are CONCRETE STRUCTS the emitter CONSTRUCTS at the call site from the endpoint's own parameters (not
26
- * leaf→leaf wire values), so a native-codegen emitter builds them as typed structs. They are OPTIONAL:
27
- * only a read with a SKIP predicate carries `whereDynamic`, only a guarded relation child carries
28
- * `guard` — a bounded read, a write, and an uncapped fetch OMIT them (native-clean, CLAUDE.md §2 "only
29
- * actually-optional predicates accumulate a plan"). bc typed-native lowers a NON-NULL struct into an
30
- * `opt<named>` port via `optSome` (bc#275), so a concrete optional port is native — no boxing, and no
31
- * empty plan carried on every statement. The fragment vocabulary is CLAUDE.md §2's: SQL + params + a
32
- * SKIP FLAG (a homogeneous `{skipped, sql, params}` struct), assembled by the leaf at run — never a
33
- * `cond`-to-null variant element (which the native-codegen emitters reject).
24
+ * Everything a statement carries BESIDES its text and its bound values rides in ONE optional CONTROL
25
+ * struct, {@link ExecOptions} (`opts`): WHICH database it runs on (`db`), how to run it (`write` /
26
+ * `returning`) and the two CONCRETE control structs — {@link DynamicWherePlan} (`whereDynamic`) and
27
+ * {@link CapGuard} (`guard`) — the
28
+ * emitter CONSTRUCTS at the call site from the endpoint's own parameters (not leaf→leaf wire values),
29
+ * so a native-codegen emitter builds them as typed structs. It is ONE argument because a mode flag is a
30
+ * NAMED FIELD there: a positional list grows a new slot per fact and every call site's remaining
31
+ * arguments shift (#193), and a trailing optional port can only be reached by passing a filler for the
32
+ * one before it. A PLAIN READ omits `opts` entirely (native-clean — the payload carries `sql`/`params`
33
+ * and nothing else); every other statement spells the whole record, so absence is `null` (a fact) and
34
+ * never a stand-in value. bc typed-native lowers a NON-NULL struct into an `opt<named>` port via
35
+ * `optSome` (bc#275), so a concrete optional port is native — no boxing. The fragment vocabulary is
36
+ * CLAUDE.md §2's: SQL + params + a SKIP FLAG (a homogeneous `{skipped, sql, params}` struct), assembled
37
+ * by the leaf at run — never a `cond`-to-null variant element (which the native-codegen emitters reject).
34
38
  */
35
39
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
36
40
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -63,21 +67,23 @@ function declarationStub(leafName, args) {
63
67
  */
64
68
  class Db {
65
69
  /**
66
- * The SOLE SQL transport: bind `params` and run `sql` through the central execute/run seam.
67
- * `write` selects `run` (INSERT/UPDATE/DELETE) vs `execute` (SELECT / RETURNING); `returning` keeps
68
- * a RETURNING write on the row path; `bigint` runs the read in exact-integer mode. A non-returning
69
- * write yields the one-row `[{changes, lastInsertRowid}]` summary so the output shape is uniform.
70
+ * The SOLE SQL transport: bind `params` and run `sql` through the central execute/run seam. Its
71
+ * whole control surface is the OPTIONAL {@link ExecOptions} record: `opts.write` is the statement's
72
+ * RUN MODE — `null` selects `execute` (a read), a {@link WriteMode} selects `run`
73
+ * (INSERT/UPDATE/DELETE), and its own `opts.write.returning` keeps a RETURNING write on the row path
74
+ * (`execute`) instead. A non-returning write yields the one-row `[{changes, lastInsertRowid}]`
75
+ * summary so the output shape is uniform. `opts.guard` is the RELATION runaway cap
76
+ * ({@link CapGuard}, the compiled op's own resolved cap) a guarded relation child fetch carries: the
77
+ * transport asserts the fetched row count against it and raises `LimitExceededError` when the batch
78
+ * overruns. It rides HERE because this is where the RAW child rows exist — past `group` the graph is
79
+ * already nested — and because SCP has no throw. `opts.whereDynamic` is the SKIP plan of a read that
80
+ * declares an optional predicate (CLAUDE.md §2 "only actually-optional predicates accumulate a plan").
70
81
  *
71
- * `guard` is the RELATION runaway cap ({@link CapGuard}, the compiled op's own resolved cap) a
72
- * guarded relation child fetch carries: the transport asserts the fetched row count against it and
73
- * raises `LimitExceededError` when the batch overruns. It rides HERE because this is where the RAW
74
- * child rows exist — past `group` the graph is already nested — and because SCP has no throw. Both
75
- * control ports are OPTIONAL: a bounded read, a write, and an uncapped fetch OMIT them (native-clean,
76
- * CLAUDE.md §2 "only actually-optional predicates accumulate a plan") — `whereDynamic` is present only
77
- * on a read with a SKIP predicate, `guard` only on a guarded relation child. bc typed-native lowers an
78
- * `opt<named>` port fed a non-null struct via `optSome` (bc#275), so a concrete OPTIONAL port is native.
82
+ * A PLAIN READ omits `opts` (native-clean: the payload is `sql` + `params`); bc typed-native lowers a
83
+ * non-null struct into the `opt<named>` port via `optSome` (bc#275), so the record is a native struct
84
+ * literal in go / rust with no boxing.
79
85
  */
80
- static executeSQL(sql, params, write, returning, bigint, whereDynamic, guard) { return declarationStub('executeSQL', [sql, params, write, returning, bigint, whereDynamic, guard]); }
86
+ static executeSQL(sql, params, opts) { return declarationStub('executeSQL', [sql, params, opts]); }
81
87
  /** Relation key extraction: the deduped, non-null key set over the ordered key-column tuple `col`. */
82
88
  static pluck(rows, col) { return declarationStub('pluck', [rows, col]); }
83
89
  /** Relation shaping: nest `children` under each parent's `into`, matching `child[fk]` to `parent[pk]`. */
@@ -87,7 +93,7 @@ exports.Db = Db;
87
93
  __decorate([
88
94
  behavior_contracts_1.leaf,
89
95
  __metadata("design:type", Function),
90
- __metadata("design:paramtypes", [String, Array, Boolean, Boolean, Boolean, Object, Object]),
96
+ __metadata("design:paramtypes", [String, Array, Object]),
91
97
  __metadata("design:returntype", Array)
92
98
  ], Db, "executeSQL", null);
93
99
  __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"leaf-transport.js","sourceRoot":"","sources":["../../src/scp/leaf-transport.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;;;;;;;;;;;;AAEH,2DAAoE;AAEpE;;;;;GAKG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,IAAwB;IACjE,KAAK,IAAI,CAAC;IACV,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,sEAAsE;QAC9F,mGAAmG,CACtG,CAAC;AACJ,CAAC;AAiDD;;;;;GAKG;AACH,MAAa,EAAE;IACb;;;;;;;;;;;;;;OAcG;IACU,AAAP,MAAM,CAAC,UAAU,CAAC,GAAW,EAAE,MAAmB,EAAE,KAAc,EAAE,SAAkB,EAAE,MAAe,EAAE,YAAsC,EAAE,KAAuB,IAAiB,OAAO,eAAe,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpS,sGAAsG;IACzF,AAAP,MAAM,CAAC,KAAK,CAAC,IAAiB,EAAE,GAAa,IAAiB,OAAO,eAAe,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnH,0GAA0G;IAC7F,AAAP,MAAM,CAAC,KAAK,CAAC,OAAoB,EAAE,QAAqB,EAAE,EAAY,EAAE,EAAY,EAAE,IAAY,EAAE,MAAe,IAAiB,OAAO,eAAe,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;CACxN;AAvBD,gBAuBC;AAPc;IAAZ,yBAAI;;;;0BAA+R;AAGvR;IAAZ,yBAAI;;;;qBAA8G;AAGtG;IAAZ,yBAAI;;;;qBAAkN"}
1
+ {"version":3,"file":"leaf-transport.js","sourceRoot":"","sources":["../../src/scp/leaf-transport.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;;;;;;;;;;;;AAEH,2DAAoE;AAEpE;;;;;GAKG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,IAAwB;IACjE,KAAK,IAAI,CAAC;IACV,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,sEAAsE;QAC9F,mGAAmG,CACtG,CAAC;AACJ,CAAC;AAqID;;;;;GAKG;AACH,MAAa,EAAE;IACb;;;;;;;;;;;;;;;;OAgBG;IACU,AAAP,MAAM,CAAC,UAAU,CAAC,GAAW,EAAE,MAAmB,EAAE,IAAyB,IAAiB,OAAO,eAAe,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhK,sGAAsG;IACzF,AAAP,MAAM,CAAC,KAAK,CAAC,IAAiB,EAAE,GAAa,IAAiB,OAAO,eAAe,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnH,0GAA0G;IAC7F,AAAP,MAAM,CAAC,KAAK,CAAC,OAAoB,EAAE,QAAqB,EAAE,EAAY,EAAE,EAAY,EAAE,IAAY,EAAE,MAAe,IAAiB,OAAO,eAAe,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;CACxN;AAzBD,gBAyBC;AAPc;IAAZ,yBAAI;;;;0BAA2J;AAGnJ;IAAZ,yBAAI;;;;qBAA8G;AAGtG;IAAZ,yBAAI;;;;qBAAkN"}
@@ -10,10 +10,11 @@
10
10
  *
11
11
  * - {@link executeSQL} — the SOLE SQL transport. Binds params and runs one statement through the
12
12
  * central {@link import('./exec-context') execute/run seam} (the ONLY driver contact). Read
13
- * (`write:false`) → rows; write (`write:true`) → a one-row `[{changes,lastInsertRowid}]` summary
14
- * (RETURNING writes return their rows via `execute`). It owns the transport-level param shaping a
15
- * relation key-set needs — the dialect array encoding + deferred PG cast resolution + `?`→`$N`
16
- * render — and, when the statement is a GUARDED relation child fetch, the runaway check on its raw
13
+ * (`write:null`) → rows; write (`write:{returning}`) → a one-row `[{changes,lastInsertRowid}]`
14
+ * summary (a RETURNING write returns its rows via `execute` instead). It owns the transport-level
15
+ * param shaping a relation key-set needs — the dialect array encoding + deferred PG cast
16
+ * resolution + `?`→`$N` render — and, when the statement is a GUARDED relation child fetch, the
17
+ * runaway check on its raw
17
18
  * rows ({@link import('./limit-config').assertRelationHardLimit}): the RAW child rows exist only
18
19
  * here, since `group` already sees a nested graph and SCP itself has no throw.
19
20
  * - {@link pluck} — rows + the ordered key-column tuple → the deduped, non-null key array (the
@@ -26,11 +27,16 @@
26
27
  * the IR (C4): {@link leafHandlers} closes over a sync {@link LeafContext} and {@link
27
28
  * leafHandlersAsync} over an {@link AsyncLeafContext}. The same three symbols are what the native
28
29
  * codegen calls directly ({@link LEAF_TRANSPORT_SYMBOLS}).
30
+ *
31
+ * What the statement DOES carry is the NAME of its database (`opts.db`) — a static property of its
32
+ * model, not an environment fact: the factory owns the connection REGISTRY, the statement owns which
33
+ * entry of it it belongs to. The two meet on the {@link StatementIntent} ({@link prepareSql}), which is
34
+ * the only input `connectionFor` routes on.
29
35
  */
30
36
  import type { Handlers, AsyncHandlers } from 'behavior-contracts/runtime';
31
37
  import { type ExecutionContext, type AsyncExecutionContext, type StatementIntent } from './exec-context';
32
38
  import { type RelationGuard } from './limit-config';
33
- import type { DynamicWherePlan } from './leaf-transport';
39
+ import type { DynamicWherePlan, WriteMode } from './leaf-transport';
34
40
  import { type Dialect } from './makesql/handler';
35
41
  /**
36
42
  * The environment boundary the handler factory captures (C4 — never on the IR). `exec` is the SYNC
@@ -53,13 +59,28 @@ export interface AsyncLeafContext {
53
59
  /** The target SQL dialect. */
54
60
  readonly dialect: Dialect;
55
61
  }
56
- /** The evaluated `executeSQL` ports a generated module hands the transport. */
62
+ /**
63
+ * The UNBOXED `executeSQL` ports the transport body runs on: the statement plus the facts its ONE
64
+ * optional control record ({@link import('./leaf-transport').ExecOptions}) carries, already read out
65
+ * ({@link executeSqlPorts}) — the same flattening the rust / go / python / php transports do after
66
+ * probing the payload. The imperative tx runner ({@link import('./makesql/tx')}) hands this record
67
+ * directly, since it holds the statement facts already and has no wire payload to decode.
68
+ */
57
69
  interface ExecuteSqlPorts {
58
70
  readonly sql: string;
59
71
  readonly params: unknown[];
60
- readonly write: boolean;
61
- readonly returning: boolean;
62
- readonly bigint: boolean;
72
+ /**
73
+ * The NAMED connection (database) this statement runs on — `null`/absent ⇒ the DEFAULT connection.
74
+ * Baked at emit from the statement's model ({@link import('./decorator-adapter').connectionOf}) or, for
75
+ * a relation child fetch, from the compiled op's target ({@link import('./relation').RelationOp.connection}).
76
+ * It reaches the router as the {@link StatementIntent}'s `db` ({@link prepareSql}).
77
+ */
78
+ readonly db?: string | null;
79
+ /**
80
+ * How the statement RUNS: `null` ⇒ a READ; a {@link WriteMode} ⇒ a write carrying its OWN
81
+ * `returning`. ONE field, three values — "returns rows but is not a write" is not representable.
82
+ */
83
+ readonly write: WriteMode | null;
63
84
  /** The DYNAMIC WHERE plan (absent on a fully-bounded statement — CLAUDE.md §2). See {@link assembleDynamicWhere}. */
64
85
  readonly whereDynamic?: DynamicWherePlan | null;
65
86
  /**
@@ -68,19 +89,27 @@ interface ExecuteSqlPorts {
68
89
  */
69
90
  readonly guard?: RelationGuard | null;
70
91
  }
71
- /** Splice a ` WHERE …` clause (leading space included, or `''`) into `baseSql` before its first tail keyword. */
72
- export declare function spliceWhere(baseSql: string, whereSql: string): string;
73
92
  /**
74
93
  * Assemble the effective statement from a DYNAMIC WHERE plan: drop the SKIPPED fragments (`skipped`
75
- * true — the per-call SKIP decision the emitter carried as DATA), join the survivors with ` WHERE ` /
76
- * ` AND `, splice the clause into the base `sql` before its first tail keyword ({@link spliceWhere}) —
77
- * the exact position a bounded WHERE occupies — and bind the surviving fragments' params BEFORE the
78
- * base params (the WHERE `?`s precede the tail's).
94
+ * true — the per-call SKIP decision the emitter carried as DATA), join the survivors with ` AND `, and
95
+ * CONCATENATE the three pieces the plan and the ports already hold — the statement's HEAD (`sql`, which
96
+ * ends at its WHERE region), the assembled clause, and the plan's `tail`. The params follow the same
97
+ * three-way order: the head's, the survivors', the tail's.
98
+ *
99
+ * There is nothing to LOCATE here. The emitter's SELECT builder is what puts the WHERE in the statement,
100
+ * so it hands the boundary over ({@link import('./makesql/compile-select').SelectBundle}) instead of
101
+ * leaving the transport to rediscover it: `plan.lead` says whether the head already ends in a WHERE (so
102
+ * the clause CONTINUES it) or not (so it OPENS one), and `plan.tailParams` are the tail's own bound
103
+ * values. That is what removed a lexical scan the five transports each carried a copy of — one that
104
+ * took a NESTED statement's tail keyword for the outer statement's (#198), counted a QUOTED `?` the
105
+ * placeholder render skips (#202), and derived a byte offset that is not the same number in five
106
+ * languages.
79
107
  *
80
108
  * A SKIP predicate's presence is per-CALL, so the FINAL statement can only be determined here, at
81
109
  * execution time — which is also why `?`→`$N` is rendered after this ({@link prepareSql}), never at
82
- * emit time. A statement with NO optional predicate carries no plan at all: its WHERE is spliced into
83
- * the static `sql` at emit time and it never reaches this function.
110
+ * emit time. Only the ACTUALLY-optional predicates are in the plan (CLAUDE.md §2): a read with none
111
+ * carries no plan at all and never reaches this function, and one whose fragments are all skipped
112
+ * leaves the emitted statement exactly as it was compiled (head + tail, no clause).
84
113
  */
85
114
  export declare function assembleDynamicWhere(p: {
86
115
  sql: string;
@@ -90,11 +119,19 @@ export declare function assembleDynamicWhere(p: {
90
119
  sql: string;
91
120
  params: unknown[];
92
121
  };
93
- /** Prepare a statement for the seam: resolve deferred PG cast(s), render `?`→`$N`, encode params. */
122
+ /**
123
+ * Prepare a statement for the seam: resolve deferred PG cast(s), render `?`→`$N`, encode params, and
124
+ * carry the ONE {@link StatementIntent} both seams take. The intent is the statement's RUN MODE
125
+ * ({@link effectiveStatement} — a write mode present ⇒ a write), NOT the branch: the branch picks the
126
+ * SEAM (`returning` ⇒ the row seam), the intent picks the CONNECTION
127
+ * ({@link import('./connection-routing').resolvePool}), so a RETURNING write runs on `execute` and
128
+ * still routes to the WRITER. The four native transports derive it the same way (#207).
129
+ */
94
130
  export declare function prepareSql(p: {
95
131
  sql: string;
96
132
  params: unknown[];
97
133
  write: boolean;
134
+ db?: string | null;
98
135
  }, dialect: Dialect): {
99
136
  sql: string;
100
137
  bound: unknown[];
@@ -110,8 +147,8 @@ export declare function prepareSql(p: {
110
147
  * int and float as DISTINCT kinds, so a column declared `Int` cannot be satisfied by a JS number on any
111
148
  * dialect, and gating exactness per endpoint made SQLite disagree with PostgreSQL and MySQL (whose
112
149
  * integer type parsers are unconditional — `configurePgDeboxTypeParsers`, `mysqlDeboxPoolOptions`),
113
- * which the conformance corpus rejects as dialect-variant. `bigint` is retained as a port because the
114
- * generated modules declare it, but it no longer selects the seam.
150
+ * which the conformance corpus rejects as dialect-variant. There is therefore no exactness port at all
151
+ * (#193 deleted the `bigint` one, which no language read).
115
152
  */
116
153
  export declare function executeSQL(p: ExecuteSqlPorts, ctx: LeafContext): Array<Record<string, unknown>>;
117
154
  /** The ASYNC (live PG / MySQL) `executeSQL` body — the twin of {@link executeSQL} over the async seam. */
@@ -1 +1 @@
1
- {"version":3,"file":"leaves.d.ts","sourceRoot":"","sources":["../../src/scp/leaves.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"leaves.d.ts","sourceRoot":"","sources":["../../src/scp/leaves.ts"],"names":[],"mappings":"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"}