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
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * litedbmodel v2 SCP — fragment RUNTIME (assemble + bind).
4
+ *
5
+ * This is the thin runtime a bundle drives. It does exactly three things:
6
+ *
7
+ * 1. ASSEMBLE — walk the ordered fragment list; drop any fragment whose `skip`
8
+ * is satisfied; concatenate the present fragments' `sql`, and their `params`
9
+ * in order. Nested-fragment params splice their own `sql` at the `?` and
10
+ * contribute their own params in order.
11
+ * 2. EVALUATE — turn each value-spec param into a concrete bound value using the
12
+ * runtime `input` (and upstream `wire` results).
13
+ * 3. RENDER — the produced `{ sql, params }` uses `?`; a dialect step turns `?`
14
+ * into `$N` for PostgreSQL (identical to the original driver's naive replace).
15
+ *
16
+ * NO SQL structure is generated here. The `sql` text is already complete; the
17
+ * runtime only splices nested-fragment text and fills `?`.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.isSkipped = isSkipped;
21
+ exports.evalValueSpec = evalValueSpec;
22
+ exports.assembleFragment = assembleFragment;
23
+ exports.assembleWhereGroup = assembleWhereGroup;
24
+ exports.assemble = assemble;
25
+ exports.toPostgres = toPostgres;
26
+ const model_1 = require("./model");
27
+ function readPath(root, path) {
28
+ let cur = root;
29
+ for (const seg of path) {
30
+ if (cur == null)
31
+ return undefined;
32
+ cur = cur[seg];
33
+ }
34
+ return cur;
35
+ }
36
+ /** Is a fragment's `skip` satisfied (⇒ omit the fragment)? */
37
+ function isSkipped(cond, scope) {
38
+ if (!cond)
39
+ return false;
40
+ const v = readPath(scope.input, cond.absent);
41
+ return v == null;
42
+ }
43
+ /** Evaluate a value-spec to its bound value against the runtime scope. */
44
+ function evalValueSpec(spec, scope) {
45
+ if ((0, model_1.isInputRef)(spec))
46
+ return readPath(scope.input, spec.input);
47
+ if ((0, model_1.isWireRef)(spec)) {
48
+ const [node, ...rest] = spec.wire;
49
+ // A wire-ref reads a value an UPSTREAM node produced (WireRef doc). Fragments carrying a
50
+ // wire-ref are dropped by `isSkipped` when their upstream is skipped, so by evaluation time the
51
+ // node MUST be present. An absent node is a wiring/ordering bug — fail loudly, NEVER a silent
52
+ // `?? {}` → null (an unspec'd fallback that would swallow the bug).
53
+ if (scope.wire === undefined || !(node in scope.wire)) {
54
+ throw new Error(`scp assemble: wire-ref to node '${node}' has no produced result in scope ` +
55
+ `(wire keys: ${scope.wire === undefined ? '<no wire scope>' : Object.keys(scope.wire).join(', ')}). ` +
56
+ `A wire-ref must reference an upstream node that produced — this is a wiring/ordering bug, not a silent null.`);
57
+ }
58
+ return readPath(scope.wire[node], rest);
59
+ }
60
+ if ((0, model_1.isLiteral)(spec))
61
+ return spec.literal;
62
+ if ((0, model_1.isValueExpr)(spec)) {
63
+ if (spec.op === 'coalesce') {
64
+ for (const a of spec.args) {
65
+ const v = evalValueSpec(a, scope);
66
+ if (v != null)
67
+ return v;
68
+ }
69
+ return null;
70
+ }
71
+ if (spec.op === 'add') {
72
+ return spec.args.reduce((acc, a) => acc + evalValueSpec(a, scope), 0);
73
+ }
74
+ }
75
+ throw new Error(`unknown value-spec: ${JSON.stringify(spec)}`);
76
+ }
77
+ /** Flatten one param (value-spec OR nested fragment) into sql text + bound params. */
78
+ function assembleParam(param, scope) {
79
+ if ((0, model_1.isFragment)(param)) {
80
+ // Nested fragment: splice its own sql at the `?`, contribute its own params.
81
+ return assembleFragment(param, scope);
82
+ }
83
+ // Value-spec: this `?` is filled by a single bound value.
84
+ return { sql: '?', params: [evalValueSpec(param, scope)] };
85
+ }
86
+ /**
87
+ * Assemble a single fragment: interleave its literal `sql` (split on `?`) with the
88
+ * rendered text of each param, concatenating params in order.
89
+ */
90
+ function assembleFragment(frag, scope) {
91
+ const chunks = frag.sql.split('?');
92
+ if (chunks.length - 1 !== frag.params.length) {
93
+ throw new Error(`fragment placeholder/param mismatch: ${chunks.length - 1} '?' vs ${frag.params.length} params in ${JSON.stringify(frag.sql)}`);
94
+ }
95
+ let sql = chunks[0];
96
+ const params = [];
97
+ for (let i = 0; i < frag.params.length; i++) {
98
+ const rendered = assembleParam(frag.params[i], scope);
99
+ sql += rendered.sql + chunks[i + 1];
100
+ params.push(...rendered.params);
101
+ }
102
+ return { sql, params };
103
+ }
104
+ /**
105
+ * Assemble a WHERE group: join present members with `" AND "`, prefix `" WHERE "`.
106
+ * If no member is present, produce the empty string (identical to the ORIGINAL
107
+ * `DBConditions.compile` → `parts.length === 0 ? '' : parts.join(' AND ')`, with the
108
+ * `" WHERE "` prefix owned by the caller/select in the original — here folded in).
109
+ */
110
+ function assembleWhereGroup(group, scope) {
111
+ const parts = [];
112
+ const params = [];
113
+ for (const member of group.where) {
114
+ if (isSkipped(member.skip, scope))
115
+ continue;
116
+ const r = assembleFragment(member, scope);
117
+ parts.push(r.sql);
118
+ params.push(...r.params);
119
+ }
120
+ if (parts.length === 0)
121
+ return { sql: '', params: [] };
122
+ return { sql: ` WHERE ${parts.join(' AND ')}`, params };
123
+ }
124
+ /**
125
+ * Assemble an ordered fragment/WHERE-group list into a single `{ sql, params }`
126
+ * (with `?`). Fragments whose `skip` is satisfied are omitted entirely (sql AND
127
+ * params). A WHERE group joins its present members with the original's text glue.
128
+ */
129
+ function assemble(nodes, scope) {
130
+ let sql = '';
131
+ const params = [];
132
+ for (const node of nodes) {
133
+ if ((0, model_1.isWhereGroup)(node)) {
134
+ const r = assembleWhereGroup(node, scope);
135
+ sql += r.sql;
136
+ params.push(...r.params);
137
+ continue;
138
+ }
139
+ if (isSkipped(node.skip, scope))
140
+ continue;
141
+ const r = assembleFragment(node, scope);
142
+ sql += r.sql;
143
+ params.push(...r.params);
144
+ }
145
+ return { sql, params };
146
+ }
147
+ /**
148
+ * PostgreSQL dialect render: `?` → `$1, $2, …`. Byte-identical to the original
149
+ * driver's `convertPlaceholders` (naive left-to-right replace; see
150
+ * `src/drivers/postgres.ts`).
151
+ */
152
+ function toPostgres(sql) {
153
+ let index = 0;
154
+ return sql.replace(/\?/g, () => `$${++index}`);
155
+ }
156
+ //# sourceMappingURL=assemble.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../../src/scp/fragment/assemble.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * litedbmodel v2 SCP — PostgreSQL compile (build time, TS).
3
+ *
4
+ * Produces the fragment list for a query. Every fragment's `sql` text is emitted by
5
+ * REUSING the ORIGINAL tuned builders (`DBConditions`, `buildSelectSQL`,
6
+ * `LazyRelation`) so that ANY SKIP combination reassembles to exactly what the
7
+ * original builder would produce for that combination. The compiler runs at build
8
+ * time (TS); its OUTPUT (the fragment list) is the pure-JSON portable bundle.
9
+ *
10
+ * NO abstract IR is produced. Only `{ sql, params, skip }` fragments (+ nested
11
+ * fragment params where a subquery/sub-expression is needed).
12
+ */
13
+ import type { Fragment, Node, ValueSpec } from './model';
14
+ /**
15
+ * An authored optional WHERE equality: `<column> = <value from input.path>`,
16
+ * present only when `input.path` is non-null (else the fragment is skipped).
17
+ */
18
+ export interface OptionalEq {
19
+ column: string;
20
+ inputPath: string[];
21
+ }
22
+ /**
23
+ * Compile one optional equality to a fragment carrying a `skip`.
24
+ *
25
+ * The condition core text (`<col> = ?`) is emitted by the ORIGINAL `DBConditions`,
26
+ * so it is byte-identical to the tuned builder. The leading `" AND "` is the exact
27
+ * connector the original uses when joining a present condition after an earlier
28
+ * (mandatory) part — see the byte-match invariant in {@link compileSelect}.
29
+ */
30
+ export declare function compileOptionalEq(cond: OptionalEq): Fragment;
31
+ /**
32
+ * belongsTo / single-key batch (PG): `SELECT … FROM t WHERE t.key = ANY(?::type[])`.
33
+ *
34
+ * This is byte-identical to `LazyRelation.batchLoadWithAnyArray`. The array of keys
35
+ * binds as ONE param (`keys` value-spec) — the `?::type[]` cast text is static,
36
+ * chosen at compile time by the ORIGINAL `inferPgArrayType`. Optional relation
37
+ * `where`-filters (config.conditions) are appended as `compileOptionalEq` fragments.
38
+ */
39
+ export declare function compileBelongsTo(opts: {
40
+ tableName: string;
41
+ selectColumn?: string;
42
+ targetKey: string;
43
+ /** compile-time sample values used ONLY for cast-type inference. */
44
+ sampleKeys: unknown[];
45
+ /** value-spec producing the runtime key array (bound as one param). */
46
+ keys: ValueSpec;
47
+ sqlCast?: string;
48
+ filters?: OptionalEq[];
49
+ }): Fragment[];
50
+ /**
51
+ * hasMany + per-parent limit (PG): `CROSS JOIN LATERAL`.
52
+ *
53
+ * Byte-identical to `LazyRelation.batchLoadWithLateral`. The inner SELECT is emitted
54
+ * by the ORIGINAL `buildSelectSQL` (reproduced here as the same template it yields:
55
+ * `SELECT <sel> FROM t WHERE t.key = _keys.key[ AND <filters>] ORDER BY <order> LIMIT n`).
56
+ * The outer wraps it in `unnest(?::type[]) AS _keys(key) CROSS JOIN LATERAL (…)`.
57
+ *
58
+ * `limit` is inlined into the text (the original inlines it: `LIMIT ${limit}`), so it
59
+ * is NOT a param. The key array binds as ONE param.
60
+ */
61
+ export declare function compileHasManyLimited(opts: {
62
+ tableName: string;
63
+ selectColumn?: string;
64
+ targetKey: string;
65
+ sampleKeys: unknown[];
66
+ keys: ValueSpec;
67
+ order: string;
68
+ limit: number;
69
+ sqlCast?: string;
70
+ filters?: OptionalEq[];
71
+ }): Fragment[];
72
+ /**
73
+ * hasMany / single-key batch WITHOUT limit (PG): `= ANY(?::type[])` + ORDER BY.
74
+ * Byte-identical to `batchLoadWithAnyArray` (used for hasMany when no limit) —
75
+ * same shape as {@link compileBelongsTo} plus a trailing ORDER BY carried on the
76
+ * base fragment (so optional filters slot BEFORE the ORDER BY, matching the
77
+ * original which appends conditions before the order clause).
78
+ */
79
+ export declare function compileHasManyAny(opts: {
80
+ tableName: string;
81
+ selectColumn?: string;
82
+ targetKey: string;
83
+ sampleKeys: unknown[];
84
+ keys: ValueSpec;
85
+ order?: string;
86
+ sqlCast?: string;
87
+ filters?: OptionalEq[];
88
+ }): Fragment[];
89
+ /**
90
+ * A plain `SELECT <sel> FROM t` with a WHERE built only from optional conditions.
91
+ *
92
+ * The WHERE is a {@link WhereGroup}: each member fragment carries the BARE condition
93
+ * core (`"status = ?"`, NO leading connector), emitted by the ORIGINAL
94
+ * `DBConditions`, and its own `skip`. At assemble time the group joins the SURVIVORS
95
+ * with `" AND "` and prefixes `" WHERE "` — byte-identical to the original
96
+ * `DBConditions.compile` → `parts.join(' AND ')` for EVERY present/absent subset,
97
+ * including when the first condition is skipped (the group's join, not a static
98
+ * connector, decides the leading text). No new SQL-structure vocabulary: the join is
99
+ * pure text glue, exactly the original's algorithm.
100
+ */
101
+ export declare function compileBaseSelect(opts: {
102
+ tableName: string;
103
+ selectColumn?: string;
104
+ /** ordered optional equality conditions */
105
+ conditions: OptionalEq[];
106
+ }): Node[];
107
+ //# sourceMappingURL=compile-pg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-pg.d.ts","sourceRoot":"","sources":["../../../src/scp/fragment/compile-pg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAqB,SAAS,EAAE,MAAM,SAAS,CAAC;AAM5E;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,QAAQ,CAU5D;AAMD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,uEAAuE;IACvE,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;CACxB,GAAG,QAAQ,EAAE,CAQb;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;CACxB,GAAG,QAAQ,EAAE,CAsBb;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;CACxB,GAAG,QAAQ,EAAE,CAUb;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B,GAAG,IAAI,EAAE,CAeT"}
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * litedbmodel v2 SCP — PostgreSQL compile (build time, TS).
4
+ *
5
+ * Produces the fragment list for a query. Every fragment's `sql` text is emitted by
6
+ * REUSING the ORIGINAL tuned builders (`DBConditions`, `buildSelectSQL`,
7
+ * `LazyRelation`) so that ANY SKIP combination reassembles to exactly what the
8
+ * original builder would produce for that combination. The compiler runs at build
9
+ * time (TS); its OUTPUT (the fragment list) is the pure-JSON portable bundle.
10
+ *
11
+ * NO abstract IR is produced. Only `{ sql, params, skip }` fragments (+ nested
12
+ * fragment params where a subquery/sub-expression is needed).
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.compileOptionalEq = compileOptionalEq;
16
+ exports.compileBelongsTo = compileBelongsTo;
17
+ exports.compileHasManyLimited = compileHasManyLimited;
18
+ exports.compileHasManyAny = compileHasManyAny;
19
+ exports.compileBaseSelect = compileBaseSelect;
20
+ const DBConditions_1 = require("../../DBConditions");
21
+ const pg_array_type_1 = require("./pg-array-type");
22
+ /**
23
+ * Compile one optional equality to a fragment carrying a `skip`.
24
+ *
25
+ * The condition core text (`<col> = ?`) is emitted by the ORIGINAL `DBConditions`,
26
+ * so it is byte-identical to the tuned builder. The leading `" AND "` is the exact
27
+ * connector the original uses when joining a present condition after an earlier
28
+ * (mandatory) part — see the byte-match invariant in {@link compileSelect}.
29
+ */
30
+ function compileOptionalEq(cond) {
31
+ const probe = [];
32
+ const core = new DBConditions_1.DBConditions({ [cond.column]: '__probe__' }).compile(probe);
33
+ // core === `<col> = ?` (source of the text is the original builder)
34
+ const param = { input: cond.inputPath };
35
+ return {
36
+ sql: ` AND ${core}`,
37
+ params: [param],
38
+ skip: { absent: cond.inputPath },
39
+ };
40
+ }
41
+ // ============================================================================
42
+ // Relation batch-load fragments — text emitted by the ORIGINAL LazyRelation paths.
43
+ // ============================================================================
44
+ /**
45
+ * belongsTo / single-key batch (PG): `SELECT … FROM t WHERE t.key = ANY(?::type[])`.
46
+ *
47
+ * This is byte-identical to `LazyRelation.batchLoadWithAnyArray`. The array of keys
48
+ * binds as ONE param (`keys` value-spec) — the `?::type[]` cast text is static,
49
+ * chosen at compile time by the ORIGINAL `inferPgArrayType`. Optional relation
50
+ * `where`-filters (config.conditions) are appended as `compileOptionalEq` fragments.
51
+ */
52
+ function compileBelongsTo(opts) {
53
+ const select = opts.selectColumn || '*';
54
+ const pgType = (0, pg_array_type_1.inferPgArrayTypeForCompile)(opts.sampleKeys, opts.sqlCast);
55
+ const base = {
56
+ sql: `SELECT ${select} FROM ${opts.tableName} WHERE ${opts.tableName}.${opts.targetKey} = ANY(?::${pgType})`,
57
+ params: [opts.keys],
58
+ };
59
+ return [base, ...(opts.filters ?? []).map(compileOptionalEq)];
60
+ }
61
+ /**
62
+ * hasMany + per-parent limit (PG): `CROSS JOIN LATERAL`.
63
+ *
64
+ * Byte-identical to `LazyRelation.batchLoadWithLateral`. The inner SELECT is emitted
65
+ * by the ORIGINAL `buildSelectSQL` (reproduced here as the same template it yields:
66
+ * `SELECT <sel> FROM t WHERE t.key = _keys.key[ AND <filters>] ORDER BY <order> LIMIT n`).
67
+ * The outer wraps it in `unnest(?::type[]) AS _keys(key) CROSS JOIN LATERAL (…)`.
68
+ *
69
+ * `limit` is inlined into the text (the original inlines it: `LIMIT ${limit}`), so it
70
+ * is NOT a param. The key array binds as ONE param.
71
+ */
72
+ function compileHasManyLimited(opts) {
73
+ const select = opts.selectColumn || '*';
74
+ const pgType = (0, pg_array_type_1.inferPgArrayTypeForCompile)(opts.sampleKeys, opts.sqlCast);
75
+ const filterFrags = (opts.filters ?? []).map(compileOptionalEq);
76
+ // The full inner+outer text (byte-identical to batchLoadWithLateral) is split into
77
+ // three fragments so optional filters slot in AFTER the mandatory `t.key=_keys.key`
78
+ // predicate and BEFORE the ORDER BY, exactly where the original appends them:
79
+ // head: ... CROSS JOIN LATERAL (SELECT * FROM t WHERE t.key = _keys.key
80
+ // [filters] each `" AND <core>"` (skip-guarded)
81
+ // tail: ORDER BY <order> LIMIT <n>) t
82
+ const head = {
83
+ sql: `SELECT ${opts.tableName}.* FROM unnest(?::${pgType}) AS _keys(key) CROSS JOIN LATERAL (` +
84
+ `SELECT ${select} FROM ${opts.tableName} WHERE ${opts.tableName}.${opts.targetKey} = _keys.key`,
85
+ params: [opts.keys],
86
+ };
87
+ const tail = {
88
+ sql: ` ORDER BY ${opts.order} LIMIT ${opts.limit}) ${opts.tableName}`,
89
+ params: [],
90
+ };
91
+ return [head, ...filterFrags, tail];
92
+ }
93
+ /**
94
+ * hasMany / single-key batch WITHOUT limit (PG): `= ANY(?::type[])` + ORDER BY.
95
+ * Byte-identical to `batchLoadWithAnyArray` (used for hasMany when no limit) —
96
+ * same shape as {@link compileBelongsTo} plus a trailing ORDER BY carried on the
97
+ * base fragment (so optional filters slot BEFORE the ORDER BY, matching the
98
+ * original which appends conditions before the order clause).
99
+ */
100
+ function compileHasManyAny(opts) {
101
+ const select = opts.selectColumn || '*';
102
+ const pgType = (0, pg_array_type_1.inferPgArrayTypeForCompile)(opts.sampleKeys, opts.sqlCast);
103
+ const head = {
104
+ sql: `SELECT ${select} FROM ${opts.tableName} WHERE ${opts.tableName}.${opts.targetKey} = ANY(?::${pgType})`,
105
+ params: [opts.keys],
106
+ };
107
+ const filterFrags = (opts.filters ?? []).map(compileOptionalEq);
108
+ const tail = opts.order ? [{ sql: ` ORDER BY ${opts.order}`, params: [] }] : [];
109
+ return [head, ...filterFrags, ...tail];
110
+ }
111
+ // ============================================================================
112
+ // Base SELECT + WHERE (all-optional conditions, no mandatory predicate).
113
+ // ============================================================================
114
+ /**
115
+ * A plain `SELECT <sel> FROM t` with a WHERE built only from optional conditions.
116
+ *
117
+ * The WHERE is a {@link WhereGroup}: each member fragment carries the BARE condition
118
+ * core (`"status = ?"`, NO leading connector), emitted by the ORIGINAL
119
+ * `DBConditions`, and its own `skip`. At assemble time the group joins the SURVIVORS
120
+ * with `" AND "` and prefixes `" WHERE "` — byte-identical to the original
121
+ * `DBConditions.compile` → `parts.join(' AND ')` for EVERY present/absent subset,
122
+ * including when the first condition is skipped (the group's join, not a static
123
+ * connector, decides the leading text). No new SQL-structure vocabulary: the join is
124
+ * pure text glue, exactly the original's algorithm.
125
+ */
126
+ function compileBaseSelect(opts) {
127
+ const select = opts.selectColumn || '*';
128
+ const base = { sql: `SELECT ${select} FROM ${opts.tableName}`, params: [] };
129
+ const group = {
130
+ where: opts.conditions.map((c) => {
131
+ const probe = [];
132
+ const core = new DBConditions_1.DBConditions({ [c.column]: '__probe__' }).compile(probe);
133
+ return {
134
+ sql: core, // bare core, e.g. `status = ?` — connector belongs to the join
135
+ params: [{ input: c.inputPath }],
136
+ skip: { absent: c.inputPath },
137
+ };
138
+ }),
139
+ };
140
+ return [base, group];
141
+ }
142
+ //# sourceMappingURL=compile-pg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-pg.js","sourceRoot":"","sources":["../../../src/scp/fragment/compile-pg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * litedbmodel v2 SCP — the MINIMAL fragment model (epic #43 reset).
3
+ *
4
+ * Public surface: the fragment types, the compile helpers (build-time TS, reuse the
5
+ * original tuned builders), and the runtime assembler (thin, language-portable).
6
+ *
7
+ * There is NO abstract IR here. The portable artifact is ONLY a combination of
8
+ * `{ sql, params, skip }` fragments, with params being either value-specs or nested
9
+ * fragments. SQL structure (`= ANY`, `CROSS JOIN LATERAL`, `UNNEST`, subquery, cast)
10
+ * is TEXT inside `sql`, never a modeled construct.
11
+ */
12
+ export * from './model';
13
+ export * from './assemble';
14
+ export * from './compile-pg';
15
+ export { inferPgArrayTypeForCompile } from './pg-array-type';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scp/fragment/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ /**
3
+ * litedbmodel v2 SCP — the MINIMAL fragment model (epic #43 reset).
4
+ *
5
+ * Public surface: the fragment types, the compile helpers (build-time TS, reuse the
6
+ * original tuned builders), and the runtime assembler (thin, language-portable).
7
+ *
8
+ * There is NO abstract IR here. The portable artifact is ONLY a combination of
9
+ * `{ sql, params, skip }` fragments, with params being either value-specs or nested
10
+ * fragments. SQL structure (`= ANY`, `CROSS JOIN LATERAL`, `UNNEST`, subquery, cast)
11
+ * is TEXT inside `sql`, never a modeled construct.
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
25
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
26
+ };
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.inferPgArrayTypeForCompile = void 0;
29
+ __exportStar(require("./model"), exports);
30
+ __exportStar(require("./assemble"), exports);
31
+ __exportStar(require("./compile-pg"), exports);
32
+ var pg_array_type_1 = require("./pg-array-type");
33
+ Object.defineProperty(exports, "inferPgArrayTypeForCompile", { enumerable: true, get: function () { return pg_array_type_1.inferPgArrayTypeForCompile; } });
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scp/fragment/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;;;;;;;;;;;;;;;AAEH,0CAAwB;AACxB,6CAA2B;AAC3B,+CAA6B;AAC7B,iDAA6D;AAApD,2HAAA,0BAA0B,OAAA"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * litedbmodel v2 SCP — the MINIMAL fragment model (epic #43 reset).
3
+ *
4
+ * ## The locked vocabulary (owner-specified — nothing else exists here)
5
+ *
6
+ * The portable artifact is ONLY a combination of **fragments**. There is NO
7
+ * abstract "Expression IR", NO relation-op / operator kinds for SQL structure,
8
+ * NO `FragmentTree` connector algebra, NO `{where}` splice marker. SQL structure
9
+ * (`= ANY`, `CROSS JOIN LATERAL`, `UNNEST`, subquery, cast, batch shapes) lives
10
+ * ENTIRELY as TEXT inside `sql`.
11
+ *
12
+ * fragment = { sql: string, params: Param[], skip?: PresenceCondition }
13
+ *
14
+ * - A query is an ordered list of fragments.
15
+ * - Assembling = concatenate the `sql` of every PRESENT fragment, and concatenate
16
+ * their `params` in order. If a fragment's `skip` is satisfied, BOTH its `sql`
17
+ * and its `params` are omitted.
18
+ *
19
+ * Param = EITHER
20
+ * (a) a **value-spec** — how to compute the bound value from input at runtime:
21
+ * an input-ref / wire-ref / a small closed value-expression
22
+ * (e.g. `coalesce(input.limit, 20)`). This computes the VALUE only.
23
+ * OR
24
+ * (b) a **nested fragment** — a raw SQL sub-piece with its own params. This is
25
+ * how subqueries / sub-expressions are represented: NOT as IR constructs,
26
+ * just a nested { sql, params }.
27
+ *
28
+ * Array-parameter placeholder expansion is DRIVER-side, not modeled here. On
29
+ * PostgreSQL an array param binds directly (`= ANY(?::int[])`), so the text is
30
+ * static and the array is ONE param. On MySQL/SQLite (no array binding) the DRIVER
31
+ * expands an array param into `(?, ?, …)` at bind time. The bundle stays
32
+ * "string + params" regardless.
33
+ *
34
+ * The whole model is plain JSON / serializable so a thin runtime in any language
35
+ * reads it identically.
36
+ */
37
+ /** Read a value from runtime input by path, e.g. `{ input: ["authorId"] }`. */
38
+ export interface InputRef {
39
+ input: string[];
40
+ }
41
+ /** Read a value produced by an upstream node/wire, e.g. `{ wire: ["node1", "id"] }`. */
42
+ export interface WireRef {
43
+ wire: string[];
44
+ }
45
+ /** A literal constant value baked into the bundle (e.g. an array of keys, or 20). */
46
+ export interface LiteralValue {
47
+ literal: unknown;
48
+ }
49
+ /**
50
+ * A small CLOSED value-expression. It computes a value from other value-specs.
51
+ * This is deliberately tiny: `coalesce` and `add` are enough for the LIMIT / key
52
+ * shapes in this slice. It is NOT an SQL-structure IR — it never emits SQL.
53
+ */
54
+ export interface ValueExpr {
55
+ op: 'coalesce' | 'add';
56
+ args: ValueSpec[];
57
+ }
58
+ /** Param variant (a): a value-spec. */
59
+ export type ValueSpec = InputRef | WireRef | LiteralValue | ValueExpr;
60
+ /**
61
+ * Param variant (b): a nested fragment. A subquery / sub-expression is just a
62
+ * `{ sql, params }` embedded as a param — its `sql` is spliced into the parent's
63
+ * `?` position, its params flow into the parent's param stream in order. This is
64
+ * how subqueries are represented WITHOUT any IR construct.
65
+ */
66
+ export type Param = ValueSpec | Fragment;
67
+ /**
68
+ * A presence condition for `skip`. When SATISFIED, the fragment (sql + params)
69
+ * is OMITTED. Deliberately closed and tiny: "the input at this path is absent /
70
+ * null / undefined". SKIP is not an operator — it is the ABSENCE of the fragment.
71
+ */
72
+ export interface PresenceCondition {
73
+ /** Skip the fragment when the input at this path is null/undefined. */
74
+ absent: string[];
75
+ }
76
+ /**
77
+ * The one and only structural type: `{ sql, params, skip? }`.
78
+ *
79
+ * `sql` is literal SQL text (leading connector included where relevant, e.g.
80
+ * `" AND status = ?"`) with `?` placeholders. `params` are 1:1 with the `?`
81
+ * (a value-spec fills one `?`; a nested-fragment param splices its own `sql`,
82
+ * which itself may contain further `?`). `skip`, when present and satisfied,
83
+ * omits the whole fragment.
84
+ */
85
+ export interface Fragment {
86
+ sql: string;
87
+ params: Param[];
88
+ skip?: PresenceCondition;
89
+ }
90
+ /**
91
+ * A WHERE clause is an ordered list of condition fragments joined by the SAME text
92
+ * glue the ORIGINAL `DBConditions.compile` uses: present members are joined with
93
+ * `" AND "` and the whole is prefixed with `" WHERE "` — and if NO member is
94
+ * present, the clause degenerates to the empty string (exactly the original's
95
+ * `parts.length === 0 → ''`).
96
+ *
97
+ * This is the "tree" form of the fragment model (a query is an ordered list/tree of
98
+ * fragments). It carries NO SQL-structure vocabulary — the join is pure text glue,
99
+ * identical to the original builder's `parts.join(' AND ')`. Each member fragment's
100
+ * `sql` is the bare condition core (`"status = ?"`, NO leading connector); the
101
+ * connector belongs to the join, so it is SKIP-stable regardless of which members
102
+ * survive.
103
+ *
104
+ * Members carry their own `skip`; a skipped member contributes neither text nor
105
+ * params, and the join simply closes over the survivors (so the first survivor never
106
+ * emits a stray leading `" AND "`).
107
+ */
108
+ export interface WhereGroup {
109
+ where: Fragment[];
110
+ }
111
+ /** A member of an assembled query: a plain fragment or a WHERE group. */
112
+ export type Node = Fragment | WhereGroup;
113
+ export declare function isFragment(p: Param | Node): p is Fragment;
114
+ export declare function isWhereGroup(n: Node): n is WhereGroup;
115
+ export declare function isInputRef(v: ValueSpec): v is InputRef;
116
+ export declare function isWireRef(v: ValueSpec): v is WireRef;
117
+ export declare function isLiteral(v: ValueSpec): v is LiteralValue;
118
+ export declare function isValueExpr(v: ValueSpec): v is ValueExpr;
119
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/scp/fragment/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAOH,+EAA+E;AAC/E,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wFAAwF;AACxF,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,qFAAqF;AACrF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAED,uCAAuC;AACvC,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,GAAG,SAAS,CAAC;AAMtE;;;;;GAKG;AACH,MAAM,MAAM,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAC;AAMzC;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,iBAAiB,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,yEAAyE;AACzE,MAAM,MAAM,IAAI,GAAG,QAAQ,GAAG,UAAU,CAAC;AAMzC,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,QAAQ,CAEzD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,UAAU,CAErD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,IAAI,QAAQ,CAEtD;AACD,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,IAAI,OAAO,CAEpD;AACD,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,IAAI,YAAY,CAEzD;AACD,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,IAAI,SAAS,CAExD"}