@kuindji/typed-sql 0.1.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 (208) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +227 -0
  3. package/dist/builder/assemble.d.ts +13 -0
  4. package/dist/builder/assemble.d.ts.map +1 -0
  5. package/dist/builder/assemble.js +86 -0
  6. package/dist/builder/assemble.js.map +1 -0
  7. package/dist/builder/condition-tree.d.ts +27 -0
  8. package/dist/builder/condition-tree.d.ts.map +1 -0
  9. package/dist/builder/condition-tree.js +91 -0
  10. package/dist/builder/condition-tree.js.map +1 -0
  11. package/dist/builder/conditional-sql.d.ts +80 -0
  12. package/dist/builder/conditional-sql.d.ts.map +1 -0
  13. package/dist/builder/conditional-sql.js +88 -0
  14. package/dist/builder/conditional-sql.js.map +1 -0
  15. package/dist/builder/db.d.ts +76 -0
  16. package/dist/builder/db.d.ts.map +1 -0
  17. package/dist/builder/db.js +12 -0
  18. package/dist/builder/db.js.map +1 -0
  19. package/dist/builder/delete.d.ts +39 -0
  20. package/dist/builder/delete.d.ts.map +1 -0
  21. package/dist/builder/delete.js +33 -0
  22. package/dist/builder/delete.js.map +1 -0
  23. package/dist/builder/extract-params.d.ts +97 -0
  24. package/dist/builder/extract-params.d.ts.map +1 -0
  25. package/dist/builder/extract-params.js +2 -0
  26. package/dist/builder/extract-params.js.map +1 -0
  27. package/dist/builder/index.d.ts +23 -0
  28. package/dist/builder/index.d.ts.map +1 -0
  29. package/dist/builder/index.js +14 -0
  30. package/dist/builder/index.js.map +1 -0
  31. package/dist/builder/insert.d.ts +51 -0
  32. package/dist/builder/insert.d.ts.map +1 -0
  33. package/dist/builder/insert.js +39 -0
  34. package/dist/builder/insert.js.map +1 -0
  35. package/dist/builder/mutate.d.ts +28 -0
  36. package/dist/builder/mutate.d.ts.map +1 -0
  37. package/dist/builder/mutate.js +17 -0
  38. package/dist/builder/mutate.js.map +1 -0
  39. package/dist/builder/params.d.ts +22 -0
  40. package/dist/builder/params.d.ts.map +1 -0
  41. package/dist/builder/params.js +65 -0
  42. package/dist/builder/params.js.map +1 -0
  43. package/dist/builder/return-type.d.ts +39 -0
  44. package/dist/builder/return-type.d.ts.map +1 -0
  45. package/dist/builder/return-type.js +2 -0
  46. package/dist/builder/return-type.js.map +1 -0
  47. package/dist/builder/scanner.d.ts +49 -0
  48. package/dist/builder/scanner.d.ts.map +1 -0
  49. package/dist/builder/scanner.js +240 -0
  50. package/dist/builder/scanner.js.map +1 -0
  51. package/dist/builder/select.d.ts +76 -0
  52. package/dist/builder/select.d.ts.map +1 -0
  53. package/dist/builder/select.js +240 -0
  54. package/dist/builder/select.js.map +1 -0
  55. package/dist/builder/sql-tag.d.ts +319 -0
  56. package/dist/builder/sql-tag.d.ts.map +1 -0
  57. package/dist/builder/sql-tag.js +3 -0
  58. package/dist/builder/sql-tag.js.map +1 -0
  59. package/dist/builder/sql.d.ts +17 -0
  60. package/dist/builder/sql.d.ts.map +1 -0
  61. package/dist/builder/sql.js +36 -0
  62. package/dist/builder/sql.js.map +1 -0
  63. package/dist/builder/state.d.ts +53 -0
  64. package/dist/builder/state.d.ts.map +1 -0
  65. package/dist/builder/state.js +18 -0
  66. package/dist/builder/state.js.map +1 -0
  67. package/dist/builder/update.d.ts +60 -0
  68. package/dist/builder/update.d.ts.map +1 -0
  69. package/dist/builder/update.js +40 -0
  70. package/dist/builder/update.js.map +1 -0
  71. package/dist/builder/write-assemble.d.ts +5 -0
  72. package/dist/builder/write-assemble.d.ts.map +1 -0
  73. package/dist/builder/write-assemble.js +57 -0
  74. package/dist/builder/write-assemble.js.map +1 -0
  75. package/dist/builder/write-state.d.ts +39 -0
  76. package/dist/builder/write-state.d.ts.map +1 -0
  77. package/dist/builder/write-state.js +6 -0
  78. package/dist/builder/write-state.js.map +1 -0
  79. package/dist/builder/write-tag.d.ts +91 -0
  80. package/dist/builder/write-tag.d.ts.map +1 -0
  81. package/dist/builder/write-tag.js +2 -0
  82. package/dist/builder/write-tag.js.map +1 -0
  83. package/dist/columns.d.ts +33 -0
  84. package/dist/columns.d.ts.map +1 -0
  85. package/dist/columns.js +2 -0
  86. package/dist/columns.js.map +1 -0
  87. package/dist/expressions.d.ts +71 -0
  88. package/dist/expressions.d.ts.map +1 -0
  89. package/dist/expressions.js +2 -0
  90. package/dist/expressions.js.map +1 -0
  91. package/dist/index.d.ts +22 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +5 -0
  94. package/dist/index.js.map +1 -0
  95. package/dist/parsing/extract.d.ts +47 -0
  96. package/dist/parsing/extract.d.ts.map +1 -0
  97. package/dist/parsing/extract.js +2 -0
  98. package/dist/parsing/extract.js.map +1 -0
  99. package/dist/parsing/normalize.d.ts +44 -0
  100. package/dist/parsing/normalize.d.ts.map +1 -0
  101. package/dist/parsing/normalize.js +2 -0
  102. package/dist/parsing/normalize.js.map +1 -0
  103. package/dist/parsing/pg-literals.d.ts +37 -0
  104. package/dist/parsing/pg-literals.d.ts.map +1 -0
  105. package/dist/parsing/pg-literals.js +2 -0
  106. package/dist/parsing/pg-literals.js.map +1 -0
  107. package/dist/parsing/split.d.ts +100 -0
  108. package/dist/parsing/split.d.ts.map +1 -0
  109. package/dist/parsing/split.js +2 -0
  110. package/dist/parsing/split.js.map +1 -0
  111. package/dist/parsing/string-utils.d.ts +29 -0
  112. package/dist/parsing/string-utils.d.ts.map +1 -0
  113. package/dist/parsing/string-utils.js +2 -0
  114. package/dist/parsing/string-utils.js.map +1 -0
  115. package/dist/parsing/tokenize.d.ts +27 -0
  116. package/dist/parsing/tokenize.d.ts.map +1 -0
  117. package/dist/parsing/tokenize.js +2 -0
  118. package/dist/parsing/tokenize.js.map +1 -0
  119. package/dist/parsing.d.ts +7 -0
  120. package/dist/parsing.d.ts.map +1 -0
  121. package/dist/parsing.js +9 -0
  122. package/dist/parsing.js.map +1 -0
  123. package/dist/partial.d.ts +30 -0
  124. package/dist/partial.d.ts.map +1 -0
  125. package/dist/partial.js +10 -0
  126. package/dist/partial.js.map +1 -0
  127. package/dist/schema.d.ts +28 -0
  128. package/dist/schema.d.ts.map +1 -0
  129. package/dist/schema.js +2 -0
  130. package/dist/schema.js.map +1 -0
  131. package/dist/tables.d.ts +34 -0
  132. package/dist/tables.d.ts.map +1 -0
  133. package/dist/tables.js +2 -0
  134. package/dist/tables.js.map +1 -0
  135. package/dist/utils.d.ts +13 -0
  136. package/dist/utils.d.ts.map +1 -0
  137. package/dist/utils.js +3 -0
  138. package/dist/utils.js.map +1 -0
  139. package/dist/validation/cte.d.ts +54 -0
  140. package/dist/validation/cte.d.ts.map +1 -0
  141. package/dist/validation/cte.js +2 -0
  142. package/dist/validation/cte.js.map +1 -0
  143. package/dist/validation/dispatch.d.ts +31 -0
  144. package/dist/validation/dispatch.d.ts.map +1 -0
  145. package/dist/validation/dispatch.js +2 -0
  146. package/dist/validation/dispatch.js.map +1 -0
  147. package/dist/validation/joins.d.ts +16 -0
  148. package/dist/validation/joins.d.ts.map +1 -0
  149. package/dist/validation/joins.js +2 -0
  150. package/dist/validation/joins.js.map +1 -0
  151. package/dist/validation/return-derived.d.ts +67 -0
  152. package/dist/validation/return-derived.d.ts.map +1 -0
  153. package/dist/validation/return-derived.js +5 -0
  154. package/dist/validation/return-derived.js.map +1 -0
  155. package/dist/validation/return-types.d.ts +41 -0
  156. package/dist/validation/return-types.d.ts.map +1 -0
  157. package/dist/validation/return-types.js +2 -0
  158. package/dist/validation/return-types.js.map +1 -0
  159. package/dist/validation/validate-columns.d.ts +63 -0
  160. package/dist/validation/validate-columns.d.ts.map +1 -0
  161. package/dist/validation/validate-columns.js +2 -0
  162. package/dist/validation/validate-columns.js.map +1 -0
  163. package/dist/validation.d.ts +7 -0
  164. package/dist/validation.d.ts.map +1 -0
  165. package/dist/validation.js +9 -0
  166. package/dist/validation.js.map +1 -0
  167. package/package.json +64 -0
  168. package/src/builder/assemble.ts +100 -0
  169. package/src/builder/condition-tree.ts +162 -0
  170. package/src/builder/conditional-sql.ts +325 -0
  171. package/src/builder/db.ts +281 -0
  172. package/src/builder/delete.ts +57 -0
  173. package/src/builder/extract-params.ts +507 -0
  174. package/src/builder/index.ts +58 -0
  175. package/src/builder/insert.ts +75 -0
  176. package/src/builder/mutate.ts +55 -0
  177. package/src/builder/params.ts +95 -0
  178. package/src/builder/return-type.ts +66 -0
  179. package/src/builder/scanner.ts +254 -0
  180. package/src/builder/select.ts +470 -0
  181. package/src/builder/sql-tag.ts +422 -0
  182. package/src/builder/sql.ts +51 -0
  183. package/src/builder/state.ts +55 -0
  184. package/src/builder/update.ts +77 -0
  185. package/src/builder/write-assemble.ts +52 -0
  186. package/src/builder/write-state.ts +43 -0
  187. package/src/builder/write-tag.ts +119 -0
  188. package/src/columns.ts +336 -0
  189. package/src/expressions.ts +745 -0
  190. package/src/index.ts +81 -0
  191. package/src/parsing/extract.ts +260 -0
  192. package/src/parsing/normalize.ts +243 -0
  193. package/src/parsing/pg-literals.ts +289 -0
  194. package/src/parsing/split.ts +288 -0
  195. package/src/parsing/string-utils.ts +172 -0
  196. package/src/parsing/tokenize.ts +321 -0
  197. package/src/parsing.ts +8 -0
  198. package/src/partial.ts +241 -0
  199. package/src/schema.ts +130 -0
  200. package/src/tables.ts +278 -0
  201. package/src/utils.ts +43 -0
  202. package/src/validation/cte.ts +198 -0
  203. package/src/validation/dispatch.ts +312 -0
  204. package/src/validation/joins.ts +198 -0
  205. package/src/validation/return-derived.ts +253 -0
  206. package/src/validation/return-types.ts +271 -0
  207. package/src/validation/validate-columns.ts +489 -0
  208. package/src/validation.ts +8 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ivan Kuindzhi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,227 @@
1
+ # @kuindji/typed-sql
2
+
3
+ **A compile-time SQL validator and result-type inferrer for TypeScript.**
4
+
5
+ You write SQL as a normal TypeScript string. The library parses and checks it
6
+ **entirely in the type system** — against a schema you describe as a type — and
7
+ infers the shape of the rows the query returns. Nothing runs at runtime for the
8
+ validation/inference: the work happens while `tsc` type-checks your code.
9
+
10
+ ```ts
11
+ import type { ValidateSQL, GetReturnType, DatabaseSchema } from "@kuindji/typed-sql";
12
+
13
+ type Schema = {
14
+ defaultSchema: "public";
15
+ schemas: {
16
+ public: {
17
+ users: { id: number; email: string; name: string | null };
18
+ };
19
+ };
20
+ };
21
+
22
+ type Ok = ValidateSQL<"select id, email from users", Schema>; // true
23
+ type Bad = ValidateSQL<"select id, nope from users", Schema>; // false
24
+ type Rows = GetReturnType<"select id, name from users", Schema>; // { id: number; name: string | null }
25
+ ```
26
+
27
+ > **Target dialect: PostgreSQL.** Quoted identifiers (`"camelCase"`), `::` casts,
28
+ > `coalesce`, `distinct on`, `returning`, etc. are interpreted with Postgres
29
+ > semantics.
30
+
31
+ ---
32
+
33
+ ## What it IS
34
+
35
+ - **A type-level SQL parser.** Validation and row-type inference run in the
36
+ TypeScript type system at compile time. The "parser" is a tower of conditional
37
+ types, not runtime code.
38
+ - **A schema-checked SQL guard.** Given a `DatabaseSchema` type, it confirms that
39
+ tables, columns, aliases, and references in a query actually exist, and rejects
40
+ ones that don't.
41
+ - **A result-type inferrer.** `GetReturnType<Q, Schema>` produces the row object a
42
+ `SELECT`/`RETURNING` query yields, including join nullability and casts.
43
+ - **A small runtime query builder** (`createSelectQuery`, `createConditionTree`,
44
+ conditional-SQL helpers) that assembles a SQL **string + ordered params** and
45
+ carries the inferred result type alongside it.
46
+
47
+ ## What it is NOT
48
+
49
+ - **Not a runtime SQL parser or engine.** It does not parse SQL at runtime, does
50
+ not execute queries, and does not connect to a database. `createSelectFn(driver)`
51
+ takes **your** executor and just hands it the assembled `(sql, params)` — you
52
+ bring the database client.
53
+ - **Not an ORM.** No models, no migrations, no relations, no lazy loading, no
54
+ query DSL that hides SQL. You write SQL; it checks SQL.
55
+ - **Not a complete SQL grammar.** The parser is **intentionally shallow**. Many
56
+ constructs are recognized just enough to extract tables/columns/result shape;
57
+ anything it doesn't model is passed through leniently rather than rejected.
58
+ - **Not a linter / style enforcer.** It checks *existence and shape*, not
59
+ formatting, performance, or SQL best practices.
60
+ - **Not a precise expression type-checker.** It does not attempt full SQL type
61
+ inference. Ambiguous expressions are deliberately typed `unknown` (see below).
62
+
63
+ ---
64
+
65
+ ## Usage
66
+
67
+ ### 1. Describe your schema as a type
68
+
69
+ ```ts
70
+ type DatabaseSchema = {
71
+ defaultSchema: string;
72
+ schemas: Record<string /* schema */, Record<string /* table */, Record<string /* column */, /* TS type */ unknown>>>;
73
+ };
74
+ ```
75
+
76
+ - A **nullable** column is encoded as `T | null` (e.g. `name: string | null`).
77
+ - Table/column/schema name matching is **case-insensitive**.
78
+ - Column types can be anything: scalars, `"a" | "b"` enums, arrays, nested
79
+ JSON-shaped objects, `Record<string, unknown>`.
80
+
81
+ ### 2. Validate and infer over plain SQL
82
+
83
+ ```ts
84
+ type Valid = ValidateSQL<"update users set name = $1 where id = $2", Schema>; // true | false
85
+ type Row = GetReturnType<"select id, name from users where id = $1", Schema>;
86
+
87
+ // DML helpers
88
+ type InsertCols = GetInsertTableColumns<"insert into users ...", Schema>;
89
+ type UpdateCols = GetUpdateTableColumns<"update users set ...", Schema>;
90
+ ```
91
+
92
+ ### 3. Or build queries with the runtime builder
93
+
94
+ ```ts
95
+ import { createSelectQuery, createSelectFn } from "@kuindji/typed-sql";
96
+
97
+ const q = createSelectQuery<Schema>()
98
+ .from("users u")
99
+ .select("u.id")
100
+ .where("u.id = :id")
101
+ .withParams({ id: 42 });
102
+
103
+ q.toString(); // "SELECT u.id FROM users u WHERE u.id = $1"
104
+ [...q.getParams()]; // [42] ← named params expanded to $1, $2… in order
105
+
106
+ // Wire YOUR driver. The library never touches the DB itself.
107
+ const select = createSelectFn<Schema>((sql, params) => pg.query(sql, params));
108
+ const rows = await select(q); // rows typed from the builder's inferred result
109
+ ```
110
+
111
+ ### Write builders (INSERT / UPDATE / DELETE) with typed params
112
+
113
+ ```ts
114
+ import { createInsertQuery, createMutateFn, createSql } from "@kuindji/typed-sql";
115
+
116
+ const q = createInsertQuery<Schema>()
117
+ .into("orders")
118
+ .value("userId", ":uid") // :uid typed to orders.userId's exact (branded) type
119
+ .value("amount", ":amt")
120
+ .valueIf(hasNote, "note", ":note") // conditional → :note optional in withParams
121
+ .returning("id")
122
+ .withParams({ uid, amt, ...(hasNote ? { note } : {}) });
123
+
124
+ q.toString(); // "insert into orders (userId, amount) values ($1, $2) returning id"
125
+ [...q.getParams()]; // [uid, amt]
126
+
127
+ // Raw typed SQL:
128
+ const sql = createSql<Schema>();
129
+ const d = sql("delete from orders where id = :id").withParams({ id });
130
+
131
+ // Executor — bring your driver; it returns the RETURNING rows (or [] when none):
132
+ const mutate = createMutateFn<Schema>((s, p) => pool.query(s, p).then(r => r.rows));
133
+ const rows = await mutate(q); // typed from RETURNING
134
+
135
+ // Passing a plain string where a branded column is expected is a compile error.
136
+ // Multi-row VALUES is rejected in the typed path — use the untyped driver call.
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Behavior notes
142
+
143
+ A few deliberate behaviors you'll observe when using the library:
144
+
145
+ - **Ambiguous expressions type as `unknown`.** The inferrer types an expression
146
+ only when its type is unambiguous — `CASE` and unmodeled functions are
147
+ `unknown` rather than a guess. `||` (string concat) → `string`. An unaliased
148
+ function/aggregate projection is named after the function (`count(*)` →
149
+ `{ count: number }`); an unaliased `CASE` is named `case`.
150
+ - **Projected literals widen to their base type** — `select 'GBP' as cur` →
151
+ `{ cur: string }`, `select 42 as n` → `{ n: number }`, not `{ cur: "GBP" }` /
152
+ `{ n: 42 }`. Locked literal types reject every other value in mutable
153
+ bindings, `useState`, props, etc.; add an explicit cast at the call site when
154
+ you want the literal back.
155
+ - **Validation is intentionally lenient.** The parser models the common shape of
156
+ real queries, not the full SQL grammar, and biases toward **never rejecting
157
+ valid SQL** — which means some invalid constructs may pass as `true`. Very
158
+ large/complex queries may fall back to `unknown`/`true` rather than failing
159
+ (TypeScript's recursion limits put a hard ceiling on type-level parsing).
160
+ - **Join nullability:** outer joins add `| null` to columns sourced from the
161
+ nullable side (`left join … x` ⇒ `x.col` becomes `T | null`). This applies
162
+ inside `coalesce(...)` too: the result is nullable only if **every** argument
163
+ is (Postgres semantics), so `coalesce(x, '')` stays non-null.
164
+
165
+ ---
166
+
167
+ ## Conditional builder methods (`*If`) — runtime vs type-level
168
+
169
+ The builder's `*If` methods — `selectIf`, `whereIf`, `joinIf`, `groupByIf`,
170
+ `havingIf`, `orderByIf`, `limitIf`, `offsetIf`, and `applyIf` — take a **runtime
171
+ boolean** as their first argument. This creates a deliberate gap between what runs
172
+ and what the types say:
173
+
174
+ - **Runtime:** the fragment is included in the emitted SQL **only if the condition
175
+ is truthy** at call time. `selectIf(false, "name")` adds nothing to the query.
176
+ - **Type-level:** TypeScript cannot see a runtime boolean's value, so the inferred
177
+ result type does **not** branch on it. It infers from the **maximal** query —
178
+ every `*If` fragment treated as present — and then marks columns that *might* be
179
+ absent as **optional**.
180
+
181
+ Per method:
182
+
183
+ - **`selectIf` / `applyIf` that introduce a column** → that column becomes an
184
+ **optional property** in the result row (`name?: T`, i.e. `T | undefined` at the
185
+ use site). Unconditional `select`/`apply` columns stay **required**, regardless
186
+ of call order.
187
+ - **If there is _no_ unconditional `select` at all**, the all-false runtime path
188
+ emits `SELECT *`, so the whole row falls back to `Partial<…>` — **every** column
189
+ optional.
190
+ - **Clause-only `*If`** (`whereIf`, `joinIf`, `groupByIf`, `havingIf`, `orderByIf`,
191
+ `limitIf`, `offsetIf`) conditionally changes the **SQL text** at runtime but does
192
+ **not** change the result column set — the type is computed as if the clause is
193
+ present.
194
+
195
+ ```ts
196
+ const dyn: boolean = /* computed at runtime */;
197
+ const q = createSelectQuery<Schema>()
198
+ .from("users")
199
+ .select("id") // unconditional → required
200
+ .selectIf(dyn, "name"); // conditional → optional
201
+
202
+ type Row = BuilderReturnType<typeof q>;
203
+ // { id: number; name?: string } ← id required; name is `string | undefined`
204
+ ```
205
+
206
+ ## Two kinds of "maybe missing": `| null` vs optional (`| undefined`)
207
+
208
+ These look similar but mean **different** things:
209
+
210
+ | | Source | Type shape | Meaning |
211
+ |---|---|---|---|
212
+ | **`\| null`** | `LEFT`/outer join (nullable side) | `col: T \| null` — **key always present** | The column is in every row, but its **value** can be SQL `NULL` (the join didn't match). |
213
+ | **optional (`\| undefined`)** | `selectIf` / `applyIf` conditional projection | `col?: T` — **key may be absent** | The column may **not be in the result object at all**, because it wasn't selected at runtime. |
214
+
215
+ A left-joined column that is *also* conditionally selected is **both**:
216
+ `col?: T | null`.
217
+
218
+ ---
219
+
220
+ ## Contributing
221
+
222
+ Contributing or reviewing? See [CONTRIBUTING.md](./CONTRIBUTING.md) for the
223
+ design contracts, internals, and things that look like bugs but are intended.
224
+
225
+ ## License
226
+
227
+ MIT © Ivan Kuindzhi
@@ -0,0 +1,13 @@
1
+ import type { RuntimeSelectState } from "./state.js";
2
+ /**
3
+ * Assemble a SQL string from runtime builder state.
4
+ *
5
+ * - Uses user-provided fragments as-is (no parsing/normalization).
6
+ * - Inserts SQL keywords in uppercase.
7
+ * - Skips empty clauses; defaults to SELECT * when no select fragments.
8
+ * - Expands :name params to $n (first-appearance order; arrays expand).
9
+ *
10
+ * Ported from the predecessor package; byte-identical output.
11
+ */
12
+ export declare function assembleSelectSQL(state: RuntimeSelectState): string;
13
+ //# sourceMappingURL=assemble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/builder/assemble.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAqFnE"}
@@ -0,0 +1,86 @@
1
+ // src/builder/assemble.ts
2
+ import { expandNamedParams } from "./params.js";
3
+ /**
4
+ * Assemble a SQL string from runtime builder state.
5
+ *
6
+ * - Uses user-provided fragments as-is (no parsing/normalization).
7
+ * - Inserts SQL keywords in uppercase.
8
+ * - Skips empty clauses; defaults to SELECT * when no select fragments.
9
+ * - Expands :name params to $n (first-appearance order; arrays expand).
10
+ *
11
+ * Ported from the predecessor package; byte-identical output.
12
+ */
13
+ export function assembleSelectSQL(state) {
14
+ const parts = [];
15
+ const cteIds = Object.keys(state.cteSql);
16
+ if (cteIds.length > 0) {
17
+ const withParts = cteIds.map(id => state.cteSql[id]).join(", ");
18
+ parts.push(`WITH ${withParts}`);
19
+ }
20
+ const selectIds = Object.keys(state.selectSql);
21
+ if (selectIds.length === 0) {
22
+ parts.push("SELECT *");
23
+ }
24
+ else {
25
+ const selectFragments = [];
26
+ for (const id of selectIds) {
27
+ const cols = state.selectSql[id];
28
+ if (cols && cols.length > 0) {
29
+ selectFragments.push(cols.join(", "));
30
+ }
31
+ }
32
+ const selectSql = selectFragments.length > 0
33
+ ? selectFragments.join(", ")
34
+ : "*";
35
+ parts.push(state.distinct ? `SELECT DISTINCT ${selectSql}` : `SELECT ${selectSql}`);
36
+ }
37
+ if (state.fromSql) {
38
+ parts.push(`FROM ${state.fromSql}`);
39
+ }
40
+ for (const join of state.joins) {
41
+ const sql = state.joinSql[join.id];
42
+ if (sql) {
43
+ parts.push(sql);
44
+ }
45
+ }
46
+ const whereParts = Object.keys(state.whereSql)
47
+ .map(id => state.whereSql[id])
48
+ .filter(Boolean);
49
+ if (whereParts.length > 0) {
50
+ parts.push(`WHERE ${whereParts.join(" AND ")}`);
51
+ }
52
+ const groupParts = Object.keys(state.groupBySql)
53
+ .map(id => state.groupBySql[id])
54
+ .filter(Boolean);
55
+ if (groupParts.length > 0) {
56
+ parts.push(`GROUP BY ${groupParts.join(", ")}`);
57
+ }
58
+ const havingParts = Object.keys(state.havingSql)
59
+ .map(id => state.havingSql[id])
60
+ .filter(Boolean);
61
+ if (havingParts.length > 0) {
62
+ parts.push(`HAVING ${havingParts.join(" AND ")}`);
63
+ }
64
+ const orderParts = Object.keys(state.orderBySql)
65
+ .map(id => state.orderBySql[id])
66
+ .filter(Boolean);
67
+ if (orderParts.length > 0) {
68
+ parts.push(`ORDER BY ${orderParts.join(", ")}`);
69
+ }
70
+ if (typeof state.limit === "number") {
71
+ parts.push(`LIMIT ${state.limit}`);
72
+ }
73
+ if (typeof state.offset === "number") {
74
+ parts.push(`OFFSET ${state.offset}`);
75
+ }
76
+ if (state.unionSql) {
77
+ parts.push(state.unionSql);
78
+ }
79
+ const sql = parts.join(" ");
80
+ const namedParams = state.namedParams;
81
+ if (namedParams && Object.keys(namedParams).length > 0) {
82
+ return expandNamedParams(sql, namedParams);
83
+ }
84
+ return sql;
85
+ }
86
+ //# sourceMappingURL=assemble.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/builder/assemble.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export type ConditionTreePart = string | ConditionTreeState;
2
+ export interface ConditionTreeState {
3
+ readonly operator: "and" | "or";
4
+ readonly parts: ReadonlyArray<{
5
+ readonly id: string;
6
+ readonly condition: string | ConditionTreeState;
7
+ }>;
8
+ }
9
+ type UppercaseOperator<Op extends "and" | "or"> = Op extends "and" ? "AND" : "OR";
10
+ type AppendCondition<Current extends string, Part extends string, Op extends "and" | "or"> = string extends Current | Part ? string : Part extends "()" ? Current : Current extends "()" ? `(${Part})` : Current extends `(${infer Body})` ? `(${Body} ${UppercaseOperator<Op>} ${Part})` : string;
11
+ export declare class ConditionTreeBuilder<Op extends "and" | "or" = "and" | "or", Expr extends string = string> {
12
+ private readonly state;
13
+ private constructor();
14
+ static create<Op extends "and" | "or">(operator: Op): ConditionTreeBuilder<Op, "()">;
15
+ getState(): ConditionTreeState;
16
+ isEmpty(): boolean;
17
+ add<Part extends string | ConditionTreeBuilder<any, any>, Id extends string | undefined = undefined>(part: Part, id?: Id): ConditionTreeBuilder<Op, Id extends string ? string : AppendCondition<Expr, Part extends ConditionTreeBuilder<any, infer P extends string> ? P : Part extends string ? Part : string, Op>>;
18
+ remove(id: string): ConditionTreeBuilder<Op, string>;
19
+ when<Next extends ConditionTreeBuilder<any, any>>(condition: boolean, ifTrue: (b: ConditionTreeBuilder<Op, Expr>) => Next, ifFalse?: (b: ConditionTreeBuilder<Op, Expr>) => Next): ConditionTreeBuilder<Op, Expr> | Next;
20
+ toString(): Expr;
21
+ private static renderPart;
22
+ private static isConditionTreeState;
23
+ private static generateId;
24
+ }
25
+ export declare function createConditionTree<Op extends "and" | "or">(operator: Op): ConditionTreeBuilder<Op, "()">;
26
+ export {};
27
+ //# sourceMappingURL=condition-tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"condition-tree.d.ts","sourceRoot":"","sources":["../../src/builder/condition-tree.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,kBAAkB,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,KAAK,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;QAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,CAAC;KACnD,CAAC,CAAC;CACN;AAED,KAAK,iBAAiB,CAAC,EAAE,SAAS,KAAK,GAAG,IAAI,IAAI,EAAE,SAAS,KAAK,GAAG,KAAK,GAAG,IAAI,CAAC;AAElF,KAAK,eAAe,CAChB,OAAO,SAAS,MAAM,EACtB,IAAI,SAAS,MAAM,EACnB,EAAE,SAAS,KAAK,GAAG,IAAI,IACvB,MAAM,SAAS,OAAO,GAAG,IAAI,GAAG,MAAM,GAGpC,IAAI,SAAS,IAAI,GAAG,OAAO,GAC3B,OAAO,SAAS,IAAI,GAAG,IAAI,IAAI,GAAG,GAClC,OAAO,SAAS,IAAI,MAAM,IAAI,GAAG,GAC7B,IAAI,IAAI,IAAI,iBAAiB,CAAC,EAAE,CAAC,IAAI,IAAI,GAAG,GAChD,MAAM,CAAC;AAEb,qBAAa,oBAAoB,CAC7B,EAAE,SAAS,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,EACtC,IAAI,SAAS,MAAM,GAAG,MAAM;IAE5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAE3C,OAAO;IAIP,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,KAAK,GAAG,IAAI,EACjC,QAAQ,EAAE,EAAE,GACb,oBAAoB,CAAC,EAAE,EAAE,IAAI,CAAC;IAIjC,QAAQ,IAAI,kBAAkB;IAS9B,OAAO,IAAI,OAAO;IAIlB,GAAG,CAAC,IAAI,SAAS,MAAM,GAAG,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,SAAS,GAAG,SAAS,EAC/F,IAAI,EAAE,IAAI,EACV,EAAE,CAAC,EAAE,EAAE,GACR,oBAAoB,CACnB,EAAE,EAIF,EAAE,SAAS,MAAM,GACX,MAAM,GACN,eAAe,CACb,IAAI,EACJ,IAAI,SAAS,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,GAC5D,IAAI,SAAS,MAAM,GAAG,IAAI,GAC1B,MAAM,EACZ,EAAE,CACL,CACR;IA2BD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,oBAAoB,CAAC,EAAE,EAAE,MAAM,CAAC;IAWpD,IAAI,CAAC,IAAI,SAAS,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,EAC5C,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,CAAC,CAAC,EAAE,oBAAoB,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,IAAI,EACnD,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,oBAAoB,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,IAAI,GACtD,oBAAoB,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,IAAI;IAOxC,QAAQ,IAAI,IAAI;IAYhB,OAAO,CAAC,MAAM,CAAC,UAAU;IAOzB,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAWnC,OAAO,CAAC,MAAM,CAAC,UAAU;CAG5B;AAED,wBAAgB,mBAAmB,CAAC,EAAE,SAAS,KAAK,GAAG,IAAI,EACvD,QAAQ,EAAE,EAAE,GACb,oBAAoB,CAAC,EAAE,EAAE,IAAI,CAAC,CAEhC"}
@@ -0,0 +1,91 @@
1
+ // src/builder/condition-tree.ts
2
+ export class ConditionTreeBuilder {
3
+ state;
4
+ constructor(state) {
5
+ this.state = state;
6
+ }
7
+ static create(operator) {
8
+ return new ConditionTreeBuilder({ operator, parts: [] });
9
+ }
10
+ getState() {
11
+ return this.state;
12
+ }
13
+ // True when this tree contributes no SQL: it holds no parts (so toString()
14
+ // would render the bare "()"). Consumers and the SELECT builder use this to
15
+ // skip empty trees entirely — legacy parity, where an empty condition tree
16
+ // (e.g. an empty status[] filter built as an empty OR-tree) was a no-op
17
+ // rather than an invalid `WHERE ()`.
18
+ isEmpty() {
19
+ return this.state.parts.length === 0;
20
+ }
21
+ add(part, id) {
22
+ // Skip an empty child tree: adding it would otherwise render a bare
23
+ // "()" inside this expression (e.g. "(a = 1 AND ())"), an invalid
24
+ // fragment. Legacy Query.ts trees skipped empty children too. Returning
25
+ // `this` keeps the builder unchanged (no part, no id slot consumed).
26
+ if (part instanceof ConditionTreeBuilder && part.isEmpty()) {
27
+ return this;
28
+ }
29
+ const partId = id ?? ConditionTreeBuilder.generateId();
30
+ const condition = part instanceof ConditionTreeBuilder ? part.getState() : part;
31
+ const existingIndex = this.state.parts.findIndex(p => p.id === partId);
32
+ const nextParts = existingIndex === -1
33
+ ? [...this.state.parts, { id: partId, condition }]
34
+ : this.state.parts.map((p, idx) => idx === existingIndex ? { id: partId, condition } : p);
35
+ return new ConditionTreeBuilder({
36
+ operator: this.state.operator,
37
+ parts: nextParts,
38
+ });
39
+ }
40
+ // remove() drops a part; the rendered literal can no longer be reconstructed
41
+ // from `Expr` alone (the type doesn't track parts as a tuple), so widen to
42
+ // `string`. A `string`-typed tree fragment is accepted-but-untyped by
43
+ // ValidQueryBuilder's allow-unknown path (spec Open Questions) — no
44
+ // rejection, only reduced BuilderSQL precision for that one query.
45
+ remove(id) {
46
+ const nextParts = this.state.parts.filter(p => p.id !== id);
47
+ if (nextParts.length === this.state.parts.length) {
48
+ return this;
49
+ }
50
+ return new ConditionTreeBuilder({
51
+ operator: this.state.operator,
52
+ parts: nextParts,
53
+ });
54
+ }
55
+ when(condition, ifTrue, ifFalse) {
56
+ if (condition) {
57
+ return ifTrue(this);
58
+ }
59
+ return ifFalse ? ifFalse(this) : this;
60
+ }
61
+ toString() {
62
+ if (this.state.parts.length === 0) {
63
+ return "()";
64
+ }
65
+ const op = this.state.operator.toUpperCase();
66
+ const rendered = this.state.parts
67
+ .map(part => ConditionTreeBuilder.renderPart(part.condition))
68
+ .filter(s => s.length > 0)
69
+ .join(` ${op} `);
70
+ return `(${rendered})`;
71
+ }
72
+ static renderPart(condition) {
73
+ if (ConditionTreeBuilder.isConditionTreeState(condition)) {
74
+ return new ConditionTreeBuilder(condition).toString();
75
+ }
76
+ return String(condition ?? "").trim();
77
+ }
78
+ static isConditionTreeState(value) {
79
+ return (typeof value === "object"
80
+ && value !== null
81
+ && value.operator !== undefined
82
+ && Array.isArray(value.parts));
83
+ }
84
+ static generateId() {
85
+ return `cond_${Math.random().toString(36).slice(2, 10)}`;
86
+ }
87
+ }
88
+ export function createConditionTree(operator) {
89
+ return ConditionTreeBuilder.create(operator);
90
+ }
91
+ //# sourceMappingURL=condition-tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"condition-tree.js","sourceRoot":"","sources":["../../src/builder/condition-tree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import type { DatabaseSchema } from "../schema.js";
2
+ import type { GetReturnType, ValidateSQL } from "../index.js";
3
+ import type { QueryParamValue } from "./params.js";
4
+ export interface ConditionalSQLOptions {
5
+ /** If true, preserves conditional comment markers in output (debugging). */
6
+ preserveMarkers?: boolean;
7
+ }
8
+ export interface ConditionalSQLOutput {
9
+ /** The processed SQL string with conditions applied. */
10
+ sql: string;
11
+ /** The parameter values in order of appearance. */
12
+ params: QueryParamValue[];
13
+ }
14
+ /** Process conditional blocks in a SQL template (innermost-first, iterative). */
15
+ export declare function processConditionalSQL(template: string, conditions: Record<string, unknown>): string;
16
+ /** Convert :name placeholders to positional $n; return processed SQL + values. */
17
+ export declare function processParams(sql: string, params: Record<string, QueryParamValue>): ConditionalSQLOutput;
18
+ /** Process a template with both conditions and parameters. */
19
+ export declare function conditionalSQL(template: string, conditions: Record<string, unknown>, params?: Record<string, QueryParamValue>): ConditionalSQLOutput;
20
+ /** Normalize whitespace in SQL (collapse spaces, tidy commas/parens). */
21
+ export declare function normalizeWhitespace(sql: string): string;
22
+ /** Get a nested value type using a dot-notation path. */
23
+ export type GetPath<T, Path extends string> = Path extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? GetPath<T[Key], Rest> : undefined : Path extends keyof T ? T[Path] : undefined;
24
+ /** Type-level truthiness; resolves to `boolean` for non-literal wide types. */
25
+ export type IsTruthy<T> = [
26
+ T
27
+ ] extends [false | 0 | "" | null | undefined] ? false : [T] extends [never] ? false : [T] extends [boolean] ? ([boolean] extends [T] ? boolean : true) : [T] extends [string] ? ([string] extends [T] ? boolean : true) : [T] extends [number] ? ([number] extends [T] ? boolean : true) : true;
28
+ /** Evaluate a condition string against a data type (supports `!` negation). */
29
+ export type EvalCondition<Cond extends string, Data> = Cond extends `!${infer Key}` ? IsTruthy<GetPath<Data, Key>> extends true ? false : IsTruthy<GetPath<Data, Key>> extends false ? true : boolean : IsTruthy<GetPath<Data, Cond>>;
30
+ /** Check if a string contains a specific pattern. */
31
+ type Contains<S extends string, Pattern extends string> = S extends `${string}${Pattern}${string}` ? true : false;
32
+ /** Check if any condition in the template has an indeterminate (wide) type. */
33
+ type HasIndeterminateCondition<Template extends string, Data extends Record<string, unknown>> = Template extends `${string}/*if:${infer Cond}*/${infer Rest}` ? EvalCondition<Cond, Data> extends boolean ? boolean extends EvalCondition<Cond, Data> ? true : HasIndeterminateCondition<Rest, Data> : HasIndeterminateCondition<Rest, Data> : false;
34
+ /** Process the innermost conditional block (inside-out). */
35
+ type ProcessInnermost<Template extends string, Data extends Record<string, unknown>> = Template extends `${infer Before}/*if:${infer Cond}*/${infer Content}/*endif*/${infer After}` ? Contains<Content, "/*if:"> extends true ? `${Before}/*if:${Cond}*/${ProcessInnermost<`${Content}/*endif*/${After}`, Data>}` : EvalCondition<Cond, Data> extends true ? `${Before}${Content}${After}` : EvalCondition<Cond, Data> extends false ? `${Before}${After}` : string : Template;
36
+ /** Recursively process all conditional blocks until none remain. */
37
+ export type ProcessConditionalSQL<Template extends string, Data extends Record<string, unknown>, Depth extends number[] = []> = HasIndeterminateCondition<Template, Data> extends true ? string : Depth["length"] extends 20 ? Template : Contains<Template, "/*if:"> extends true ? ProcessConditionalSQL<ProcessInnermost<Template, Data>, Data, [
38
+ ...Depth,
39
+ 0
40
+ ]> : Template;
41
+ /** Force every condition value true (maximal column set). */
42
+ export type AllConditionsTrue<Data extends Record<string, unknown>> = {
43
+ [K in keyof Data]: Data[K] extends Record<string, unknown> ? AllConditionsTrue<Data[K]> : true;
44
+ };
45
+ /** Force every condition value false (minimal column set). */
46
+ export type AllConditionsFalse<Data extends Record<string, unknown>> = {
47
+ [K in keyof Data]: Data[K] extends Record<string, unknown> ? AllConditionsFalse<Data[K]> : false;
48
+ };
49
+ /** Marker: columns from conditional SELECT clauses are `T | undefined`. */
50
+ export type ConditionalColumn<T> = T | undefined;
51
+ /** Marker: columns from conditional LEFT JOINs are `T | null | undefined`. */
52
+ export type ConditionalLeftJoinColumn<T> = T | null | undefined;
53
+ /** Extract :name parameter names from a SQL string. */
54
+ export type ExtractParamNames<SQL extends string, Acc extends string[] = []> = SQL extends `${string}:${infer Name}${infer Rest}` ? Name extends `${infer ParamName}${" " | "," | ")" | "\n" | "\t"}` ? ExtractParamNames<Rest, [...Acc, ParamName]> : ExtractParamNames<Rest, [...Acc, Name]> : Acc;
55
+ /** Validate that all required params are provided. */
56
+ export type ValidateParams<SQL extends string, Params extends Record<string, unknown>> = ExtractParamNames<SQL> extends infer Names extends string[] ? Names[number] extends keyof Params ? true : `Missing parameter: ${Exclude<Names[number], keyof Params>}` : true;
57
+ type Flatten<T> = {
58
+ [K in keyof T]: T[K];
59
+ } & {};
60
+ /**
61
+ * Result type for a conditional SQL query, rewired onto the new core.
62
+ * 1. all conditions TRUE -> full column set (GetReturnType<FullSQL>)
63
+ * 2. all conditions FALSE -> base column set (GetReturnType<BaseSQL>)
64
+ * 3. columns in full but not base -> `| undefined`
65
+ */
66
+ export type ConditionalQueryResult<Template extends string, Conditions extends Record<string, unknown>, Schema extends DatabaseSchema> = ProcessConditionalSQL<Template, AllConditionsTrue<Conditions>> extends infer FullSQL extends string ? ProcessConditionalSQL<Template, AllConditionsFalse<Conditions>> extends infer BaseSQL extends string ? GetReturnType<FullSQL, Schema> extends infer Full ? GetReturnType<BaseSQL, Schema> extends infer Base ? MergeConditionalResults<Full, Base> : Full : {} : {} : {};
67
+ export type MergeConditionalResults<Full, Base> = Flatten<{
68
+ [K in keyof Full as K extends keyof Base ? K : never]: Full[K];
69
+ } & {
70
+ [K in keyof Full as K extends keyof Base ? never : K]: Full[K] | undefined;
71
+ }>;
72
+ export type ProcessedSQL<Template extends string, Conditions extends Record<string, unknown>> = ProcessConditionalSQL<Template, Conditions>;
73
+ export type ValidateConditionalSQL<Template extends string, Conditions extends Record<string, unknown>, Schema extends DatabaseSchema> = ProcessConditionalSQL<Template, AllConditionsTrue<Conditions>> extends infer FullSQL extends string ? ValidateSQL<FullSQL, Schema> : false;
74
+ export interface TypedConditionalSQLOutput<Result> extends ConditionalSQLOutput {
75
+ readonly __resultType?: Result;
76
+ }
77
+ export declare function createConditionalQuery<Schema extends DatabaseSchema>(): <Template extends string, Conditions extends Record<string, unknown>, Params extends Record<string, QueryParamValue> = {}>(template: Template, conditions: Conditions, params?: Params) => TypedConditionalSQLOutput<ConditionalQueryResult<Template, Conditions, Schema>>;
78
+ export declare function withConditions<StaticConditions extends Record<string, unknown>>(queryFn: ReturnType<typeof createConditionalQuery>): <Template extends string, Params extends Record<string, QueryParamValue> = {}>(template: Template, conditions: StaticConditions, params?: Params) => TypedConditionalSQLOutput<ConditionalQueryResult<Template, StaticConditions, DatabaseSchema>>;
79
+ export {};
80
+ //# sourceMappingURL=conditional-sql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditional-sql.d.ts","sourceRoot":"","sources":["../../src/builder/conditional-sql.ts"],"names":[],"mappings":"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"}