litedbmodel 2.0.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +7 -0
  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 +127 -24
  15. package/dist/decorators.js.map +1 -1
  16. package/dist/drivers/mysql.d.ts.map +1 -1
  17. package/dist/drivers/mysql.js +12 -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 +13 -2
  21. package/dist/drivers/postgres.js.map +1 -1
  22. package/dist/drivers/sqlite.d.ts +2 -0
  23. package/dist/drivers/sqlite.d.ts.map +1 -1
  24. package/dist/drivers/sqlite.js +49 -4
  25. package/dist/drivers/sqlite.js.map +1 -1
  26. package/dist/index.cjs +10741 -0
  27. package/dist/index.d.cts +1 -0
  28. package/dist/scp/coltype.d.ts +108 -0
  29. package/dist/scp/coltype.d.ts.map +1 -1
  30. package/dist/scp/coltype.js +293 -6
  31. package/dist/scp/coltype.js.map +1 -1
  32. package/dist/scp/connection-routing.d.ts +312 -0
  33. package/dist/scp/connection-routing.d.ts.map +1 -0
  34. package/dist/scp/connection-routing.js +394 -0
  35. package/dist/scp/connection-routing.js.map +1 -0
  36. package/dist/scp/dbmodel-runtime.d.ts +101 -0
  37. package/dist/scp/dbmodel-runtime.d.ts.map +1 -0
  38. package/dist/scp/dbmodel-runtime.js +174 -0
  39. package/dist/scp/dbmodel-runtime.js.map +1 -0
  40. package/dist/scp/decorator-adapter.d.ts +196 -0
  41. package/dist/scp/decorator-adapter.d.ts.map +1 -0
  42. package/dist/scp/decorator-adapter.js +286 -0
  43. package/dist/scp/decorator-adapter.js.map +1 -0
  44. package/dist/scp/emit/emitter.d.ts +108 -0
  45. package/dist/scp/emit/emitter.d.ts.map +1 -0
  46. package/dist/scp/emit/emitter.js +782 -0
  47. package/dist/scp/emit/emitter.js.map +1 -0
  48. package/dist/scp/emit/endpoint.d.ts +248 -0
  49. package/dist/scp/emit/endpoint.d.ts.map +1 -0
  50. package/dist/scp/emit/endpoint.js +20 -0
  51. package/dist/scp/emit/endpoint.js.map +1 -0
  52. package/dist/scp/emit/index.d.ts +11 -0
  53. package/dist/scp/emit/index.d.ts.map +1 -0
  54. package/dist/scp/emit/index.js +13 -0
  55. package/dist/scp/emit/index.js.map +1 -0
  56. package/dist/scp/errors.d.ts +45 -1
  57. package/dist/scp/errors.d.ts.map +1 -1
  58. package/dist/scp/errors.js +47 -1
  59. package/dist/scp/errors.js.map +1 -1
  60. package/dist/scp/exec-context.d.ts +390 -0
  61. package/dist/scp/exec-context.d.ts.map +1 -0
  62. package/dist/scp/exec-context.js +540 -0
  63. package/dist/scp/exec-context.js.map +1 -0
  64. package/dist/scp/grouping.d.ts +32 -0
  65. package/dist/scp/grouping.d.ts.map +1 -0
  66. package/dist/scp/grouping.js +0 -0
  67. package/dist/scp/grouping.js.map +1 -0
  68. package/dist/scp/index.cjs +6432 -17579
  69. package/dist/scp/index.d.cts +1 -0
  70. package/dist/scp/index.d.mts +1 -0
  71. package/dist/scp/index.d.ts +51 -52
  72. package/dist/scp/index.d.ts.map +1 -1
  73. package/dist/scp/index.js +189 -152
  74. package/dist/scp/index.js.map +1 -1
  75. package/dist/scp/index.mjs +6067 -3659
  76. package/dist/scp/leaf-transport.d.ts +50 -0
  77. package/dist/scp/leaf-transport.d.ts.map +1 -0
  78. package/dist/scp/leaf-transport.js +92 -0
  79. package/dist/scp/leaf-transport.js.map +1 -0
  80. package/dist/scp/leaves.d.ts +174 -0
  81. package/dist/scp/leaves.d.ts.map +1 -0
  82. package/dist/scp/leaves.js +287 -0
  83. package/dist/scp/leaves.js.map +1 -0
  84. package/dist/scp/limit-config.d.ts +118 -0
  85. package/dist/scp/limit-config.d.ts.map +1 -0
  86. package/dist/scp/limit-config.js +126 -0
  87. package/dist/scp/limit-config.js.map +1 -0
  88. package/dist/scp/makesql/compile-relation.d.ts +49 -23
  89. package/dist/scp/makesql/compile-relation.d.ts.map +1 -1
  90. package/dist/scp/makesql/compile-relation.js +101 -76
  91. package/dist/scp/makesql/compile-relation.js.map +1 -1
  92. package/dist/scp/makesql/compile-select.d.ts +45 -10
  93. package/dist/scp/makesql/compile-select.d.ts.map +1 -1
  94. package/dist/scp/makesql/compile-select.js +50 -10
  95. package/dist/scp/makesql/compile-select.js.map +1 -1
  96. package/dist/scp/makesql/handler.d.ts +1 -1
  97. package/dist/scp/makesql/handler.d.ts.map +1 -1
  98. package/dist/scp/makesql/index.d.ts +7 -10
  99. package/dist/scp/makesql/index.d.ts.map +1 -1
  100. package/dist/scp/makesql/index.js +19 -30
  101. package/dist/scp/makesql/index.js.map +1 -1
  102. package/dist/scp/makesql/json-array.d.ts +65 -0
  103. package/dist/scp/makesql/json-array.d.ts.map +1 -1
  104. package/dist/scp/makesql/json-array.js +99 -10
  105. package/dist/scp/makesql/json-array.js.map +1 -1
  106. package/dist/scp/makesql/json-batch.d.ts.map +1 -1
  107. package/dist/scp/makesql/json-batch.js +21 -19
  108. package/dist/scp/makesql/json-batch.js.map +1 -1
  109. package/dist/scp/makesql/makesql.d.ts +1 -1
  110. package/dist/scp/makesql/makesql.d.ts.map +1 -1
  111. package/dist/scp/makesql/mysql-returning.d.ts +93 -0
  112. package/dist/scp/makesql/mysql-returning.d.ts.map +1 -0
  113. package/dist/scp/makesql/mysql-returning.js +215 -0
  114. package/dist/scp/makesql/mysql-returning.js.map +1 -0
  115. package/dist/scp/makesql/outtype.d.ts +75 -34
  116. package/dist/scp/makesql/outtype.d.ts.map +1 -1
  117. package/dist/scp/makesql/outtype.js +91 -118
  118. package/dist/scp/makesql/outtype.js.map +1 -1
  119. package/dist/scp/makesql/pool-executor.d.ts +135 -13
  120. package/dist/scp/makesql/pool-executor.d.ts.map +1 -1
  121. package/dist/scp/makesql/pool-executor.js +229 -21
  122. package/dist/scp/makesql/pool-executor.js.map +1 -1
  123. package/dist/scp/makesql/tx.d.ts +107 -22
  124. package/dist/scp/makesql/tx.d.ts.map +1 -1
  125. package/dist/scp/makesql/tx.js +451 -97
  126. package/dist/scp/makesql/tx.js.map +1 -1
  127. package/dist/scp/makesql/writeouttype.d.ts +7 -8
  128. package/dist/scp/makesql/writeouttype.d.ts.map +1 -1
  129. package/dist/scp/makesql/writeouttype.js +8 -7
  130. package/dist/scp/makesql/writeouttype.js.map +1 -1
  131. package/dist/scp/middleware.d.ts +287 -0
  132. package/dist/scp/middleware.d.ts.map +1 -0
  133. package/dist/scp/middleware.js +358 -0
  134. package/dist/scp/middleware.js.map +1 -0
  135. package/dist/scp/relation.d.ts +80 -9
  136. package/dist/scp/relation.d.ts.map +1 -1
  137. package/dist/scp/relation.js +198 -78
  138. package/dist/scp/relation.js.map +1 -1
  139. package/dist/scp/tx-options.d.ts +136 -0
  140. package/dist/scp/tx-options.d.ts.map +1 -0
  141. package/dist/scp/tx-options.js +184 -0
  142. package/dist/scp/tx-options.js.map +1 -0
  143. package/dist/scp/write-bundle.d.ts +131 -0
  144. package/dist/scp/write-bundle.d.ts.map +1 -0
  145. package/dist/scp/write-bundle.js +160 -0
  146. package/dist/scp/write-bundle.js.map +1 -0
  147. package/dist/types.d.ts +7 -0
  148. package/dist/types.d.ts.map +1 -1
  149. package/dist/types.js.map +1 -1
  150. package/docs/BENCHMARK.md +58 -56
  151. package/docs/benchmark-chart.svg +166 -166
  152. package/docs/design/phase-a-execution-context.md +139 -0
  153. package/package.json +16 -9
  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 -155
  159. package/dist/scp/authoring.d.ts.map +0 -1
  160. package/dist/scp/authoring.js +0 -162
  161. package/dist/scp/authoring.js.map +0 -1
  162. package/dist/scp/catalog.d.ts +0 -94
  163. package/dist/scp/catalog.d.ts.map +0 -1
  164. package/dist/scp/catalog.js +0 -234
  165. package/dist/scp/catalog.js.map +0 -1
  166. package/dist/scp/codegen.d.ts +0 -189
  167. package/dist/scp/codegen.d.ts.map +0 -1
  168. package/dist/scp/codegen.js +0 -421
  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 -134
  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 -494
  181. package/dist/scp/makesql/authoring-compile.js.map +0 -1
  182. package/dist/scp/makesql/ir.d.ts +0 -42
  183. package/dist/scp/makesql/ir.d.ts.map +0 -1
  184. package/dist/scp/makesql/ir.js +0 -66
  185. package/dist/scp/makesql/ir.js.map +0 -1
  186. package/dist/scp/makesql/static-bundle.d.ts +0 -187
  187. package/dist/scp/makesql/static-bundle.d.ts.map +0 -1
  188. package/dist/scp/makesql/static-bundle.js +0 -1113
  189. package/dist/scp/makesql/static-bundle.js.map +0 -1
  190. package/dist/scp/runtime.d.ts +0 -242
  191. package/dist/scp/runtime.d.ts.map +0 -1
  192. package/dist/scp/runtime.js +0 -400
  193. package/dist/scp/runtime.js.map +0 -1
@@ -29,11 +29,21 @@
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
30
  exports.RELATION_KEYS_HEAD = void 0;
31
31
  exports.compileRelationOp = compileRelationOp;
32
+ exports.parentKeyCols = parentKeyCols;
33
+ exports.targetKeyCols = targetKeyCols;
34
+ exports.relationGuard = relationGuard;
32
35
  exports.runRelationOp = runRelationOp;
33
36
  exports.distributeToParent = distributeToParent;
34
37
  const makesql_1 = require("./makesql/makesql");
35
38
  const handler_1 = require("./makesql/handler");
39
+ const exec_context_1 = require("./exec-context");
40
+ const coltype_1 = require("./coltype");
41
+ const outtype_1 = require("./makesql/outtype");
42
+ const limit_config_1 = require("./limit-config");
43
+ const grouping_1 = require("./grouping");
44
+ const json_array_1 = require("./makesql/json-array");
36
45
  const compile_relation_1 = require("./makesql/compile-relation");
46
+ const tx_1 = require("./makesql/tx");
37
47
  /** The reserved input head the relation batch query binds its deduped key array to. */
38
48
  exports.RELATION_KEYS_HEAD = '__keys';
39
49
  /**
@@ -44,7 +54,7 @@ exports.RELATION_KEYS_HEAD = '__keys';
44
54
  * LATERAL (PG) / ROW_NUMBER (MySQL·SQLite) form. The SQL text is FIXED (the array binds as one
45
55
  * param regardless of length), so it needs no per-input recompile.
46
56
  */
47
- function compileRelationOp(decl) {
57
+ function compileRelationOp(decl, resolveColumnType) {
48
58
  if (decl.kind !== 'hasMany' && decl.limit !== undefined) {
49
59
  throw new Error(`relation '${decl.name}': a per-parent 'limit' is only valid for hasMany (got ${decl.kind})`);
50
60
  }
@@ -56,10 +66,48 @@ function compileRelationOp(decl) {
56
66
  }
57
67
  const dialect = decl.dialect ?? 'sqlite';
58
68
  const composite = isCompositeDecl(decl);
59
- const sql = compiledBatchSql(decl, dialect);
69
+ const sql = compiledBatchSql(decl, dialect, resolveColumnType);
60
70
  // CROSS-DB (V0 R1): carry the target connection tag ONLY when set (a same-DB relation stays
61
71
  // untagged, so existing bundles are byte-unchanged — the field is additive/optional).
62
72
  const conn = decl.connection !== undefined ? { connection: decl.connection } : {};
73
+ // Carry the child table + projection AND bake the STATIC child materializers (issue #59) using the
74
+ // SHARED `parseProjectionColumn` + the SINGLE column-type resolver — the SAME resolution the primary
75
+ // read uses (no separate bare-regex pass). Every projection shape (bare / qualified `t.col` /
76
+ // aliased `col AS b`) resolves + fail-closes identically; a `*` / computed / undeclared column
77
+ // THROWS. The batch's child rows then de-box with ZERO per-read introspection.
78
+ const materializers = {};
79
+ if (resolveColumnType !== undefined) {
80
+ const at = `relation '${decl.name}'`;
81
+ for (const c of decl.select) {
82
+ const entry = (0, outtype_1.parseProjectionColumn)(c, decl.targetTable, at); // `*`/computed → throw
83
+ if (entry.kind === 'computed')
84
+ continue; // a relation child rarely projects computed; leave raw
85
+ const sqlType = resolveColumnType(entry.qualifier ?? decl.targetTable, entry.underlying); // undeclared → throw
86
+ const klass = (0, coltype_1.sqlTypeToMaterializeClass)(sqlType);
87
+ if (klass !== 'passthrough')
88
+ materializers[entry.outputKey] = klass;
89
+ }
90
+ }
91
+ // CHAINED relations (nested `with`): compile each grandchild relation recursively, inheriting THIS
92
+ // relation's dialect. The SAME single compiler — a child is just another RelationDecl whose parent is
93
+ // this relation's target rows; no separate nested-relation path. Absent ⇒ a leaf (byte-unchanged).
94
+ const childRelations = decl.childRelations !== undefined && decl.childRelations.length > 0
95
+ ? decl.childRelations.map((c) => compileRelationOp({ ...c, dialect: c.dialect ?? dialect }, resolveColumnType))
96
+ : undefined;
97
+ const target = {
98
+ targetTable: decl.targetTable,
99
+ select: [...decl.select],
100
+ ...(Object.keys(materializers).length > 0 ? { materializers } : {}),
101
+ ...(childRelations !== undefined ? { childRelations } : {}),
102
+ };
103
+ // Hard-limit runaway cap (Phase E-2, epic #74; v1 `_selectForRelation`): resolve the effective
104
+ // batch-total cap ONCE at compile (per-relation override → global) and bake it onto the op as a
105
+ // plain number the native ports read. Only a `hasMany` is capped (single-cardinality fetches ≤1
106
+ // child per parent). A relation with an INTRINSIC per-parent `limit` window SKIPS the check — its
107
+ // fanout is already bounded per parent (v1 raw-SQL-with-LIMIT skip). `null` (per-relation or global)
108
+ // ⇒ disabled ⇒ the field is omitted (op stays byte-unchanged for the uncapped path).
109
+ const effectiveHardLimit = decl.kind === 'hasMany' && decl.limit === undefined ? (0, limit_config_1.resolveHasManyHardLimit)(decl.hardLimit) : null;
110
+ const guard = effectiveHardLimit !== null ? { hardLimit: effectiveHardLimit } : {};
63
111
  if (composite) {
64
112
  return {
65
113
  name: decl.name,
@@ -69,6 +117,8 @@ function compileRelationOp(decl) {
69
117
  dialect,
70
118
  ...conn,
71
119
  sql,
120
+ ...target,
121
+ ...guard,
72
122
  };
73
123
  }
74
124
  return {
@@ -79,6 +129,8 @@ function compileRelationOp(decl) {
79
129
  dialect,
80
130
  ...conn,
81
131
  sql,
132
+ ...target,
133
+ ...guard,
82
134
  };
83
135
  }
84
136
  /**
@@ -105,25 +157,43 @@ function isCompositeDecl(decl) {
105
157
  }
106
158
  return true;
107
159
  }
160
+ /**
161
+ * The PG element type of each COMPOSITE key column, from the CHILD column's DECLARED type — the same
162
+ * schema-derived derivation the composite `tupleIn` predicate uses (`pgTypeSpecimen` →
163
+ * `inferPgElementType`), so the two composite PG forms cast identically. The child column is the one
164
+ * the key row is compared against, so its declared type is the type the key must carry.
165
+ *
166
+ * A composite PG batch cannot be compiled without them (the key rows come out of JSON as `text` and
167
+ * `int = text` fails at plan time), so a missing resolver is a LOUD compile error, never a silent
168
+ * `text` fallback.
169
+ */
170
+ function pgKeyTypesOf(decl, targetKeys, resolveColumnType) {
171
+ if (resolveColumnType === undefined) {
172
+ throw new Error(`relation '${decl.name}': a COMPOSITE-key relation on postgres needs the target model's column types ` +
173
+ `(keys ${targetKeys.join(', ')} on '${decl.targetTable}') — pass a ColumnTypeResolver to compileRelationOp`);
174
+ }
175
+ return targetKeys.map((k) => (0, compile_relation_1.inferPgElementType)([(0, tx_1.pgTypeSpecimen)(resolveColumnType(decl.targetTable, k))]));
176
+ }
108
177
  /**
109
178
  * Compile the STATIC batch SELECT text: the makeSQL relation builder emits complete tuned SQL
110
179
  * whose deduped-key array is ONE param. We compile against a single placeholder key array so
111
180
  * the text is fixed; the runtime re-binds the real deduped keys against the SAME text (the
112
181
  * single-JSON / `= ANY` forms are length-independent, so the text is stable).
113
182
  */
114
- function compiledBatchSql(decl, dialect) {
115
- // A COMPOSITE decl compiles to the STATIC composite form (PG: one array param per key column;
116
- // MySQL/SQLite: one JSON array-of-tuples param) — length-independent, so the text is fixed. A
117
- // per-parent `limit` selects the STATIC composite-LIMITED builder (PG LATERAL / MySQL·SQLite
118
- // ROW_NUMBER window over the SAME static key-set predicate — #47 last completeness gap).
183
+ function compiledBatchSql(decl, dialect, resolveColumnType) {
184
+ // A COMPOSITE decl compiles to the STATIC composite form — ONE JSON array-of-tuples param on every
185
+ // dialect, length-independent, so the text is fixed. A per-parent `limit` selects the STATIC
186
+ // composite-LIMITED builder (PG LATERAL / MySQL·SQLite ROW_NUMBER window over the SAME static
187
+ // key-set predicate — #47 last completeness gap).
119
188
  if (decl.parentKeys !== undefined) {
189
+ const targetKeys = [...decl.targetKeys];
120
190
  const compositeBase = {
121
191
  dialect,
122
192
  tableName: decl.targetTable,
123
193
  select: decl.select.join(', '),
124
194
  order: decl.order,
125
- targetKeys: [...decl.targetKeys],
126
- deferPgArrayCast: true,
195
+ targetKeys,
196
+ ...(dialect === 'postgres' ? { pgKeyTypes: pgKeyTypesOf(decl, targetKeys, resolveColumnType) } : {}),
127
197
  };
128
198
  const node = decl.limit !== undefined
129
199
  ? (0, compile_relation_1.compileCompositeKeyStaticLimited)({ ...compositeBase, limit: decl.limit })
@@ -133,6 +203,15 @@ function compiledBatchSql(decl, dialect) {
133
203
  // A one-element placeholder key set fixes the SQL text (single-JSON-param / `= ANY` forms are
134
204
  // value-length-independent). The concrete keys are bound at execute time.
135
205
  const placeholderKeys = [null];
206
+ // The PG `= ANY(?::<T>[])` element type comes from the target key COLUMN's DECLARED type — the same
207
+ // schema-derived derivation the composite path uses (`pgKeyTypesOf`). It must NOT be inferred at
208
+ // render from a bound value: the value's type differs by language (a bc int is a BigInt on the TS
209
+ // plane → `bigint[]`, a native int in python/php → `int[]`), which broke cross-language byte-identity.
210
+ // The column is the authority (an int column → `int[]`, byte-identical to v1's live-correct cast, and
211
+ // never the #43 `text[]`). Only fall back to render-time inference when no resolver is available.
212
+ const pgKeyCast = dialect === 'postgres' && resolveColumnType !== undefined
213
+ ? (0, compile_relation_1.inferPgElementType)([(0, tx_1.pgTypeSpecimen)(resolveColumnType(decl.targetTable, decl.targetKey))])
214
+ : undefined;
136
215
  const base = {
137
216
  dialect,
138
217
  tableName: decl.targetTable,
@@ -140,11 +219,9 @@ function compiledBatchSql(decl, dialect) {
140
219
  order: decl.order,
141
220
  targetKey: decl.targetKey,
142
221
  values: placeholderKeys,
143
- // The keys are UNKNOWN at symbolic compile (placeholder set), so the PG `= ANY(?::<T>[])`
144
- // element type is DEFERRED to render (#46) — resolved from the real deduped keys via
145
- // `inferPgArrayType`, reproducing v1's live-correct cast (`::int[]` for int keys). Baking a
146
- // compile-time `text[]` here was the #43 regression (`integer = text` on real PG).
147
- deferPgArrayCast: true,
222
+ ...(pgKeyCast !== undefined
223
+ ? { sqlCastMap: new Map([[decl.targetKey, pgKeyCast]]) }
224
+ : { deferPgArrayCast: true }),
148
225
  };
149
226
  const node = decl.limit !== undefined
150
227
  ? (0, compile_relation_1.compileSingleKeyLimited)({ ...base, limit: decl.limit })
@@ -152,6 +229,30 @@ function compiledBatchSql(decl, dialect) {
152
229
  // The builder emits the SQL with ONE `?` (the whole key array). Assemble to the flat text.
153
230
  return (0, makesql_1.assembleMakeSQL)(node).sql;
154
231
  }
232
+ /**
233
+ * Coerce a relation target to an {@link ExecutionContext}. A raw {@link RelationDriver} (read-only
234
+ * `prepare`) is adapted to a full sync driver (its `run` is never reached on the read-only relation
235
+ * path) and wrapped via {@link contextForDriver} — the backward-compat seam. So the relation batch
236
+ * ALSO funnels through the central seam (middleware → connectionFor → execute), no direct driver.
237
+ */
238
+ function relationContext(target) {
239
+ if ('connectionFor' in target)
240
+ return target;
241
+ const driver = {
242
+ prepare(sql) {
243
+ const s = target.prepare(sql);
244
+ return {
245
+ all: (...p) => s.all(...p),
246
+ // The read-only relation path never runs a write; a defensive stub keeps the driver shape total.
247
+ run: () => {
248
+ throw new Error('relation batch: unexpected write on a read-only relation driver');
249
+ },
250
+ safeIntegers: s.safeIntegers?.bind(s),
251
+ };
252
+ },
253
+ };
254
+ return (0, exec_context_1.contextForDriver)(driver);
255
+ }
155
256
  /** The ordered PARENT key columns of an op (single-key → 1-element list; composite → the tuple). */
156
257
  function parentKeyCols(op) {
157
258
  return op.parentKeys ?? [op.parentKey];
@@ -160,28 +261,39 @@ function parentKeyCols(op) {
160
261
  function targetKeyCols(op) {
161
262
  return op.targetKeys ?? [op.targetKey];
162
263
  }
163
- /** The stringified key identity for dedupe/grouping. Single scalar → `String(v)`; tuple → joined. */
164
- function keyIdentity(values) {
165
- // A NUL separator no scalar `String(v)` contains, so distinct tuples never collide.
166
- return values.map((v) => String(v)).join('');
264
+ /**
265
+ * The op's RELATION RUNAWAY GUARD, or `null` when it baked none (disabled, or an intrinsic per-parent
266
+ * `limit` window whose fanout is already bounded). The ONE projection of a compiled op onto the
267
+ * {@link RelationGuard} record — read by BOTH consumers of the cap: {@link runRelationOp} (the
268
+ * typed-object / lazy batch) and the emitter, which bakes this record into the generated child fetch's
269
+ * `guard` port so the leaf enforces the SAME resolved cap. Nothing downstream re-derives it.
270
+ */
271
+ function relationGuard(op) {
272
+ if (op.hardLimit === undefined)
273
+ return null;
274
+ return {
275
+ limit: op.hardLimit,
276
+ ...(op.targetTable !== undefined ? { model: op.targetTable } : {}),
277
+ relation: op.name,
278
+ };
167
279
  }
168
280
  /**
169
- * Bind the deduped keys to the batch op's params per dialect + arity. Single-key: PG binds the
170
- * scalar array verbatim (`= ANY(?::t[])`); MySQL/SQLite bind the JSON-encoded array. Composite: PG
171
- * binds ONE array param PER key column (transposed tuples → `unnest(?::t1[], ?::t2[])`);
172
- * MySQL/SQLite bind ONE JSON array-of-tuples string. Returns the positional param list.
281
+ * Bind the deduped keys to the batch op's params — ONE param, every dialect and arity. A COMPOSITE
282
+ * key set is the JSON array-of-tuples every dialect expands server-side (PG `json_array_elements`,
283
+ * MySQL `JSON_TABLE`, SQLite `json_each`), so the key binding is dialect-INDEPENDENT: no key-tuple
284
+ * transpose anywhere. A SINGLE-key set is the scalar array — bound raw on PG (`= ANY(?::t[])` takes a
285
+ * native array) and JSON-encoded on MySQL/SQLite.
286
+ *
287
+ * The JSON encoding goes through {@link encodeJsonParam}, the one serializer every JSON param uses.
288
+ * These keys came OFF a read, so an `int` key is a `BigInt` — a bare `JSON.stringify` here does not
289
+ * "diverge subtly", it THROWS `Do not know how to serialize a BigInt` and takes every relation read
290
+ * with an integer parent key down with it.
173
291
  */
174
292
  function bindKeys(op, tuples) {
175
- const composite = op.parentKeys !== undefined;
176
- if (op.dialect === 'postgres') {
177
- if (!composite)
178
- return [tuples.map((t) => t[0])]; // ONE scalar array param
179
- // Transpose tuples → per-column arrays: `[[1,a],[2,b]] → [[1,2],[a,b]]` — one array param each.
180
- return parentKeyCols(op).map((_, col) => tuples.map((t) => t[col]));
181
- }
182
- // MySQL/SQLite: single-key → JSON scalar array; composite → JSON array-of-tuples. ONE param.
183
- const payload = composite ? tuples.map((t) => [...t]) : tuples.map((t) => t[0]);
184
- return [JSON.stringify(payload)];
293
+ if (op.parentKeys !== undefined)
294
+ return [(0, json_array_1.encodeJsonParam)(op.dialect, tuples.map((t) => [...t]))];
295
+ const keys = tuples.map((t) => t[0]);
296
+ return [op.dialect === 'postgres' ? keys : (0, json_array_1.encodeJsonParam)(op.dialect, keys)];
185
297
  }
186
298
  /**
187
299
  * Run ONE {@link RelationOp} for a set of parent rows: dedup the parent-key tuples, render the
@@ -194,64 +306,72 @@ function bindKeys(op, tuples) {
194
306
  * NO query (the correct empty-set behavior — the membership over no keys selects nothing).
195
307
  */
196
308
  function runRelationOp(op, parents, db) {
309
+ const ctx = relationContext(db);
197
310
  const pCols = parentKeyCols(op);
198
- const keys = dedupeKeys(parents, pCols);
311
+ const keys = (0, grouping_1.dedupeKeyTuples)(parents, pCols);
199
312
  const batch = new Map();
200
- // Resolve the deferred PG array cast(s) (#46) from the REAL keys BEFORE the `?`→`$N` render. A
201
- // single-key op has ONE cast; a composite PG op has ONE cast PER key column — resolve each from
202
- // its own column's key values, left-to-right (resolvePgArrayCast resolves the first token each
203
- // call). MySQL/SQLite carry no cast token.
204
- let cast = op.sql;
205
- if (op.dialect === 'postgres') {
206
- for (let col = 0; col < pCols.length; col++)
207
- cast = (0, compile_relation_1.resolvePgArrayCast)(cast, keys.map((t) => t[col]));
208
- }
313
+ // Resolve the deferred PG array cast (#46) from the REAL keys BEFORE the `?`→`$N` render: the
314
+ // SINGLE-key `= ANY(?::<T>[])` is the only cast whose element type is value-derived. A composite
315
+ // batch carries no token (its key rows are cast from the DECLARED column types at compile) and
316
+ // MySQL/SQLite carry none at all.
317
+ const cast = op.dialect === 'postgres' && op.parentKeys === undefined
318
+ ? (0, compile_relation_1.resolvePgArrayCast)(op.sql, keys.map((t) => t[0]))
319
+ : op.sql;
209
320
  const sql = (0, handler_1.renderPlaceholders)(cast, op.dialect);
210
321
  if (keys.length === 0)
211
322
  return { sql, keys, batch };
212
323
  const tCols = targetKeyCols(op);
213
- const rows = db.prepare(sql).all(...bindKeys(op, keys));
214
- for (const row of rows) {
215
- const k = keyIdentity(tCols.map((c) => row[c]));
216
- const list = batch.get(k);
217
- if (list === undefined)
218
- batch.set(k, [row]);
219
- else
220
- list.push(row);
221
- }
222
- return { sql, keys, batch };
324
+ // Materialize the child rows (issue #59) exactly like the primary read, using the STATIC
325
+ // materializers baked onto the op at compile (from the model's DDL — ZERO per-read introspection).
326
+ // A BIGINT/DATE/BOOL child column de-boxes identically to a top-level read (INT→number /
327
+ // BIGINT→string / DATE→string / bool).
328
+ const childCols = op.materializers;
329
+ // The EXACT-integer seam, unconditionally — the same one the `executeSQL` leaf reads through. This
330
+ // used to switch to the inexact seam unless a child column was declared `int64`, which made ONE
331
+ // column read back as two different JS types depending on which surface fetched it: `1n` through
332
+ // codegen, `1` through the lazy path. Exactness is not a per-endpoint choice; the DECLARED type
333
+ // decides the consumer-facing shape, and that narrowing is `materializeCell`'s job below.
334
+ const boundParams = bindKeys(op, keys);
335
+ const rawRows = (0, exec_context_1.executeSafe)(ctx, sql, boundParams);
336
+ // Hard-limit runaway guard (Phase E-2, epic #74; v1 `_selectForRelation`): POST-fetch, if the batch
337
+ // TOTAL exceeds the baked cap, throw with the EXACT count (the batch is fetched in full, no N+1).
338
+ // The check itself is the SHARED relation primitive (`assertRelationHardLimit`) over the op's own
339
+ // guard — the SAME two functions the codegen path runs in the `executeSQL` leaf, so the two read
340
+ // surfaces cannot drift on the cap, the count or the error identity. Runs BEFORE grouping/hydration
341
+ // so an over-cap read never assembles an unbounded result set.
342
+ (0, limit_config_1.assertRelationHardLimit)(rawRows, relationGuard(op));
343
+ const rows = materializeChildRows(rawRows, childCols);
344
+ // Group the child rows by their target-key identity — the shared grouping SSoT ({@link groupByKey}),
345
+ // the SAME core the eager `group` leaf uses (no duplicated grouping).
346
+ return { sql, keys, batch: (0, grouping_1.groupByKey)(rows, tCols) };
223
347
  }
224
- /**
225
- * The deduped, non-null parent-key TUPLES (insertion order preserved — deterministic). A tuple is
226
- * dropped if ANY of its key columns is null/undefined (no partial keys). Deduped on the stringified
227
- * tuple identity (so `1` and `"1"` collapse exactly as `String(v)`).
228
- */
229
- function dedupeKeys(parents, keyCols) {
230
- const seen = new Set();
231
- const out = [];
232
- for (const p of parents) {
233
- const tuple = keyCols.map((c) => p[c]);
234
- if (tuple.some((v) => v === undefined || v === null))
235
- continue;
236
- const s = keyIdentity(tuple);
237
- if (seen.has(s))
238
- continue;
239
- seen.add(s);
240
- out.push(tuple);
348
+ /** Materialize relation child rows (issue #59): same coercion as the primary read. */
349
+ function materializeChildRows(rows, cols) {
350
+ for (const row of rows) {
351
+ for (const key of Object.keys(row)) {
352
+ const klass = cols?.[key];
353
+ if (klass !== undefined) {
354
+ row[key] = (0, coltype_1.materializeCell)(row[key], klass);
355
+ continue;
356
+ }
357
+ // An UNDECLARED integer column arrives as bigint from the exact seam — narrow it here. There is
358
+ // no longer a mode in which it does not, so this is the normal path, not a defensive one.
359
+ if (typeof row[key] === 'bigint') {
360
+ const v = row[key];
361
+ row[key] = v >= BigInt(Number.MIN_SAFE_INTEGER) && v <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(v) : v.toString();
362
+ }
363
+ }
241
364
  }
242
- return out;
365
+ return rows;
243
366
  }
244
367
  /**
245
368
  * Distribute a resolved {@link RelationBatch} onto ONE parent per the relation cardinality:
246
- * `hasMany` → the child list (`[]` when none); `belongsTo`/`hasOne` → the single child (or
247
- * `null`). Keyed by the parent's key-tuple identity. `null`/`[]` is the declared cardinality's
248
- * empty representation, not an ad-hoc default.
369
+ * `hasMany` → the child list (`[]` when none); `belongsTo`/`hasOne` → the single child (or `null`).
370
+ * A thin consumer over the shared grouping SSoT ({@link attachToParent}) — the SAME core the eager
371
+ * `group` leaf uses (no duplicated grouping). `null`/`[]` is the declared cardinality's empty
372
+ * representation, not an ad-hoc default.
249
373
  */
250
374
  function distributeToParent(op, parent, batch) {
251
- const tuple = parentKeyCols(op).map((c) => parent[c]);
252
- const rows = tuple.some((v) => v === undefined || v === null) ? undefined : batch.get(keyIdentity(tuple));
253
- if (op.kind === 'hasMany')
254
- return rows ?? [];
255
- return rows !== undefined && rows.length > 0 ? rows[0] : null;
375
+ return (0, grouping_1.attachToParent)(parent, parentKeyCols(op), batch, op.kind !== 'hasMany');
256
376
  }
257
377
  //# sourceMappingURL=relation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/scp/relation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/scp/relation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * litedbmodel v2 SCP — the **tx-completeness contract** (Phase B-1 / #81): the TransactionOptions
3
+ * shape, the guard errors, the per-dialect isolation-level SQL, and the retryable-error classifier.
4
+ *
5
+ * This module is the **API REFERENCE** for Phase B — the 4 native ports (rust #82 / go #83 / py #84
6
+ * / php #85) mirror THIS contract exactly (option field names + defaults, guard-error semantics,
7
+ * isolation-level→SQL mapping per dialect, retryable-error classification, retry-loop policy). It is
8
+ * dialect-neutral and driver-agnostic on purpose: `withTransactionAsync` (exec-context.ts) consumes
9
+ * it; nothing here touches a connection.
10
+ *
11
+ * It builds ON the Phase A {@link import('./exec-context').ExecutionContext} + owned-connection
12
+ * ownership (`withTransactionAsync`); it does NOT re-implement connection ownership — it layers the
13
+ * options/guards/retry/isolation on top of that seam. It mirrors v1 `src/DBModel.ts`
14
+ * (`transaction` :2787, `checkWriteAllowed` :886, `isRetryableError` :2865) but on the SCP seam.
15
+ */
16
+ import { WriteOutsideTransactionError, WriteInReadOnlyContextError } from '../types';
17
+ import type { Dialect } from './makesql/handler';
18
+ export { WriteOutsideTransactionError, WriteInReadOnlyContextError };
19
+ /**
20
+ * The three portable SQL isolation levels the tx API exposes (lowercased, matching the v2 public
21
+ * surface). READ UNCOMMITTED is deliberately NOT offered — neither PG (which silently upgrades it to
22
+ * READ COMMITTED) nor a correctness-minded default wants it, and omitting it keeps the 4 ports' enum
23
+ * identical. The value maps to the canonical SQL phrase via {@link isolationSql}.
24
+ */
25
+ export type IsolationLevel = 'read committed' | 'repeatable read' | 'serializable';
26
+ /** The canonical SQL phrase for an {@link IsolationLevel} (e.g. `SERIALIZABLE`). */
27
+ export declare function isolationPhrase(level: IsolationLevel): string;
28
+ /**
29
+ * The tx-start statements for `dialect` at `isolation` (in issue order). Per-dialect because the
30
+ * three engines express per-transaction isolation DIFFERENTLY:
31
+ *
32
+ * - **postgres**: `BEGIN ISOLATION LEVEL <phrase>` — one statement, the level rides the BEGIN.
33
+ * - **mysql**: `SET TRANSACTION ISOLATION LEVEL <phrase>` MUST precede `BEGIN` (it scopes the very
34
+ * NEXT transaction only), so this returns TWO statements: the SET, then a bare `BEGIN`.
35
+ * - **sqlite**: SQLite has NO per-transaction isolation-level knob. Its isolation is a
36
+ * process/PRAGMA-level property (`journal_mode=WAL` gives snapshot reads; the default rollback
37
+ * journal serializes writers), NOT something a `BEGIN` clause selects. So an isolation request on
38
+ * SQLite is a HARD ERROR here — we do NOT silently drop it (that would fake honoring the level).
39
+ * The conformance/bench SQLite path never passes `isolation`, so it always emits a bare `BEGIN`.
40
+ *
41
+ * With no `isolation`, every dialect emits a single bare `BEGIN` (the Phase A behavior, byte-identical).
42
+ */
43
+ export declare function beginStatements(dialect: Dialect, isolation?: IsolationLevel): readonly string[];
44
+ /**
45
+ * Options for a transaction (the Phase B contract; mirrors v1 `TransactionOptions` in `src/types.ts`
46
+ * plus the new `isolation`). Every field is optional with a stable default; the 4 native ports MUST
47
+ * expose the SAME field names + defaults.
48
+ */
49
+ export interface TransactionOptions {
50
+ /**
51
+ * Per-transaction isolation level. Issued via {@link beginStatements} on the tx-owned connection
52
+ * (PG: on BEGIN; MySQL: a preceding SET). Omit for the engine default (PG/MySQL: READ COMMITTED /
53
+ * REPEATABLE READ respectively). SQLite has no per-tx level ⇒ passing this on SQLite is an error.
54
+ */
55
+ readonly isolation?: IsolationLevel;
56
+ /** Retry the whole tx on a retryable error (deadlock / serialization / connection). @default true */
57
+ readonly retryOnError?: boolean;
58
+ /** Max attempts before giving up (the FIRST try counts as attempt 1). @default 3 */
59
+ readonly retryLimit?: number;
60
+ /** Backoff base in ms; attempt k waits `retryDuration * 2^(k-1)` (exponential). @default 200 */
61
+ readonly retryDuration?: number;
62
+ /**
63
+ * ROLLBACK instead of COMMIT at the end of a SUCCESSFUL body (dry-run / preview): the body runs and
64
+ * its result is returned, but NO change is committed. A body error still ROLLBACKs + re-raises as
65
+ * usual. @default false
66
+ */
67
+ readonly rollbackOnly?: boolean;
68
+ /**
69
+ * Override the GLOBAL writer-after-transaction setting FOR THIS TRANSACTION (v1 parity —
70
+ * `TransactionOptions.useWriterAfterTransaction`, honored at `DBModel.transaction` :3103).
71
+ *
72
+ * `false` means this transaction's COMMIT does NOT arm writer-stickiness: the reads that follow it
73
+ * go back to the reader pool immediately instead of being pinned to the writer for
74
+ * `writerStickyDuration`. Use it for a transaction whose writes nobody needs to read back (a
75
+ * bookkeeping / audit / fire-and-forget write), so it does not cost every following read its
76
+ * replica.
77
+ *
78
+ * Omitted (or `true`) ⇒ the GLOBAL setting decides, exactly as before: the arming call lands on the
79
+ * ctx's {@link import('./connection-routing').WriterStickyClock}, which is itself disabled when the
80
+ * deployment configured `useWriterAfterTransaction: false`. This mirrors v1, where a per-tx `true`
81
+ * likewise cannot switch stickiness ON against a global `false` (`_shouldUseWriterSticky` :487
82
+ * re-checks the global). @default true
83
+ */
84
+ readonly useWriterAfterTransaction?: boolean;
85
+ }
86
+ /** The resolved (defaults-applied) options the tx runtime uses — no `undefined` holes. */
87
+ export interface ResolvedTxOptions {
88
+ readonly isolation?: IsolationLevel;
89
+ readonly retryOnError: boolean;
90
+ readonly retryLimit: number;
91
+ readonly retryDuration: number;
92
+ readonly rollbackOnly: boolean;
93
+ readonly useWriterAfterTransaction: boolean;
94
+ }
95
+ /** Apply the Phase B defaults (v1-parity: retryOnError=true, retryLimit=3, retryDuration=200). */
96
+ export declare function resolveTxOptions(opts?: TransactionOptions): ResolvedTxOptions;
97
+ /**
98
+ * Is `error` a RETRYABLE transaction failure — a deadlock, a serialization failure, or a broken
99
+ * connection — for which re-running the whole transaction can succeed? Classification is by the
100
+ * driver's stable error CODE first (PG `SQLSTATE`, MySQL `errno`), with the v1 message substrings as
101
+ * a fallback (mirrors v1 `DBModel.isRetryableError` :2865). A data conflict (unique/FK/check) is NOT
102
+ * retryable — re-running would fail identically.
103
+ *
104
+ * Codes (per dialect):
105
+ * - **postgres** SQLSTATE: `40001` serialization_failure, `40P01` deadlock_detected.
106
+ * - **mysql** errno: `1213` ER_LOCK_DEADLOCK, `1205` ER_LOCK_WAIT_TIMEOUT.
107
+ * - **connection errors** (either dialect): via {@link isConnectionError} — a dropped/reset/refused
108
+ * connection is retryable (reconnect on the next attempt).
109
+ */
110
+ export declare function isRetryableTxError(error: unknown, isConnectionError: (e: Error) => boolean): boolean;
111
+ /** Sleep `ms` (the retry backoff). */
112
+ export declare function sleep(ms: number): Promise<void>;
113
+ /** Run `fn` with the "inside a transaction" marker set (called by the tx runtime around the body). */
114
+ export declare function runInTransactionScope<R>(fn: () => R): R;
115
+ /**
116
+ * Run `fn` in a READ-ONLY context (mirror v1 `DBModel.withWriter`): reads are allowed, but ANY write
117
+ * inside `fn` throws {@link WriteInReadOnlyContextError}. Use for a read-your-writes / writer-pinned
118
+ * read scope that must never accidentally mutate.
119
+ */
120
+ export declare function withReadOnly<R>(fn: () => R): R;
121
+ /** True if the current async scope is inside an active transaction (guard/nested detection). */
122
+ export declare function isInTransaction(): boolean;
123
+ /** True if the current async scope is a read-only context ({@link withReadOnly}). */
124
+ export declare function isReadOnly(): boolean;
125
+ /**
126
+ * Enforce the write=tx guard (mirror v1 `DBModel._checkWriteAllowed`, DBModel.ts:886-896): a write
127
+ * inside a {@link withReadOnly} scope throws {@link WriteInReadOnlyContextError}; a write with NO
128
+ * active transaction throws {@link WriteOutsideTransactionError}. Called at every write ENTRY
129
+ * (create/update/delete/upsert/batch) BEFORE any SQL is issued. The order matches v1: read-only is
130
+ * checked first (a read-only scope is the more specific rejection).
131
+ *
132
+ * @param operation the write op name (INSERT/UPDATE/DELETE/UPSERT/BATCH) — carried in the error.
133
+ * @param modelName optional model/table name — carried in the error for diagnosis.
134
+ */
135
+ export declare function checkWriteAllowed(operation: string, modelName?: string): void;
136
+ //# sourceMappingURL=tx-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tx-options.d.ts","sourceRoot":"","sources":["../../src/scp/tx-options.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,CAAC;AAIrE;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,cAAc,CAAC;AAEnF,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAe7D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,cAAc,GAAG,SAAS,MAAM,EAAE,CAoB/F;AAID;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC;IACpC,qGAAqG;IACrG,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC,oFAAoF;IACpF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,gGAAgG;IAChG,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CAC9C;AAED,0FAA0F;AAC1F,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC;IACpC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,yBAAyB,EAAE,OAAO,CAAC;CAC7C;AAED,kGAAkG;AAClG,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,kBAAuB,GAAG,iBAAiB,CASjF;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,OAAO,GAAG,OAAO,CAsBpG;AAED,sCAAsC;AACtC,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAkBD,sGAAsG;AACtG,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE9C;AAED,gGAAgG;AAChG,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,qFAAqF;AACrF,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAG7E"}