@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.
- 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 +73 -8
- 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 +3 -1
- 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/validate-columns.d.ts +14 -14
- 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 +550 -57
- package/src/parsing/extract.ts +72 -32
- package/src/parsing/normalize.ts +54 -8
- 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 -214
- package/src/validation/dispatch.ts +58 -52
- package/src/validation/joins.ts +15 -19
- package/src/validation/validate-columns.ts +54 -64
package/src/tables.ts
CHANGED
|
@@ -1,13 +1,34 @@
|
|
|
1
1
|
import type { DatabaseSchema, NormalizeTableKey, TableExists } from "./schema.js";
|
|
2
|
-
import type { CleanIdent,
|
|
2
|
+
import type { CleanIdent, CollectorScanView, CollectorToken, CommaSep, SplitOnDotClean, SqlKeyword } from "./parsing.js";
|
|
3
3
|
|
|
4
4
|
// Table and alias extraction
|
|
5
|
+
//
|
|
6
|
+
// The collectors walk the `CollectorScanView` STRING directly, word by word —
|
|
7
|
+
// replacing the old `SplitCollectorTokens` token-array build plus array-walking
|
|
8
|
+
// state machines (round-10): every array build/destructure step minted a
|
|
9
|
+
// unique-content tuple and its apparent-`Array` types, while a word-jump string
|
|
10
|
+
// walk interns its substrings and `[any, ...Steps]` counter tuples. The old
|
|
11
|
+
// walkers branched on the token at the current position plus 1–3 tokens of
|
|
12
|
+
// lookahead; here the lookahead is a `Mode` register — a keyword arms a mode and
|
|
13
|
+
// the decision fires when the NEXT kept token materializes (the round-9
|
|
14
|
+
// deferred-decision pattern). A word whose `CollectorToken` is `""` never
|
|
15
|
+
// occupied an array position, so it updates NO register (it does consume the
|
|
16
|
+
// step cap, exactly like the old split's per-word budget).
|
|
17
|
+
//
|
|
18
|
+
// Each walker is CHUNKED (the chunked-driver pattern): the worker walks 100
|
|
19
|
+
// words per evaluation and yields `{ __c: [state...] }`, and the driver
|
|
20
|
+
// re-invokes it with a fresh step counter — a whole-query walk in one tail
|
|
21
|
+
// evaluation exceeds TypeScript's conditional-evaluation budget on report-scale
|
|
22
|
+
// queries (TS2589). 20 chunks × 100 words = the old split's 2000-word cap: on
|
|
23
|
+
// the final chunk boundary the remainder is blobbed into ONE trailing token and
|
|
24
|
+
// dispatched in whatever state the walk had reached (the `*Final` arms), exactly
|
|
25
|
+
// like the old capped split + collector tail.
|
|
5
26
|
|
|
6
27
|
export type TablesInQuery<N extends string, S extends DatabaseSchema> =
|
|
7
|
-
|
|
28
|
+
CtDrive<CtWalk<CollectorScanView<N>, S, never, false, N extends `delete ${string}` ? true : false>, S>;
|
|
8
29
|
|
|
9
30
|
export type AliasesInQuery<N extends string, S extends DatabaseSchema> =
|
|
10
|
-
|
|
31
|
+
CaDrive<CaWalk<CollectorScanView<N>, S, never, false, N extends `delete ${string}` ? true : false>, S>;
|
|
11
32
|
|
|
12
33
|
export type TableKeyValid<Key extends string, S extends DatabaseSchema> =
|
|
13
34
|
Key extends `${infer Schema}.${infer Table}`
|
|
@@ -33,185 +54,374 @@ export type ParseTableToken<Token extends string, S extends DatabaseSchema> =
|
|
|
33
54
|
|
|
34
55
|
// Insert/update/delete target table
|
|
35
56
|
|
|
57
|
+
// The target scan walks the RAW normalized query (never comma-marked — same as
|
|
58
|
+
// the old `SplitCollectorTokens<N>` path) and STOPS at the token after the
|
|
59
|
+
// keyword: `insert into orders ...` resolves in two words instead of first
|
|
60
|
+
// splitting the whole query into a token array.
|
|
36
61
|
export type InsertTargetTable<N extends string, S extends DatabaseSchema> =
|
|
37
|
-
|
|
62
|
+
TableAfterScan<N, "into", S>;
|
|
38
63
|
|
|
39
64
|
export type UpdateTargetTable<N extends string, S extends DatabaseSchema> =
|
|
40
|
-
|
|
65
|
+
TableAfterScan<N, "update", S>;
|
|
41
66
|
|
|
42
67
|
export type DeleteTargetTable<N extends string, S extends DatabaseSchema> =
|
|
43
|
-
|
|
68
|
+
TableAfterScan<N, "from", S>;
|
|
44
69
|
|
|
45
70
|
// Collect tables by keyword
|
|
46
71
|
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
// `
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
// State registers (mirroring the old array walker exactly):
|
|
73
|
+
// - `InList` tracks whether we are inside a FROM-source list, so a TOP-LEVEL
|
|
74
|
+
// comma (preserved as a `CommaSep` token by `CollectorScanView`) introduces
|
|
75
|
+
// ANOTHER table source — the ANSI comma cross-join `from a, b`. The flag is
|
|
76
|
+
// turned on after a `from`/`join`/`into`/`update` source and off at the next
|
|
77
|
+
// clause keyword, so commas in the SELECT list / GROUP BY / ORDER BY / value
|
|
78
|
+
// tuples are ignored.
|
|
79
|
+
// - `InDelete` marks that we are inside a DELETE statement, where `USING` is a
|
|
80
|
+
// table-source clause (`DELETE FROM a USING b, c`) — collected like FROM/JOIN.
|
|
81
|
+
// `USING` in a SELECT (the JOIN ... USING (cols) join condition) is NOT a
|
|
82
|
+
// table source, so the branch is gated: outside a DELETE, `using` is skipped.
|
|
83
|
+
// - `Mode` is the armed-keyword state: "src" = saw from|join|into (next token is
|
|
84
|
+
// the source), "usingsrc" = saw DELETE-using (next token collected with NO
|
|
85
|
+
// keyword/lateral skip — the old branch collected unconditionally), "upd" =
|
|
86
|
+
// saw update, "del"/"delfrom" = DELETE prefix, "comma" = top-level comma in a
|
|
87
|
+
// source list (next token is the candidate), "commaeq" = comma candidate seen
|
|
88
|
+
// (held in `Pend`; an `=` after it marks an UPDATE SET-list separator, not a
|
|
89
|
+
// source — `UPDATE t SET a = (select ... from x), b = ...`), "dist" = saw
|
|
90
|
+
// `distinct` (a following `from` is the `IS [NOT] DISTINCT FROM` operator
|
|
91
|
+
// tail, not a FROM clause).
|
|
92
|
+
// The never-guard matters: a completed walk returns `never` for a query with no
|
|
93
|
+
// sources, and `[never]` matches ANY wrapped pattern — without the guard the
|
|
94
|
+
// `__c` infers fall back to their `string` constraints and the driver re-walks a
|
|
95
|
+
// wide string, returning `string` (which poisons every downstream qualifier
|
|
96
|
+
// match).
|
|
97
|
+
type CtDrive<R, S extends DatabaseSchema, C extends any[] = []> =
|
|
98
|
+
[R] extends [never]
|
|
99
|
+
? never
|
|
100
|
+
: [R] extends [{ __c: [infer V extends string, infer Acc extends string, infer IL extends boolean, infer ID extends boolean, infer Mode extends string, infer Pend extends string] }]
|
|
101
|
+
? C["length"] extends 19
|
|
102
|
+
? CtFinal<V, S, Acc, Mode, Pend>
|
|
103
|
+
: CtDrive<CtWalk<V, S, Acc, IL, ID, Mode, Pend>, S, [any, ...C]>
|
|
104
|
+
: R;
|
|
105
|
+
|
|
106
|
+
type CtWalk<
|
|
107
|
+
V extends string,
|
|
59
108
|
S extends DatabaseSchema,
|
|
60
|
-
Acc extends string
|
|
61
|
-
InList extends boolean
|
|
62
|
-
InDelete extends boolean
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
// `TokenizeTables`, leaving a leading SQL keyword (`select`/`values`)
|
|
76
|
-
// as the source token. That keyword is NOT a base table; collecting it
|
|
77
|
-
// fabricates a bogus `public.select`/`public.values` key that fails the
|
|
78
|
-
// existence check. A real (unquoted) table is never a SQL keyword, so
|
|
79
|
-
// skipping keyword sources here is safe; the source's `) AS alias` is
|
|
80
|
-
// handled leniently in qualified-ref validation.
|
|
81
|
-
: Next extends SqlKeyword
|
|
82
|
-
? CollectTables<Rest, S, Acc, true, InDelete>
|
|
83
|
-
: CollectTables<Rest, S, Acc | TableKeyFromToken<Next, S>, true, InDelete>
|
|
84
|
-
: T extends "update"
|
|
85
|
-
? Next extends "set"
|
|
86
|
-
? CollectTables<Rest, S, Acc, false, InDelete>
|
|
87
|
-
: CollectTables<Rest, S, Acc | TableKeyFromToken<Next, S>, true, InDelete>
|
|
88
|
-
: T extends "delete"
|
|
89
|
-
? Next extends "from"
|
|
90
|
-
? Rest extends [infer DelTable extends string, ...infer Rest2 extends string[]]
|
|
91
|
-
? CollectTables<Rest2, S, Acc | TableKeyFromToken<DelTable, S>, false, true>
|
|
92
|
-
: Acc
|
|
93
|
-
: CollectTables<[Next, ...Rest], S, Acc, false, true>
|
|
94
|
-
: T extends "using"
|
|
95
|
-
? InDelete extends true
|
|
96
|
-
? CollectTables<Rest, S, Acc | TableKeyFromToken<Next, S>, true, InDelete>
|
|
97
|
-
: CollectTables<[Next, ...Rest], S, Acc, InList, InDelete>
|
|
98
|
-
: T extends CommaSep
|
|
99
|
-
? InList extends true
|
|
100
|
-
// `UPDATE t SET a = (select ... from x), b = ...` — the
|
|
101
|
-
// subquery's parens are stripped by tokenization, so its
|
|
102
|
-
// `from x` leaves `InList` on and the TOP-LEVEL SET comma
|
|
103
|
-
// would collect the next SET column (`b`) as a table. A
|
|
104
|
-
// FROM-source name is never followed by `=`, so a comma
|
|
105
|
-
// whose candidate source is followed by `=` is a SET-list
|
|
106
|
-
// separator: skip it and leave source-list mode.
|
|
107
|
-
? Rest extends ["=", ...infer Rest2 extends string[]]
|
|
108
|
-
? CollectTables<Rest2, S, Acc, false, InDelete>
|
|
109
|
-
: CollectTables<Rest, S, Acc | TableKeyFromToken<Next, S>, true, InDelete>
|
|
110
|
-
: CollectTables<[Next, ...Rest], S, Acc, false, InDelete>
|
|
111
|
-
: T extends "as"
|
|
112
|
-
? CollectTables<[Next, ...Rest], S, Acc, InList, InDelete>
|
|
113
|
-
// `IS [NOT] DISTINCT FROM` is a comparison
|
|
114
|
-
// operator, not a FROM clause: the `from` after
|
|
115
|
-
// `distinct` must NOT be collected as a table
|
|
116
|
-
// source. Drop the operator `from` (process
|
|
117
|
-
// `Rest`) so its RHS isn't mistaken for a table.
|
|
118
|
-
: T extends "distinct"
|
|
119
|
-
? Next extends "from"
|
|
120
|
-
? CollectTables<Rest, S, Acc, false, InDelete>
|
|
121
|
-
: CollectTables<[Next, ...Rest], S, Acc, false, InDelete>
|
|
122
|
-
: T extends SqlKeyword
|
|
123
|
-
? CollectTables<[Next, ...Rest], S, Acc, false, InDelete>
|
|
124
|
-
: CollectTables<[Next, ...Rest], S, Acc, InList, InDelete>
|
|
125
|
-
: Acc;
|
|
109
|
+
Acc extends string,
|
|
110
|
+
InList extends boolean,
|
|
111
|
+
InDelete extends boolean,
|
|
112
|
+
Mode extends string = "",
|
|
113
|
+
Pend extends string = "",
|
|
114
|
+
Steps extends any[] = []
|
|
115
|
+
> = Steps["length"] extends 100
|
|
116
|
+
? { __c: [V, Acc, InList, InDelete, Mode, Pend] }
|
|
117
|
+
: V extends `${infer H} ${infer R}`
|
|
118
|
+
? CollectorToken<H> extends infer M extends string
|
|
119
|
+
? M extends ""
|
|
120
|
+
? CtWalk<R, S, Acc, InList, InDelete, Mode, Pend, [any, ...Steps]>
|
|
121
|
+
: CtTok<M, R, S, Acc, InList, InDelete, Mode, Pend, Steps>
|
|
122
|
+
: never
|
|
123
|
+
: CtFinal<V, S, Acc, Mode, Pend>;
|
|
126
124
|
|
|
127
|
-
|
|
125
|
+
type CtTok<
|
|
126
|
+
M extends string,
|
|
127
|
+
R extends string,
|
|
128
|
+
S extends DatabaseSchema,
|
|
129
|
+
Acc extends string,
|
|
130
|
+
InList extends boolean,
|
|
131
|
+
InDelete extends boolean,
|
|
132
|
+
Mode extends string,
|
|
133
|
+
Pend extends string,
|
|
134
|
+
Steps extends any[]
|
|
135
|
+
> = Mode extends ""
|
|
136
|
+
? CtNorm<M, R, S, Acc, InList, InDelete, Steps>
|
|
137
|
+
: Mode extends "src"
|
|
138
|
+
// `JOIN LATERAL (subquery|func(...)) alias` — `LATERAL` is a source
|
|
139
|
+
// modifier, not a relation. A parenthesised FROM/JOIN source — a
|
|
140
|
+
// subquery (`from (select ...)`) or VALUES list — has its `(` stripped
|
|
141
|
+
// by tokenization, leaving a leading SQL keyword as the source token;
|
|
142
|
+
// collecting it would fabricate a bogus `public.select`/`public.values`
|
|
143
|
+
// key. A real (unquoted) table is never a SQL keyword, so both skip.
|
|
144
|
+
? M extends "lateral" | SqlKeyword
|
|
145
|
+
? CtWalk<R, S, Acc, true, InDelete, "", "", [any, ...Steps]>
|
|
146
|
+
: CtWalk<R, S, Acc | TableKeyFromToken<M, S>, true, InDelete, "", "", [any, ...Steps]>
|
|
147
|
+
: Mode extends "usingsrc"
|
|
148
|
+
? CtWalk<R, S, Acc | TableKeyFromToken<M, S>, true, InDelete, "", "", [any, ...Steps]>
|
|
149
|
+
: Mode extends "upd"
|
|
150
|
+
? M extends "set"
|
|
151
|
+
? CtWalk<R, S, Acc, false, InDelete, "", "", [any, ...Steps]>
|
|
152
|
+
: CtWalk<R, S, Acc | TableKeyFromToken<M, S>, true, InDelete, "", "", [any, ...Steps]>
|
|
153
|
+
: Mode extends "del"
|
|
154
|
+
? M extends "from"
|
|
155
|
+
? CtWalk<R, S, Acc, false, true, "delfrom", "", [any, ...Steps]>
|
|
156
|
+
: CtNorm<M, R, S, Acc, false, true, Steps>
|
|
157
|
+
: Mode extends "delfrom"
|
|
158
|
+
? CtWalk<R, S, Acc | TableKeyFromToken<M, S>, false, true, "", "", [any, ...Steps]>
|
|
159
|
+
: Mode extends "comma"
|
|
160
|
+
? CtWalk<R, S, Acc, InList, InDelete, "commaeq", M, [any, ...Steps]>
|
|
161
|
+
: Mode extends "commaeq"
|
|
162
|
+
// A FROM-source name is never followed by `=`, so a
|
|
163
|
+
// comma whose candidate is followed by `=` is a
|
|
164
|
+
// SET-list separator: drop it and leave source-list
|
|
165
|
+
// mode. Otherwise collect the candidate and
|
|
166
|
+
// re-dispatch the current token in normal mode.
|
|
167
|
+
? M extends "="
|
|
168
|
+
? CtWalk<R, S, Acc, false, InDelete, "", "", [any, ...Steps]>
|
|
169
|
+
: CtNorm<M, R, S, Acc | TableKeyFromToken<Pend, S>, true, InDelete, Steps>
|
|
170
|
+
: // "dist": `IS [NOT] DISTINCT FROM` — the `from`
|
|
171
|
+
// after `distinct` is operator text; drop it so
|
|
172
|
+
// its RHS isn't mistaken for a table.
|
|
173
|
+
M extends "from"
|
|
174
|
+
? CtWalk<R, S, Acc, false, InDelete, "", "", [any, ...Steps]>
|
|
175
|
+
: CtNorm<M, R, S, Acc, false, InDelete, Steps>;
|
|
128
176
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
// aliased table source (`DELETE FROM a USING users u`); outside one it is left
|
|
133
|
-
// alone (the JOIN ... USING (cols) join condition is not a source).
|
|
134
|
-
export type CollectAliases<
|
|
135
|
-
Tokens extends string[],
|
|
177
|
+
type CtNorm<
|
|
178
|
+
M extends string,
|
|
179
|
+
R extends string,
|
|
136
180
|
S extends DatabaseSchema,
|
|
137
|
-
Acc extends string
|
|
138
|
-
InList extends boolean
|
|
139
|
-
InDelete extends boolean
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// its `(` stripped, leaving a leading SQL keyword token. It is not a
|
|
149
|
-
// base-table source, so skip it rather than register a garbage alias
|
|
150
|
-
// from the keyword + the next token.
|
|
151
|
-
: Next extends SqlKeyword
|
|
152
|
-
? CollectAliases<Rest, S, Acc, true, InDelete>
|
|
153
|
-
: ParseAliasSource<Next, Rest, S, Acc, InDelete>
|
|
154
|
-
: T extends "using"
|
|
181
|
+
Acc extends string,
|
|
182
|
+
InList extends boolean,
|
|
183
|
+
InDelete extends boolean,
|
|
184
|
+
Steps extends any[]
|
|
185
|
+
> = M extends "from" | "join" | "into"
|
|
186
|
+
? CtWalk<R, S, Acc, InList, InDelete, "src", "", [any, ...Steps]>
|
|
187
|
+
: M extends "update"
|
|
188
|
+
? CtWalk<R, S, Acc, InList, InDelete, "upd", "", [any, ...Steps]>
|
|
189
|
+
: M extends "delete"
|
|
190
|
+
? CtWalk<R, S, Acc, false, true, "del", "", [any, ...Steps]>
|
|
191
|
+
: M extends "using"
|
|
155
192
|
? InDelete extends true
|
|
156
|
-
?
|
|
157
|
-
:
|
|
158
|
-
:
|
|
193
|
+
? CtWalk<R, S, Acc, InList, InDelete, "usingsrc", "", [any, ...Steps]>
|
|
194
|
+
: CtWalk<R, S, Acc, InList, InDelete, "", "", [any, ...Steps]>
|
|
195
|
+
: M extends CommaSep
|
|
159
196
|
? InList extends true
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
?
|
|
166
|
-
:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
197
|
+
? CtWalk<R, S, Acc, InList, InDelete, "comma", "", [any, ...Steps]>
|
|
198
|
+
: CtWalk<R, S, Acc, false, InDelete, "", "", [any, ...Steps]>
|
|
199
|
+
: M extends "as"
|
|
200
|
+
? CtWalk<R, S, Acc, InList, InDelete, "", "", [any, ...Steps]>
|
|
201
|
+
: M extends "distinct"
|
|
202
|
+
? CtWalk<R, S, Acc, false, InDelete, "dist", "", [any, ...Steps]>
|
|
203
|
+
: M extends SqlKeyword
|
|
204
|
+
? CtWalk<R, S, Acc, false, InDelete, "", "", [any, ...Steps]>
|
|
205
|
+
: CtWalk<R, S, Acc, InList, InDelete, "", "", [any, ...Steps]>;
|
|
206
|
+
|
|
207
|
+
// Final word (or capped remainder) as one token. Modes that would consume it as
|
|
208
|
+
// their armed lookahead apply their collection effect; everything else has no
|
|
209
|
+
// effect at end of stream (a trailing keyword never had a `Next` to act on in
|
|
210
|
+
// the old pairwise array match either).
|
|
211
|
+
type CtFinal<
|
|
212
|
+
H extends string,
|
|
213
|
+
S extends DatabaseSchema,
|
|
214
|
+
Acc extends string,
|
|
215
|
+
Mode extends string,
|
|
216
|
+
Pend extends string
|
|
217
|
+
> = CollectorToken<H> extends infer M extends string
|
|
218
|
+
? M extends ""
|
|
219
|
+
? CtEnd<S, Acc, Mode, Pend>
|
|
220
|
+
: Mode extends "src"
|
|
221
|
+
? M extends "lateral" | SqlKeyword
|
|
222
|
+
? Acc
|
|
223
|
+
: Acc | TableKeyFromToken<M, S>
|
|
224
|
+
: Mode extends "usingsrc" | "delfrom" | "comma"
|
|
225
|
+
? Acc | TableKeyFromToken<M, S>
|
|
226
|
+
: Mode extends "upd"
|
|
227
|
+
? M extends "set"
|
|
228
|
+
? Acc
|
|
229
|
+
: Acc | TableKeyFromToken<M, S>
|
|
230
|
+
: Mode extends "commaeq"
|
|
231
|
+
? M extends "="
|
|
232
|
+
? Acc
|
|
233
|
+
: Acc | TableKeyFromToken<Pend, S>
|
|
234
|
+
: Acc
|
|
235
|
+
: never;
|
|
236
|
+
|
|
237
|
+
// Stream ended on a dropped word: only a pending comma candidate still owes its
|
|
238
|
+
// collection (the old `[..., comma, cand]` tail collected `cand`).
|
|
239
|
+
type CtEnd<S extends DatabaseSchema, Acc extends string, Mode extends string, Pend extends string> =
|
|
240
|
+
Mode extends "commaeq" ? Acc | TableKeyFromToken<Pend, S> : Acc;
|
|
241
|
+
|
|
242
|
+
// Collect aliases for tables in FROM/JOIN/UPDATE
|
|
243
|
+
|
|
244
|
+
// `InList`/`InDelete` mirror the tables walker. Additional registers: `TK` holds
|
|
245
|
+
// the table key of the source whose alias position we are in ("alias" mode = the
|
|
246
|
+
// old `ParseAliasSource` MaybeAlias position; "aliasname" = after its `as`), and
|
|
247
|
+
// `Pend` holds a comma candidate awaiting the `=` SET-list check.
|
|
248
|
+
type CaDrive<R, S extends DatabaseSchema, C extends any[] = []> =
|
|
249
|
+
[R] extends [never]
|
|
250
|
+
? never
|
|
251
|
+
: [R] extends [{ __c: [infer V extends string, infer Acc extends string, infer IL extends boolean, infer ID extends boolean, infer Mode extends string, infer TK extends string, infer Pend extends string] }]
|
|
252
|
+
? C["length"] extends 19
|
|
253
|
+
? CaFinal<V, S, Acc, ID, Mode, TK, Pend>
|
|
254
|
+
: CaDrive<CaWalk<V, S, Acc, IL, ID, Mode, TK, Pend>, S, [any, ...C]>
|
|
255
|
+
: R;
|
|
256
|
+
|
|
257
|
+
type CaWalk<
|
|
258
|
+
V extends string,
|
|
259
|
+
S extends DatabaseSchema,
|
|
260
|
+
Acc extends string,
|
|
261
|
+
InList extends boolean,
|
|
262
|
+
InDelete extends boolean,
|
|
263
|
+
Mode extends string = "",
|
|
264
|
+
TK extends string = never,
|
|
265
|
+
Pend extends string = "",
|
|
266
|
+
Steps extends any[] = []
|
|
267
|
+
> = Steps["length"] extends 100
|
|
268
|
+
? { __c: [V, Acc, InList, InDelete, Mode, TK, Pend] }
|
|
269
|
+
: V extends `${infer H} ${infer R}`
|
|
270
|
+
? CollectorToken<H> extends infer M extends string
|
|
271
|
+
? M extends ""
|
|
272
|
+
? CaWalk<R, S, Acc, InList, InDelete, Mode, TK, Pend, [any, ...Steps]>
|
|
273
|
+
: CaTok<M, R, S, Acc, InList, InDelete, Mode, TK, Pend, Steps>
|
|
274
|
+
: never
|
|
275
|
+
: CaFinal<V, S, Acc, InDelete, Mode, TK, Pend>;
|
|
276
|
+
|
|
277
|
+
type CaTok<
|
|
278
|
+
M extends string,
|
|
279
|
+
R extends string,
|
|
280
|
+
S extends DatabaseSchema,
|
|
281
|
+
Acc extends string,
|
|
282
|
+
InList extends boolean,
|
|
283
|
+
InDelete extends boolean,
|
|
284
|
+
Mode extends string,
|
|
285
|
+
TK extends string,
|
|
286
|
+
Pend extends string,
|
|
287
|
+
Steps extends any[]
|
|
288
|
+
> = Mode extends ""
|
|
289
|
+
? CaNorm<M, R, S, Acc, InList, InDelete, Steps>
|
|
290
|
+
: Mode extends "src"
|
|
291
|
+
// Mirror the tables walker: skip `lateral` and keyword sources (a
|
|
292
|
+
// parenthesised subquery/VALUES source must not register a garbage
|
|
293
|
+
// alias from the keyword + the next token).
|
|
294
|
+
? M extends "lateral" | SqlKeyword
|
|
295
|
+
? CaWalk<R, S, Acc, true, InDelete, "", never, "", [any, ...Steps]>
|
|
296
|
+
: CaEnterAlias<M, R, S, Acc, InDelete, Steps>
|
|
297
|
+
: Mode extends "usingsrc"
|
|
298
|
+
? CaEnterAlias<M, R, S, Acc, InDelete, Steps>
|
|
299
|
+
: Mode extends "alias"
|
|
300
|
+
? CaAliasTok<M, R, S, Acc, InDelete, TK, Steps>
|
|
301
|
+
: Mode extends "aliasname"
|
|
302
|
+
? CaWalk<R, S, Acc | AliasEntry<M, TK>, true, InDelete, "", never, "", [any, ...Steps]>
|
|
303
|
+
: Mode extends "comma"
|
|
304
|
+
? CaWalk<R, S, Acc, InList, InDelete, "commaeq", never, M, [any, ...Steps]>
|
|
305
|
+
: Mode extends "commaeq"
|
|
306
|
+
// Mirror the tables walker: a comma whose candidate is
|
|
307
|
+
// followed by `=` is an UPDATE SET-list separator, not
|
|
308
|
+
// another aliased FROM source.
|
|
309
|
+
? M extends "="
|
|
310
|
+
? CaWalk<R, S, Acc, false, InDelete, "", never, "", [any, ...Steps]>
|
|
311
|
+
: TableKeyFromToken<Pend, S> extends infer TK2 extends string
|
|
312
|
+
? CaAliasTok<M, R, S, Acc, InDelete, TK2, Steps>
|
|
313
|
+
: CaNorm<M, R, S, Acc, true, InDelete, Steps>
|
|
314
|
+
: // "dist": the `IS [NOT] DISTINCT FROM` operator
|
|
315
|
+
// `from` must not open an aliased source.
|
|
316
|
+
M extends "from"
|
|
317
|
+
? CaWalk<R, S, Acc, false, InDelete, "", never, "", [any, ...Steps]>
|
|
318
|
+
: CaNorm<M, R, S, Acc, false, InDelete, Steps>;
|
|
319
|
+
|
|
320
|
+
// Enter the alias position for source token `M` (the old `ParseAliasSource`
|
|
321
|
+
// head: resolve the table key, then judge the next token as MaybeAlias).
|
|
322
|
+
type CaEnterAlias<
|
|
323
|
+
M extends string,
|
|
324
|
+
R extends string,
|
|
325
|
+
S extends DatabaseSchema,
|
|
326
|
+
Acc extends string,
|
|
327
|
+
InDelete extends boolean,
|
|
328
|
+
Steps extends any[]
|
|
329
|
+
> = TableKeyFromToken<M, S> extends infer TK extends string
|
|
330
|
+
? CaWalk<R, S, Acc, true, InDelete, "alias", TK, "", [any, ...Steps]>
|
|
331
|
+
: CaWalk<R, S, Acc, true, InDelete, "", never, "", [any, ...Steps]>;
|
|
332
|
+
|
|
333
|
+
// The MaybeAlias judgment (old `ParseAliasSource` body): `as` arms the explicit
|
|
334
|
+
// alias name; an immediate comma is the next source (no alias); inside a DELETE
|
|
335
|
+
// a following `using` opens the next table source rather than naming this one;
|
|
336
|
+
// a bare candidate (non-keyword) is the alias; any other keyword re-dispatches
|
|
337
|
+
// in normal mode with `InList` on.
|
|
338
|
+
type CaAliasTok<
|
|
339
|
+
M extends string,
|
|
340
|
+
R extends string,
|
|
341
|
+
S extends DatabaseSchema,
|
|
342
|
+
Acc extends string,
|
|
343
|
+
InDelete extends boolean,
|
|
344
|
+
TK extends string,
|
|
345
|
+
Steps extends any[]
|
|
346
|
+
> = M extends "as"
|
|
347
|
+
? CaWalk<R, S, Acc, true, InDelete, "aliasname", TK, "", [any, ...Steps]>
|
|
348
|
+
: M extends CommaSep
|
|
349
|
+
? CaWalk<R, S, Acc, true, InDelete, "comma", never, "", [any, ...Steps]>
|
|
350
|
+
: InDelete extends true
|
|
351
|
+
? M extends "using"
|
|
352
|
+
? CaWalk<R, S, Acc, true, InDelete, "usingsrc", never, "", [any, ...Steps]>
|
|
353
|
+
: IsAliasCandidate<M> extends true
|
|
354
|
+
? CaWalk<R, S, Acc | AliasEntry<M, TK>, true, InDelete, "", never, "", [any, ...Steps]>
|
|
355
|
+
: CaNorm<M, R, S, Acc, true, InDelete, Steps>
|
|
356
|
+
: IsAliasCandidate<M> extends true
|
|
357
|
+
? CaWalk<R, S, Acc | AliasEntry<M, TK>, true, InDelete, "", never, "", [any, ...Steps]>
|
|
358
|
+
: CaNorm<M, R, S, Acc, true, InDelete, Steps>;
|
|
180
359
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
// An immediate `,` after the table (no alias) is handed back to `CollectAliases`
|
|
185
|
-
// rather than mistaken for an alias.
|
|
186
|
-
export type ParseAliasSource<
|
|
187
|
-
Next extends string,
|
|
188
|
-
Rest extends string[],
|
|
360
|
+
type CaNorm<
|
|
361
|
+
M extends string,
|
|
362
|
+
R extends string,
|
|
189
363
|
S extends DatabaseSchema,
|
|
190
364
|
Acc extends string,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
365
|
+
InList extends boolean,
|
|
366
|
+
InDelete extends boolean,
|
|
367
|
+
Steps extends any[]
|
|
368
|
+
> = M extends "from" | "join" | "update"
|
|
369
|
+
? CaWalk<R, S, Acc, InList, InDelete, "src", never, "", [any, ...Steps]>
|
|
370
|
+
: M extends "using"
|
|
371
|
+
? InDelete extends true
|
|
372
|
+
? CaWalk<R, S, Acc, InList, InDelete, "usingsrc", never, "", [any, ...Steps]>
|
|
373
|
+
: CaWalk<R, S, Acc, InList, InDelete, "", never, "", [any, ...Steps]>
|
|
374
|
+
: M extends CommaSep
|
|
375
|
+
? InList extends true
|
|
376
|
+
? CaWalk<R, S, Acc, InList, InDelete, "comma", never, "", [any, ...Steps]>
|
|
377
|
+
: CaWalk<R, S, Acc, false, InDelete, "", never, "", [any, ...Steps]>
|
|
378
|
+
: M extends "as"
|
|
379
|
+
? CaWalk<R, S, Acc, InList, InDelete, "", never, "", [any, ...Steps]>
|
|
380
|
+
: M extends "distinct"
|
|
381
|
+
? CaWalk<R, S, Acc, false, InDelete, "dist", never, "", [any, ...Steps]>
|
|
382
|
+
: M extends SqlKeyword
|
|
383
|
+
? CaWalk<R, S, Acc, false, InDelete, "", never, "", [any, ...Steps]>
|
|
384
|
+
: CaWalk<R, S, Acc, InList, InDelete, "", never, "", [any, ...Steps]>;
|
|
385
|
+
|
|
386
|
+
// Final word as one token. Only the alias-name positions still owe a recording;
|
|
387
|
+
// a bare source at end of stream has no alias to record (old `ParseAliasSource`
|
|
388
|
+
// with an empty Rest returned `Acc`).
|
|
389
|
+
type CaFinal<
|
|
390
|
+
H extends string,
|
|
391
|
+
S extends DatabaseSchema,
|
|
392
|
+
Acc extends string,
|
|
393
|
+
InDelete extends boolean,
|
|
394
|
+
Mode extends string,
|
|
395
|
+
TK extends string,
|
|
396
|
+
Pend extends string
|
|
397
|
+
> = CollectorToken<H> extends infer M extends string
|
|
398
|
+
? M extends ""
|
|
399
|
+
? Acc
|
|
400
|
+
: Mode extends "alias"
|
|
401
|
+
? CaAliasFinal<M, Acc, InDelete, TK>
|
|
402
|
+
: Mode extends "aliasname"
|
|
403
|
+
? Acc | AliasEntry<M, TK>
|
|
404
|
+
: Mode extends "commaeq"
|
|
405
|
+
? M extends "="
|
|
406
|
+
? Acc
|
|
407
|
+
: TableKeyFromToken<Pend, S> extends infer TK2 extends string
|
|
408
|
+
? CaAliasFinal<M, Acc, InDelete, TK2>
|
|
409
|
+
: Acc
|
|
198
410
|
: Acc
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
: Acc
|
|
214
|
-
: CollectAliases<Rest, S, Acc, true, InDelete>;
|
|
411
|
+
: never;
|
|
412
|
+
|
|
413
|
+
type CaAliasFinal<M extends string, Acc extends string, InDelete extends boolean, TK extends string> =
|
|
414
|
+
M extends "as" | CommaSep
|
|
415
|
+
? Acc
|
|
416
|
+
: InDelete extends true
|
|
417
|
+
? M extends "using"
|
|
418
|
+
? Acc
|
|
419
|
+
: IsAliasCandidate<M> extends true
|
|
420
|
+
? Acc | AliasEntry<M, TK>
|
|
421
|
+
: Acc
|
|
422
|
+
: IsAliasCandidate<M> extends true
|
|
423
|
+
? Acc | AliasEntry<M, TK>
|
|
424
|
+
: Acc;
|
|
215
425
|
|
|
216
426
|
// Outer-join nullability
|
|
217
427
|
//
|
|
@@ -228,69 +438,191 @@ export type ParseAliasSource<
|
|
|
228
438
|
// (Limitation: an UNqualified projected column from an outer-joined relation is
|
|
229
439
|
// not nullablized, since it carries no qualifier to match.)
|
|
230
440
|
export type NullableRelations<N extends string, S extends DatabaseSchema> =
|
|
231
|
-
|
|
441
|
+
CnDrive<CnWalk<CollectorScanView<N>, "none", never, never>>;
|
|
232
442
|
|
|
233
443
|
// `Mod` is the pending join modifier ("left"/"right"/"full"/"none"); `Left` is
|
|
234
444
|
// the set of qualifiers accumulated so far (the left side of any later join);
|
|
235
445
|
// `Acc` is the nullable-qualifier accumulator. `outer` is noise (keeps `Mod`);
|
|
236
446
|
// `inner`/`cross` reset `Mod` to "none". On a `join <table>`: LEFT adds the
|
|
237
447
|
// joined relation; RIGHT adds the accumulated left side; FULL adds both.
|
|
238
|
-
|
|
239
|
-
|
|
448
|
+
//
|
|
449
|
+
// Modes: "nsrc-f"/"nsrc-j" = saw from|into / join (next token is the relation,
|
|
450
|
+
// stored in `Tbl`); "qual-f"/"qual-j" = peeking at the token after the relation
|
|
451
|
+
// to pick its qualifier (alias if a candidate follows, else the table name —
|
|
452
|
+
// the old `SourceQualifier` lookahead, which did NOT consume those tokens: the
|
|
453
|
+
// peeked token is re-dispatched in normal mode after the qualifier applies);
|
|
454
|
+
// "qualas-f"/"qualas-j" = the peek saw `as`, the next token is the alias name.
|
|
455
|
+
type CnDrive<R, C extends any[] = []> =
|
|
456
|
+
[R] extends [never]
|
|
457
|
+
? never
|
|
458
|
+
: [R] extends [{ __c: [infer V extends string, infer Mod extends string, infer Left extends string, infer Acc extends string, infer Mode extends string, infer Tbl extends string] }]
|
|
459
|
+
? C["length"] extends 19
|
|
460
|
+
? CnFinal<V, Mod, Left, Acc, Mode, Tbl>
|
|
461
|
+
: CnDrive<CnWalk<V, Mod, Left, Acc, Mode, Tbl>, [any, ...C]>
|
|
462
|
+
: R;
|
|
463
|
+
|
|
464
|
+
type CnWalk<
|
|
465
|
+
V extends string,
|
|
240
466
|
Mod extends string,
|
|
241
467
|
Left extends string,
|
|
242
|
-
Acc extends string
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
468
|
+
Acc extends string,
|
|
469
|
+
Mode extends string = "",
|
|
470
|
+
Tbl extends string = "",
|
|
471
|
+
Steps extends any[] = []
|
|
472
|
+
> = Steps["length"] extends 100
|
|
473
|
+
? { __c: [V, Mod, Left, Acc, Mode, Tbl] }
|
|
474
|
+
: V extends `${infer H} ${infer R}`
|
|
475
|
+
? CollectorToken<H> extends infer M extends string
|
|
476
|
+
? M extends ""
|
|
477
|
+
? CnWalk<R, Mod, Left, Acc, Mode, Tbl, [any, ...Steps]>
|
|
478
|
+
: CnTok<M, R, Mod, Left, Acc, Mode, Tbl, Steps>
|
|
479
|
+
: never
|
|
480
|
+
: CnFinal<V, Mod, Left, Acc, Mode, Tbl>;
|
|
481
|
+
|
|
482
|
+
type CnTok<
|
|
483
|
+
M extends string,
|
|
484
|
+
R extends string,
|
|
485
|
+
Mod extends string,
|
|
486
|
+
Left extends string,
|
|
487
|
+
Acc extends string,
|
|
488
|
+
Mode extends string,
|
|
489
|
+
Tbl extends string,
|
|
490
|
+
Steps extends any[]
|
|
491
|
+
> = Mode extends ""
|
|
492
|
+
? CnNorm<M, R, Mod, Left, Acc, Steps>
|
|
493
|
+
: Mode extends "nsrc-f"
|
|
494
|
+
? CnWalk<R, Mod, Left, Acc, "qual-f", M, [any, ...Steps]>
|
|
495
|
+
: Mode extends "nsrc-j"
|
|
496
|
+
? CnWalk<R, Mod, Left, Acc, "qual-j", M, [any, ...Steps]>
|
|
497
|
+
: Mode extends "qual-f"
|
|
498
|
+
? M extends "as"
|
|
499
|
+
? CnWalk<R, Mod, Left, Acc, "qualas-f", Tbl, [any, ...Steps]>
|
|
500
|
+
: CnQualPick<M, Tbl> extends infer Q extends string
|
|
501
|
+
? CnNorm<M, R, "none", Left | Q, Acc, Steps>
|
|
502
|
+
: never
|
|
503
|
+
: Mode extends "qual-j"
|
|
504
|
+
? M extends "as"
|
|
505
|
+
? CnWalk<R, Mod, Left, Acc, "qualas-j", Tbl, [any, ...Steps]>
|
|
506
|
+
: CnQualPick<M, Tbl> extends infer Q extends string
|
|
507
|
+
? CnNorm<M, R, "none", Left | Q, CnJoinAcc<Mod, Left, Acc, Q>, Steps>
|
|
508
|
+
: never
|
|
509
|
+
: Mode extends "qualas-f"
|
|
510
|
+
? CleanIdent<M> extends infer Q extends string
|
|
511
|
+
? CnNorm<M, R, "none", Left | Q, Acc, Steps>
|
|
512
|
+
: never
|
|
513
|
+
: // "qualas-j"
|
|
514
|
+
CleanIdent<M> extends infer Q extends string
|
|
515
|
+
? CnNorm<M, R, "none", Left | Q, CnJoinAcc<Mod, Left, Acc, Q>, Steps>
|
|
516
|
+
: never;
|
|
273
517
|
|
|
274
518
|
// The qualifier a relation is referenced by in projections: its alias when one
|
|
275
|
-
// is present
|
|
276
|
-
//
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
519
|
+
// is present, else the (cleaned) table name. A following keyword (`on`,
|
|
520
|
+
// `where`, another `join`, ...) is not an alias.
|
|
521
|
+
type CnQualPick<M extends string, Tbl extends string> =
|
|
522
|
+
IsAliasCandidate<M> extends true ? CleanIdent<M> : CleanIdent<Tbl>;
|
|
523
|
+
|
|
524
|
+
// `Acc | Left` for RIGHT uses the PRE-join `Left` (the joined relation itself
|
|
525
|
+
// is not nullablized by its own RIGHT join), exactly like the old arms.
|
|
526
|
+
type CnJoinAcc<Mod extends string, Left extends string, Acc extends string, Q extends string> =
|
|
527
|
+
Mod extends "left"
|
|
528
|
+
? Acc | Q
|
|
529
|
+
: Mod extends "right"
|
|
530
|
+
? Acc | Left
|
|
531
|
+
: Mod extends "full"
|
|
532
|
+
? Acc | Left | Q
|
|
533
|
+
: Acc;
|
|
534
|
+
|
|
535
|
+
type CnNorm<
|
|
536
|
+
M extends string,
|
|
537
|
+
R extends string,
|
|
538
|
+
Mod extends string,
|
|
539
|
+
Left extends string,
|
|
540
|
+
Acc extends string,
|
|
541
|
+
Steps extends any[]
|
|
542
|
+
> = M extends "left" | "right" | "full"
|
|
543
|
+
? CnWalk<R, M, Left, Acc, "", "", [any, ...Steps]>
|
|
544
|
+
: M extends "inner" | "cross"
|
|
545
|
+
? CnWalk<R, "none", Left, Acc, "", "", [any, ...Steps]>
|
|
546
|
+
: M extends "outer"
|
|
547
|
+
? CnWalk<R, Mod, Left, Acc, "", "", [any, ...Steps]>
|
|
548
|
+
: M extends "from" | "into"
|
|
549
|
+
? CnWalk<R, Mod, Left, Acc, "nsrc-f", "", [any, ...Steps]>
|
|
550
|
+
: M extends "join"
|
|
551
|
+
? CnWalk<R, Mod, Left, Acc, "nsrc-j", "", [any, ...Steps]>
|
|
552
|
+
: CnWalk<R, Mod, Left, Acc, "", "", [any, ...Steps]>;
|
|
553
|
+
|
|
554
|
+
// Final word as one token: a join relation (or its qualifier peek) at end of
|
|
555
|
+
// stream still applies its nullability effect; from-kind effects only update
|
|
556
|
+
// `Left`, which is dead at end of stream.
|
|
557
|
+
type CnFinal<
|
|
558
|
+
H extends string,
|
|
559
|
+
Mod extends string,
|
|
560
|
+
Left extends string,
|
|
561
|
+
Acc extends string,
|
|
562
|
+
Mode extends string,
|
|
563
|
+
Tbl extends string
|
|
564
|
+
> = CollectorToken<H> extends infer M extends string
|
|
565
|
+
? M extends ""
|
|
566
|
+
? CnEnd<Mod, Left, Acc, Mode, Tbl>
|
|
567
|
+
: Mode extends "nsrc-j"
|
|
568
|
+
? CnJoinAcc<Mod, Left, Acc, CleanIdent<M>>
|
|
569
|
+
: Mode extends "qual-j"
|
|
570
|
+
? M extends "as"
|
|
571
|
+
? CnJoinAcc<Mod, Left, Acc, CleanIdent<Tbl>>
|
|
572
|
+
: CnJoinAcc<Mod, Left, Acc, CnQualPick<M, Tbl>>
|
|
573
|
+
: Mode extends "qualas-j"
|
|
574
|
+
? CnJoinAcc<Mod, Left, Acc, CleanIdent<M>>
|
|
575
|
+
: Acc
|
|
576
|
+
: never;
|
|
577
|
+
|
|
578
|
+
type CnEnd<Mod extends string, Left extends string, Acc extends string, Mode extends string, Tbl extends string> =
|
|
579
|
+
Mode extends "qual-j" | "qualas-j"
|
|
580
|
+
? CnJoinAcc<Mod, Left, Acc, CleanIdent<Tbl>>
|
|
581
|
+
: Acc;
|
|
286
582
|
|
|
287
583
|
// Table lookup after a keyword
|
|
288
584
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
585
|
+
// Early-terminating word scan: resolves the token after the FIRST `Keyword`
|
|
586
|
+
// token and stops — it never walks the rest of the query.
|
|
587
|
+
type TableAfterScan<V extends string, Keyword extends string, S extends DatabaseSchema> =
|
|
588
|
+
TaDrive<TaWalk<V, Keyword, S>, Keyword, S>;
|
|
589
|
+
|
|
590
|
+
type TaDrive<R, Keyword extends string, S extends DatabaseSchema, C extends any[] = []> =
|
|
591
|
+
[R] extends [never]
|
|
592
|
+
? never
|
|
593
|
+
: [R] extends [{ __c: [infer V extends string, infer Found extends boolean] }]
|
|
594
|
+
? C["length"] extends 19
|
|
595
|
+
? TaFinal<V, S, Found>
|
|
596
|
+
: TaDrive<TaWalk<V, Keyword, S, Found>, Keyword, S, [any, ...C]>
|
|
597
|
+
: R;
|
|
598
|
+
|
|
599
|
+
type TaWalk<
|
|
600
|
+
V extends string,
|
|
601
|
+
Keyword extends string,
|
|
602
|
+
S extends DatabaseSchema,
|
|
603
|
+
Found extends boolean = false,
|
|
604
|
+
Steps extends any[] = []
|
|
605
|
+
> = Steps["length"] extends 100
|
|
606
|
+
? { __c: [V, Found] }
|
|
607
|
+
: V extends `${infer H} ${infer R}`
|
|
608
|
+
? CollectorToken<H> extends infer M extends string
|
|
609
|
+
? M extends ""
|
|
610
|
+
? TaWalk<R, Keyword, S, Found, [any, ...Steps]>
|
|
611
|
+
: Found extends true
|
|
612
|
+
? TableKeyFromToken<M, S>
|
|
613
|
+
: M extends Keyword
|
|
614
|
+
? TaWalk<R, Keyword, S, true, [any, ...Steps]>
|
|
615
|
+
: TaWalk<R, Keyword, S, false, [any, ...Steps]>
|
|
616
|
+
: never
|
|
617
|
+
: TaFinal<V, S, Found>;
|
|
618
|
+
|
|
619
|
+
type TaFinal<H extends string, S extends DatabaseSchema, Found extends boolean> =
|
|
620
|
+
Found extends true
|
|
621
|
+
? CollectorToken<H> extends infer M extends string
|
|
622
|
+
? M extends ""
|
|
623
|
+
? never
|
|
624
|
+
: TableKeyFromToken<M, S>
|
|
625
|
+
: never
|
|
294
626
|
: never;
|
|
295
627
|
|
|
296
628
|
// Aliases
|