@kuindji/typed-sql 0.2.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.
- package/README.md +11 -3
- package/dist/columns.d.ts +11 -3
- package/dist/columns.d.ts.map +1 -1
- package/dist/expressions.d.ts +84 -13
- package/dist/expressions.d.ts.map +1 -1
- package/dist/parsing/extract.d.ts +13 -9
- package/dist/parsing/extract.d.ts.map +1 -1
- package/dist/parsing/normalize.d.ts +9 -3
- package/dist/parsing/normalize.d.ts.map +1 -1
- package/dist/parsing/pg-literals.d.ts +10 -2
- package/dist/parsing/pg-literals.d.ts.map +1 -1
- package/dist/parsing/split.d.ts +27 -3
- package/dist/parsing/split.d.ts.map +1 -1
- package/dist/parsing/string-utils.d.ts +2 -4
- package/dist/parsing/string-utils.d.ts.map +1 -1
- package/dist/parsing/tokenize.d.ts +27 -17
- package/dist/parsing/tokenize.d.ts.map +1 -1
- package/dist/partial.d.ts +6 -6
- package/dist/partial.d.ts.map +1 -1
- package/dist/tables.d.ts +58 -13
- package/dist/tables.d.ts.map +1 -1
- package/dist/validation/dispatch.d.ts +7 -5
- package/dist/validation/dispatch.d.ts.map +1 -1
- package/dist/validation/joins.d.ts +3 -3
- package/dist/validation/joins.d.ts.map +1 -1
- package/dist/validation/return-derived.d.ts +8 -4
- package/dist/validation/return-derived.d.ts.map +1 -1
- package/dist/validation/return-derived.js.map +1 -1
- package/dist/validation/return-types.d.ts +1 -1
- package/dist/validation/return-types.d.ts.map +1 -1
- package/dist/validation/validate-columns.d.ts +27 -16
- package/dist/validation/validate-columns.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/columns.ts +168 -32
- package/src/expressions.ts +589 -63
- package/src/parsing/extract.ts +72 -32
- package/src/parsing/normalize.ts +114 -10
- package/src/parsing/pg-literals.ts +32 -10
- package/src/parsing/split.ts +236 -72
- package/src/parsing/string-utils.ts +15 -15
- package/src/parsing/tokenize.ts +224 -146
- package/src/partial.ts +9 -15
- package/src/tables.ts +546 -183
- package/src/validation/dispatch.ts +58 -52
- package/src/validation/joins.ts +15 -19
- package/src/validation/return-derived.ts +60 -4
- package/src/validation/return-types.ts +9 -3
- package/src/validation/validate-columns.ts +161 -67
|
@@ -1,12 +1,12 @@
|
|
|
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,
|
|
5
|
-
import type { ColumnRefValidLooseWith, IsSimpleRefPart,
|
|
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
|
-
import type { CteRow, SingleCteMatch } from "./cte.js";
|
|
7
|
+
import type { CteNames, CteRow, SingleCteMatch } from "./cte.js";
|
|
8
8
|
import type { DatabaseSchema } from "../schema.js";
|
|
9
|
-
import type { DerivedRenamedRow, DerivedTableMatch } from "./return-derived.js";
|
|
9
|
+
import type { AliasHasNoSpace, DerivedRenamedRow, DerivedTableMatch } from "./return-derived.js";
|
|
10
10
|
import type { ExprsValidList } from "../expressions.js";
|
|
11
11
|
import type { HasReturning, QueryKind, ValidateSQLNormalized } from "./dispatch.js";
|
|
12
12
|
|
|
@@ -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
|
|
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
|
-
:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
:
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
?
|
|
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
|
-
|
|
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,
|
|
258
|
-
UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases,
|
|
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,
|
|
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,
|
|
281
|
+
? UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefScanSegment<N>, never>
|
|
288
282
|
: And<
|
|
289
|
-
UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases,
|
|
290
|
-
UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases,
|
|
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
|
|
@@ -309,7 +303,7 @@ export type ColumnsValidInSelectOrReturningFor<
|
|
|
309
303
|
HasReturning<N> extends true
|
|
310
304
|
? [Tables] extends [never]
|
|
311
305
|
? true
|
|
312
|
-
: ExprsValidList<SplitSelectList<ReplaceAll<ExtractReturningList<N>, DQuoteSpaceSentinel, " ">>, Tables, Aliases, S
|
|
306
|
+
: ExprsValidList<SplitSelectList<ReplaceAll<ExtractReturningList<N>, DQuoteSpaceSentinel, " ">>, Tables, Aliases, S, [], SelectLocalRels<N>>
|
|
313
307
|
: QueryKind<N> extends "select"
|
|
314
308
|
? [Tables] extends [never]
|
|
315
309
|
? true
|
|
@@ -318,9 +312,18 @@ export type ColumnsValidInSelectOrReturningFor<
|
|
|
318
312
|
// The alias set restores those spaces, so restore them here too or a
|
|
319
313
|
// qualifier through a space-bearing quoted alias (`"user alias".id`)
|
|
320
314
|
// would never match its registered alias (round-12 regression).
|
|
321
|
-
: ExprsValidList<SplitSelectList<ReplaceAll<ExtractSelectList<N>, DQuoteSpaceSentinel, " ">>, Tables, Aliases, S
|
|
315
|
+
: ExprsValidList<SplitSelectList<ReplaceAll<ExtractSelectList<N>, DQuoteSpaceSentinel, " ">>, Tables, Aliases, S, [], SelectLocalRels<N>>
|
|
322
316
|
: true;
|
|
323
317
|
|
|
318
|
+
// Query-local relation names whose qualified refs the projection-list validator
|
|
319
|
+
// must bless: a `WITH`-query's CTE names. (A CTE that reaches the core validator
|
|
320
|
+
// — e.g. `WITH ... SELECT ... JOIN ...` — is collected into `TablesInQuery` as a
|
|
321
|
+
// bogus base table for the ref-resolution, so `cte.col` in the SELECT list would
|
|
322
|
+
// otherwise resolve `never` and falsely reject.) Gated on the `with ` prefix so
|
|
323
|
+
// CTE-free queries pay nothing.
|
|
324
|
+
type SelectLocalRels<N extends string> =
|
|
325
|
+
N extends `with ${string}` ? CteNames<N> : never;
|
|
326
|
+
|
|
324
327
|
// insert
|
|
325
328
|
|
|
326
329
|
export type ColumnsValidInInsert<N extends string, S extends DatabaseSchema> =
|
|
@@ -356,9 +359,7 @@ export type ColumnsValidInUpdate<N extends string, S extends DatabaseSchema> =
|
|
|
356
359
|
export type QualifiedColumnRefsValid<N extends string, S extends DatabaseSchema> =
|
|
357
360
|
TablesInQuery<N, S> extends infer Tables extends string
|
|
358
361
|
? AliasesInQuery<N, S> extends infer Aliases extends string
|
|
359
|
-
?
|
|
360
|
-
? QualifiedColumnRefsValidFor<N, S, Tables, Aliases, LooseTokens>
|
|
361
|
-
: true
|
|
362
|
+
? QualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefScanSegment<N>>
|
|
362
363
|
: true
|
|
363
364
|
: true;
|
|
364
365
|
|
|
@@ -367,11 +368,67 @@ export type QualifiedColumnRefsValidFor<
|
|
|
367
368
|
S extends DatabaseSchema,
|
|
368
369
|
Tables extends string,
|
|
369
370
|
Aliases extends string,
|
|
370
|
-
|
|
371
|
-
> =
|
|
372
|
-
|
|
371
|
+
RefSeg extends string
|
|
372
|
+
> =
|
|
373
|
+
// Common path: with no CTE and no parenthesised FROM source there is no local
|
|
374
|
+
// relation that could qualify a ref, so skip the (per-ref) local-relation
|
|
375
|
+
// blessing entirely — exact prior behavior, zero added cost.
|
|
376
|
+
HasLocalRelations<N> extends true
|
|
377
|
+
? QualifiedRefsValidWithLocal<N, S, Tables, Aliases, RefSeg, CteNames<N>>
|
|
378
|
+
: QualifiedRefScan<RefSeg> extends infer Cols
|
|
379
|
+
? AllTrue<Cols extends string ? ColumnRefValidLooseWith<Cols, Tables, Aliases, S> : true>
|
|
380
|
+
: true;
|
|
381
|
+
|
|
382
|
+
// A "local relation" is a query-local name that is NOT a base table: a CTE name, or
|
|
383
|
+
// the alias bound to a derived / VALUES / subquery FROM source (`from (…) [as]
|
|
384
|
+
// x[(cols)]`). Its columns are not modeled in the schema, so a ref qualified by it
|
|
385
|
+
// must be accepted leniently rather than resolved against a (non-existent) base
|
|
386
|
+
// table. Blessing only ever turns a reject into an accept — never the reverse —
|
|
387
|
+
// consistent with the lenient-parser contract.
|
|
388
|
+
type HasLocalRelations<N extends string> =
|
|
389
|
+
N extends `with ${string}` ? true :
|
|
390
|
+
N extends `${string} from (${string}` ? true :
|
|
391
|
+
N extends `${string} join (${string}` ? true :
|
|
392
|
+
false;
|
|
393
|
+
|
|
394
|
+
type QualifiedRefsValidWithLocal<
|
|
395
|
+
N extends string,
|
|
396
|
+
S extends DatabaseSchema,
|
|
397
|
+
Tables extends string,
|
|
398
|
+
Aliases extends string,
|
|
399
|
+
RefSeg extends string,
|
|
400
|
+
Ctes extends string
|
|
401
|
+
> = QualifiedRefScan<RefSeg> extends infer Cols
|
|
402
|
+
? AllTrue<
|
|
403
|
+
Cols extends string
|
|
404
|
+
? IsLocalRelation<RefQualifierOf<Cols>, Ctes, N> extends true
|
|
405
|
+
? true
|
|
406
|
+
: ColumnRefValidLooseWith<Cols, Tables, Aliases, S>
|
|
407
|
+
: true
|
|
408
|
+
>
|
|
373
409
|
: true;
|
|
374
410
|
|
|
411
|
+
// The qualifier (text before the first `.`) of a qualified column ref.
|
|
412
|
+
type RefQualifierOf<Col extends string> =
|
|
413
|
+
Col extends `${infer Q}.${string}` ? CleanIdent<Q> : never;
|
|
414
|
+
|
|
415
|
+
type IsLocalRelation<Q extends string, Ctes extends string, N extends string> =
|
|
416
|
+
[Q] extends [never] ? false :
|
|
417
|
+
Q extends Ctes ? true :
|
|
418
|
+
IsDerivedSourceAlias<Q, N>;
|
|
419
|
+
|
|
420
|
+
// Detect `… ) [as] q …` / `… ) [as] q( …` — q is the alias bound to a parenthesised
|
|
421
|
+
// (derived / VALUES / subquery) FROM source. N is already normalized (lowercase
|
|
422
|
+
// outside quotes); q is the cleaned, lowercased qualifier.
|
|
423
|
+
type IsDerivedSourceAlias<Q extends string, N extends string> =
|
|
424
|
+
N extends `${string}) as ${Q} ${string}` ? true :
|
|
425
|
+
N extends `${string}) as ${Q}(${string}` ? true :
|
|
426
|
+
N extends `${string}) as ${Q}` ? true :
|
|
427
|
+
N extends `${string}) ${Q} ${string}` ? true :
|
|
428
|
+
N extends `${string}) ${Q}(${string}` ? true :
|
|
429
|
+
N extends `${string}) ${Q}` ? true :
|
|
430
|
+
false;
|
|
431
|
+
|
|
375
432
|
// Once a table is given a range alias (`FROM products p`), PostgreSQL hides the
|
|
376
433
|
// original table name as a correlation name for that query level — `products.id`
|
|
377
434
|
// is then invalid; only `p.id` works. The lenient qualified-ref check accepts
|
|
@@ -403,12 +460,12 @@ export type NoAliasShadowedQualifiers<
|
|
|
403
460
|
[AliasedTableKeys<Aliases>] extends [never]
|
|
404
461
|
? true
|
|
405
462
|
// A shadowable qualifier is a `qualifier.column` token, which requires a
|
|
406
|
-
// `.`. With no `.` anywhere, `
|
|
407
|
-
// `AllTrue<never>` is `true` — so skip the whole-query
|
|
408
|
-
//
|
|
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.
|
|
409
466
|
: N extends `${string}.${string}`
|
|
410
467
|
? AllTrue<
|
|
411
|
-
|
|
468
|
+
QualifiedRefScan<N> extends infer R
|
|
412
469
|
? R extends `${infer Q}.${string}`
|
|
413
470
|
? QualifierShadowedByAlias<Q, Tables, Aliases, S> extends true
|
|
414
471
|
? false
|
|
@@ -456,7 +513,7 @@ export type OuterScopeUnqualifiedValid<N extends string, S extends DatabaseSchem
|
|
|
456
513
|
S,
|
|
457
514
|
OT,
|
|
458
515
|
OA,
|
|
459
|
-
|
|
516
|
+
RefScanSegment<Stripped>,
|
|
460
517
|
SelectAliasesInQuery<Stripped>
|
|
461
518
|
>
|
|
462
519
|
: true
|
|
@@ -469,10 +526,8 @@ export type OuterScopeUnqualifiedValid<N extends string, S extends DatabaseSchem
|
|
|
469
526
|
export type UnqualifiedColumnRefsValid<N extends string, S extends DatabaseSchema> =
|
|
470
527
|
TablesInQuery<N, S> extends infer Tables extends string
|
|
471
528
|
? AliasesInQuery<N, S> extends infer Aliases extends string
|
|
472
|
-
?
|
|
473
|
-
?
|
|
474
|
-
? UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, LooseTokens, SelectAliases>
|
|
475
|
-
: true
|
|
529
|
+
? SelectAliasesInQuery<N> extends infer SelectAliases extends string
|
|
530
|
+
? UnqualifiedColumnRefsValidFor<N, S, Tables, Aliases, RefScanSegment<N>, SelectAliases>
|
|
476
531
|
: true
|
|
477
532
|
: true
|
|
478
533
|
: true;
|
|
@@ -482,14 +537,53 @@ export type UnqualifiedColumnRefsValidFor<
|
|
|
482
537
|
S extends DatabaseSchema,
|
|
483
538
|
Tables extends string,
|
|
484
539
|
Aliases extends string,
|
|
485
|
-
|
|
540
|
+
RefSeg extends string,
|
|
486
541
|
SelectAliases extends string
|
|
487
|
-
> =
|
|
542
|
+
> = UnqualifiedRefScan<RefSeg, S, Tables, Aliases> extends infer Cols
|
|
488
543
|
? AllTrue<
|
|
489
544
|
Cols extends string
|
|
490
545
|
? CleanIdent<Cols> extends SelectAliases
|
|
491
546
|
? true
|
|
492
|
-
: UnqualifiedColumnValid<Cols, Tables, Aliases, S>
|
|
547
|
+
: UnqualifiedColumnValid<Cols, Tables, Aliases, S> extends true
|
|
548
|
+
? true
|
|
549
|
+
// A derived/VALUES source's column-alias list (`... ) as
|
|
550
|
+
// src(id, t)`) survives tokenization as bare identifier tokens,
|
|
551
|
+
// and `t` is not a schema column anywhere — bless names that
|
|
552
|
+
// belong to such a list. Checked ONLY after normal resolution
|
|
553
|
+
// fails, so valid queries never pay for the extraction, and
|
|
554
|
+
// blessing can only turn a reject into an accept (lenient
|
|
555
|
+
// contract).
|
|
556
|
+
: CleanIdent<Cols> extends SourceAliasListCols<N>
|
|
557
|
+
? true
|
|
558
|
+
: false
|
|
493
559
|
: true
|
|
494
560
|
>
|
|
495
561
|
: true;
|
|
562
|
+
|
|
563
|
+
// Every column name bound by a derived-source column-alias list — `) as p(a, b)`
|
|
564
|
+
// / `) p(a, b)` — plus CTE column-alias lists (`with c(x, y) as (`). Collected
|
|
565
|
+
// across ALL occurrences in the (normalized, single-line) query. The alias word
|
|
566
|
+
// itself must be space-free, mirroring `DerivedColsAfterAlias`'s guard, so a
|
|
567
|
+
// trailing `WHERE ... IN (...)` paren group is not misread as a column list.
|
|
568
|
+
type SourceAliasListCols<N extends string> =
|
|
569
|
+
N extends `with ${infer CteHead}(${infer CteCols}) as (${infer Rest}`
|
|
570
|
+
? AliasHasNoSpace<Trim<CteHead>> extends true
|
|
571
|
+
? ColNamesFromList<CteCols> | DerivedAliasListCols<Rest>
|
|
572
|
+
: DerivedAliasListCols<N>
|
|
573
|
+
: DerivedAliasListCols<N>;
|
|
574
|
+
|
|
575
|
+
type DerivedAliasListCols<N extends string, Steps extends any[] = []> =
|
|
576
|
+
Steps["length"] extends 15
|
|
577
|
+
? never
|
|
578
|
+
: N extends `${string}) as ${infer Rest}`
|
|
579
|
+
? Rest extends `${infer Alias}(${infer Cols})${infer Tail}`
|
|
580
|
+
? AliasHasNoSpace<Trim<Alias>> extends true
|
|
581
|
+
? ColNamesFromList<Cols> | DerivedAliasListCols<Tail, [any, ...Steps]>
|
|
582
|
+
: DerivedAliasListCols<Tail, [any, ...Steps]>
|
|
583
|
+
: never
|
|
584
|
+
: never;
|
|
585
|
+
|
|
586
|
+
type ColNamesFromList<L extends string> =
|
|
587
|
+
L extends `${infer A},${infer R}`
|
|
588
|
+
? CleanIdent<A> | ColNamesFromList<R>
|
|
589
|
+
: CleanIdent<L>;
|