@kuindji/typed-sql 0.3.0 → 0.4.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 (41) hide show
  1. package/README.md +11 -3
  2. package/dist/columns.d.ts +11 -3
  3. package/dist/columns.d.ts.map +1 -1
  4. package/dist/expressions.d.ts +73 -8
  5. package/dist/expressions.d.ts.map +1 -1
  6. package/dist/parsing/extract.d.ts +13 -9
  7. package/dist/parsing/extract.d.ts.map +1 -1
  8. package/dist/parsing/normalize.d.ts +3 -1
  9. package/dist/parsing/normalize.d.ts.map +1 -1
  10. package/dist/parsing/pg-literals.d.ts +10 -2
  11. package/dist/parsing/pg-literals.d.ts.map +1 -1
  12. package/dist/parsing/split.d.ts +27 -3
  13. package/dist/parsing/split.d.ts.map +1 -1
  14. package/dist/parsing/string-utils.d.ts +2 -4
  15. package/dist/parsing/string-utils.d.ts.map +1 -1
  16. package/dist/parsing/tokenize.d.ts +27 -17
  17. package/dist/parsing/tokenize.d.ts.map +1 -1
  18. package/dist/partial.d.ts +6 -6
  19. package/dist/partial.d.ts.map +1 -1
  20. package/dist/tables.d.ts +58 -13
  21. package/dist/tables.d.ts.map +1 -1
  22. package/dist/validation/dispatch.d.ts +7 -5
  23. package/dist/validation/dispatch.d.ts.map +1 -1
  24. package/dist/validation/joins.d.ts +3 -3
  25. package/dist/validation/joins.d.ts.map +1 -1
  26. package/dist/validation/validate-columns.d.ts +14 -14
  27. package/dist/validation/validate-columns.d.ts.map +1 -1
  28. package/package.json +1 -1
  29. package/src/columns.ts +168 -32
  30. package/src/expressions.ts +550 -57
  31. package/src/parsing/extract.ts +72 -32
  32. package/src/parsing/normalize.ts +54 -8
  33. package/src/parsing/pg-literals.ts +32 -10
  34. package/src/parsing/split.ts +236 -72
  35. package/src/parsing/string-utils.ts +15 -15
  36. package/src/parsing/tokenize.ts +224 -146
  37. package/src/partial.ts +9 -15
  38. package/src/tables.ts +546 -214
  39. package/src/validation/dispatch.ts +58 -52
  40. package/src/validation/joins.ts +15 -19
  41. package/src/validation/validate-columns.ts +54 -64
@@ -6,7 +6,7 @@ import type { CteNames, NonCteTables, SingleCteMatch } from "./cte.js";
6
6
  import type { DatabaseSchema } from "../schema.js";
7
7
  import type { DerivedAliasName, DerivedFirstWord, DerivedTableMatch } from "./return-derived.js";
8
8
  import type { DistinctOnColsValid, JoinUsingColsValid, WindowFilterColsValid } from "./joins.js";
9
- import type { ExceedsLengthBudget, ExtractBefore, ExtractLastWhere, HasLineBreaks, TokenizeLoose, Trim, ValidationScanView } from "../parsing.js";
9
+ import type { ExceedsLengthBudget, ExtractBefore, ExtractLastWhere, HasLineBreaks, Trim, ValidationScanView } from "../parsing.js";
10
10
  import type { RefScanSegment } from "./return-types.js";
11
11
  // Core validation / inference
12
12
 
@@ -126,16 +126,13 @@ export type WhereColsValidForUpdate<
126
126
  TargetKey extends string,
127
127
  AliasEntry extends string,
128
128
  S extends DatabaseSchema
129
- > =
130
- TokenizeLoose<W> extends infer WT extends string[]
131
- ? And<
132
- QualifiedColumnRefsValidFor<W, S, TargetKey, AliasEntry, WT>,
133
- UnqualifiedColumnRefsValidFor<W, S, TargetKey, AliasEntry, WT, never>,
134
- true,
135
- true,
136
- true
137
- >
138
- : true;
129
+ > = And<
130
+ QualifiedColumnRefsValidFor<W, S, TargetKey, AliasEntry, W>,
131
+ UnqualifiedColumnRefsValidFor<W, S, TargetKey, AliasEntry, W, never>,
132
+ true,
133
+ true,
134
+ true
135
+ >;
139
136
 
140
137
  // "Light" validator for high-complexity SELECTs: validate the cheap, bounded
141
138
  // parts (every referenced table exists, and the select/returning list resolves)
@@ -217,21 +214,19 @@ export type LightSelectTablesAndList<N extends string, S extends DatabaseSchema>
217
214
  export type ValidateSQLNormalizedCore<N extends string, S extends DatabaseSchema> =
218
215
  TablesInQuery<N, S> extends infer Tables extends string
219
216
  ? AliasesInQuery<N, S> extends infer Aliases extends string
220
- ? TokenizeLoose<RefScanSegment<N>> extends infer LooseTokens extends string[]
221
- ? AllTablesValidFor<NonCteTables<N, S, Tables>, S> extends true
222
- ? AllColumnsValidFor<N, S, Tables, Aliases, LooseTokens> extends true
223
- ? NoAliasShadowedQualifiers<N, S, Tables, Aliases> extends true
224
- ? OuterScopeUnqualifiedValid<N, S> extends true
225
- ? WindowFilterColsValid<N, S, Tables, Aliases> extends true
226
- ? JoinUsingColsValid<N, S, Tables> extends true
227
- ? DistinctOnColsValid<N, S, Tables, Aliases> extends true
228
- ? true
229
- : false
217
+ ? AllTablesValidFor<NonCteTables<N, S, Tables>, S> extends true
218
+ ? AllColumnsValidFor<N, S, Tables, Aliases, RefScanSegment<N>> extends true
219
+ ? NoAliasShadowedQualifiers<N, S, Tables, Aliases> extends true
220
+ ? OuterScopeUnqualifiedValid<N, S> extends true
221
+ ? WindowFilterColsValid<N, S, Tables, Aliases> extends true
222
+ ? JoinUsingColsValid<N, S, Tables> extends true
223
+ ? DistinctOnColsValid<N, S, Tables, Aliases> extends true
224
+ ? true
230
225
  : false
231
226
  : false
232
227
  : false
233
- : false
234
228
  : false
229
+ : false
235
230
  : false
236
231
  : false
237
232
  : false
@@ -290,41 +285,52 @@ export type HasReturning<N extends string> =
290
285
 
291
286
  // Quote-free fast-path: a query with no `'` and no `"` has no place for a
292
287
  // ` 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.
296
- export type HasReturningQuoteAware<
297
- S extends string,
298
- InString extends boolean = false,
299
- InDString extends boolean = false,
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;
288
+ // is exact and skips the walk (these run on every DML). Only quote-bearing
289
+ // queries pay for the walk below. The fast-path pattern matches the step-cap
290
+ // fallback this walk already uses, so it is consistent with prior behavior.
291
+ export type HasReturningQuoteAware<S extends string> =
292
+ string extends S
293
+ ? false
294
+ : S extends `${string}'${string}`
295
+ ? HasReturningQuoteAwareWalk<S>
296
+ : S extends `${string}"${string}`
297
+ ? HasReturningQuoteAwareWalk<S>
298
+ : S extends `${string} returning ${string}` ? true : false;
308
299
 
300
+ // Quote-jump, not per-char (the old walk minted the tail string PER CHARACTER on
301
+ // every quote-bearing DML). Find the leftmost ` returning `; if no quote opens
302
+ // before it, it is top-level — answer found. Otherwise jump the leftmost quote
303
+ // span whole (`'…'` or `"…"`, whichever opens first — a quote of the other kind
304
+ // inside the span is data, mirroring the old InString/InDString suppression) and
305
+ // re-test the remainder. O(quote spans) instead of O(chars); an unterminated
306
+ // quote swallows the rest, exactly like the old walk-to-EOF inside a literal.
309
307
  type HasReturningQuoteAwareWalk<
310
308
  S extends string,
311
- InString extends boolean = false,
312
- InDString extends boolean = false,
313
309
  Steps extends any[] = []
314
310
  > = string extends S
315
311
  ? false
316
- : Steps["length"] extends 1200
312
+ : Steps["length"] extends 400
317
313
  ? S extends `${string} returning ${string}` ? true : false
318
- : InString extends true
319
- ? S extends `${infer C}${infer Rest}`
320
- ? HasReturningQuoteAwareWalk<Rest, C extends "'" ? false : true, InDString, [any, ...Steps]>
314
+ : S extends `${infer Before} returning ${string}`
315
+ ? Before extends `${string}'${string}` | `${string}"${string}`
316
+ ? HrqaQuoteJump<S, Steps>
317
+ : true
318
+ : false;
319
+
320
+ // Leftmost of `'` / `"` (the caller guarantees at least one occurs before the
321
+ // first ` returning `): skip its whole span, resume after the closing quote.
322
+ type HrqaQuoteJump<S extends string, Steps extends any[]> =
323
+ S extends `${infer P}'${infer R}`
324
+ ? P extends `${string}"${string}`
325
+ ? HrqaDQuoteJump<S, Steps>
326
+ : R extends `${string}'${infer R2}`
327
+ ? HasReturningQuoteAwareWalk<R2, [any, ...Steps]>
321
328
  : false
322
- : InDString extends true
323
- ? S extends `${infer C}${infer Rest}`
324
- ? HasReturningQuoteAwareWalk<Rest, InString, C extends `"` ? false : true, [any, ...Steps]>
325
- : false
326
- : S extends ` returning ${string}`
327
- ? true
328
- : S extends `${infer C}${infer Rest}`
329
- ? HasReturningQuoteAwareWalk<Rest, C extends "'" ? true : false, C extends `"` ? true : false, [any, ...Steps]>
330
- : false;
329
+ : HrqaDQuoteJump<S, Steps>;
330
+
331
+ type HrqaDQuoteJump<S extends string, Steps extends any[]> =
332
+ S extends `${string}"${infer R}`
333
+ ? R extends `${string}"${infer R2}`
334
+ ? HasReturningQuoteAwareWalk<R2, [any, ...Steps]>
335
+ : false
336
+ : false;
@@ -1,6 +1,6 @@
1
1
  // JOIN USING / window-filter / DISTINCT ON column validation.
2
2
  import type { AllTrue, And, IsUnion } from "../utils.js";
3
- import type { CleanIdent, ExtractCallParenBodies, SplitCommaSimple, TokenizeLoose, Trim } from "../parsing.js";
3
+ import type { CleanIdent, ExtractCallParenBodies, SplitCommaSimple, Trim } from "../parsing.js";
4
4
  import type { ColumnExists, DatabaseSchema } from "../schema.js";
5
5
  import type { QualifiedColumnRefsValidFor, UnqualifiedColumnRefsValidFor } from "./validate-columns.js";
6
6
  import type { QueryKind } from "./dispatch.js";
@@ -151,15 +151,13 @@ export type WindowFilterColsValid<
151
151
  ? `${ExtractCallParenBodies<N, " over (">} ${ExtractCallParenBodies<N, " over(">} ${ExtractCallParenBodies<N, " filter (">} ${ExtractCallParenBodies<N, " filter(">} ${ExtractCallParenBodies<N, " within group (">} ${ExtractCallParenBodies<N, " within group(">}` extends infer Seg extends string
152
152
  ? Trim<Seg> extends ""
153
153
  ? true
154
- : TokenizeLoose<Seg> extends infer Toks extends string[]
155
- ? And<
156
- QualifiedColumnRefsValidFor<N, S, Tables, Aliases, Toks>,
157
- UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, Toks, never>,
158
- true,
159
- true,
160
- true
161
- >
162
- : true
154
+ : And<
155
+ QualifiedColumnRefsValidFor<N, S, Tables, Aliases, Seg>,
156
+ UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, Seg, never>,
157
+ true,
158
+ true,
159
+ true
160
+ >
163
161
  : true
164
162
  : true;
165
163
 
@@ -183,15 +181,13 @@ export type DistinctOnColsValid<
183
181
  ? `${ExtractCallParenBodies<N, " distinct on (">} ${ExtractCallParenBodies<N, " distinct on(">}` extends infer Seg extends string
184
182
  ? Trim<Seg> extends ""
185
183
  ? true
186
- : TokenizeLoose<Seg> extends infer Toks extends string[]
187
- ? And<
188
- QualifiedColumnRefsValidFor<N, S, Tables, Aliases, Toks>,
189
- UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, Toks, never>,
190
- true,
191
- true,
192
- true
193
- >
194
- : true
184
+ : And<
185
+ QualifiedColumnRefsValidFor<N, S, Tables, Aliases, Seg>,
186
+ UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, Seg, never>,
187
+ true,
188
+ true,
189
+ true
190
+ >
195
191
  : true
196
192
  : true
197
193
  : true;
@@ -1,8 +1,8 @@
1
1
  // Table/column existence + qualified/unqualified ref + scope-shape validation.
2
2
  import type { AliasesInQuery, InsertTargetTable, TableKeyValid, TablesInQuery, UpdateTargetTable } from "../tables.js";
3
3
  import type { AllTrue, And, StartsWith } from "../utils.js";
4
- import type { CleanIdent, DQuoteSpaceSentinel, ExceedsLengthBudget, ExtractAliasResult, ExtractBefore, ExtractConflictColumns, ExtractConflictUpdateExcludedCols, ExtractConflictUpdateSetColumns, ExtractInsertColumns, ExtractLastWhere, ExtractReturningList, ExtractSelectList, ExtractUpdateSetColumns, ReplaceAll, SplitSelectList, StripSubqueries, TokenizeLoose, Trim } from "../parsing.js";
5
- import type { ColumnRefValidLooseWith, IsSimpleRefPart, QualifiedColumnRefs, ResolveAlias, TableKeysByName, UnqualifiedColumnRefs, UnqualifiedColumnValid } from "../columns.js";
4
+ import type { CleanIdent, DQuoteSpaceSentinel, ExceedsLengthBudget, ExtractAliasResult, ExtractBefore, ExtractConflictColumns, ExtractConflictUpdateExcludedCols, ExtractConflictUpdateSetColumns, ExtractInsertColumns, ExtractLastWhere, ExtractReturningList, ExtractSelectList, ExtractUpdateSetColumns, ReplaceAll, SplitSelectList, StripSubqueries, Trim } from "../parsing.js";
5
+ import type { ColumnRefValidLooseWith, IsSimpleRefPart, QualifiedRefScan, ResolveAlias, TableKeysByName, UnqualifiedRefScan, UnqualifiedColumnValid } from "../columns.js";
6
6
  import type { ColumnsExistInTable, RefScanBeforeOrderBy, RefScanOrderBy, RefScanSegment, SelectAliasesInQuery, SelectAliasSet } from "./return-types.js";
7
7
  import type { CteNames, CteRow, SingleCteMatch } from "./cte.js";
8
8
  import type { DatabaseSchema } from "../schema.js";
@@ -105,7 +105,7 @@ export type KeyInRow<K extends string, Row> = [K] extends [keyof Row] ? true : f
105
105
 
106
106
  // Validate every column-reference candidate in an arbitrary text segment (an
107
107
  // outer WHERE predicate, or a function call's argument list) against the
108
- // CTE/derived relation's exposed `Row`. Reuses the same token walkers the core
108
+ // CTE/derived relation's exposed `Row`. Reuses the same ref-scan walkers the core
109
109
  // validator uses to surface refs, then checks each via `ProjRefInRow` (qualifier
110
110
  // must equal the relation `Name`, column must be a key of `Row`). `Tables`/
111
111
  // `Aliases` are `never`: the walkers only consult them to EXCLUDE table/alias
@@ -115,22 +115,20 @@ export type KeyInRow<K extends string, Row> = [K] extends [keyof Row] ? true : f
115
115
  export type SegRefsInRow<Seg extends string, Name extends string, Row, S extends DatabaseSchema> =
116
116
  Trim<Seg> extends ""
117
117
  ? true
118
- : TokenizeLoose<Seg> extends infer Toks extends string[]
119
- ? And<
120
- AllTrue<
121
- QualifiedColumnRefs<Toks, S, never, never> extends infer R
122
- ? R extends string ? ProjRefInRow<R, Name, Row, S> : true
123
- : true
124
- >,
125
- AllTrue<
126
- UnqualifiedColumnRefs<Toks, S, never, never> extends infer R
127
- ? R extends string ? ProjRefInRow<R, Name, Row, S> : true
128
- : true
129
- >,
130
- true,
131
- true
132
- >
133
- : true;
118
+ : And<
119
+ AllTrue<
120
+ QualifiedRefScan<Seg> extends infer R
121
+ ? R extends string ? ProjRefInRow<R, Name, Row, S> : true
122
+ : true
123
+ >,
124
+ AllTrue<
125
+ UnqualifiedRefScan<Seg, S, never, never> extends infer R
126
+ ? R extends string ? ProjRefInRow<R, Name, Row, S> : true
127
+ : true
128
+ >,
129
+ true,
130
+ true
131
+ >;
134
132
 
135
133
  // The outer query's WHERE predicate, scoped to the CTE/derived relation's exposed
136
134
  // row. Strip subquery bodies FIRST so the derived/CTE body's own WHERE is never
@@ -191,22 +189,20 @@ type ExtractOrderByExpr<S extends string> =
191
189
  export type SegRefsInRowWithAliases<Seg extends string, Name extends string, Row, S extends DatabaseSchema, SelAliases extends string> =
192
190
  Trim<Seg> extends ""
193
191
  ? true
194
- : TokenizeLoose<Seg> extends infer Toks extends string[]
195
- ? And<
196
- AllTrue<
197
- QualifiedColumnRefs<Toks, S, never, never> extends infer R
198
- ? R extends string ? RefInRowOrAlias<R, Name, Row, S, SelAliases> : true
199
- : true
200
- >,
201
- AllTrue<
202
- UnqualifiedColumnRefs<Toks, S, never, never> extends infer R
203
- ? R extends string ? RefInRowOrAlias<R, Name, Row, S, SelAliases> : true
204
- : true
205
- >,
206
- true,
207
- true
208
- >
209
- : true;
192
+ : And<
193
+ AllTrue<
194
+ QualifiedRefScan<Seg> extends infer R
195
+ ? R extends string ? RefInRowOrAlias<R, Name, Row, S, SelAliases> : true
196
+ : true
197
+ >,
198
+ AllTrue<
199
+ UnqualifiedRefScan<Seg, S, never, never> extends infer R
200
+ ? R extends string ? RefInRowOrAlias<R, Name, Row, S, SelAliases> : true
201
+ : true
202
+ >,
203
+ true,
204
+ true
205
+ >;
210
206
 
211
207
  export type RefInRowOrAlias<R extends string, Name extends string, Row, S extends DatabaseSchema, SelAliases extends string> =
212
208
  [SelAliases] extends [never]
@@ -231,9 +227,7 @@ export type AllTablesValidFor<Tables extends string, S extends DatabaseSchema> =
231
227
  export type AllColumnsValid<N extends string, S extends DatabaseSchema> =
232
228
  TablesInQuery<N, S> extends infer Tables extends string
233
229
  ? AliasesInQuery<N, S> extends infer Aliases extends string
234
- ? TokenizeLoose<RefScanSegment<N>> extends infer LooseTokens extends string[]
235
- ? AllColumnsValidFor<N, S, Tables, Aliases, LooseTokens>
236
- : false
230
+ ? AllColumnsValidFor<N, S, Tables, Aliases, RefScanSegment<N>>
237
231
  : false
238
232
  : false;
239
233
 
@@ -242,7 +236,7 @@ export type AllColumnsValidFor<
242
236
  S extends DatabaseSchema,
243
237
  Tables extends string,
244
238
  Aliases extends string,
245
- LooseTokens extends string[]
239
+ RefSeg extends string
246
240
  > = SelectAliasSet<N> extends infer SelectAliases extends string
247
241
  ? QueryKind<N> extends "update"
248
242
  // A normal (non-high-complexity) UPDATE has no subquery/CASE SET, so its
@@ -254,14 +248,14 @@ export type AllColumnsValidFor<
254
248
  ColumnsValidInUpdate<N, S>,
255
249
  ColumnsValidInInsert<N, S>,
256
250
  ColumnsValidInSelectOrReturningFor<N, S, Tables, Aliases>,
257
- QualifiedColumnRefsValidFor<N, S, Tables, Aliases, LooseTokens>,
258
- UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, LooseTokens, never>
251
+ QualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefSeg>,
252
+ UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefSeg, never>
259
253
  >
260
254
  : And<
261
255
  ColumnsValidInSelectOrReturningFor<N, S, Tables, Aliases>,
262
256
  ColumnsValidInInsert<N, S>,
263
257
  ColumnsValidInUpdate<N, S>,
264
- QualifiedColumnRefsValidFor<N, S, Tables, Aliases, LooseTokens>,
258
+ QualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefSeg>,
265
259
  // A SELECT-list alias is only resolvable in ORDER BY — NOT in
266
260
  // WHERE/GROUP/HAVING. So the unqualified ref-scan blesses the alias
267
261
  // set ONLY for the ORDER BY token slice; the FROM..(pre-order-by)
@@ -284,10 +278,10 @@ export type SelectUnqualifiedRefsScoped<
284
278
  SelectAliases extends string
285
279
  > =
286
280
  [SelectAliases] extends [never]
287
- ? UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, TokenizeLoose<RefScanSegment<N>>, never>
281
+ ? UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefScanSegment<N>, never>
288
282
  : And<
289
- UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, TokenizeLoose<RefScanBeforeOrderBy<N>>, never>,
290
- UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, TokenizeLoose<RefScanOrderBy<N>>, SelectAliases>,
283
+ UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefScanBeforeOrderBy<N>, never>,
284
+ UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefScanOrderBy<N>, SelectAliases>,
291
285
  true,
292
286
  true,
293
287
  true
@@ -365,9 +359,7 @@ export type ColumnsValidInUpdate<N extends string, S extends DatabaseSchema> =
365
359
  export type QualifiedColumnRefsValid<N extends string, S extends DatabaseSchema> =
366
360
  TablesInQuery<N, S> extends infer Tables extends string
367
361
  ? AliasesInQuery<N, S> extends infer Aliases extends string
368
- ? TokenizeLoose<RefScanSegment<N>> extends infer LooseTokens extends string[]
369
- ? QualifiedColumnRefsValidFor<N, S, Tables, Aliases, LooseTokens>
370
- : true
362
+ ? QualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefScanSegment<N>>
371
363
  : true
372
364
  : true;
373
365
 
@@ -376,14 +368,14 @@ export type QualifiedColumnRefsValidFor<
376
368
  S extends DatabaseSchema,
377
369
  Tables extends string,
378
370
  Aliases extends string,
379
- LooseTokens extends string[]
371
+ RefSeg extends string
380
372
  > =
381
373
  // Common path: with no CTE and no parenthesised FROM source there is no local
382
374
  // relation that could qualify a ref, so skip the (per-ref) local-relation
383
375
  // blessing entirely — exact prior behavior, zero added cost.
384
376
  HasLocalRelations<N> extends true
385
- ? QualifiedRefsValidWithLocal<N, S, Tables, Aliases, LooseTokens, CteNames<N>>
386
- : QualifiedColumnRefs<LooseTokens, S, Tables, Aliases> extends infer Cols
377
+ ? QualifiedRefsValidWithLocal<N, S, Tables, Aliases, RefSeg, CteNames<N>>
378
+ : QualifiedRefScan<RefSeg> extends infer Cols
387
379
  ? AllTrue<Cols extends string ? ColumnRefValidLooseWith<Cols, Tables, Aliases, S> : true>
388
380
  : true;
389
381
 
@@ -404,9 +396,9 @@ type QualifiedRefsValidWithLocal<
404
396
  S extends DatabaseSchema,
405
397
  Tables extends string,
406
398
  Aliases extends string,
407
- LooseTokens extends string[],
399
+ RefSeg extends string,
408
400
  Ctes extends string
409
- > = QualifiedColumnRefs<LooseTokens, S, Tables, Aliases> extends infer Cols
401
+ > = QualifiedRefScan<RefSeg> extends infer Cols
410
402
  ? AllTrue<
411
403
  Cols extends string
412
404
  ? IsLocalRelation<RefQualifierOf<Cols>, Ctes, N> extends true
@@ -468,12 +460,12 @@ export type NoAliasShadowedQualifiers<
468
460
  [AliasedTableKeys<Aliases>] extends [never]
469
461
  ? true
470
462
  // A shadowable qualifier is a `qualifier.column` token, which requires a
471
- // `.`. With no `.` anywhere, `QualifiedColumnRefs` accumulates `never` and
472
- // `AllTrue<never>` is `true` — so skip the whole-query `TokenizeLoose<N>`
473
- // re-walk (computed nowhere else) on dot-free queries. Exact-equivalent.
463
+ // `.`. With no `.` anywhere, `QualifiedRefScan` accumulates `never` and
464
+ // `AllTrue<never>` is `true` — so skip the whole-query re-scan (computed
465
+ // nowhere else) on dot-free queries. Exact-equivalent.
474
466
  : N extends `${string}.${string}`
475
467
  ? AllTrue<
476
- QualifiedColumnRefs<TokenizeLoose<N>, S, Tables, Aliases> extends infer R
468
+ QualifiedRefScan<N> extends infer R
477
469
  ? R extends `${infer Q}.${string}`
478
470
  ? QualifierShadowedByAlias<Q, Tables, Aliases, S> extends true
479
471
  ? false
@@ -521,7 +513,7 @@ export type OuterScopeUnqualifiedValid<N extends string, S extends DatabaseSchem
521
513
  S,
522
514
  OT,
523
515
  OA,
524
- TokenizeLoose<RefScanSegment<Stripped>>,
516
+ RefScanSegment<Stripped>,
525
517
  SelectAliasesInQuery<Stripped>
526
518
  >
527
519
  : true
@@ -534,10 +526,8 @@ export type OuterScopeUnqualifiedValid<N extends string, S extends DatabaseSchem
534
526
  export type UnqualifiedColumnRefsValid<N extends string, S extends DatabaseSchema> =
535
527
  TablesInQuery<N, S> extends infer Tables extends string
536
528
  ? AliasesInQuery<N, S> extends infer Aliases extends string
537
- ? TokenizeLoose<RefScanSegment<N>> extends infer LooseTokens extends string[]
538
- ? SelectAliasesInQuery<N> extends infer SelectAliases extends string
539
- ? UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, LooseTokens, SelectAliases>
540
- : true
529
+ ? SelectAliasesInQuery<N> extends infer SelectAliases extends string
530
+ ? UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefScanSegment<N>, SelectAliases>
541
531
  : true
542
532
  : true
543
533
  : true;
@@ -547,9 +537,9 @@ export type UnqualifiedColumnRefsValidFor<
547
537
  S extends DatabaseSchema,
548
538
  Tables extends string,
549
539
  Aliases extends string,
550
- LooseTokens extends string[],
540
+ RefSeg extends string,
551
541
  SelectAliases extends string
552
- > = UnqualifiedColumnRefs<LooseTokens, S, Tables, Aliases> extends infer Cols
542
+ > = UnqualifiedRefScan<RefSeg, S, Tables, Aliases> extends infer Cols
553
543
  ? AllTrue<
554
544
  Cols extends string
555
545
  ? CleanIdent<Cols> extends SelectAliases