@kuindji/typed-sql 0.1.0 → 0.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.
- package/README.md +7 -0
- package/dist/builder/assemble.d.ts.map +1 -1
- package/dist/builder/assemble.js +9 -10
- package/dist/builder/assemble.js.map +1 -1
- package/dist/builder/conditional-sql.d.ts +7 -2
- package/dist/builder/conditional-sql.d.ts.map +1 -1
- package/dist/builder/conditional-sql.js +9 -22
- package/dist/builder/conditional-sql.js.map +1 -1
- package/dist/builder/params.d.ts +2 -1
- package/dist/builder/params.d.ts.map +1 -1
- package/dist/builder/params.js +34 -27
- package/dist/builder/params.js.map +1 -1
- package/dist/builder/select.d.ts +7 -0
- package/dist/builder/select.d.ts.map +1 -1
- package/dist/builder/select.js +7 -2
- package/dist/builder/select.js.map +1 -1
- package/dist/builder/state.d.ts +3 -6
- package/dist/builder/state.d.ts.map +1 -1
- package/dist/builder/state.js +1 -2
- package/dist/builder/state.js.map +1 -1
- package/dist/expressions.d.ts +1 -1
- package/dist/expressions.d.ts.map +1 -1
- package/dist/parsing/extract.d.ts +2 -1
- package/dist/parsing/extract.d.ts.map +1 -1
- package/dist/parsing/normalize.d.ts +4 -3
- package/dist/parsing/normalize.d.ts.map +1 -1
- package/dist/parsing/pg-literals.d.ts +2 -2
- package/dist/parsing/pg-literals.d.ts.map +1 -1
- package/dist/parsing/tokenize.d.ts +8 -6
- package/dist/parsing/tokenize.d.ts.map +1 -1
- package/dist/validation/dispatch.d.ts +3 -1
- package/dist/validation/dispatch.d.ts.map +1 -1
- package/dist/validation/validate-columns.d.ts +1 -1
- package/dist/validation/validate-columns.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/builder/assemble.ts +9 -13
- package/src/builder/conditional-sql.ts +9 -27
- package/src/builder/params.ts +33 -27
- package/src/builder/select.ts +19 -2
- package/src/builder/state.ts +4 -6
- package/src/expressions.ts +8 -1
- package/src/parsing/extract.ts +18 -4
- package/src/parsing/normalize.ts +83 -46
- package/src/parsing/pg-literals.ts +23 -12
- package/src/parsing/tokenize.ts +56 -23
- package/src/validation/dispatch.ts +21 -3
- package/src/validation/validate-columns.ts +13 -7
package/src/parsing/tokenize.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Tokenization, sentinels, operators, and SQL keyword sets.
|
|
2
|
-
import type {
|
|
2
|
+
import type { CleanIdent, CleanLooseToken, CollapseSpaces, ReplaceAll, Split, Trim, TrimPunctuation } from "./string-utils.js";
|
|
3
3
|
import type { ExceedsLengthBudget, HasLineBreaks } from "./normalize.js";
|
|
4
4
|
// Tokenization & parsing helpers
|
|
5
5
|
|
|
6
|
-
export type Tokenize<N extends string> =
|
|
6
|
+
export type Tokenize<N extends string> = CleanFilterTokens<Split<N, " ">>;
|
|
7
7
|
|
|
8
8
|
// Sentinel token standing in for a TOP-LEVEL comma. It survives `MapClean`
|
|
9
9
|
// (no stripped punctuation, non-empty identifier) whereas a bare `,` does not,
|
|
@@ -64,12 +64,12 @@ export type TokenizeTables<N extends string> =
|
|
|
64
64
|
? Tokenize<N>
|
|
65
65
|
: ExceedsLengthBudget<N> extends true
|
|
66
66
|
? Tokenize<N>
|
|
67
|
-
:
|
|
67
|
+
: RestoreCleanFilterTokens<Split<MaybeMarkDQuotedSpaces<MarkTopLevelCommas<N>>, " ">>;
|
|
68
68
|
|
|
69
69
|
export type TokenizeLoose<N extends string> =
|
|
70
|
-
|
|
70
|
+
RestoreCleanLooseFilterTokens<
|
|
71
71
|
Split<CollapseSpaces<RestoreWildcards<PadOperators<ProtectWildcards<MaybeMarkDQuotedSpaces<MaybeStripDQuotedPunct<N>>>>>>, " ">
|
|
72
|
-
|
|
72
|
+
> extends infer Toks extends string[]
|
|
73
73
|
? N extends `${string}distinct ${string}`
|
|
74
74
|
? DropDistinctFrom<Toks>
|
|
75
75
|
: Toks
|
|
@@ -168,12 +168,45 @@ export type MarkDQuotedSpaces<
|
|
|
168
168
|
: MarkDQuotedSpaces<Rest, InDQ, `${Acc}${C}`, [any, ...Steps]>
|
|
169
169
|
: Acc;
|
|
170
170
|
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
|
|
171
|
+
// Fused token post-passes: one walk instead of the old
|
|
172
|
+
// `FilterEmpty<MapClean<RestoreDQuotedSpaces<…>>>` three-walk chain. Each pass was
|
|
173
|
+
// an independent element-wise map/filter, so composing them per token yields the
|
|
174
|
+
// identical list (ordering preserved) while building the result spine once.
|
|
175
|
+
//
|
|
176
|
+
// The DQuote-space sentinel restore (`ReplaceAll<H, DQuoteSpaceSentinel, " ">`) lets
|
|
177
|
+
// a quoted identifier that survived the space-split as one token (`"Order ID"`,
|
|
178
|
+
// `"user alias".id`) clean to its true value. `CleanFilterTokens` is the no-restore
|
|
179
|
+
// variant (plain `Tokenize`, which never marks sentinels).
|
|
180
|
+
//
|
|
181
|
+
// MapClean maps each token to `CleanIdent<H> extends "" ? "" : TrimPunctuation<Trim<H>>`
|
|
182
|
+
// and FilterEmpty drops the `""`s. Since `CleanIdent = Lowercase<Unquote<TrimPunctuation<
|
|
183
|
+
// Trim<S>>>>`, a non-empty `CleanIdent<H>` guarantees a non-empty `TrimPunctuation<Trim<H>>`,
|
|
184
|
+
// so the kept value is never empty — the empty-token filter collapses to the single
|
|
185
|
+
// `CleanIdent<H> extends ""` test. (The loose variant keeps an explicit empty filter
|
|
186
|
+
// because `CleanLooseToken` can return `""` for a non-operator empty ident.)
|
|
187
|
+
export type CleanFilterTokens<Tokens extends string[], Acc extends string[] = []> =
|
|
175
188
|
Tokens extends [infer H extends string, ...infer R extends string[]]
|
|
176
|
-
?
|
|
189
|
+
? CleanIdent<H> extends ""
|
|
190
|
+
? CleanFilterTokens<R, Acc>
|
|
191
|
+
: CleanFilterTokens<R, [...Acc, TrimPunctuation<Trim<H>>]>
|
|
192
|
+
: Acc;
|
|
193
|
+
|
|
194
|
+
export type RestoreCleanFilterTokens<Tokens extends string[], Acc extends string[] = []> =
|
|
195
|
+
Tokens extends [infer H0 extends string, ...infer R extends string[]]
|
|
196
|
+
? ReplaceAll<H0, DQuoteSpaceSentinel, " "> extends infer H extends string
|
|
197
|
+
? CleanIdent<H> extends ""
|
|
198
|
+
? RestoreCleanFilterTokens<R, Acc>
|
|
199
|
+
: RestoreCleanFilterTokens<R, [...Acc, TrimPunctuation<Trim<H>>]>
|
|
200
|
+
: never
|
|
201
|
+
: Acc;
|
|
202
|
+
|
|
203
|
+
export type RestoreCleanLooseFilterTokens<Tokens extends string[], Acc extends string[] = []> =
|
|
204
|
+
Tokens extends [infer H0 extends string, ...infer R extends string[]]
|
|
205
|
+
? CleanLooseToken<ReplaceAll<H0, DQuoteSpaceSentinel, " ">> extends infer M extends string
|
|
206
|
+
? M extends ""
|
|
207
|
+
? RestoreCleanLooseFilterTokens<R, Acc>
|
|
208
|
+
: RestoreCleanLooseFilterTokens<R, [...Acc, M]>
|
|
209
|
+
: never
|
|
177
210
|
: Acc;
|
|
178
211
|
|
|
179
212
|
// A validation-only view of a query: blank the CONTENTS of every single-quoted
|
|
@@ -198,26 +231,26 @@ export type ValidationScanView<S extends string> =
|
|
|
198
231
|
? MaybeMarkDQuotedSpaces<BlankSingleQuotedLiterals<S>>
|
|
199
232
|
: MaybeMarkDQuotedSpaces<S>;
|
|
200
233
|
|
|
234
|
+
// Pairwise marker-jump: hop to the opening `'`, then to its closing `'`, emitting
|
|
235
|
+
// the verbatim prefix plus a blanked body `''`, and recurse on the tail. The `''`
|
|
236
|
+
// SQL escape pairs LEFTMOST exactly as the old per-char toggle did (`'it''s'` →
|
|
237
|
+
// `''''`); an UNTERMINATED opener (no closing `'`) is closed off with an appended
|
|
238
|
+
// `'`, matching the old EOF-in-string branch (`${Acc}'`), so `…'xyz` → `…''`. Depth
|
|
239
|
+
// is now the NUMBER OF LITERALS (a handful), not the string length (≤600 before).
|
|
240
|
+
// Step cap retained purely as a runaway backstop for a pathological quote storm.
|
|
201
241
|
export type BlankSingleQuotedLiterals<
|
|
202
242
|
S extends string,
|
|
203
|
-
InString extends boolean = false,
|
|
204
243
|
Acc extends string = "",
|
|
205
244
|
Steps extends any[] = []
|
|
206
245
|
> = string extends S
|
|
207
246
|
? S
|
|
208
|
-
: Steps["length"] extends
|
|
247
|
+
: Steps["length"] extends 300
|
|
209
248
|
? `${Acc}${S}`
|
|
210
|
-
:
|
|
211
|
-
?
|
|
212
|
-
?
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
: `${Acc}'`
|
|
216
|
-
: S extends `${infer C}${infer R}`
|
|
217
|
-
? C extends "'"
|
|
218
|
-
? BlankSingleQuotedLiterals<R, true, `${Acc}'`, [any, ...Steps]>
|
|
219
|
-
: BlankSingleQuotedLiterals<R, false, `${Acc}${C}`, [any, ...Steps]>
|
|
220
|
-
: Acc;
|
|
249
|
+
: S extends `${infer Pre}'${infer Rest}`
|
|
250
|
+
? Rest extends `${infer _Lit}'${infer After}`
|
|
251
|
+
? BlankSingleQuotedLiterals<After, `${Acc}${Pre}''`, [any, ...Steps]>
|
|
252
|
+
: `${Acc}${Pre}''`
|
|
253
|
+
: `${Acc}${S}`;
|
|
221
254
|
|
|
222
255
|
export type OperatorToken =
|
|
223
256
|
| "(" | ")" | "," | "=" | "<" | ">" | "+" | "-" | "*" | "/" | "|" | "&" | "!" | "?"
|
|
@@ -288,25 +288,43 @@ export type HasReturning<N extends string> =
|
|
|
288
288
|
? false
|
|
289
289
|
: HasReturningQuoteAware<N>;
|
|
290
290
|
|
|
291
|
+
// Quote-free fast-path: a query with no `'` and no `"` has no place for a
|
|
292
|
+
// ` returning ` to hide, so every occurrence is top-level — a single pattern test
|
|
293
|
+
// is exact and skips the ~1200-step char-walk (these run on every DML). Only
|
|
294
|
+
// quote-bearing queries pay for the walk below. The fast-path pattern matches the
|
|
295
|
+
// step-cap fallback this walk already uses, so it is consistent with prior behavior.
|
|
291
296
|
export type HasReturningQuoteAware<
|
|
292
297
|
S extends string,
|
|
293
298
|
InString extends boolean = false,
|
|
294
299
|
InDString extends boolean = false,
|
|
295
300
|
Steps extends any[] = []
|
|
301
|
+
> = string extends S
|
|
302
|
+
? false
|
|
303
|
+
: S extends `${string}'${string}`
|
|
304
|
+
? HasReturningQuoteAwareWalk<S, InString, InDString, Steps>
|
|
305
|
+
: S extends `${string}"${string}`
|
|
306
|
+
? HasReturningQuoteAwareWalk<S, InString, InDString, Steps>
|
|
307
|
+
: S extends `${string} returning ${string}` ? true : false;
|
|
308
|
+
|
|
309
|
+
type HasReturningQuoteAwareWalk<
|
|
310
|
+
S extends string,
|
|
311
|
+
InString extends boolean = false,
|
|
312
|
+
InDString extends boolean = false,
|
|
313
|
+
Steps extends any[] = []
|
|
296
314
|
> = string extends S
|
|
297
315
|
? false
|
|
298
316
|
: Steps["length"] extends 1200
|
|
299
317
|
? S extends `${string} returning ${string}` ? true : false
|
|
300
318
|
: InString extends true
|
|
301
319
|
? S extends `${infer C}${infer Rest}`
|
|
302
|
-
?
|
|
320
|
+
? HasReturningQuoteAwareWalk<Rest, C extends "'" ? false : true, InDString, [any, ...Steps]>
|
|
303
321
|
: false
|
|
304
322
|
: InDString extends true
|
|
305
323
|
? S extends `${infer C}${infer Rest}`
|
|
306
|
-
?
|
|
324
|
+
? HasReturningQuoteAwareWalk<Rest, InString, C extends `"` ? false : true, [any, ...Steps]>
|
|
307
325
|
: false
|
|
308
326
|
: S extends ` returning ${string}`
|
|
309
327
|
? true
|
|
310
328
|
: S extends `${infer C}${infer Rest}`
|
|
311
|
-
?
|
|
329
|
+
? HasReturningQuoteAwareWalk<Rest, C extends "'" ? true : false, C extends `"` ? true : false, [any, ...Steps]>
|
|
312
330
|
: false;
|
|
@@ -402,15 +402,21 @@ export type NoAliasShadowedQualifiers<
|
|
|
402
402
|
> =
|
|
403
403
|
[AliasedTableKeys<Aliases>] extends [never]
|
|
404
404
|
? true
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
405
|
+
// A shadowable qualifier is a `qualifier.column` token, which requires a
|
|
406
|
+
// `.`. With no `.` anywhere, `QualifiedColumnRefs` accumulates `never` and
|
|
407
|
+
// `AllTrue<never>` is `true` — so skip the whole-query `TokenizeLoose<N>`
|
|
408
|
+
// re-walk (computed nowhere else) on dot-free queries. Exact-equivalent.
|
|
409
|
+
: N extends `${string}.${string}`
|
|
410
|
+
? AllTrue<
|
|
411
|
+
QualifiedColumnRefs<TokenizeLoose<N>, S, Tables, Aliases> extends infer R
|
|
412
|
+
? R extends `${infer Q}.${string}`
|
|
413
|
+
? QualifierShadowedByAlias<Q, Tables, Aliases, S> extends true
|
|
414
|
+
? false
|
|
415
|
+
: true
|
|
410
416
|
: true
|
|
411
417
|
: true
|
|
412
|
-
|
|
413
|
-
|
|
418
|
+
>
|
|
419
|
+
: true;
|
|
414
420
|
|
|
415
421
|
// A table introduced INSIDE a subquery is in scope only there — it must not
|
|
416
422
|
// satisfy an UNQUALIFIED column reference in the OUTER query. The whole-query
|