@typed-sql/postgres 2.0.0-rc.1 → 2.1.0-rc.1

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 (116) hide show
  1. package/CHANGELOG.md +201 -0
  2. package/README.md +17 -0
  3. package/dist/packages/postgres/src/bulk.d.ts.map +1 -1
  4. package/dist/packages/postgres/src/bulk.js +1 -1
  5. package/dist/packages/postgres/src/bulk.js.map +1 -1
  6. package/dist/packages/postgres/src/capabilities.d.ts +19 -0
  7. package/dist/packages/postgres/src/capabilities.d.ts.map +1 -0
  8. package/dist/packages/postgres/src/capabilities.js +120 -0
  9. package/dist/packages/postgres/src/capabilities.js.map +1 -0
  10. package/dist/packages/postgres/src/catalog/generated/14.d.ts +4 -0
  11. package/dist/packages/postgres/src/catalog/generated/14.d.ts.map +1 -0
  12. package/dist/packages/postgres/src/catalog/generated/14.js +2018 -0
  13. package/dist/packages/postgres/src/catalog/generated/14.js.map +1 -0
  14. package/dist/packages/postgres/src/catalog/generated/15.d.ts +4 -0
  15. package/dist/packages/postgres/src/catalog/generated/15.d.ts.map +1 -0
  16. package/dist/packages/postgres/src/catalog/generated/15.js +2012 -0
  17. package/dist/packages/postgres/src/catalog/generated/15.js.map +1 -0
  18. package/dist/packages/postgres/src/catalog/generated/16.d.ts +4 -0
  19. package/dist/packages/postgres/src/catalog/generated/16.d.ts.map +1 -0
  20. package/dist/packages/postgres/src/catalog/generated/16.js +2012 -0
  21. package/dist/packages/postgres/src/catalog/generated/16.js.map +1 -0
  22. package/dist/packages/postgres/src/catalog/generated/17.d.ts +4 -0
  23. package/dist/packages/postgres/src/catalog/generated/17.d.ts.map +1 -0
  24. package/dist/packages/postgres/src/catalog/generated/17.js +2012 -0
  25. package/dist/packages/postgres/src/catalog/generated/17.js.map +1 -0
  26. package/dist/packages/postgres/src/catalog/generated/18.d.ts +4 -0
  27. package/dist/packages/postgres/src/catalog/generated/18.d.ts.map +1 -0
  28. package/dist/packages/postgres/src/catalog/generated/18.js +2048 -0
  29. package/dist/packages/postgres/src/catalog/generated/18.js.map +1 -0
  30. package/dist/packages/postgres/src/catalog/generated/19.d.ts +4 -0
  31. package/dist/packages/postgres/src/catalog/generated/19.d.ts.map +1 -0
  32. package/dist/packages/postgres/src/catalog/generated/19.js +2048 -0
  33. package/dist/packages/postgres/src/catalog/generated/19.js.map +1 -0
  34. package/dist/packages/postgres/src/catalog/index.d.ts +14 -0
  35. package/dist/packages/postgres/src/catalog/index.d.ts.map +1 -0
  36. package/dist/packages/postgres/src/catalog/index.js +86 -0
  37. package/dist/packages/postgres/src/catalog/index.js.map +1 -0
  38. package/dist/packages/postgres/src/catalog/types.d.ts +46 -0
  39. package/dist/packages/postgres/src/catalog/types.d.ts.map +1 -0
  40. package/dist/packages/postgres/src/catalog/types.js +2 -0
  41. package/dist/packages/postgres/src/catalog/types.js.map +1 -0
  42. package/dist/packages/postgres/src/expression-evidence.d.ts +11 -0
  43. package/dist/packages/postgres/src/expression-evidence.d.ts.map +1 -0
  44. package/dist/packages/postgres/src/expression-evidence.js +33 -0
  45. package/dist/packages/postgres/src/expression-evidence.js.map +1 -0
  46. package/dist/packages/postgres/src/extensions.d.ts +61 -0
  47. package/dist/packages/postgres/src/extensions.d.ts.map +1 -0
  48. package/dist/packages/postgres/src/extensions.js +311 -0
  49. package/dist/packages/postgres/src/extensions.js.map +1 -0
  50. package/dist/packages/postgres/src/index.d.ts +13 -0
  51. package/dist/packages/postgres/src/index.d.ts.map +1 -1
  52. package/dist/packages/postgres/src/index.js +51 -17
  53. package/dist/packages/postgres/src/index.js.map +1 -1
  54. package/dist/packages/postgres/src/parser/index.d.ts +8 -0
  55. package/dist/packages/postgres/src/parser/index.d.ts.map +1 -0
  56. package/dist/packages/postgres/src/parser/index.js +4 -0
  57. package/dist/packages/postgres/src/parser/index.js.map +1 -0
  58. package/dist/packages/postgres/src/parser/parser.d.ts +14 -0
  59. package/dist/packages/postgres/src/parser/parser.d.ts.map +1 -0
  60. package/dist/packages/postgres/src/parser/parser.js +2683 -0
  61. package/dist/packages/postgres/src/parser/parser.js.map +1 -0
  62. package/dist/packages/postgres/src/parser/tokenizer.d.ts +15 -0
  63. package/dist/packages/postgres/src/parser/tokenizer.d.ts.map +1 -0
  64. package/dist/packages/postgres/src/parser/tokenizer.js +470 -0
  65. package/dist/packages/postgres/src/parser/tokenizer.js.map +1 -0
  66. package/dist/packages/postgres/src/parser/types.d.ts +652 -0
  67. package/dist/packages/postgres/src/parser/types.d.ts.map +1 -0
  68. package/dist/packages/postgres/src/parser/types.js +9 -0
  69. package/dist/packages/postgres/src/parser/types.js.map +1 -0
  70. package/dist/packages/postgres/src/parser/walk.d.ts +13 -0
  71. package/dist/packages/postgres/src/parser/walk.d.ts.map +1 -0
  72. package/dist/packages/postgres/src/parser/walk.js +374 -0
  73. package/dist/packages/postgres/src/parser/walk.js.map +1 -0
  74. package/dist/packages/postgres/src/pg.d.ts +35 -4
  75. package/dist/packages/postgres/src/pg.d.ts.map +1 -1
  76. package/dist/packages/postgres/src/pg.js +355 -40
  77. package/dist/packages/postgres/src/pg.js.map +1 -1
  78. package/dist/packages/postgres/src/prepared.d.ts +5 -3
  79. package/dist/packages/postgres/src/prepared.d.ts.map +1 -1
  80. package/dist/packages/postgres/src/prepared.js +23 -15
  81. package/dist/packages/postgres/src/prepared.js.map +1 -1
  82. package/dist/packages/postgres/src/provider.d.ts +149 -11
  83. package/dist/packages/postgres/src/provider.d.ts.map +1 -1
  84. package/dist/packages/postgres/src/provider.js +652 -42
  85. package/dist/packages/postgres/src/provider.js.map +1 -1
  86. package/dist/packages/postgres/src/resolver.d.ts +1 -1
  87. package/dist/packages/postgres/src/resolver.d.ts.map +1 -1
  88. package/dist/packages/postgres/src/resolver.js +2767 -203
  89. package/dist/packages/postgres/src/resolver.js.map +1 -1
  90. package/dist/packages/postgres/src/routing.d.ts.map +1 -1
  91. package/dist/packages/postgres/src/routing.js +1 -1
  92. package/dist/packages/postgres/src/routing.js.map +1 -1
  93. package/dist/packages/postgres/src/runtime-compatibility.d.ts +14 -0
  94. package/dist/packages/postgres/src/runtime-compatibility.d.ts.map +1 -0
  95. package/dist/packages/postgres/src/runtime-compatibility.js +63 -0
  96. package/dist/packages/postgres/src/runtime-compatibility.js.map +1 -0
  97. package/dist/packages/postgres/src/runtime.d.ts +10 -1
  98. package/dist/packages/postgres/src/runtime.d.ts.map +1 -1
  99. package/dist/packages/postgres/src/runtime.js +50 -2
  100. package/dist/packages/postgres/src/runtime.js.map +1 -1
  101. package/dist/packages/postgres/src/semantics.d.ts +1 -1
  102. package/dist/packages/postgres/src/semantics.d.ts.map +1 -1
  103. package/dist/packages/postgres/src/semantics.js +19 -6
  104. package/dist/packages/postgres/src/semantics.js.map +1 -1
  105. package/dist/packages/postgres/src/support.d.ts +29 -0
  106. package/dist/packages/postgres/src/support.d.ts.map +1 -0
  107. package/dist/packages/postgres/src/support.js +45 -0
  108. package/dist/packages/postgres/src/support.js.map +1 -0
  109. package/dist/packages/postgres/src/type-policy.d.ts.map +1 -1
  110. package/dist/packages/postgres/src/type-policy.js +34 -43
  111. package/dist/packages/postgres/src/type-policy.js.map +1 -1
  112. package/dist/packages/postgres/src/type-resolution.d.ts +33 -0
  113. package/dist/packages/postgres/src/type-resolution.d.ts.map +1 -0
  114. package/dist/packages/postgres/src/type-resolution.js +906 -0
  115. package/dist/packages/postgres/src/type-resolution.js.map +1 -0
  116. package/package.json +7 -4
@@ -0,0 +1,2683 @@
1
+ import { SqlToolkitError, TokenCursor } from "@typed-sql/ast/toolkit";
2
+ import { SqlTokenizeError, tokenize } from "./tokenizer.js";
3
+ import { mergeRanges, } from "./types.js";
4
+ export const DEFAULT_MAX_PARSE_DEPTH = 128;
5
+ export class SqlParseError extends Error {
6
+ code;
7
+ range;
8
+ constructor(message, range, code = "TSQ001") {
9
+ super(message);
10
+ this.name = "SqlParseError";
11
+ this.code = code;
12
+ this.range = range;
13
+ }
14
+ }
15
+ const precedence = new Map([
16
+ ["OR", 1],
17
+ ["AND", 2],
18
+ ["=", 3],
19
+ ["!=", 3],
20
+ ["<>", 3],
21
+ ["<", 3],
22
+ ["<=", 3],
23
+ [">", 3],
24
+ [">=", 3],
25
+ ["IS", 3],
26
+ ["LIKE", 3],
27
+ ["ILIKE", 3],
28
+ ["SIMILAR TO", 3],
29
+ ["~", 3],
30
+ ["~*", 3],
31
+ ["!~", 3],
32
+ ["!~*", 3],
33
+ ["@>", 3],
34
+ ["<@", 3],
35
+ ["?", 3],
36
+ ["?|", 3],
37
+ ["?&", 3],
38
+ ["&&", 3],
39
+ ["<<", 3],
40
+ ["<<=", 3],
41
+ [">>", 3],
42
+ [">>=", 3],
43
+ ["&<", 3],
44
+ ["&>", 3],
45
+ ["-\u007c-", 3],
46
+ ["@?", 3],
47
+ ["@@", 3],
48
+ ["^@", 3],
49
+ ["<<|", 3],
50
+ ["|>>", 3],
51
+ ["&<|", 3],
52
+ ["|&>", 3],
53
+ ["<^", 3],
54
+ [">^", 3],
55
+ ["?#", 3],
56
+ ["?-", 3],
57
+ ["?|", 3],
58
+ ["?-|", 3],
59
+ ["?||", 3],
60
+ ["~=", 3],
61
+ ["<->", 4],
62
+ ["##", 4],
63
+ ["||", 4],
64
+ ["&", 4],
65
+ ["|", 4],
66
+ ["#", 4],
67
+ ["->", 4],
68
+ ["->>", 4],
69
+ ["#>", 4],
70
+ ["#>>", 4],
71
+ ["#-", 4],
72
+ ["+", 5],
73
+ ["-", 5],
74
+ ["*", 6],
75
+ ["/", 6],
76
+ ["%", 6],
77
+ ["^", 7],
78
+ ]);
79
+ const typeContinuationWords = new Set([
80
+ "BIT",
81
+ "CHARACTER",
82
+ "DOUBLE",
83
+ "INTERVAL",
84
+ "PRECISION",
85
+ "TIME",
86
+ "TIMESTAMP",
87
+ "VARYING",
88
+ "WITH",
89
+ "WITHOUT",
90
+ "ZONE",
91
+ ]);
92
+ const intervalFields = new Set(["YEAR", "MONTH", "DAY", "HOUR", "MINUTE", "SECOND"]);
93
+ const intervalFieldRanges = new Map([
94
+ ["YEAR", new Set(["MONTH"])],
95
+ ["DAY", new Set(["HOUR", "MINUTE", "SECOND"])],
96
+ ["HOUR", new Set(["MINUTE", "SECOND"])],
97
+ ["MINUTE", new Set(["SECOND"])],
98
+ ]);
99
+ const simpleTypedLiteralTypes = new Set(["JSON", "JSONB", "JSONPATH"]);
100
+ class Parser {
101
+ #source;
102
+ #cursor;
103
+ #syntax = "postgres";
104
+ #stopSelectListBeforeJsonFormat = false;
105
+ constructor(source, options) {
106
+ this.#source = source;
107
+ this.#cursor = new TokenCursor(tokenize(source, options), {
108
+ maxDepth: options.maxDepth ?? DEFAULT_MAX_PARSE_DEPTH,
109
+ });
110
+ }
111
+ parse() {
112
+ const statement = this.#parseStatement();
113
+ this.#matchPunctuation(";");
114
+ this.#expect("eof", "end of query");
115
+ return statement;
116
+ }
117
+ #parseStatement() {
118
+ return this.#nested(() => {
119
+ const withClause = this.#current().value === "WITH" ? this.#parseWithClause() : undefined;
120
+ if (this.#current().value === "SELECT")
121
+ return this.#parseSelect(withClause);
122
+ if (withClause === undefined && this.#current().value === "(") {
123
+ const statement = this.#parseParenthesizedSelect();
124
+ return this.#parseSelectTail(this.#parseCompoundExpression(statement, 0));
125
+ }
126
+ if (this.#current().value === "INSERT")
127
+ return this.#parseInsert(withClause);
128
+ if (this.#current().value === "UPDATE")
129
+ return this.#parseUpdate(withClause);
130
+ if (this.#current().value === "DELETE")
131
+ return this.#parseDelete(withClause);
132
+ if (this.#current().value === "MERGE")
133
+ return this.#parseMerge(withClause);
134
+ throw this.#error(`Expected SELECT, INSERT, UPDATE, DELETE, or MERGE, found ${this.#current().text || "end of query"}`, this.#current().range);
135
+ });
136
+ }
137
+ #parseWithClause() {
138
+ const start = this.#expectKeyword("WITH").range;
139
+ const recursive = this.#matchKeyword("RECURSIVE");
140
+ const queries = [];
141
+ do {
142
+ const name = this.#parseIdentifier();
143
+ const columns = [];
144
+ if (this.#matchPunctuation("(")) {
145
+ if (!this.#matchPunctuation(")")) {
146
+ do
147
+ columns.push(this.#parseIdentifier());
148
+ while (this.#matchPunctuation(","));
149
+ this.#expectPunctuation(")");
150
+ }
151
+ }
152
+ this.#expectKeyword("AS");
153
+ let materialization;
154
+ if (this.#matchKeyword("NOT")) {
155
+ this.#expectKeyword("MATERIALIZED");
156
+ materialization = "not-materialized";
157
+ }
158
+ else if (this.#matchKeyword("MATERIALIZED"))
159
+ materialization = "materialized";
160
+ this.#expectPunctuation("(");
161
+ const statement = this.#parseStatement();
162
+ const close = this.#expectPunctuation(")");
163
+ let search;
164
+ if (this.#matchKeyword("SEARCH")) {
165
+ const searchStart = this.#previous().range;
166
+ let order;
167
+ if (this.#matchKeyword("BREADTH"))
168
+ order = "breadth";
169
+ else if (this.#matchKeyword("DEPTH"))
170
+ order = "depth";
171
+ else
172
+ throw this.#error("SEARCH requires BREADTH or DEPTH", this.#current().range);
173
+ this.#expectKeyword("FIRST");
174
+ this.#expectKeyword("BY");
175
+ const by = [];
176
+ do
177
+ by.push(this.#parseIdentifier());
178
+ while (this.#matchPunctuation(","));
179
+ this.#expectKeyword("SET");
180
+ const set = this.#parseIdentifier();
181
+ search = { order, by, set, range: mergeRanges(searchStart, set.range) };
182
+ }
183
+ let cycle;
184
+ if (this.#matchKeyword("CYCLE")) {
185
+ const cycleStart = this.#previous().range;
186
+ const cycleColumns = [];
187
+ do
188
+ cycleColumns.push(this.#parseIdentifier());
189
+ while (this.#matchPunctuation(","));
190
+ this.#expectKeyword("SET");
191
+ const set = this.#parseIdentifier();
192
+ let markValue;
193
+ let markDefault;
194
+ if (this.#matchKeyword("TO")) {
195
+ markValue = this.#parseExpression();
196
+ this.#expectKeyword("DEFAULT");
197
+ markDefault = this.#parseExpression();
198
+ }
199
+ this.#expectKeyword("USING");
200
+ const using = this.#parseIdentifier();
201
+ cycle = {
202
+ columns: cycleColumns,
203
+ set,
204
+ ...(markValue === undefined ? {} : { markValue }),
205
+ ...(markDefault === undefined ? {} : { markDefault }),
206
+ using,
207
+ range: mergeRanges(cycleStart, using.range),
208
+ };
209
+ }
210
+ queries.push({
211
+ name,
212
+ columns,
213
+ statement,
214
+ ...(materialization === undefined ? {} : { materialization }),
215
+ ...(search === undefined ? {} : { search }),
216
+ ...(cycle === undefined ? {} : { cycle }),
217
+ range: mergeRanges(name.range, cycle?.range ?? search?.range ?? close.range),
218
+ });
219
+ } while (this.#matchPunctuation(","));
220
+ return { recursive, queries, range: mergeRanges(start, queries.at(-1)?.range ?? start) };
221
+ }
222
+ #parseSelect(withClause, minimumCompoundPrecedence = 0) {
223
+ const start = withClause?.range ?? this.#current().range;
224
+ this.#expectKeyword("SELECT");
225
+ let distinct = false;
226
+ const distinctOn = [];
227
+ if (this.#matchKeyword("DISTINCT")) {
228
+ distinct = true;
229
+ if (this.#matchKeyword("ON")) {
230
+ this.#expectPunctuation("(");
231
+ distinctOn.push(...this.#parseExpressionList());
232
+ this.#expectPunctuation(")");
233
+ }
234
+ }
235
+ else
236
+ this.#matchKeyword("ALL");
237
+ const columns = this.#parseSelectList();
238
+ let from;
239
+ const joins = [];
240
+ let where;
241
+ let groupModifier;
242
+ const groupBy = [];
243
+ let having;
244
+ const windows = [];
245
+ if (this.#matchKeyword("FROM")) {
246
+ from = this.#parseTableReference();
247
+ while (true) {
248
+ if (this.#matchPunctuation(",")) {
249
+ const table = this.#parseTableReference();
250
+ joins.push({ kind: "cross", table, range: table.range });
251
+ }
252
+ else if (this.#isJoinStart())
253
+ joins.push(this.#parseJoin());
254
+ else
255
+ break;
256
+ }
257
+ }
258
+ if (this.#matchKeyword("WHERE"))
259
+ where = this.#parseExpression();
260
+ if (this.#matchKeyword("GROUP")) {
261
+ this.#expectKeyword("BY");
262
+ if (this.#matchKeyword("ALL"))
263
+ groupModifier = "all";
264
+ else if (this.#matchKeyword("DISTINCT"))
265
+ groupModifier = "distinct";
266
+ groupBy.push(...this.#parseGroupingList());
267
+ }
268
+ if (this.#matchKeyword("HAVING"))
269
+ having = this.#parseExpression();
270
+ if (this.#matchKeyword("WINDOW")) {
271
+ do {
272
+ const name = this.#parseIdentifier();
273
+ this.#expectKeyword("AS");
274
+ const specification = this.#parseWindowSpecification();
275
+ windows.push({ name, specification, range: mergeRanges(name.range, specification.range) });
276
+ } while (this.#matchPunctuation(","));
277
+ }
278
+ const end = this.#previous().range;
279
+ const core = {
280
+ kind: "select",
281
+ ...(withClause === undefined ? {} : { with: withClause }),
282
+ distinct,
283
+ distinctOn,
284
+ columns,
285
+ ...(from === undefined ? {} : { from }),
286
+ joins,
287
+ ...(where === undefined ? {} : { where }),
288
+ ...(groupModifier === undefined ? {} : { groupModifier }),
289
+ groupBy,
290
+ ...(having === undefined ? {} : { having }),
291
+ windows,
292
+ orderBy: [],
293
+ locking: [],
294
+ compounds: [],
295
+ range: mergeRanges(start, end),
296
+ };
297
+ const compound = this.#parseCompoundExpression(core, minimumCompoundPrecedence);
298
+ return minimumCompoundPrecedence === 0 ? this.#parseSelectTail(compound) : compound;
299
+ }
300
+ #parseParenthesizedSelect() {
301
+ const open = this.#expectPunctuation("(");
302
+ const statement = this.#parseStatement();
303
+ if (statement.kind !== "select")
304
+ throw this.#error("A compound query operand must be a SELECT", statement.range);
305
+ const close = this.#expectPunctuation(")");
306
+ return { ...statement, range: mergeRanges(open.range, close.range) };
307
+ }
308
+ #parseCompoundExpression(initial, minimumPrecedence) {
309
+ let statement = initial;
310
+ while (["UNION", "INTERSECT", "EXCEPT"].includes(this.#current().value)) {
311
+ const precedence = this.#current().value === "INTERSECT" ? 2 : 1;
312
+ if (precedence < minimumPrecedence)
313
+ break;
314
+ const operatorToken = this.#current();
315
+ this.#advance();
316
+ const all = this.#matchKeyword("ALL");
317
+ if (this.#syntax === "sqlite" && all && operatorToken.value !== "UNION") {
318
+ throw this.#error(`SQLite does not support ${operatorToken.value} ALL`, this.#previous().range);
319
+ }
320
+ const right = this.#current().value === "(" ? this.#parseParenthesizedSelect() : this.#parseSelect(undefined, precedence + 1);
321
+ const compound = {
322
+ operator: operatorToken.value.toLowerCase(),
323
+ all,
324
+ statement: right,
325
+ range: mergeRanges(operatorToken.range, right.range),
326
+ };
327
+ statement = {
328
+ ...statement,
329
+ compounds: [...statement.compounds, compound],
330
+ range: mergeRanges(statement.range, right.range),
331
+ };
332
+ }
333
+ return statement;
334
+ }
335
+ #parseSelectTail(statement) {
336
+ let orderBy = [];
337
+ let limit;
338
+ let limitAll = false;
339
+ let offset;
340
+ let fetch;
341
+ const locking = [];
342
+ if (this.#matchKeyword("ORDER")) {
343
+ this.#expectKeyword("BY");
344
+ orderBy = this.#parseOrderByList();
345
+ }
346
+ if (this.#matchKeyword("LIMIT")) {
347
+ if (this.#matchKeyword("ALL"))
348
+ limitAll = true;
349
+ else
350
+ limit = this.#parseExpression();
351
+ if (this.#syntax !== "postgres" && this.#matchPunctuation(",")) {
352
+ offset = limit;
353
+ limit = this.#parseExpression();
354
+ }
355
+ }
356
+ if (this.#matchKeyword("OFFSET")) {
357
+ offset = this.#parseExpression();
358
+ this.#matchKeyword("ROW") || this.#matchKeyword("ROWS");
359
+ }
360
+ if (this.#matchKeyword("FETCH")) {
361
+ const fetchStart = this.#previous().range;
362
+ if (!this.#matchKeyword("FIRST"))
363
+ this.#expectKeyword("NEXT");
364
+ const count = ["ROW", "ROWS"].includes(this.#current().value) ? undefined : this.#parseExpression();
365
+ if (!this.#matchKeyword("ROW"))
366
+ this.#expectKeyword("ROWS");
367
+ let withTies = false;
368
+ if (this.#matchKeyword("WITH")) {
369
+ this.#expectKeyword("TIES");
370
+ withTies = true;
371
+ }
372
+ else
373
+ this.#expectKeyword("ONLY");
374
+ fetch = {
375
+ ...(count === undefined ? {} : { count }),
376
+ withTies,
377
+ range: mergeRanges(fetchStart, this.#previous().range),
378
+ };
379
+ }
380
+ while (this.#current().value === "FOR")
381
+ locking.push(this.#parseSelectLockingClause());
382
+ if (this.#current().value === "LOCK") {
383
+ if (this.#syntax !== "mysql")
384
+ throw this.#error("LOCK IN SHARE MODE is MySQL syntax", this.#current().range);
385
+ if (locking.length > 0) {
386
+ throw this.#error("LOCK IN SHARE MODE cannot follow another MySQL locking clause", this.#current().range);
387
+ }
388
+ const lockStart = this.#expectKeyword("LOCK").range;
389
+ this.#expectKeyword("IN");
390
+ this.#expectKeyword("SHARE");
391
+ const lockEnd = this.#expectKeyword("MODE").range;
392
+ locking.push({ strength: "share", relations: [], range: mergeRanges(lockStart, lockEnd) });
393
+ }
394
+ const end = this.#previous().range;
395
+ return {
396
+ ...statement,
397
+ orderBy,
398
+ ...(limit === undefined ? {} : { limit }),
399
+ ...(limitAll ? { limitAll: true } : {}),
400
+ ...(offset === undefined ? {} : { offset }),
401
+ ...(fetch === undefined ? {} : { fetch }),
402
+ locking,
403
+ range: mergeRanges(statement.range, end),
404
+ };
405
+ }
406
+ #parseSelectLockingClause() {
407
+ const start = this.#expectKeyword("FOR").range;
408
+ let strength;
409
+ if (this.#matchKeyword("UPDATE"))
410
+ strength = "update";
411
+ else if (this.#matchKeyword("SHARE"))
412
+ strength = "share";
413
+ else if (this.#matchKeyword("NO")) {
414
+ if (this.#syntax !== "postgres")
415
+ throw this.#error("FOR NO KEY UPDATE is PostgreSQL syntax", start);
416
+ this.#expectKeyword("KEY");
417
+ this.#expectKeyword("UPDATE");
418
+ strength = "no-key-update";
419
+ }
420
+ else if (this.#matchKeyword("KEY")) {
421
+ if (this.#syntax !== "postgres")
422
+ throw this.#error("FOR KEY SHARE is PostgreSQL syntax", start);
423
+ this.#expectKeyword("SHARE");
424
+ strength = "key-share";
425
+ }
426
+ else {
427
+ throw this.#error("Expected UPDATE, NO KEY UPDATE, SHARE, or KEY SHARE after FOR", this.#current().range);
428
+ }
429
+ const relations = [];
430
+ if (this.#matchKeyword("OF")) {
431
+ do
432
+ relations.push(this.#parseIdentifier());
433
+ while (this.#matchPunctuation(","));
434
+ }
435
+ let wait;
436
+ if (this.#matchKeyword("NOWAIT"))
437
+ wait = "nowait";
438
+ else if (this.#matchKeyword("SKIP")) {
439
+ this.#expectKeyword("LOCKED");
440
+ wait = "skip-locked";
441
+ }
442
+ return {
443
+ strength,
444
+ relations,
445
+ ...(wait === undefined ? {} : { wait }),
446
+ range: mergeRanges(start, this.#previous().range),
447
+ };
448
+ }
449
+ #parseInsert(withClause) {
450
+ const start = withClause?.range ?? this.#expectKeyword("INSERT").range;
451
+ if (withClause !== undefined)
452
+ this.#expectKeyword("INSERT");
453
+ this.#expectKeyword("INTO");
454
+ const table = this.#parseNamedTableReference(true);
455
+ const columns = [];
456
+ if (this.#matchPunctuation("(")) {
457
+ if (!this.#matchPunctuation(")")) {
458
+ do
459
+ columns.push(this.#parseIdentifier());
460
+ while (this.#matchPunctuation(","));
461
+ this.#expectPunctuation(")");
462
+ }
463
+ }
464
+ let overriding;
465
+ if (this.#matchKeyword("OVERRIDING")) {
466
+ if (this.#matchWord("SYSTEM"))
467
+ overriding = "system";
468
+ else {
469
+ this.#expectWord("USER");
470
+ overriding = "user";
471
+ }
472
+ this.#expectWord("VALUE");
473
+ }
474
+ let source;
475
+ if (this.#matchKeyword("DEFAULT")) {
476
+ const sourceStart = this.#previous().range;
477
+ const end = this.#expectKeyword("VALUES").range;
478
+ source = { kind: "default-values", range: mergeRanges(sourceStart, end) };
479
+ }
480
+ else if (this.#matchKeyword("VALUES")) {
481
+ const sourceStart = this.#previous().range;
482
+ const rows = [];
483
+ do {
484
+ this.#expectPunctuation("(");
485
+ const row = this.#matchPunctuation(")") ? [] : [...this.#parseExpressionList()];
486
+ const close = this.#previous().value === ")" ? this.#previous() : this.#expectPunctuation(")");
487
+ rows.push(row);
488
+ if (close.value !== ")")
489
+ throw this.#error("Expected ) after VALUES row", close.range);
490
+ } while (this.#matchPunctuation(","));
491
+ source = { kind: "values", rows, range: mergeRanges(sourceStart, this.#previous().range) };
492
+ }
493
+ else if (this.#current().value === "SELECT" || this.#current().value === "WITH") {
494
+ const statement = this.#parseStatement();
495
+ if (statement.kind !== "select")
496
+ throw this.#error("INSERT source must be SELECT or VALUES", statement.range);
497
+ source = statement;
498
+ }
499
+ else
500
+ throw this.#error("Expected VALUES, DEFAULT VALUES, or SELECT after INSERT target", this.#current().range);
501
+ const conflict = this.#matchKeyword("ON") ? this.#parseInsertConflictClause() : undefined;
502
+ const { aliases: returningAliases, items: returning } = this.#parseReturning();
503
+ return {
504
+ kind: "insert",
505
+ ...(withClause === undefined ? {} : { with: withClause }),
506
+ table,
507
+ columns,
508
+ ...(overriding === undefined ? {} : { overriding }),
509
+ source,
510
+ ...(conflict === undefined ? {} : { conflict }),
511
+ ...(returningAliases === undefined ? {} : { returningAliases }),
512
+ returning,
513
+ range: mergeRanges(start, this.#previous().range),
514
+ };
515
+ }
516
+ #parseUpdate(withClause) {
517
+ const start = withClause?.range ?? this.#expectKeyword("UPDATE").range;
518
+ if (withClause !== undefined)
519
+ this.#expectKeyword("UPDATE");
520
+ const table = this.#parseNamedTableReference(true);
521
+ this.#expectKeyword("SET");
522
+ const assignments = this.#parseUpdateAssignments();
523
+ let from;
524
+ const joins = [];
525
+ if (this.#matchKeyword("FROM")) {
526
+ from = this.#parseTableReference();
527
+ while (true) {
528
+ if (this.#matchPunctuation(",")) {
529
+ const table = this.#parseTableReference();
530
+ joins.push({ kind: "cross", table, range: table.range });
531
+ }
532
+ else if (this.#isJoinStart())
533
+ joins.push(this.#parseJoin());
534
+ else
535
+ break;
536
+ }
537
+ }
538
+ let where;
539
+ let currentOf;
540
+ if (this.#matchKeyword("WHERE")) {
541
+ const whereStart = this.#previous().range;
542
+ if (this.#matchKeyword("CURRENT")) {
543
+ this.#expectKeyword("OF");
544
+ const cursor = this.#parseIdentifier(true);
545
+ currentOf = { cursor, range: mergeRanges(whereStart, cursor.range) };
546
+ }
547
+ else
548
+ where = this.#parseExpression();
549
+ }
550
+ const { aliases: returningAliases, items: returning } = this.#parseReturning();
551
+ return {
552
+ kind: "update",
553
+ ...(withClause === undefined ? {} : { with: withClause }),
554
+ table,
555
+ assignments,
556
+ ...(from === undefined ? {} : { from }),
557
+ joins,
558
+ ...(where === undefined ? {} : { where }),
559
+ ...(currentOf === undefined ? {} : { currentOf }),
560
+ ...(returningAliases === undefined ? {} : { returningAliases }),
561
+ returning,
562
+ range: mergeRanges(start, this.#previous().range),
563
+ };
564
+ }
565
+ #parseDelete(withClause) {
566
+ const start = withClause?.range ?? this.#expectKeyword("DELETE").range;
567
+ if (withClause !== undefined)
568
+ this.#expectKeyword("DELETE");
569
+ this.#expectKeyword("FROM");
570
+ const table = this.#parseNamedTableReference(true);
571
+ const using = [];
572
+ const joins = [];
573
+ if (this.#matchKeyword("USING")) {
574
+ using.push(this.#parseTableReference());
575
+ while (true) {
576
+ if (this.#matchPunctuation(","))
577
+ using.push(this.#parseTableReference());
578
+ else if (this.#isJoinStart())
579
+ joins.push(this.#parseJoin());
580
+ else
581
+ break;
582
+ }
583
+ }
584
+ let where;
585
+ let currentOf;
586
+ if (this.#matchKeyword("WHERE")) {
587
+ const whereStart = this.#previous().range;
588
+ if (this.#matchKeyword("CURRENT")) {
589
+ this.#expectKeyword("OF");
590
+ const cursor = this.#parseIdentifier(true);
591
+ currentOf = { cursor, range: mergeRanges(whereStart, cursor.range) };
592
+ }
593
+ else
594
+ where = this.#parseExpression();
595
+ }
596
+ const { aliases: returningAliases, items: returning } = this.#parseReturning();
597
+ return {
598
+ kind: "delete",
599
+ ...(withClause === undefined ? {} : { with: withClause }),
600
+ table,
601
+ using,
602
+ joins,
603
+ ...(where === undefined ? {} : { where }),
604
+ ...(currentOf === undefined ? {} : { currentOf }),
605
+ ...(returningAliases === undefined ? {} : { returningAliases }),
606
+ returning,
607
+ range: mergeRanges(start, this.#previous().range),
608
+ };
609
+ }
610
+ #parseMerge(withClause) {
611
+ const start = withClause?.range ?? this.#expectKeyword("MERGE").range;
612
+ if (withClause !== undefined)
613
+ this.#expectKeyword("MERGE");
614
+ this.#expectKeyword("INTO");
615
+ const table = this.#parseNamedTableReference(true);
616
+ this.#expectKeyword("USING");
617
+ const source = this.#parseMergeSource();
618
+ this.#expectKeyword("ON");
619
+ const on = this.#parseExpression();
620
+ const clauses = [];
621
+ while (this.#matchKeyword("WHEN")) {
622
+ const clauseStart = this.#previous().range;
623
+ let match;
624
+ let by;
625
+ if (this.#matchKeyword("MATCHED"))
626
+ match = "matched";
627
+ else {
628
+ this.#expectKeyword("NOT");
629
+ this.#expectKeyword("MATCHED");
630
+ if (this.#matchKeyword("BY")) {
631
+ if (this.#matchWord("SOURCE")) {
632
+ match = "not-matched-source";
633
+ by = "source";
634
+ }
635
+ else {
636
+ this.#expectWord("TARGET");
637
+ match = "not-matched-target";
638
+ by = "target";
639
+ }
640
+ }
641
+ else
642
+ match = "not-matched-target";
643
+ }
644
+ const condition = this.#matchKeyword("AND") ? this.#parseExpression() : undefined;
645
+ this.#expectKeyword("THEN");
646
+ let action;
647
+ if (this.#matchKeyword("DO")) {
648
+ this.#expectKeyword("NOTHING");
649
+ action = { kind: "nothing", range: mergeRanges(clauseStart, this.#previous().range) };
650
+ }
651
+ else if (this.#matchKeyword("DELETE")) {
652
+ action = { kind: "delete", range: mergeRanges(clauseStart, this.#previous().range) };
653
+ }
654
+ else if (this.#matchKeyword("UPDATE")) {
655
+ this.#expectKeyword("SET");
656
+ const assignments = this.#parseUpdateAssignments();
657
+ action = {
658
+ kind: "update",
659
+ assignments,
660
+ range: mergeRanges(clauseStart, assignments.at(-1)?.range ?? clauseStart),
661
+ };
662
+ }
663
+ else {
664
+ this.#expectKeyword("INSERT");
665
+ const columns = [];
666
+ if (this.#matchPunctuation("(")) {
667
+ do
668
+ columns.push(this.#parseIdentifier());
669
+ while (this.#matchPunctuation(","));
670
+ this.#expectPunctuation(")");
671
+ }
672
+ let overriding;
673
+ if (this.#matchKeyword("OVERRIDING")) {
674
+ if (this.#matchWord("SYSTEM"))
675
+ overriding = "system";
676
+ else {
677
+ this.#expectWord("USER");
678
+ overriding = "user";
679
+ }
680
+ this.#expectWord("VALUE");
681
+ }
682
+ let actionSource;
683
+ if (this.#matchKeyword("DEFAULT")) {
684
+ const sourceStart = this.#previous().range;
685
+ const end = this.#expectKeyword("VALUES").range;
686
+ actionSource = { kind: "default-values", range: mergeRanges(sourceStart, end) };
687
+ }
688
+ else {
689
+ const sourceStart = this.#expectKeyword("VALUES").range;
690
+ this.#expectPunctuation("(");
691
+ const row = this.#matchPunctuation(")") ? [] : [...this.#parseExpressionList()];
692
+ const close = this.#previous().value === ")" ? this.#previous() : this.#expectPunctuation(")");
693
+ actionSource = { kind: "values", rows: [row], range: mergeRanges(sourceStart, close.range) };
694
+ }
695
+ action = {
696
+ kind: "insert",
697
+ columns,
698
+ ...(overriding === undefined ? {} : { overriding }),
699
+ source: actionSource,
700
+ range: mergeRanges(clauseStart, actionSource.range),
701
+ };
702
+ }
703
+ clauses.push({
704
+ match,
705
+ ...(by === undefined ? {} : { by }),
706
+ ...(condition === undefined ? {} : { condition }),
707
+ action,
708
+ range: mergeRanges(clauseStart, action.range),
709
+ });
710
+ }
711
+ if (clauses.length === 0)
712
+ throw this.#error("MERGE requires at least one WHEN clause", this.#current().range);
713
+ const { aliases: returningAliases, items: returning } = this.#parseReturning();
714
+ return {
715
+ kind: "merge",
716
+ ...(withClause === undefined ? {} : { with: withClause }),
717
+ table,
718
+ source,
719
+ on,
720
+ clauses,
721
+ ...(returningAliases === undefined ? {} : { returningAliases }),
722
+ returning,
723
+ range: mergeRanges(start, this.#previous().range),
724
+ };
725
+ }
726
+ #parseInsertConflictClause() {
727
+ const start = this.#previous().range;
728
+ this.#expectKeyword("CONFLICT");
729
+ let target;
730
+ if (this.#matchKeyword("ON")) {
731
+ this.#expectKeyword("CONSTRAINT");
732
+ const constraint = this.#parseIdentifier(true);
733
+ target = { kind: "constraint", constraint, range: mergeRanges(start, constraint.range) };
734
+ }
735
+ else if (this.#matchPunctuation("(")) {
736
+ const elements = [];
737
+ do {
738
+ const elementStart = this.#current().range;
739
+ let expression = this.#parseExpression();
740
+ let collation;
741
+ if (expression.kind === "collate") {
742
+ collation = expression.collation;
743
+ expression = expression.expression;
744
+ }
745
+ else if (this.#matchKeyword("COLLATE"))
746
+ collation = this.#parseQualifiedIdentifier();
747
+ const operatorClass = this.#current().value !== "," && this.#current().value !== ")" ? this.#parseQualifiedIdentifier() : undefined;
748
+ elements.push({
749
+ expression,
750
+ ...(collation === undefined ? {} : { collation }),
751
+ ...(operatorClass === undefined ? {} : { operatorClass }),
752
+ range: mergeRanges(elementStart, operatorClass?.range ?? collation?.range ?? expression.range),
753
+ });
754
+ } while (this.#matchPunctuation(","));
755
+ const close = this.#expectPunctuation(")");
756
+ const predicate = this.#matchKeyword("WHERE") ? this.#parseExpression() : undefined;
757
+ target = {
758
+ kind: "inference",
759
+ elements,
760
+ ...(predicate === undefined ? {} : { predicate }),
761
+ range: mergeRanges(start, predicate?.range ?? close.range),
762
+ };
763
+ }
764
+ this.#expectKeyword("DO");
765
+ let action;
766
+ if (this.#matchKeyword("NOTHING")) {
767
+ action = { kind: "nothing", range: mergeRanges(start, this.#previous().range) };
768
+ }
769
+ else {
770
+ this.#expectKeyword("UPDATE");
771
+ this.#expectKeyword("SET");
772
+ const assignments = this.#parseUpdateAssignments();
773
+ const where = this.#matchKeyword("WHERE") ? this.#parseExpression() : undefined;
774
+ action = {
775
+ kind: "update",
776
+ assignments,
777
+ ...(where === undefined ? {} : { where }),
778
+ range: mergeRanges(start, where?.range ?? assignments.at(-1)?.range ?? start),
779
+ };
780
+ }
781
+ return { ...(target === undefined ? {} : { target }), action, range: mergeRanges(start, action.range) };
782
+ }
783
+ #parseMergeSource() {
784
+ const start = this.#current().range;
785
+ if (this.#current().value !== "(" || this.#peekToken(1).value !== "VALUES")
786
+ return this.#parseTableReference();
787
+ this.#expectPunctuation("(");
788
+ this.#expectKeyword("VALUES");
789
+ const rows = [];
790
+ do {
791
+ this.#expectPunctuation("(");
792
+ const row = this.#matchPunctuation(")") ? [] : [...this.#parseExpressionList()];
793
+ if (this.#previous().value !== ")")
794
+ this.#expectPunctuation(")");
795
+ rows.push(row);
796
+ } while (this.#matchPunctuation(","));
797
+ this.#expectPunctuation(")");
798
+ let alias;
799
+ if (this.#matchKeyword("AS"))
800
+ alias = this.#parseIdentifier(true);
801
+ else if (this.#current().kind === "identifier" || this.#current().kind === "quoted-identifier")
802
+ alias = this.#parseIdentifier();
803
+ const columns = [];
804
+ if (alias !== undefined && this.#matchPunctuation("(")) {
805
+ do
806
+ columns.push(this.#parseIdentifier());
807
+ while (this.#matchPunctuation(","));
808
+ this.#expectPunctuation(")");
809
+ }
810
+ return {
811
+ kind: "values",
812
+ rows,
813
+ ...(alias === undefined ? {} : { alias }),
814
+ columns,
815
+ range: mergeRanges(start, this.#previous().range),
816
+ };
817
+ }
818
+ #parseUpdateAssignments() {
819
+ const assignments = [];
820
+ do {
821
+ if (this.#matchPunctuation("(")) {
822
+ const start = this.#previous().range;
823
+ const columns = [];
824
+ do
825
+ columns.push(this.#parseIdentifier());
826
+ while (this.#matchPunctuation(","));
827
+ this.#expectPunctuation(")");
828
+ this.#expectOperator("=");
829
+ const value = this.#matchKeyword("ROW")
830
+ ? (() => {
831
+ const rowStart = this.#previous().range;
832
+ this.#expectPunctuation("(");
833
+ const elements = [...this.#parseExpressionList()];
834
+ const close = this.#expectPunctuation(")");
835
+ return { kind: "row", elements, range: mergeRanges(rowStart, close.range) };
836
+ })()
837
+ : this.#parseExpression();
838
+ assignments.push({ columns, value, range: mergeRanges(start, value.range) });
839
+ }
840
+ else {
841
+ const column = this.#parseIdentifier();
842
+ this.#expectOperator("=");
843
+ const value = this.#parseExpression();
844
+ assignments.push({ column, value, range: mergeRanges(column.range, value.range) });
845
+ }
846
+ } while (this.#matchPunctuation(","));
847
+ return assignments;
848
+ }
849
+ #parseReturning() {
850
+ if (!this.#matchKeyword("RETURNING"))
851
+ return { items: [] };
852
+ let aliases;
853
+ if (this.#matchKeyword("WITH")) {
854
+ const start = this.#previous().range;
855
+ this.#expectPunctuation("(");
856
+ let oldAlias;
857
+ let newAlias;
858
+ do {
859
+ const kind = this.#current().value;
860
+ if (kind !== "OLD" && kind !== "NEW")
861
+ throw this.#error("RETURNING aliases require OLD or NEW", this.#current().range);
862
+ this.#advance();
863
+ this.#expectKeyword("AS");
864
+ const alias = this.#parseIdentifier(true);
865
+ if (kind === "OLD")
866
+ oldAlias = alias;
867
+ else
868
+ newAlias = alias;
869
+ } while (this.#matchPunctuation(","));
870
+ const close = this.#expectPunctuation(")");
871
+ aliases = {
872
+ ...(oldAlias === undefined ? {} : { old: oldAlias }),
873
+ ...(newAlias === undefined ? {} : { new: newAlias }),
874
+ range: mergeRanges(start, close.range),
875
+ };
876
+ }
877
+ return { ...(aliases === undefined ? {} : { aliases }), items: this.#parseSelectList() };
878
+ }
879
+ #parseSelectList() {
880
+ const items = [];
881
+ do {
882
+ const expression = this.#parseExpression();
883
+ let alias;
884
+ if (this.#matchKeyword("AS"))
885
+ alias = this.#parseIdentifier();
886
+ else if ((this.#current().kind === "identifier" || this.#current().kind === "quoted-identifier") &&
887
+ !this.#isJsonArrayQueryFormatStart())
888
+ alias = this.#parseIdentifier();
889
+ items.push({
890
+ expression,
891
+ ...(alias === undefined ? {} : { alias }),
892
+ range: mergeRanges(expression.range, alias?.range ?? expression.range),
893
+ });
894
+ } while (this.#matchPunctuation(","));
895
+ return items;
896
+ }
897
+ #parseTableReference() {
898
+ const lateral = this.#matchKeyword("LATERAL");
899
+ const start = lateral ? this.#previous().range : this.#current().range;
900
+ if (this.#matchPunctuation("(")) {
901
+ if (!this.#isStatementStart()) {
902
+ throw this.#error("A parenthesized FROM item must be a SELECT subquery", this.#current().range);
903
+ }
904
+ const statement = this.#parseStatement();
905
+ if (statement.kind !== "select")
906
+ throw this.#error("FROM subquery must be SELECT", statement.range);
907
+ const close = this.#expectPunctuation(")");
908
+ let alias;
909
+ if (this.#matchKeyword("AS"))
910
+ alias = this.#parseIdentifier(true);
911
+ else if (!this.#isJsonArrayQueryFormatStart() &&
912
+ (this.#current().kind === "identifier" || this.#current().kind === "quoted-identifier"))
913
+ alias = this.#parseIdentifier();
914
+ const columns = [];
915
+ if (alias !== undefined && this.#matchPunctuation("(")) {
916
+ do
917
+ columns.push(this.#parseIdentifier());
918
+ while (this.#matchPunctuation(","));
919
+ this.#expectPunctuation(")");
920
+ }
921
+ return {
922
+ kind: "subquery",
923
+ query: statement,
924
+ ...(alias === undefined ? {} : { alias }),
925
+ columns,
926
+ lateral,
927
+ range: mergeRanges(start, alias === undefined ? close.range : this.#previous().range),
928
+ };
929
+ }
930
+ if (this.#isWord(this.#current(), "JSON_TABLE") && this.#peekToken(1).value === "(") {
931
+ return this.#parseJsonTableReference(lateral, start);
932
+ }
933
+ if (this.#current().value === "ROWS" || this.#isTableFunctionStart()) {
934
+ return this.#parseFunctionTableReference(lateral, start);
935
+ }
936
+ return this.#parseNamedTableReference(true, lateral, start);
937
+ }
938
+ #parseJsonTableReference(lateral, start) {
939
+ this.#expectWord("JSON_TABLE");
940
+ this.#expectPunctuation("(");
941
+ const context = this.#parseJsonValueExpression();
942
+ this.#expectPunctuation(",");
943
+ const path = this.#parseExpression();
944
+ const pathName = this.#matchKeyword("AS") ? this.#parseIdentifier(true) : undefined;
945
+ const passing = this.#parseJsonPassing();
946
+ this.#expectWord("COLUMNS");
947
+ this.#expectPunctuation("(");
948
+ const jsonColumns = this.#parseJsonTableColumns();
949
+ this.#expectPunctuation(")");
950
+ const onError = this.#isJsonTableBehaviorStart() ? this.#parseJsonOnErrorBehavior() : undefined;
951
+ const close = this.#expectPunctuation(")");
952
+ let alias;
953
+ if (this.#matchKeyword("AS"))
954
+ alias = this.#parseIdentifier(true);
955
+ else if (!this.#isJsonArrayQueryFormatStart() &&
956
+ (this.#current().kind === "identifier" || this.#current().kind === "quoted-identifier"))
957
+ alias = this.#parseIdentifier();
958
+ const columns = [];
959
+ if (alias !== undefined && this.#matchPunctuation("(")) {
960
+ do
961
+ columns.push(this.#parseIdentifier());
962
+ while (this.#matchPunctuation(","));
963
+ this.#expectPunctuation(")");
964
+ }
965
+ return {
966
+ kind: "json-table",
967
+ context,
968
+ path,
969
+ ...(pathName === undefined ? {} : { pathName }),
970
+ passing,
971
+ jsonColumns,
972
+ ...(onError === undefined ? {} : { onError }),
973
+ ...(alias === undefined ? {} : { alias }),
974
+ columns,
975
+ lateral,
976
+ range: mergeRanges(start, alias === undefined ? close.range : this.#previous().range),
977
+ };
978
+ }
979
+ #parseJsonTableColumns() {
980
+ if (this.#current().value === ")") {
981
+ throw this.#error("JSON_TABLE COLUMNS requires at least one column", this.#current().range);
982
+ }
983
+ const columns = [];
984
+ do
985
+ columns.push(this.#parseJsonTableColumn());
986
+ while (this.#matchPunctuation(","));
987
+ return columns;
988
+ }
989
+ #parseJsonTableColumn() {
990
+ const start = this.#current();
991
+ if (this.#matchWord("NESTED")) {
992
+ this.#matchWord("PATH");
993
+ const path = this.#parseJsonTablePathLiteral();
994
+ const pathName = this.#matchKeyword("AS") ? this.#parseIdentifier(true) : undefined;
995
+ this.#expectWord("COLUMNS");
996
+ this.#expectPunctuation("(");
997
+ const columns = this.#parseJsonTableColumns();
998
+ const close = this.#expectPunctuation(")");
999
+ return {
1000
+ kind: "nested",
1001
+ path,
1002
+ ...(pathName === undefined ? {} : { pathName }),
1003
+ columns,
1004
+ range: mergeRanges(start.range, close.range),
1005
+ };
1006
+ }
1007
+ const name = this.#parseIdentifier(true);
1008
+ if (this.#matchKeyword("FOR")) {
1009
+ const ordinality = this.#expectWord("ORDINALITY");
1010
+ return { kind: "ordinality", name, range: mergeRanges(start.range, ordinality.range) };
1011
+ }
1012
+ const databaseType = this.#parseTypeName(false, () => this.#isJsonTableColumnClauseStart());
1013
+ if (this.#matchWord("EXISTS")) {
1014
+ const path = this.#matchWord("PATH") ? this.#parseJsonTablePathLiteral() : undefined;
1015
+ const onError = this.#isJsonTableBehaviorStart() ? this.#parseJsonOnErrorBehavior() : undefined;
1016
+ return {
1017
+ kind: "exists",
1018
+ name,
1019
+ databaseType,
1020
+ ...(path === undefined ? {} : { path }),
1021
+ ...(onError === undefined ? {} : { onError }),
1022
+ range: mergeRanges(start.range, onError?.range ?? path?.range ?? databaseType.range),
1023
+ };
1024
+ }
1025
+ const format = this.#parseJsonFormat();
1026
+ const path = this.#matchWord("PATH") ? this.#parseJsonTablePathLiteral() : undefined;
1027
+ const wrapper = this.#parseJsonWrapper();
1028
+ const quotes = this.#parseJsonQuotes();
1029
+ let onEmpty;
1030
+ let onError;
1031
+ if (this.#isJsonTableBehaviorStart()) {
1032
+ const clause = this.#parseJsonBehaviorClause(true);
1033
+ if (clause.target === "empty")
1034
+ onEmpty = clause.behavior;
1035
+ else
1036
+ onError = clause.behavior;
1037
+ }
1038
+ if (onEmpty !== undefined && this.#isJsonTableBehaviorStart()) {
1039
+ const clause = this.#parseJsonBehaviorClause(true);
1040
+ if (clause.target !== "error") {
1041
+ throw this.#error("JSON_TABLE ON EMPTY must precede ON ERROR", clause.behavior.range);
1042
+ }
1043
+ onError = clause.behavior;
1044
+ }
1045
+ return {
1046
+ kind: "value",
1047
+ name,
1048
+ databaseType,
1049
+ ...(format === undefined ? {} : { format }),
1050
+ ...(path === undefined ? {} : { path }),
1051
+ ...(wrapper === undefined ? {} : { wrapper }),
1052
+ ...(quotes === undefined ? {} : { quotes }),
1053
+ ...(onEmpty === undefined ? {} : { onEmpty }),
1054
+ ...(onError === undefined ? {} : { onError }),
1055
+ range: mergeRanges(start.range, onError?.range ?? onEmpty?.range ?? this.#previous().range),
1056
+ };
1057
+ }
1058
+ #parseJsonTablePathLiteral() {
1059
+ const token = this.#expect("string", "JSON_TABLE path string literal");
1060
+ return { kind: "literal", value: token.value, range: token.range };
1061
+ }
1062
+ #isJsonTableColumnClauseStart() {
1063
+ if ([
1064
+ "EXISTS",
1065
+ "FORMAT",
1066
+ "PATH",
1067
+ "KEEP",
1068
+ "OMIT",
1069
+ "DEFAULT",
1070
+ "ERROR",
1071
+ "NULL",
1072
+ "TRUE",
1073
+ "FALSE",
1074
+ "UNKNOWN",
1075
+ "EMPTY",
1076
+ ].some((word) => this.#isWord(this.#current(), word)))
1077
+ return true;
1078
+ if (this.#isWord(this.#current(), "WITHOUT")) {
1079
+ return this.#isWord(this.#peekToken(1), "ARRAY") || this.#isWord(this.#peekToken(1), "WRAPPER");
1080
+ }
1081
+ if (!this.#isWord(this.#current(), "WITH"))
1082
+ return false;
1083
+ return ["CONDITIONAL", "UNCONDITIONAL", "ARRAY", "WRAPPER"].some((word) => this.#isWord(this.#peekToken(1), word));
1084
+ }
1085
+ #isTableFunctionStart() {
1086
+ if (!this.#isIdentifierLike(this.#current()))
1087
+ return false;
1088
+ if (this.#peekToken(1).value === "(")
1089
+ return true;
1090
+ return (this.#peekToken(1).value === "." && this.#isIdentifierLike(this.#peekToken(2)) && this.#peekToken(3).value === "(");
1091
+ }
1092
+ #parseFunctionTableReference(lateral, start) {
1093
+ const functions = [];
1094
+ const rowsFrom = this.#matchKeyword("ROWS");
1095
+ if (rowsFrom) {
1096
+ this.#expectKeyword("FROM");
1097
+ this.#expectPunctuation("(");
1098
+ do
1099
+ functions.push(this.#parseTableFunctionItem(true));
1100
+ while (this.#matchPunctuation(","));
1101
+ this.#expectPunctuation(")");
1102
+ }
1103
+ else
1104
+ functions.push(this.#parseTableFunctionItem(false));
1105
+ const withOrdinality = this.#matchKeyword("WITH");
1106
+ if (withOrdinality)
1107
+ this.#expectKeyword("ORDINALITY");
1108
+ const hasAs = this.#matchKeyword("AS");
1109
+ const alias = !this.#isJsonArrayQueryFormatStart() && this.#isIdentifierLike(this.#current())
1110
+ ? this.#parseIdentifier(true)
1111
+ : undefined;
1112
+ if (hasAs && alias === undefined && this.#current().value !== "(") {
1113
+ throw this.#error("Expected table-function alias or column definition list", this.#current().range);
1114
+ }
1115
+ const columns = this.#matchPunctuation("(") ? this.#parseTableFunctionColumns(false) : [];
1116
+ return {
1117
+ kind: "function",
1118
+ ...(rowsFrom ? { rowsFrom: true } : {}),
1119
+ functions,
1120
+ withOrdinality,
1121
+ ...(alias === undefined ? {} : { alias }),
1122
+ columns,
1123
+ lateral,
1124
+ range: mergeRanges(start, this.#previous().range),
1125
+ };
1126
+ }
1127
+ #parseTableFunctionItem(allowDefinition) {
1128
+ const first = this.#parseIdentifier(true);
1129
+ let schema;
1130
+ let name = first;
1131
+ if (this.#matchPunctuation(".")) {
1132
+ schema = first;
1133
+ name = this.#parseIdentifier(true);
1134
+ }
1135
+ this.#expectPunctuation("(");
1136
+ const expression = this.#parseCall(schema, name);
1137
+ if (expression.kind !== "call")
1138
+ throw this.#error("FROM function must be a routine call", expression.range);
1139
+ let columns = [];
1140
+ if (allowDefinition && this.#current().value === "AS" && this.#peekToken(1).value === "(") {
1141
+ this.#advance();
1142
+ this.#expectPunctuation("(");
1143
+ columns = this.#parseTableFunctionColumns(true);
1144
+ }
1145
+ return { call: expression, columns, range: mergeRanges(first.range, this.#previous().range) };
1146
+ }
1147
+ #parseTableFunctionColumns(requireTypes) {
1148
+ const columns = [];
1149
+ if (!this.#matchPunctuation(")")) {
1150
+ do {
1151
+ const name = this.#parseIdentifier(true);
1152
+ const databaseType = requireTypes || (this.#current().value !== "," && this.#current().value !== ")")
1153
+ ? this.#parseTypeName(false)
1154
+ : undefined;
1155
+ columns.push({
1156
+ name,
1157
+ ...(databaseType === undefined ? {} : { databaseType }),
1158
+ range: mergeRanges(name.range, databaseType?.range ?? name.range),
1159
+ });
1160
+ } while (this.#matchPunctuation(","));
1161
+ this.#expectPunctuation(")");
1162
+ }
1163
+ return columns;
1164
+ }
1165
+ #parseNamedTableReference(allowAlias, lateral = false, start = this.#current().range) {
1166
+ const only = this.#matchKeyword("ONLY");
1167
+ const first = this.#parseIdentifier();
1168
+ let schema;
1169
+ let name = first;
1170
+ if (this.#matchPunctuation(".")) {
1171
+ schema = first;
1172
+ name = this.#parseIdentifier();
1173
+ }
1174
+ const includeDescendants = this.#matchOperator("*");
1175
+ let alias;
1176
+ if (allowAlias && this.#matchKeyword("AS"))
1177
+ alias = this.#parseIdentifier(true);
1178
+ else if (allowAlias &&
1179
+ !this.#isJsonArrayQueryFormatStart() &&
1180
+ (this.#current().kind === "identifier" || this.#current().kind === "quoted-identifier"))
1181
+ alias = this.#parseIdentifier();
1182
+ let sample;
1183
+ if (allowAlias && this.#matchKeyword("TABLESAMPLE")) {
1184
+ const sampleStart = this.#previous().range;
1185
+ const method = this.#parseIdentifier(true);
1186
+ this.#expectPunctuation("(");
1187
+ const empty = this.#matchPunctuation(")");
1188
+ const argumentsList = empty ? [] : [...this.#parseExpressionList()];
1189
+ if (!empty)
1190
+ this.#expectPunctuation(")");
1191
+ let repeatable;
1192
+ if (this.#matchKeyword("REPEATABLE")) {
1193
+ this.#expectPunctuation("(");
1194
+ repeatable = this.#parseExpression();
1195
+ this.#expectPunctuation(")");
1196
+ }
1197
+ sample = {
1198
+ method,
1199
+ arguments: argumentsList,
1200
+ ...(repeatable === undefined ? {} : { repeatable }),
1201
+ range: mergeRanges(sampleStart, this.#previous().range),
1202
+ };
1203
+ }
1204
+ return {
1205
+ kind: "table",
1206
+ name,
1207
+ ...(schema === undefined ? {} : { schema }),
1208
+ ...(alias === undefined ? {} : { alias }),
1209
+ lateral,
1210
+ ...(only ? { only: true } : {}),
1211
+ ...(includeDescendants ? { includeDescendants: true } : {}),
1212
+ ...(sample === undefined ? {} : { sample }),
1213
+ range: mergeRanges(start, sample?.range ?? alias?.range ?? name.range),
1214
+ };
1215
+ }
1216
+ #isJoinStart() {
1217
+ return ["JOIN", "INNER", "LEFT", "RIGHT", "FULL", "CROSS"].includes(this.#current().value);
1218
+ }
1219
+ #parseJoin() {
1220
+ const start = this.#current().range;
1221
+ let kind = "inner";
1222
+ if (this.#matchKeyword("INNER"))
1223
+ kind = "inner";
1224
+ else if (this.#matchKeyword("LEFT"))
1225
+ kind = "left";
1226
+ else if (this.#matchKeyword("RIGHT"))
1227
+ kind = "right";
1228
+ else if (this.#matchKeyword("FULL"))
1229
+ kind = "full";
1230
+ else if (this.#matchKeyword("CROSS"))
1231
+ kind = "cross";
1232
+ this.#matchKeyword("OUTER");
1233
+ this.#expectKeyword("JOIN");
1234
+ const table = this.#parseTableReference();
1235
+ if (kind === "cross")
1236
+ return { kind, table, range: mergeRanges(start, table.range) };
1237
+ if (this.#matchKeyword("ON")) {
1238
+ const on = this.#parseExpression();
1239
+ return { kind, table, on, range: mergeRanges(start, on.range) };
1240
+ }
1241
+ if (this.#matchKeyword("USING")) {
1242
+ this.#expectPunctuation("(");
1243
+ const using = [];
1244
+ do
1245
+ using.push(this.#parseIdentifier());
1246
+ while (this.#matchPunctuation(","));
1247
+ const close = this.#expectPunctuation(")");
1248
+ return { kind, table, using, range: mergeRanges(start, close.range) };
1249
+ }
1250
+ throw this.#error("JOIN requires ON or USING", this.#current().range);
1251
+ }
1252
+ #parseExpressionList() {
1253
+ const expressions = [];
1254
+ do
1255
+ expressions.push(this.#parseExpression());
1256
+ while (this.#matchPunctuation(","));
1257
+ return expressions;
1258
+ }
1259
+ #parseGroupingList() {
1260
+ const elements = [];
1261
+ do
1262
+ elements.push(this.#parseGroupingElement());
1263
+ while (this.#matchPunctuation(","));
1264
+ return elements;
1265
+ }
1266
+ #parseGroupingElement() {
1267
+ if (this.#matchPunctuation("(")) {
1268
+ const start = this.#previous().range;
1269
+ if (this.#matchPunctuation(")")) {
1270
+ return { kind: "empty-group", range: mergeRanges(start, this.#previous().range) };
1271
+ }
1272
+ const elements = this.#parseGroupingList();
1273
+ const close = this.#expectPunctuation(")");
1274
+ return { kind: "grouping-set", elements, range: mergeRanges(start, close.range) };
1275
+ }
1276
+ let kind;
1277
+ let start;
1278
+ if (this.#matchKeyword("ROLLUP")) {
1279
+ kind = "rollup";
1280
+ start = this.#previous().range;
1281
+ }
1282
+ else if (this.#matchKeyword("CUBE")) {
1283
+ kind = "cube";
1284
+ start = this.#previous().range;
1285
+ }
1286
+ else if (this.#matchKeyword("GROUPING")) {
1287
+ start = this.#previous().range;
1288
+ this.#expectKeyword("SETS");
1289
+ kind = "grouping-sets";
1290
+ }
1291
+ if (kind !== undefined && start !== undefined) {
1292
+ this.#expectPunctuation("(");
1293
+ const empty = this.#matchPunctuation(")");
1294
+ const elements = empty ? [] : [...this.#parseGroupingList()];
1295
+ const close = empty ? this.#previous() : this.#expectPunctuation(")");
1296
+ return { kind, elements, range: mergeRanges(start, close.range) };
1297
+ }
1298
+ return this.#parseExpression();
1299
+ }
1300
+ #parseOrderByList() {
1301
+ const orderBy = [];
1302
+ do {
1303
+ const expression = this.#parseExpression();
1304
+ const direction = this.#matchKeyword("ASC") ? "asc" : this.#matchKeyword("DESC") ? "desc" : undefined;
1305
+ let using;
1306
+ if (direction === undefined && this.#matchKeyword("USING")) {
1307
+ const operator = this.#expect("operator", "ordering operator");
1308
+ using = operator.value;
1309
+ }
1310
+ let nulls;
1311
+ if (this.#matchKeyword("NULLS")) {
1312
+ if (this.#matchKeyword("FIRST"))
1313
+ nulls = "first";
1314
+ else {
1315
+ this.#expectKeyword("LAST");
1316
+ nulls = "last";
1317
+ }
1318
+ }
1319
+ orderBy.push({
1320
+ expression,
1321
+ ...(direction === undefined ? {} : { direction }),
1322
+ ...(using === undefined ? {} : { using }),
1323
+ ...(nulls === undefined ? {} : { nulls }),
1324
+ range: mergeRanges(expression.range, this.#previous().range),
1325
+ });
1326
+ } while (this.#matchPunctuation(","));
1327
+ return orderBy;
1328
+ }
1329
+ #parseExpression(minimum = 0) {
1330
+ return this.#nested(() => {
1331
+ let left = this.#parseUnary();
1332
+ while (true) {
1333
+ if (this.#current().value === ".") {
1334
+ left = this.#parseFieldAccess(left);
1335
+ continue;
1336
+ }
1337
+ if (this.#current().value === "[") {
1338
+ left = this.#parseSubscript(left);
1339
+ continue;
1340
+ }
1341
+ if (this.#syntax === "postgres" && this.#matchOperator("::")) {
1342
+ const databaseType = this.#parseTypeName(false);
1343
+ left = {
1344
+ kind: "cast",
1345
+ expression: left,
1346
+ databaseType,
1347
+ syntax: "postgres",
1348
+ range: mergeRanges(left.range, databaseType.range),
1349
+ };
1350
+ continue;
1351
+ }
1352
+ if (this.#syntax === "postgres" && this.#matchKeyword("COLLATE")) {
1353
+ const collation = this.#parseQualifiedIdentifier();
1354
+ left = {
1355
+ kind: "collate",
1356
+ expression: left,
1357
+ collation,
1358
+ range: mergeRanges(left.range, collation.range),
1359
+ };
1360
+ continue;
1361
+ }
1362
+ if (this.#syntax === "postgres" && this.#current().value === "AT") {
1363
+ const strength = 8;
1364
+ if (strength < minimum)
1365
+ break;
1366
+ this.#advance();
1367
+ if (this.#matchKeyword("TIME")) {
1368
+ this.#expectKeyword("ZONE");
1369
+ const zone = this.#parseExpression(strength + 1);
1370
+ left = {
1371
+ kind: "at-time-zone",
1372
+ expression: left,
1373
+ zone,
1374
+ local: false,
1375
+ range: mergeRanges(left.range, zone.range),
1376
+ };
1377
+ }
1378
+ else {
1379
+ const local = this.#expectKeyword("LOCAL");
1380
+ left = {
1381
+ kind: "at-time-zone",
1382
+ expression: left,
1383
+ local: true,
1384
+ range: mergeRanges(left.range, local.range),
1385
+ };
1386
+ }
1387
+ continue;
1388
+ }
1389
+ const negated = this.#current().value === "NOT" &&
1390
+ ["IN", "BETWEEN", "LIKE", "ILIKE", "SIMILAR"].includes(this.#peekToken(1).value);
1391
+ const special = negated ? this.#peekToken(1).value : this.#current().value;
1392
+ if (special === "IN") {
1393
+ const strength = 3;
1394
+ if (strength < minimum)
1395
+ break;
1396
+ if (negated)
1397
+ this.#advance();
1398
+ this.#advance();
1399
+ const start = left.range;
1400
+ this.#expectPunctuation("(");
1401
+ let values;
1402
+ if (this.#isStatementStart()) {
1403
+ const statement = this.#parseStatement();
1404
+ if (statement.kind !== "select")
1405
+ throw this.#error("IN subquery must be SELECT", statement.range);
1406
+ values = statement;
1407
+ }
1408
+ else {
1409
+ if (this.#current().value === ")")
1410
+ throw this.#error("IN requires at least one value", this.#current().range);
1411
+ values = this.#parseExpressionList();
1412
+ }
1413
+ const close = this.#expectPunctuation(")");
1414
+ left = { kind: "in", expression: left, values, negated, range: mergeRanges(start, close.range) };
1415
+ continue;
1416
+ }
1417
+ if (special === "BETWEEN") {
1418
+ const strength = 3;
1419
+ if (strength < minimum)
1420
+ break;
1421
+ if (negated)
1422
+ this.#advance();
1423
+ this.#advance();
1424
+ const lower = this.#parseExpression(strength + 1);
1425
+ this.#expectKeyword("AND");
1426
+ const upper = this.#parseExpression(strength + 1);
1427
+ left = {
1428
+ kind: "between",
1429
+ expression: left,
1430
+ lower,
1431
+ upper,
1432
+ negated,
1433
+ range: mergeRanges(left.range, upper.range),
1434
+ };
1435
+ continue;
1436
+ }
1437
+ let operator = this.#current().value.toUpperCase();
1438
+ if (special === "SIMILAR")
1439
+ operator = negated ? "NOT SIMILAR TO" : "SIMILAR TO";
1440
+ else if (negated)
1441
+ operator = `NOT ${special}`;
1442
+ const strength = precedence.get(operator.replace(/^NOT /u, ""));
1443
+ if (strength === undefined || strength < minimum)
1444
+ break;
1445
+ if (negated)
1446
+ this.#advance();
1447
+ this.#advance();
1448
+ if (operator.endsWith("SIMILAR TO"))
1449
+ this.#expectKeyword("TO");
1450
+ if (operator === "IS") {
1451
+ if (this.#matchKeyword("NOT"))
1452
+ operator = "IS NOT";
1453
+ if (this.#matchKeyword("DISTINCT")) {
1454
+ this.#expectKeyword("FROM");
1455
+ operator += " DISTINCT FROM";
1456
+ }
1457
+ }
1458
+ if (this.#syntax === "postgres" && (operator === "IS" || operator === "IS NOT") && this.#matchWord("JSON")) {
1459
+ let constraint = "value";
1460
+ if (this.#matchWord("VALUE"))
1461
+ constraint = "value";
1462
+ else if (this.#matchWord("SCALAR"))
1463
+ constraint = "scalar";
1464
+ else if (this.#matchWord("ARRAY"))
1465
+ constraint = "array";
1466
+ else if (this.#matchWord("OBJECT"))
1467
+ constraint = "object";
1468
+ const uniqueKeys = this.#parseJsonUniqueKeys();
1469
+ left = {
1470
+ kind: "json-is",
1471
+ expression: left,
1472
+ constraint,
1473
+ negated: operator === "IS NOT",
1474
+ uniqueKeys,
1475
+ range: mergeRanges(left.range, this.#previous().range),
1476
+ };
1477
+ continue;
1478
+ }
1479
+ if (this.#syntax === "postgres" && ["ANY", "SOME", "ALL"].includes(this.#current().value)) {
1480
+ const quantifier = this.#advance().value.toLowerCase();
1481
+ this.#expectPunctuation("(");
1482
+ let right;
1483
+ if (this.#isStatementStart()) {
1484
+ const statement = this.#parseStatement();
1485
+ if (statement.kind !== "select")
1486
+ throw this.#error(`${quantifier.toUpperCase()} requires a SELECT subquery`, statement.range);
1487
+ right = statement;
1488
+ }
1489
+ else
1490
+ right = this.#parseExpression();
1491
+ const close = this.#expectPunctuation(")");
1492
+ left = {
1493
+ kind: "quantified-comparison",
1494
+ left,
1495
+ operator,
1496
+ quantifier,
1497
+ right,
1498
+ range: mergeRanges(left.range, close.range),
1499
+ };
1500
+ continue;
1501
+ }
1502
+ const right = this.#parseExpression(strength + 1);
1503
+ left = { kind: "binary", left, operator, right, range: mergeRanges(left.range, right.range) };
1504
+ }
1505
+ return left;
1506
+ });
1507
+ }
1508
+ #parseUnary() {
1509
+ const token = this.#current();
1510
+ if (this.#matchKeyword("NOT") ||
1511
+ this.#matchOperator("+") ||
1512
+ this.#matchOperator("-") ||
1513
+ this.#matchOperator("~") ||
1514
+ this.#matchOperator("!!") ||
1515
+ this.#matchOperator("@-@") ||
1516
+ this.#matchOperator("@@") ||
1517
+ this.#matchOperator("#") ||
1518
+ this.#matchOperator("?-") ||
1519
+ this.#matchOperator("?|") ||
1520
+ this.#matchOperator("@") ||
1521
+ this.#matchOperator("|/") ||
1522
+ this.#matchOperator("||/")) {
1523
+ const expression = this.#parseUnary();
1524
+ return {
1525
+ kind: "unary",
1526
+ operator: token.value.toUpperCase(),
1527
+ expression,
1528
+ range: mergeRanges(token.range, expression.range),
1529
+ };
1530
+ }
1531
+ if (this.#matchKeyword("EXISTS")) {
1532
+ this.#expectPunctuation("(");
1533
+ const statement = this.#parseStatement();
1534
+ if (statement.kind !== "select")
1535
+ throw this.#error("EXISTS requires a SELECT subquery", statement.range);
1536
+ const close = this.#expectPunctuation(")");
1537
+ return { kind: "exists", query: statement, range: mergeRanges(token.range, close.range) };
1538
+ }
1539
+ let expression = this.#parsePrimary();
1540
+ while (this.#current().value === "[" || this.#current().value === ".") {
1541
+ expression =
1542
+ this.#current().value === "[" ? this.#parseSubscript(expression) : this.#parseFieldAccess(expression);
1543
+ }
1544
+ return expression;
1545
+ }
1546
+ #parseFieldAccess(expression) {
1547
+ this.#expectPunctuation(".");
1548
+ const field = this.#parseIdentifier(true);
1549
+ return { kind: "field-access", expression, field, range: mergeRanges(expression.range, field.range) };
1550
+ }
1551
+ #parseSubscript(expression) {
1552
+ this.#expectPunctuation("[");
1553
+ let index;
1554
+ let lower;
1555
+ let upper;
1556
+ let slice = false;
1557
+ if (this.#matchPunctuation(":")) {
1558
+ slice = true;
1559
+ if (this.#current().value !== "]")
1560
+ upper = this.#parseExpression();
1561
+ }
1562
+ else {
1563
+ if (this.#current().value === "]")
1564
+ throw this.#error("Array subscript cannot be empty", this.#current().range);
1565
+ const first = this.#parseExpression();
1566
+ if (this.#matchPunctuation(":")) {
1567
+ slice = true;
1568
+ lower = first;
1569
+ if (this.#current().value !== "]")
1570
+ upper = this.#parseExpression();
1571
+ }
1572
+ else
1573
+ index = first;
1574
+ }
1575
+ const close = this.#expectPunctuation("]");
1576
+ return {
1577
+ kind: "subscript",
1578
+ expression,
1579
+ ...(index === undefined ? {} : { index }),
1580
+ ...(lower === undefined ? {} : { lower }),
1581
+ ...(upper === undefined ? {} : { upper }),
1582
+ slice,
1583
+ range: mergeRanges(expression.range, close.range),
1584
+ };
1585
+ }
1586
+ #parsePrimary() {
1587
+ const token = this.#current();
1588
+ if (this.#matchPunctuation("(")) {
1589
+ if (this.#isStatementStart()) {
1590
+ const statement = this.#parseStatement();
1591
+ if (statement.kind !== "select")
1592
+ throw this.#error("Scalar subquery must be SELECT", statement.range);
1593
+ const close = this.#expectPunctuation(")");
1594
+ return { kind: "subquery", query: statement, range: mergeRanges(token.range, close.range) };
1595
+ }
1596
+ const first = this.#parseExpression();
1597
+ if (this.#matchPunctuation(",")) {
1598
+ const elements = [first];
1599
+ do
1600
+ elements.push(this.#parseExpression());
1601
+ while (this.#matchPunctuation(","));
1602
+ const close = this.#expectPunctuation(")");
1603
+ return { kind: "row", elements, range: mergeRanges(token.range, close.range) };
1604
+ }
1605
+ this.#expectPunctuation(")");
1606
+ return first;
1607
+ }
1608
+ if (this.#matchKeyword("ARRAY")) {
1609
+ this.#expectPunctuation("[");
1610
+ const elements = this.#matchPunctuation("]") ? [] : [...this.#parseExpressionList()];
1611
+ const close = this.#previous().value === "]" ? this.#previous() : this.#expectPunctuation("]");
1612
+ return { kind: "array", elements, range: mergeRanges(token.range, close.range) };
1613
+ }
1614
+ if (this.#matchKeyword("ROW")) {
1615
+ this.#expectPunctuation("(");
1616
+ const elements = this.#matchPunctuation(")") ? [] : [...this.#parseExpressionList()];
1617
+ const close = this.#previous().value === ")" ? this.#previous() : this.#expectPunctuation(")");
1618
+ return { kind: "row", elements, range: mergeRanges(token.range, close.range) };
1619
+ }
1620
+ if (this.#matchKeyword("CAST"))
1621
+ return this.#parseCast(token.range);
1622
+ if (this.#isIntervalLiteralStart())
1623
+ return this.#parseIntervalLiteral();
1624
+ if (simpleTypedLiteralTypes.has(token.value) && this.#peekToken(1).kind === "string") {
1625
+ return this.#parseSimpleTypedLiteral();
1626
+ }
1627
+ if (this.#isWord(token, "JSON_OBJECTAGG") && this.#peekToken(1).value === "(") {
1628
+ this.#advance();
1629
+ return this.#parseJsonObjectAggregate(token);
1630
+ }
1631
+ if (this.#isWord(token, "JSON_ARRAYAGG") && this.#peekToken(1).value === "(") {
1632
+ this.#advance();
1633
+ return this.#parseJsonArrayAggregate(token);
1634
+ }
1635
+ if (this.#isWord(token, "JSON_OBJECT") &&
1636
+ this.#peekToken(1).value === "(" &&
1637
+ this.#isJsonObjectConstructorStart()) {
1638
+ this.#advance();
1639
+ return this.#parseJsonObject(token);
1640
+ }
1641
+ if (this.#isWord(token, "JSON_ARRAY") && this.#peekToken(1).value === "(") {
1642
+ this.#advance();
1643
+ return this.#parseJsonArray(token);
1644
+ }
1645
+ if (this.#isWord(token, "JSON") && this.#peekToken(1).value === "(") {
1646
+ this.#advance();
1647
+ return this.#parseJsonParse(token);
1648
+ }
1649
+ if (this.#isWord(token, "JSON_SCALAR") && this.#peekToken(1).value === "(") {
1650
+ this.#advance();
1651
+ return this.#parseJsonScalar(token);
1652
+ }
1653
+ if (this.#isWord(token, "JSON_SERIALIZE") && this.#peekToken(1).value === "(") {
1654
+ this.#advance();
1655
+ return this.#parseJsonSerialize(token);
1656
+ }
1657
+ if (this.#isWord(token, "JSON_EXISTS") && this.#peekToken(1).value === "(") {
1658
+ this.#advance();
1659
+ return this.#parseJsonExists(token);
1660
+ }
1661
+ if (this.#isWord(token, "JSON_QUERY") && this.#peekToken(1).value === "(") {
1662
+ this.#advance();
1663
+ return this.#parseJsonQuery(token);
1664
+ }
1665
+ if (this.#isWord(token, "JSON_VALUE") && this.#peekToken(1).value === "(") {
1666
+ this.#advance();
1667
+ return this.#parseJsonValueQuery(token);
1668
+ }
1669
+ if (this.#matchKeyword("CASE"))
1670
+ return this.#parseCase(token.range);
1671
+ if (this.#matchKeyword("NULL"))
1672
+ return { kind: "literal", value: null, range: token.range };
1673
+ if (this.#matchKeyword("TRUE"))
1674
+ return { kind: "literal", value: true, range: token.range };
1675
+ if (this.#matchKeyword("FALSE"))
1676
+ return { kind: "literal", value: false, range: token.range };
1677
+ if (this.#matchKeyword("DEFAULT"))
1678
+ return { kind: "column", column: { name: "DEFAULT", quoted: false, range: token.range }, range: token.range };
1679
+ if (token.kind === "number") {
1680
+ this.#advance();
1681
+ return { kind: "literal", value: Number(token.value), range: token.range };
1682
+ }
1683
+ if (token.kind === "string") {
1684
+ this.#advance();
1685
+ return { kind: "literal", value: token.value, range: token.range };
1686
+ }
1687
+ if (token.kind === "parameter") {
1688
+ this.#advance();
1689
+ return { kind: "parameter", index: Number(token.value), range: token.range };
1690
+ }
1691
+ if (this.#matchOperator("*"))
1692
+ return { kind: "star", range: token.range };
1693
+ if (this.#isIdentifierLike(token)) {
1694
+ const first = this.#parseIdentifier(true);
1695
+ if (this.#matchPunctuation("("))
1696
+ return this.#parseCall(undefined, first);
1697
+ if (this.#matchPunctuation(".")) {
1698
+ if (this.#matchOperator("*"))
1699
+ return { kind: "star", relation: first, range: mergeRanges(first.range, this.#previous().range) };
1700
+ const second = this.#parseIdentifier(true);
1701
+ if (this.#matchPunctuation("("))
1702
+ return this.#parseCall(first, second);
1703
+ return { kind: "column", relation: first, column: second, range: mergeRanges(first.range, second.range) };
1704
+ }
1705
+ return { kind: "column", column: first, range: first.range };
1706
+ }
1707
+ throw this.#error(`Expected expression, found ${token.text || "end of query"}`, token.range);
1708
+ }
1709
+ #isJsonObjectConstructorStart() {
1710
+ let nesting = 0;
1711
+ let sawTopLevelToken = false;
1712
+ for (let offset = 1;; offset += 1) {
1713
+ const token = this.#peekToken(offset);
1714
+ if (token.kind === "eof")
1715
+ return false;
1716
+ if (token.value === "(" || token.value === "[") {
1717
+ nesting += 1;
1718
+ continue;
1719
+ }
1720
+ if (token.value === "]") {
1721
+ nesting -= 1;
1722
+ continue;
1723
+ }
1724
+ if (token.value === ")") {
1725
+ if (nesting === 1)
1726
+ return !sawTopLevelToken;
1727
+ nesting -= 1;
1728
+ continue;
1729
+ }
1730
+ if (nesting !== 1)
1731
+ continue;
1732
+ if (!sawTopLevelToken && this.#isWord(token, "RETURNING"))
1733
+ return true;
1734
+ sawTopLevelToken = true;
1735
+ if (token.value === ":" || this.#isWord(token, "VALUE"))
1736
+ return true;
1737
+ if (token.value === ",")
1738
+ return false;
1739
+ }
1740
+ }
1741
+ #parseJsonObject(start) {
1742
+ this.#expectPunctuation("(");
1743
+ const entries = [];
1744
+ if (this.#current().value !== ")" && !this.#isWord(this.#current(), "RETURNING")) {
1745
+ do {
1746
+ const key = this.#parseExpression();
1747
+ if (!this.#matchWord("VALUE"))
1748
+ this.#expectPunctuation(":");
1749
+ const value = this.#parseJsonValueExpression();
1750
+ entries.push({ key, value, range: mergeRanges(key.range, value.range) });
1751
+ } while (this.#matchPunctuation(","));
1752
+ }
1753
+ const nullPolicy = this.#parseJsonConstructorNullPolicy("null");
1754
+ const uniqueKeys = this.#parseJsonUniqueKeys();
1755
+ const returning = this.#parseJsonReturning();
1756
+ const close = this.#expectPunctuation(")");
1757
+ return {
1758
+ kind: "json-object",
1759
+ entries,
1760
+ nullPolicy,
1761
+ uniqueKeys,
1762
+ ...(returning === undefined ? {} : { returning }),
1763
+ range: mergeRanges(start.range, close.range),
1764
+ };
1765
+ }
1766
+ #parseJsonArray(start) {
1767
+ this.#expectPunctuation("(");
1768
+ const values = [];
1769
+ let query;
1770
+ let queryFormat;
1771
+ let nullPolicy = "absent";
1772
+ if (this.#isStatementStart()) {
1773
+ const previousStop = this.#stopSelectListBeforeJsonFormat;
1774
+ this.#stopSelectListBeforeJsonFormat = true;
1775
+ let statement;
1776
+ try {
1777
+ statement = this.#parseStatement();
1778
+ }
1779
+ finally {
1780
+ this.#stopSelectListBeforeJsonFormat = previousStop;
1781
+ }
1782
+ if (statement.kind !== "select")
1783
+ throw this.#error("JSON_ARRAY query must be SELECT", statement.range);
1784
+ query = statement;
1785
+ queryFormat = this.#parseJsonFormat();
1786
+ }
1787
+ else if (this.#current().value !== ")" && !this.#isWord(this.#current(), "RETURNING")) {
1788
+ do
1789
+ values.push(this.#parseJsonValueExpression());
1790
+ while (this.#matchPunctuation(","));
1791
+ nullPolicy = this.#parseJsonConstructorNullPolicy("absent");
1792
+ }
1793
+ const returning = this.#parseJsonReturning();
1794
+ const close = this.#expectPunctuation(")");
1795
+ return {
1796
+ kind: "json-array",
1797
+ values,
1798
+ ...(query === undefined ? {} : { query }),
1799
+ ...(queryFormat === undefined ? {} : { queryFormat }),
1800
+ nullPolicy,
1801
+ ...(returning === undefined ? {} : { returning }),
1802
+ range: mergeRanges(start.range, close.range),
1803
+ };
1804
+ }
1805
+ #parseJsonObjectAggregate(start) {
1806
+ this.#expectPunctuation("(");
1807
+ const key = this.#parseExpression();
1808
+ if (!this.#matchWord("VALUE"))
1809
+ this.#expectPunctuation(":");
1810
+ const value = this.#parseJsonValueExpression();
1811
+ const nullPolicy = this.#parseJsonConstructorNullPolicy("null");
1812
+ const uniqueKeys = this.#parseJsonUniqueKeys();
1813
+ const returning = this.#parseJsonReturning();
1814
+ const close = this.#expectPunctuation(")");
1815
+ const suffix = this.#parseAggregateSuffix(close);
1816
+ return {
1817
+ kind: "json-object-aggregate",
1818
+ key,
1819
+ value,
1820
+ nullPolicy,
1821
+ uniqueKeys,
1822
+ ...(returning === undefined ? {} : { returning }),
1823
+ ...suffix,
1824
+ range: mergeRanges(start.range, suffix.end.range),
1825
+ };
1826
+ }
1827
+ #parseJsonArrayAggregate(start) {
1828
+ this.#expectPunctuation("(");
1829
+ const value = this.#parseJsonValueExpression();
1830
+ let orderBy = [];
1831
+ if (this.#matchKeyword("ORDER")) {
1832
+ this.#expectKeyword("BY");
1833
+ orderBy = this.#parseOrderByList();
1834
+ }
1835
+ const nullPolicy = this.#parseJsonConstructorNullPolicy("absent");
1836
+ const returning = this.#parseJsonReturning();
1837
+ const close = this.#expectPunctuation(")");
1838
+ const suffix = this.#parseAggregateSuffix(close);
1839
+ return {
1840
+ kind: "json-array-aggregate",
1841
+ value,
1842
+ orderBy,
1843
+ nullPolicy,
1844
+ ...(returning === undefined ? {} : { returning }),
1845
+ ...suffix,
1846
+ range: mergeRanges(start.range, suffix.end.range),
1847
+ };
1848
+ }
1849
+ #parseAggregateSuffix(close) {
1850
+ let end = close;
1851
+ let filter;
1852
+ if (this.#syntax !== "mysql" && this.#matchKeyword("FILTER")) {
1853
+ this.#expectPunctuation("(");
1854
+ this.#expectKeyword("WHERE");
1855
+ filter = this.#parseExpression();
1856
+ end = this.#expectPunctuation(")");
1857
+ }
1858
+ let over;
1859
+ if (this.#matchKeyword("OVER")) {
1860
+ if (this.#current().kind === "identifier" || this.#current().kind === "quoted-identifier") {
1861
+ over = this.#parseIdentifier();
1862
+ }
1863
+ else {
1864
+ over = this.#parseWindowSpecification();
1865
+ }
1866
+ end = { ...end, range: over.range };
1867
+ }
1868
+ return {
1869
+ ...(filter === undefined ? {} : { filter }),
1870
+ ...(over === undefined ? {} : { over }),
1871
+ end,
1872
+ };
1873
+ }
1874
+ #parseJsonParse(start) {
1875
+ this.#expectPunctuation("(");
1876
+ const value = this.#parseJsonValueExpression();
1877
+ const uniqueKeys = this.#parseJsonUniqueKeys();
1878
+ const close = this.#expectPunctuation(")");
1879
+ return { kind: "json-parse", value, uniqueKeys, range: mergeRanges(start.range, close.range) };
1880
+ }
1881
+ #parseJsonScalar(start) {
1882
+ this.#expectPunctuation("(");
1883
+ const expression = this.#parseExpression();
1884
+ const close = this.#expectPunctuation(")");
1885
+ return { kind: "json-scalar", expression, range: mergeRanges(start.range, close.range) };
1886
+ }
1887
+ #parseJsonSerialize(start) {
1888
+ this.#expectPunctuation("(");
1889
+ const value = this.#parseJsonValueExpression();
1890
+ const returning = this.#parseJsonReturning();
1891
+ const close = this.#expectPunctuation(")");
1892
+ return {
1893
+ kind: "json-serialize",
1894
+ value,
1895
+ ...(returning === undefined ? {} : { returning }),
1896
+ range: mergeRanges(start.range, close.range),
1897
+ };
1898
+ }
1899
+ #parseJsonConstructorNullPolicy(defaultPolicy) {
1900
+ const nullPolicy = this.#isWord(this.#current(), "NULL")
1901
+ ? "null"
1902
+ : this.#isWord(this.#current(), "ABSENT")
1903
+ ? "absent"
1904
+ : undefined;
1905
+ if (nullPolicy === undefined ||
1906
+ !this.#isWord(this.#peekToken(1), "ON") ||
1907
+ !this.#isWord(this.#peekToken(2), "NULL")) {
1908
+ return defaultPolicy;
1909
+ }
1910
+ this.#advance();
1911
+ this.#expectKeyword("ON");
1912
+ this.#expectKeyword("NULL");
1913
+ return nullPolicy;
1914
+ }
1915
+ #parseJsonUniqueKeys() {
1916
+ if ((!this.#isWord(this.#current(), "WITH") && !this.#isWord(this.#current(), "WITHOUT")) ||
1917
+ !this.#isWord(this.#peekToken(1), "UNIQUE")) {
1918
+ return false;
1919
+ }
1920
+ const unique = this.#matchWord("WITH");
1921
+ if (!unique)
1922
+ this.#expectWord("WITHOUT");
1923
+ this.#expectWord("UNIQUE");
1924
+ this.#matchWord("KEYS");
1925
+ return unique;
1926
+ }
1927
+ #parseJsonReturning() {
1928
+ if (!this.#matchKeyword("RETURNING"))
1929
+ return undefined;
1930
+ const start = this.#previous();
1931
+ const databaseType = this.#parseTypeName(false, () => this.#isWord(this.#current(), "FORMAT"));
1932
+ const format = this.#parseJsonFormat();
1933
+ return {
1934
+ databaseType,
1935
+ ...(format === undefined ? {} : { format }),
1936
+ range: mergeRanges(start.range, format?.range ?? databaseType.range),
1937
+ };
1938
+ }
1939
+ #parseJsonExists(start) {
1940
+ this.#expectPunctuation("(");
1941
+ const context = this.#parseJsonValueExpression();
1942
+ this.#expectPunctuation(",");
1943
+ const path = this.#parseExpression();
1944
+ const passing = this.#parseJsonPassing();
1945
+ let onError;
1946
+ if (["TRUE", "FALSE", "UNKNOWN", "ERROR"].some((word) => this.#isWord(this.#current(), word)) &&
1947
+ this.#isWord(this.#peekToken(1), "ON") &&
1948
+ this.#isWord(this.#peekToken(2), "ERROR")) {
1949
+ onError = this.#advance().value.toLowerCase();
1950
+ this.#expectKeyword("ON");
1951
+ this.#expectWord("ERROR");
1952
+ }
1953
+ const close = this.#expectPunctuation(")");
1954
+ return {
1955
+ kind: "json-exists",
1956
+ context,
1957
+ path,
1958
+ passing,
1959
+ ...(onError === undefined ? {} : { onError }),
1960
+ range: mergeRanges(start.range, close.range),
1961
+ };
1962
+ }
1963
+ #parseJsonQuery(start) {
1964
+ this.#expectPunctuation("(");
1965
+ const context = this.#parseJsonValueExpression();
1966
+ this.#expectPunctuation(",");
1967
+ const path = this.#parseExpression();
1968
+ const passing = this.#parseJsonPassing();
1969
+ let returning;
1970
+ if (this.#matchKeyword("RETURNING")) {
1971
+ const returningStart = this.#previous();
1972
+ const databaseType = this.#parseTypeName(false, () => this.#isJsonQueryClauseStart());
1973
+ const format = this.#parseJsonFormat();
1974
+ returning = {
1975
+ databaseType,
1976
+ ...(format === undefined ? {} : { format }),
1977
+ range: mergeRanges(returningStart.range, format?.range ?? databaseType.range),
1978
+ };
1979
+ }
1980
+ const wrapper = this.#parseJsonWrapper();
1981
+ const quotes = this.#parseJsonQuotes();
1982
+ let onEmpty;
1983
+ let onError;
1984
+ if (this.#isJsonQueryBehaviorStart()) {
1985
+ const clause = this.#parseJsonBehaviorClause();
1986
+ if (clause.target === "empty")
1987
+ onEmpty = clause.behavior;
1988
+ else
1989
+ onError = clause.behavior;
1990
+ }
1991
+ if (onEmpty !== undefined && this.#isJsonQueryBehaviorStart()) {
1992
+ const clause = this.#parseJsonBehaviorClause();
1993
+ if (clause.target !== "error") {
1994
+ throw this.#error("JSON_QUERY ON EMPTY must precede ON ERROR", clause.behavior.range);
1995
+ }
1996
+ onError = clause.behavior;
1997
+ }
1998
+ const close = this.#expectPunctuation(")");
1999
+ return {
2000
+ kind: "json-query",
2001
+ context,
2002
+ path,
2003
+ passing,
2004
+ ...(returning === undefined ? {} : { returning }),
2005
+ ...(wrapper === undefined ? {} : { wrapper }),
2006
+ ...(quotes === undefined ? {} : { quotes }),
2007
+ ...(onEmpty === undefined ? {} : { onEmpty }),
2008
+ ...(onError === undefined ? {} : { onError }),
2009
+ range: mergeRanges(start.range, close.range),
2010
+ };
2011
+ }
2012
+ #parseJsonValueQuery(start) {
2013
+ this.#expectPunctuation("(");
2014
+ const context = this.#parseJsonValueExpression();
2015
+ this.#expectPunctuation(",");
2016
+ const path = this.#parseExpression();
2017
+ const passing = this.#parseJsonPassing();
2018
+ let returning;
2019
+ if (this.#matchKeyword("RETURNING")) {
2020
+ const returningStart = this.#previous();
2021
+ const databaseType = this.#parseTypeName(false, () => this.#isJsonQueryClauseStart());
2022
+ const format = this.#parseJsonFormat();
2023
+ returning = {
2024
+ databaseType,
2025
+ ...(format === undefined ? {} : { format }),
2026
+ range: mergeRanges(returningStart.range, format?.range ?? databaseType.range),
2027
+ };
2028
+ }
2029
+ let onEmpty;
2030
+ let onError;
2031
+ if (this.#isJsonQueryBehaviorStart()) {
2032
+ const clause = this.#parseJsonBehaviorClause();
2033
+ if (clause.target === "empty")
2034
+ onEmpty = clause.behavior;
2035
+ else
2036
+ onError = clause.behavior;
2037
+ }
2038
+ if (onEmpty !== undefined && this.#isJsonQueryBehaviorStart()) {
2039
+ const clause = this.#parseJsonBehaviorClause();
2040
+ if (clause.target !== "error") {
2041
+ throw this.#error("JSON_VALUE ON EMPTY must precede ON ERROR", clause.behavior.range);
2042
+ }
2043
+ onError = clause.behavior;
2044
+ }
2045
+ const close = this.#expectPunctuation(")");
2046
+ return {
2047
+ kind: "json-value",
2048
+ context,
2049
+ path,
2050
+ passing,
2051
+ ...(returning === undefined ? {} : { returning }),
2052
+ ...(onEmpty === undefined ? {} : { onEmpty }),
2053
+ ...(onError === undefined ? {} : { onError }),
2054
+ range: mergeRanges(start.range, close.range),
2055
+ };
2056
+ }
2057
+ #parseJsonPassing() {
2058
+ const passing = [];
2059
+ if (!this.#matchWord("PASSING"))
2060
+ return passing;
2061
+ do {
2062
+ const value = this.#parseJsonValueExpression();
2063
+ this.#expectKeyword("AS");
2064
+ const name = this.#parseIdentifier(true);
2065
+ passing.push({ value, name, range: mergeRanges(value.range, name.range) });
2066
+ } while (this.#matchPunctuation(","));
2067
+ return passing;
2068
+ }
2069
+ #parseJsonValueExpression() {
2070
+ const expression = this.#parseExpression();
2071
+ const format = this.#parseJsonFormat();
2072
+ if (format === undefined)
2073
+ return { expression, range: expression.range };
2074
+ return { expression, format, range: mergeRanges(expression.range, format.range) };
2075
+ }
2076
+ #parseJsonFormat() {
2077
+ if (!this.#matchWord("FORMAT"))
2078
+ return undefined;
2079
+ const formatStart = this.#previous();
2080
+ const json = this.#expectWord("JSON");
2081
+ let encoding;
2082
+ let end = json;
2083
+ if (this.#matchWord("ENCODING")) {
2084
+ const token = this.#current();
2085
+ const normalized = token.value.toUpperCase();
2086
+ if (!this.#isIdentifierLike(token) || !["UTF8", "UTF16", "UTF32"].includes(normalized)) {
2087
+ throw this.#error(`Unsupported JSON encoding ${token.text || "end of query"}`, token.range);
2088
+ }
2089
+ this.#advance();
2090
+ encoding = normalized;
2091
+ end = token;
2092
+ }
2093
+ return {
2094
+ ...(encoding === undefined ? {} : { encoding }),
2095
+ range: mergeRanges(formatStart.range, end.range),
2096
+ };
2097
+ }
2098
+ #isJsonQueryBehaviorStart() {
2099
+ return ["DEFAULT", "ERROR", "NULL", "EMPTY"].some((word) => this.#isWord(this.#current(), word));
2100
+ }
2101
+ #isJsonTableBehaviorStart() {
2102
+ return ["DEFAULT", "ERROR", "NULL", "TRUE", "FALSE", "UNKNOWN", "EMPTY"].some((word) => this.#isWord(this.#current(), word));
2103
+ }
2104
+ #parseJsonWrapper() {
2105
+ if (this.#matchWord("WITHOUT")) {
2106
+ this.#matchKeyword("ARRAY");
2107
+ this.#expectWord("WRAPPER");
2108
+ return "without";
2109
+ }
2110
+ if (!this.#matchWord("WITH"))
2111
+ return undefined;
2112
+ const wrapper = this.#matchWord("CONDITIONAL") ? "conditional" : "unconditional";
2113
+ if (wrapper === "unconditional")
2114
+ this.#matchWord("UNCONDITIONAL");
2115
+ this.#matchKeyword("ARRAY");
2116
+ this.#expectWord("WRAPPER");
2117
+ return wrapper;
2118
+ }
2119
+ #parseJsonQuotes() {
2120
+ if (!this.#matchWord("KEEP") && !this.#matchWord("OMIT"))
2121
+ return undefined;
2122
+ const quotes = this.#previous().value.toLowerCase();
2123
+ this.#expectWord("QUOTES");
2124
+ if (this.#matchKeyword("ON")) {
2125
+ this.#expectWord("SCALAR");
2126
+ this.#expectWord("STRING");
2127
+ }
2128
+ return quotes;
2129
+ }
2130
+ #isJsonQueryClauseStart() {
2131
+ if (["FORMAT", "KEEP", "OMIT", "DEFAULT", "ERROR", "NULL", "EMPTY"].some((word) => this.#isWord(this.#current(), word))) {
2132
+ return true;
2133
+ }
2134
+ if (this.#isWord(this.#current(), "WITHOUT")) {
2135
+ return this.#isWord(this.#peekToken(1), "ARRAY") || this.#isWord(this.#peekToken(1), "WRAPPER");
2136
+ }
2137
+ if (!this.#isWord(this.#current(), "WITH"))
2138
+ return false;
2139
+ return ["CONDITIONAL", "UNCONDITIONAL", "ARRAY", "WRAPPER"].some((word) => this.#isWord(this.#peekToken(1), word));
2140
+ }
2141
+ #parseJsonBehaviorClause(allowTruthValues = false) {
2142
+ const start = this.#current();
2143
+ let behavior;
2144
+ if (this.#matchKeyword("DEFAULT")) {
2145
+ const expression = this.#parseExpression();
2146
+ behavior = { kind: "default", expression, range: mergeRanges(start.range, expression.range) };
2147
+ }
2148
+ else if (this.#matchWord("ERROR")) {
2149
+ behavior = { kind: "error", range: start.range };
2150
+ }
2151
+ else if (this.#matchKeyword("NULL")) {
2152
+ behavior = { kind: "null", range: start.range };
2153
+ }
2154
+ else if (allowTruthValues &&
2155
+ (this.#matchKeyword("TRUE") || this.#matchKeyword("FALSE") || this.#matchWord("UNKNOWN"))) {
2156
+ behavior = {
2157
+ kind: this.#previous().value.toLowerCase(),
2158
+ range: start.range,
2159
+ };
2160
+ }
2161
+ else {
2162
+ this.#expectWord("EMPTY");
2163
+ const object = this.#matchWord("OBJECT");
2164
+ if (!object)
2165
+ this.#matchKeyword("ARRAY");
2166
+ behavior = {
2167
+ kind: object ? "empty-object" : "empty-array",
2168
+ range: mergeRanges(start.range, this.#previous().range),
2169
+ };
2170
+ }
2171
+ this.#expectKeyword("ON");
2172
+ if (this.#matchWord("EMPTY"))
2173
+ return { behavior, target: "empty" };
2174
+ this.#expectWord("ERROR");
2175
+ return { behavior, target: "error" };
2176
+ }
2177
+ #parseJsonOnErrorBehavior() {
2178
+ const clause = this.#parseJsonBehaviorClause(true);
2179
+ if (clause.target !== "error") {
2180
+ throw this.#error("JSON_TABLE behavior must target ON ERROR", clause.behavior.range);
2181
+ }
2182
+ return clause.behavior;
2183
+ }
2184
+ #parseCall(schema, name) {
2185
+ const distinct = this.#matchKeyword("DISTINCT");
2186
+ const args = [];
2187
+ const argumentNames = [];
2188
+ let named = false;
2189
+ let variadic = false;
2190
+ let orderBy = [];
2191
+ let close;
2192
+ if (this.#matchPunctuation(")"))
2193
+ close = this.#previous();
2194
+ else {
2195
+ do {
2196
+ if (variadic)
2197
+ throw this.#error("VARIADIC must be the final function argument", this.#current().range);
2198
+ if (this.#matchKeyword("VARIADIC")) {
2199
+ if (named)
2200
+ throw this.#error("VARIADIC cannot follow a named function argument", this.#previous().range);
2201
+ variadic = true;
2202
+ argumentNames.push(undefined);
2203
+ args.push(this.#parseExpression());
2204
+ }
2205
+ else if (this.#isIdentifierLike(this.#current()) &&
2206
+ this.#peekToken(1).kind === "operator" &&
2207
+ (this.#peekToken(1).value === "=>" || this.#peekToken(1).value === ":=")) {
2208
+ const argumentName = this.#parseIdentifier(true);
2209
+ this.#advance();
2210
+ named = true;
2211
+ argumentNames.push(argumentName);
2212
+ args.push(this.#parseExpression());
2213
+ }
2214
+ else {
2215
+ if (named) {
2216
+ throw this.#error("Positional arguments cannot follow named function arguments", this.#current().range);
2217
+ }
2218
+ argumentNames.push(undefined);
2219
+ args.push(this.#parseExpression());
2220
+ }
2221
+ if (!this.#matchPunctuation(","))
2222
+ break;
2223
+ } while (this.#current().value !== "ORDER");
2224
+ if (this.#matchKeyword("ORDER")) {
2225
+ this.#expectKeyword("BY");
2226
+ orderBy = this.#parseOrderByList();
2227
+ }
2228
+ close = this.#expectPunctuation(")");
2229
+ }
2230
+ let withinGroup = [];
2231
+ if (this.#matchKeyword("WITHIN")) {
2232
+ this.#expectKeyword("GROUP");
2233
+ this.#expectPunctuation("(");
2234
+ this.#expectKeyword("ORDER");
2235
+ this.#expectKeyword("BY");
2236
+ withinGroup = this.#parseOrderByList();
2237
+ close = this.#expectPunctuation(")");
2238
+ }
2239
+ let filter;
2240
+ if (this.#syntax !== "mysql" && this.#matchKeyword("FILTER")) {
2241
+ this.#expectPunctuation("(");
2242
+ this.#expectKeyword("WHERE");
2243
+ filter = this.#parseExpression();
2244
+ close = this.#expectPunctuation(")");
2245
+ }
2246
+ let over;
2247
+ if (this.#matchKeyword("OVER")) {
2248
+ if (this.#current().kind === "identifier" || this.#current().kind === "quoted-identifier")
2249
+ over = this.#parseIdentifier();
2250
+ else
2251
+ over = this.#parseWindowSpecification();
2252
+ close = { ...close, range: over.range };
2253
+ }
2254
+ return {
2255
+ kind: "call",
2256
+ name,
2257
+ ...(schema === undefined ? {} : { schema }),
2258
+ arguments: args,
2259
+ ...(named ? { argumentNames } : {}),
2260
+ ...(variadic ? { variadic: true } : {}),
2261
+ distinct,
2262
+ ...(orderBy.length === 0 ? {} : { orderBy }),
2263
+ ...(withinGroup.length === 0 ? {} : { withinGroup }),
2264
+ ...(filter === undefined ? {} : { filter }),
2265
+ ...(over === undefined ? {} : { over }),
2266
+ range: mergeRanges(schema?.range ?? name.range, close.range),
2267
+ };
2268
+ }
2269
+ #parseWindowSpecification() {
2270
+ const start = this.#expectPunctuation("(").range;
2271
+ const base = this.#current().kind === "identifier" || this.#current().kind === "quoted-identifier"
2272
+ ? this.#parseIdentifier()
2273
+ : undefined;
2274
+ const partitionBy = [];
2275
+ let orderBy = [];
2276
+ if (this.#matchKeyword("PARTITION")) {
2277
+ this.#expectKeyword("BY");
2278
+ partitionBy.push(...this.#parseExpressionList());
2279
+ }
2280
+ if (this.#matchKeyword("ORDER")) {
2281
+ this.#expectKeyword("BY");
2282
+ orderBy = this.#parseOrderByList();
2283
+ }
2284
+ let frame;
2285
+ if (["ROWS", "RANGE", "GROUPS"].includes(this.#current().value)) {
2286
+ const frameStart = this.#advance();
2287
+ const unit = frameStart.value.toLowerCase();
2288
+ let frameBound;
2289
+ let end;
2290
+ if (this.#matchKeyword("BETWEEN")) {
2291
+ frameBound = this.#parseWindowFrameBound();
2292
+ this.#expectKeyword("AND");
2293
+ end = this.#parseWindowFrameBound();
2294
+ }
2295
+ else
2296
+ frameBound = this.#parseWindowFrameBound();
2297
+ let exclusion;
2298
+ if (this.#matchKeyword("EXCLUDE")) {
2299
+ if (this.#matchKeyword("CURRENT")) {
2300
+ this.#expectKeyword("ROW");
2301
+ exclusion = "current-row";
2302
+ }
2303
+ else if (this.#matchKeyword("GROUP"))
2304
+ exclusion = "group";
2305
+ else if (this.#matchKeyword("TIES"))
2306
+ exclusion = "ties";
2307
+ else {
2308
+ this.#expectKeyword("NO");
2309
+ this.#expectKeyword("OTHERS");
2310
+ exclusion = "no-others";
2311
+ }
2312
+ }
2313
+ frame = {
2314
+ unit,
2315
+ start: frameBound,
2316
+ ...(end === undefined ? {} : { end }),
2317
+ ...(exclusion === undefined ? {} : { exclusion }),
2318
+ range: mergeRanges(frameStart.range, this.#previous().range),
2319
+ };
2320
+ }
2321
+ const close = this.#expectPunctuation(")");
2322
+ return {
2323
+ ...(base === undefined ? {} : { base }),
2324
+ partitionBy,
2325
+ orderBy,
2326
+ ...(frame === undefined ? {} : { frame }),
2327
+ range: mergeRanges(start, close.range),
2328
+ };
2329
+ }
2330
+ #parseWindowFrameBound() {
2331
+ const start = this.#current().range;
2332
+ if (this.#matchKeyword("UNBOUNDED")) {
2333
+ if (this.#matchKeyword("PRECEDING"))
2334
+ return { kind: "unbounded-preceding", range: mergeRanges(start, this.#previous().range) };
2335
+ this.#expectKeyword("FOLLOWING");
2336
+ return { kind: "unbounded-following", range: mergeRanges(start, this.#previous().range) };
2337
+ }
2338
+ if (this.#matchKeyword("CURRENT")) {
2339
+ const end = this.#expectKeyword("ROW").range;
2340
+ return { kind: "current-row", range: mergeRanges(start, end) };
2341
+ }
2342
+ const expression = this.#parseExpression();
2343
+ if (this.#matchKeyword("PRECEDING")) {
2344
+ return { kind: "preceding", expression, range: mergeRanges(start, this.#previous().range) };
2345
+ }
2346
+ this.#expectKeyword("FOLLOWING");
2347
+ return { kind: "following", expression, range: mergeRanges(start, this.#previous().range) };
2348
+ }
2349
+ #parseCast(start) {
2350
+ this.#expectPunctuation("(");
2351
+ const expression = this.#parseExpression();
2352
+ this.#expectKeyword("AS");
2353
+ const databaseType = this.#parseTypeName(true);
2354
+ const close = this.#expectPunctuation(")");
2355
+ return { kind: "cast", expression, databaseType, syntax: "cast", range: mergeRanges(start, close.range) };
2356
+ }
2357
+ #isIntervalLiteralStart() {
2358
+ if (this.#current().value !== "INTERVAL")
2359
+ return false;
2360
+ if (this.#peekToken(1).kind === "string")
2361
+ return true;
2362
+ return (this.#peekToken(1).value === "(" &&
2363
+ this.#peekToken(2).kind === "number" &&
2364
+ this.#peekToken(3).value === ")" &&
2365
+ this.#peekToken(4).kind === "string");
2366
+ }
2367
+ #parseIntervalLiteral() {
2368
+ const start = this.#advance();
2369
+ let typeEnd = start;
2370
+ let typeName = start.text;
2371
+ let prefixPrecision = false;
2372
+ if (this.#current().value === "(") {
2373
+ const precision = this.#parseIntervalPrecision();
2374
+ typeEnd = precision.end;
2375
+ typeName += this.#source.slice(precision.start.range.start, precision.end.range.end);
2376
+ prefixPrecision = true;
2377
+ }
2378
+ const value = this.#expect("string", "interval string literal");
2379
+ let end = value;
2380
+ if (prefixPrecision && intervalFields.has(this.#current().value)) {
2381
+ throw this.#error("Interval fields cannot follow prefix precision", this.#current().range);
2382
+ }
2383
+ if (!prefixPrecision && intervalFields.has(this.#current().value)) {
2384
+ const qualifier = this.#parseIntervalFields();
2385
+ typeEnd = qualifier.end;
2386
+ typeName += ` ${qualifier.text}`;
2387
+ end = qualifier.end;
2388
+ if (this.#current().value === "(") {
2389
+ if (qualifier.endField !== "SECOND") {
2390
+ throw this.#error("Interval precision requires SECOND as the least significant field", this.#current().range);
2391
+ }
2392
+ const precision = this.#parseIntervalPrecision();
2393
+ typeEnd = precision.end;
2394
+ typeName += this.#source.slice(precision.start.range.start, precision.end.range.end);
2395
+ end = precision.end;
2396
+ }
2397
+ }
2398
+ return {
2399
+ kind: "cast",
2400
+ expression: { kind: "literal", value: value.value, range: value.range },
2401
+ databaseType: { name: typeName, range: mergeRanges(start.range, typeEnd.range) },
2402
+ syntax: "typed-literal",
2403
+ range: mergeRanges(start.range, end.range),
2404
+ };
2405
+ }
2406
+ #parseSimpleTypedLiteral() {
2407
+ const type = this.#advance();
2408
+ const value = this.#expect("string", `${type.value.toLowerCase()} string literal`);
2409
+ return {
2410
+ kind: "cast",
2411
+ expression: { kind: "literal", value: value.value, range: value.range },
2412
+ databaseType: { name: type.text, range: type.range },
2413
+ syntax: "typed-literal",
2414
+ range: mergeRanges(type.range, value.range),
2415
+ };
2416
+ }
2417
+ #parseIntervalFields() {
2418
+ const start = this.#current();
2419
+ if (!intervalFields.has(start.value)) {
2420
+ throw this.#error(`Expected interval field, found ${start.text || "end of query"}`, start.range);
2421
+ }
2422
+ this.#advance();
2423
+ let end = start;
2424
+ let endField = start.value;
2425
+ if (this.#matchWord("TO")) {
2426
+ const target = this.#current();
2427
+ if (!intervalFieldRanges.get(start.value)?.has(target.value)) {
2428
+ throw this.#error(`Invalid interval field range ${start.value} TO ${target.value}`, target.range);
2429
+ }
2430
+ end = this.#advance();
2431
+ endField = end.value;
2432
+ }
2433
+ return {
2434
+ text: this.#source.slice(start.range.start, end.range.end),
2435
+ end,
2436
+ endField,
2437
+ };
2438
+ }
2439
+ #parseIntervalPrecision() {
2440
+ const start = this.#expectPunctuation("(");
2441
+ const precision = this.#expect("number", "interval precision");
2442
+ if (!/^\d+$/u.test(precision.value)) {
2443
+ throw this.#error("Interval precision must be a non-negative integer", precision.range);
2444
+ }
2445
+ return { start, end: this.#expectPunctuation(")") };
2446
+ }
2447
+ #parseTypeName(stopAtClose, stopBefore) {
2448
+ const start = this.#current();
2449
+ if (!this.#isIdentifierLike(start))
2450
+ throw this.#error(`Expected identifier, found ${start.text || "end of query"}`, start.range);
2451
+ this.#advance();
2452
+ let end = start;
2453
+ let schemaSeparatorAllowed = true;
2454
+ if (start.value === "INTERVAL" && this.#current().value !== ".") {
2455
+ let prefixPrecision = false;
2456
+ if (this.#current().value === "(") {
2457
+ end = this.#parseIntervalPrecision().end;
2458
+ prefixPrecision = true;
2459
+ }
2460
+ if (prefixPrecision && intervalFields.has(this.#current().value)) {
2461
+ throw this.#error("Interval fields cannot follow prefix precision", this.#current().range);
2462
+ }
2463
+ if (!prefixPrecision && intervalFields.has(this.#current().value)) {
2464
+ const qualifier = this.#parseIntervalFields();
2465
+ end = qualifier.end;
2466
+ if (this.#current().value === "(") {
2467
+ if (qualifier.endField !== "SECOND") {
2468
+ throw this.#error("Interval precision requires SECOND as the least significant field", this.#current().range);
2469
+ }
2470
+ end = this.#parseIntervalPrecision().end;
2471
+ }
2472
+ }
2473
+ while (this.#matchPunctuation("["))
2474
+ end = this.#expectPunctuation("]");
2475
+ if (stopAtClose && this.#current().value !== ")") {
2476
+ throw this.#error(`Expected ) after type name, found ${this.#current().text}`, this.#current().range);
2477
+ }
2478
+ return {
2479
+ name: this.#source.slice(start.range.start, end.range.end).trim(),
2480
+ range: mergeRanges(start.range, end.range),
2481
+ };
2482
+ }
2483
+ while (true) {
2484
+ if (stopBefore?.() === true)
2485
+ break;
2486
+ if (schemaSeparatorAllowed && this.#matchPunctuation(".")) {
2487
+ this.#parseIdentifier(true);
2488
+ end = this.#previous();
2489
+ schemaSeparatorAllowed = false;
2490
+ continue;
2491
+ }
2492
+ schemaSeparatorAllowed = false;
2493
+ if (this.#matchPunctuation("(")) {
2494
+ let depth = 1;
2495
+ while (depth > 0) {
2496
+ const token = this.#current();
2497
+ if (token.kind === "eof")
2498
+ throw this.#error("Unterminated type modifier", token.range);
2499
+ this.#advance();
2500
+ if (token.value === "(")
2501
+ depth += 1;
2502
+ else if (token.value === ")")
2503
+ depth -= 1;
2504
+ end = token;
2505
+ }
2506
+ continue;
2507
+ }
2508
+ if (this.#isIdentifierLike(this.#current()) && typeContinuationWords.has(this.#current().value.toUpperCase())) {
2509
+ end = this.#advance();
2510
+ continue;
2511
+ }
2512
+ if (this.#matchPunctuation("[")) {
2513
+ end = this.#expectPunctuation("]");
2514
+ continue;
2515
+ }
2516
+ break;
2517
+ }
2518
+ if (stopAtClose && this.#current().value !== ")")
2519
+ throw this.#error(`Expected ) after type name, found ${this.#current().text}`, this.#current().range);
2520
+ return {
2521
+ name: this.#source.slice(start.range.start, end.range.end).trim(),
2522
+ range: mergeRanges(start.range, end.range),
2523
+ };
2524
+ }
2525
+ #parseCase(start) {
2526
+ const operand = this.#current().value === "WHEN" ? undefined : this.#parseExpression();
2527
+ const branches = [];
2528
+ while (this.#matchKeyword("WHEN")) {
2529
+ const whenStart = this.#previous().range;
2530
+ const when = this.#parseExpression();
2531
+ this.#expectKeyword("THEN");
2532
+ const then = this.#parseExpression();
2533
+ branches.push({ when, then, range: mergeRanges(whenStart, then.range) });
2534
+ }
2535
+ if (branches.length === 0)
2536
+ throw this.#error("CASE requires at least one WHEN branch", this.#current().range);
2537
+ const elseExpression = this.#matchKeyword("ELSE") ? this.#parseExpression() : undefined;
2538
+ const end = this.#expectKeyword("END");
2539
+ return {
2540
+ kind: "case",
2541
+ ...(operand === undefined ? {} : { operand }),
2542
+ branches,
2543
+ ...(elseExpression === undefined ? {} : { elseExpression }),
2544
+ range: mergeRanges(start, end.range),
2545
+ };
2546
+ }
2547
+ #parseIdentifier(allowKeyword = false) {
2548
+ const token = this.#current();
2549
+ if (!this.#isIdentifierLike(token) || (token.kind === "keyword" && !allowKeyword)) {
2550
+ throw this.#error(`Expected identifier, found ${token.text || "end of query"}`, token.range);
2551
+ }
2552
+ this.#advance();
2553
+ return { name: token.value, quoted: token.kind === "quoted-identifier", range: token.range };
2554
+ }
2555
+ #parseQualifiedIdentifier() {
2556
+ const first = this.#parseIdentifier(true);
2557
+ const parts = [first];
2558
+ if (this.#matchPunctuation("."))
2559
+ parts.push(this.#parseIdentifier(true));
2560
+ return { parts, range: mergeRanges(first.range, parts.at(-1).range) };
2561
+ }
2562
+ #isIdentifierLike(token) {
2563
+ return token.kind === "identifier" || token.kind === "quoted-identifier" || token.kind === "keyword";
2564
+ }
2565
+ #isStatementStart() {
2566
+ return ["SELECT", "INSERT", "UPDATE", "DELETE", "MERGE", "WITH"].includes(this.#current().value);
2567
+ }
2568
+ #isJsonArrayQueryFormatStart() {
2569
+ return (this.#stopSelectListBeforeJsonFormat &&
2570
+ this.#isWord(this.#current(), "FORMAT") &&
2571
+ this.#isWord(this.#peekToken(1), "JSON"));
2572
+ }
2573
+ #current() {
2574
+ return this.#cursor.current();
2575
+ }
2576
+ #peekToken(offset) {
2577
+ return this.#cursor.peek(offset);
2578
+ }
2579
+ #previous() {
2580
+ return this.#cursor.previous();
2581
+ }
2582
+ #advance() {
2583
+ return this.#cursor.advance();
2584
+ }
2585
+ #matchKeyword(keyword) {
2586
+ if (this.#current().kind === "keyword" && this.#current().value === keyword) {
2587
+ this.#advance();
2588
+ return true;
2589
+ }
2590
+ return false;
2591
+ }
2592
+ #matchWord(word) {
2593
+ if (this.#isWord(this.#current(), word)) {
2594
+ this.#advance();
2595
+ return true;
2596
+ }
2597
+ return false;
2598
+ }
2599
+ #isWord(token, word) {
2600
+ return token.kind !== "quoted-identifier" && this.#isIdentifierLike(token) && token.value.toUpperCase() === word;
2601
+ }
2602
+ #matchOperator(operator) {
2603
+ if (this.#current().kind === "operator" && this.#current().value === operator) {
2604
+ this.#advance();
2605
+ return true;
2606
+ }
2607
+ return false;
2608
+ }
2609
+ #matchPunctuation(value) {
2610
+ if (this.#current().kind === "punctuation" && this.#current().value === value) {
2611
+ this.#advance();
2612
+ return true;
2613
+ }
2614
+ return false;
2615
+ }
2616
+ #expectKeyword(keyword) {
2617
+ const token = this.#current();
2618
+ if (!this.#matchKeyword(keyword))
2619
+ throw this.#error(`Expected ${keyword}, found ${token.text || "end of query"}`, token.range);
2620
+ return token;
2621
+ }
2622
+ #expectWord(word) {
2623
+ const token = this.#current();
2624
+ if (!this.#matchWord(word))
2625
+ throw this.#error(`Expected ${word}, found ${token.text || "end of query"}`, token.range);
2626
+ return token;
2627
+ }
2628
+ #expectOperator(operator) {
2629
+ const token = this.#current();
2630
+ if (!this.#matchOperator(operator))
2631
+ throw this.#error(`Expected ${operator}, found ${token.text || "end of query"}`, token.range);
2632
+ return token;
2633
+ }
2634
+ #expectPunctuation(value) {
2635
+ const token = this.#current();
2636
+ if (!this.#matchPunctuation(value))
2637
+ throw this.#error(`Expected ${value}, found ${token.text || "end of query"}`, token.range);
2638
+ return token;
2639
+ }
2640
+ #expect(kind, label) {
2641
+ const token = this.#current();
2642
+ if (token.kind !== kind)
2643
+ throw this.#error(`Expected ${label}, found ${token.text || "end of query"}`, token.range);
2644
+ this.#advance();
2645
+ return token;
2646
+ }
2647
+ #nested(fn) {
2648
+ return this.#cursor.nested(fn);
2649
+ }
2650
+ #error(message, range, code = "TSQ001") {
2651
+ return new SqlParseError(message, range, code);
2652
+ }
2653
+ }
2654
+ function deepFreeze(value, seen = new Set()) {
2655
+ if (typeof value !== "object" || value === null || seen.has(value))
2656
+ return value;
2657
+ seen.add(value);
2658
+ for (const nested of Object.values(value))
2659
+ deepFreeze(nested, seen);
2660
+ return Object.freeze(value);
2661
+ }
2662
+ function parse(source, options) {
2663
+ try {
2664
+ return deepFreeze(new Parser(source, options).parse());
2665
+ }
2666
+ catch (error) {
2667
+ if (error instanceof SqlTokenizeError)
2668
+ throw new SqlParseError(error.message, error.range, error.code);
2669
+ if (error instanceof SqlToolkitError)
2670
+ throw new SqlParseError(error.message, error.range, error.code);
2671
+ throw error;
2672
+ }
2673
+ }
2674
+ export function parseStatement(source, options = {}) {
2675
+ return parse(source, options);
2676
+ }
2677
+ export function parseSelect(source, options = {}) {
2678
+ const statement = parse(source, options);
2679
+ if (statement.kind !== "select")
2680
+ throw new SqlParseError(`Expected SELECT, found ${statement.kind.toUpperCase()}`, statement.range);
2681
+ return statement;
2682
+ }
2683
+ //# sourceMappingURL=parser.js.map