@yanit/jsondb 0.1.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 (118) hide show
  1. package/README.md +903 -0
  2. package/dist/bin/cli-export.d.ts +7 -0
  3. package/dist/bin/cli-export.d.ts.map +1 -0
  4. package/dist/bin/cli-export.js +318 -0
  5. package/dist/bin/cli-export.js.map +1 -0
  6. package/dist/bin/cli-import.d.ts +7 -0
  7. package/dist/bin/cli-import.d.ts.map +1 -0
  8. package/dist/bin/cli-import.js +298 -0
  9. package/dist/bin/cli-import.js.map +1 -0
  10. package/dist/bin/server.d.ts +7 -0
  11. package/dist/bin/server.d.ts.map +1 -0
  12. package/dist/bin/server.js +92 -0
  13. package/dist/bin/server.js.map +1 -0
  14. package/dist/examples/sql-example.d.ts +7 -0
  15. package/dist/examples/sql-example.d.ts.map +1 -0
  16. package/dist/examples/sql-example.js +131 -0
  17. package/dist/examples/sql-example.js.map +1 -0
  18. package/dist/src/BulkOp.d.ts +74 -0
  19. package/dist/src/BulkOp.d.ts.map +1 -0
  20. package/dist/src/BulkOp.js +143 -0
  21. package/dist/src/BulkOp.js.map +1 -0
  22. package/dist/src/Collection.d.ts +232 -0
  23. package/dist/src/Collection.d.ts.map +1 -0
  24. package/dist/src/Collection.js +705 -0
  25. package/dist/src/Collection.js.map +1 -0
  26. package/dist/src/Cursor.d.ts +94 -0
  27. package/dist/src/Cursor.d.ts.map +1 -0
  28. package/dist/src/Cursor.js +259 -0
  29. package/dist/src/Cursor.js.map +1 -0
  30. package/dist/src/Database.d.ts +98 -0
  31. package/dist/src/Database.d.ts.map +1 -0
  32. package/dist/src/Database.js +198 -0
  33. package/dist/src/Database.js.map +1 -0
  34. package/dist/src/Operators.d.ts +73 -0
  35. package/dist/src/Operators.d.ts.map +1 -0
  36. package/dist/src/Operators.js +339 -0
  37. package/dist/src/Operators.js.map +1 -0
  38. package/dist/src/QueryCache.d.ts +87 -0
  39. package/dist/src/QueryCache.d.ts.map +1 -0
  40. package/dist/src/QueryCache.js +155 -0
  41. package/dist/src/QueryCache.js.map +1 -0
  42. package/dist/src/SQLExecutor.d.ts +60 -0
  43. package/dist/src/SQLExecutor.d.ts.map +1 -0
  44. package/dist/src/SQLExecutor.js +317 -0
  45. package/dist/src/SQLExecutor.js.map +1 -0
  46. package/dist/src/SQLParser.d.ts +181 -0
  47. package/dist/src/SQLParser.d.ts.map +1 -0
  48. package/dist/src/SQLParser.js +640 -0
  49. package/dist/src/SQLParser.js.map +1 -0
  50. package/dist/src/Schema.d.ts +92 -0
  51. package/dist/src/Schema.d.ts.map +1 -0
  52. package/dist/src/Schema.js +253 -0
  53. package/dist/src/Schema.js.map +1 -0
  54. package/dist/src/Transaction.d.ts +118 -0
  55. package/dist/src/Transaction.d.ts.map +1 -0
  56. package/dist/src/Transaction.js +233 -0
  57. package/dist/src/Transaction.js.map +1 -0
  58. package/dist/src/Utils.d.ts +68 -0
  59. package/dist/src/Utils.d.ts.map +1 -0
  60. package/dist/src/Utils.js +187 -0
  61. package/dist/src/Utils.js.map +1 -0
  62. package/dist/src/errors.d.ts +58 -0
  63. package/dist/src/errors.d.ts.map +1 -0
  64. package/dist/src/errors.js +85 -0
  65. package/dist/src/errors.js.map +1 -0
  66. package/dist/src/index.d.ts +39 -0
  67. package/dist/src/index.d.ts.map +1 -0
  68. package/dist/src/index.js +44 -0
  69. package/dist/src/index.js.map +1 -0
  70. package/dist/test/basic.test.d.ts +5 -0
  71. package/dist/test/basic.test.d.ts.map +1 -0
  72. package/dist/test/basic.test.js +283 -0
  73. package/dist/test/basic.test.js.map +1 -0
  74. package/dist/test/index.test.d.ts +5 -0
  75. package/dist/test/index.test.d.ts.map +1 -0
  76. package/dist/test/index.test.js +126 -0
  77. package/dist/test/index.test.js.map +1 -0
  78. package/dist/test/jsonb.test.d.ts +5 -0
  79. package/dist/test/jsonb.test.d.ts.map +1 -0
  80. package/dist/test/jsonb.test.js +165 -0
  81. package/dist/test/jsonb.test.js.map +1 -0
  82. package/dist/test/optimization.test.d.ts +6 -0
  83. package/dist/test/optimization.test.d.ts.map +1 -0
  84. package/dist/test/optimization.test.js +196 -0
  85. package/dist/test/optimization.test.js.map +1 -0
  86. package/dist/test/schema.test.d.ts +5 -0
  87. package/dist/test/schema.test.d.ts.map +1 -0
  88. package/dist/test/schema.test.js +197 -0
  89. package/dist/test/schema.test.js.map +1 -0
  90. package/dist/test/sql.test.d.ts +7 -0
  91. package/dist/test/sql.test.d.ts.map +1 -0
  92. package/dist/test/sql.test.js +21 -0
  93. package/dist/test/sql.test.js.map +1 -0
  94. package/package.json +73 -0
  95. package/src/BulkOp.js +181 -0
  96. package/src/BulkOp.ts +191 -0
  97. package/src/Collection.js +843 -0
  98. package/src/Collection.ts +896 -0
  99. package/src/Cursor.js +315 -0
  100. package/src/Cursor.ts +319 -0
  101. package/src/Database.js +244 -0
  102. package/src/Database.ts +268 -0
  103. package/src/Operators.js +382 -0
  104. package/src/Operators.ts +375 -0
  105. package/src/QueryCache.js +190 -0
  106. package/src/QueryCache.ts +208 -0
  107. package/src/SQLExecutor.ts +391 -0
  108. package/src/SQLParser.ts +814 -0
  109. package/src/Schema.js +292 -0
  110. package/src/Schema.ts +317 -0
  111. package/src/Transaction.js +291 -0
  112. package/src/Transaction.ts +313 -0
  113. package/src/Utils.js +205 -0
  114. package/src/Utils.ts +205 -0
  115. package/src/errors.js +93 -0
  116. package/src/errors.ts +93 -0
  117. package/src/index.js +90 -0
  118. package/src/index.ts +106 -0
@@ -0,0 +1,814 @@
1
+ /**
2
+ * SQL 解析器模块
3
+ * 支持标准 SQL 语法子集,转换为 JSONDB 查询操作
4
+ */
5
+
6
+ /**
7
+ * SQL 语句类型
8
+ */
9
+ export type SQLStatementType = 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE';
10
+
11
+ /**
12
+ * SQL 解析后的 SELECT 语句结构
13
+ */
14
+ export interface SelectStatement {
15
+ type: 'SELECT';
16
+ columns: string[];
17
+ table: string;
18
+ where?: WhereClause;
19
+ orderBy?: OrderByClause[];
20
+ limit?: number;
21
+ offset?: number;
22
+ groupBy?: string[];
23
+ having?: WhereClause;
24
+ distinct?: boolean;
25
+ }
26
+
27
+ /**
28
+ * SQL 解析后的 INSERT 语句结构
29
+ */
30
+ export interface InsertStatement {
31
+ type: 'INSERT';
32
+ table: string;
33
+ columns: string[];
34
+ values: unknown[][];
35
+ }
36
+
37
+ /**
38
+ * SQL 解析后的 UPDATE 语句结构
39
+ */
40
+ export interface UpdateStatement {
41
+ type: 'UPDATE';
42
+ table: string;
43
+ set: { column: string; value: unknown }[];
44
+ where?: WhereClause;
45
+ }
46
+
47
+ /**
48
+ * SQL 解析后的 DELETE 语句结构
49
+ */
50
+ export interface DeleteStatement {
51
+ type: 'DELETE';
52
+ table: string;
53
+ where?: WhereClause;
54
+ }
55
+
56
+ /**
57
+ * WHERE 子句结构
58
+ */
59
+ export type WhereClause =
60
+ | { type: 'condition'; column: string; operator: string; value: unknown }
61
+ | { type: 'and'; conditions: WhereClause[] }
62
+ | { type: 'or'; conditions: WhereClause[] }
63
+ | { type: 'not'; condition: WhereClause };
64
+
65
+ /**
66
+ * ORDER BY 子句结构
67
+ */
68
+ export interface OrderByClause {
69
+ column: string;
70
+ direction: 'ASC' | 'DESC';
71
+ }
72
+
73
+ /**
74
+ * SQL 语句联合类型
75
+ */
76
+ export type SQLStatement = SelectStatement | InsertStatement | UpdateStatement | DeleteStatement;
77
+
78
+ /**
79
+ * SQL 解析结果
80
+ */
81
+ export interface SQLParseResult {
82
+ success: boolean;
83
+ statement?: SQLStatement;
84
+ error?: string;
85
+ }
86
+
87
+ /**
88
+ * SQL 解析器类
89
+ */
90
+ export class SQLParser {
91
+ private sql: string = '';
92
+ private pos: number = 0;
93
+ private currentChar: string = '';
94
+
95
+ /**
96
+ * 解析 SQL 语句
97
+ */
98
+ parse(sql: string): SQLParseResult {
99
+ try {
100
+ this.sql = sql.trim();
101
+ this.pos = 0;
102
+ this.currentChar = this.sql[0] || '';
103
+
104
+ // 跳过空白字符
105
+ this.skipWhitespace();
106
+
107
+ // 获取第一个词判断语句类型
108
+ const firstWord = this.readWord().toUpperCase();
109
+
110
+ this.skipWhitespace();
111
+
112
+ switch (firstWord) {
113
+ case 'SELECT':
114
+ return { success: true, statement: this.parseSelect() };
115
+ case 'INSERT':
116
+ return { success: true, statement: this.parseInsert() };
117
+ case 'UPDATE':
118
+ return { success: true, statement: this.parseUpdate() };
119
+ case 'DELETE':
120
+ return { success: true, statement: this.parseDelete() };
121
+ default:
122
+ return { success: false, error: `不支持的 SQL 语句类型:${firstWord}` };
123
+ }
124
+ } catch (error) {
125
+ return {
126
+ success: false,
127
+ error: `SQL 解析错误:${(error as Error).message}`
128
+ };
129
+ }
130
+ }
131
+
132
+ /**
133
+ * 解析 SELECT 语句
134
+ */
135
+ private parseSelect(): SelectStatement {
136
+ const statement: SelectStatement = {
137
+ type: 'SELECT',
138
+ columns: [],
139
+ table: '',
140
+ distinct: false
141
+ };
142
+
143
+ // 检查 DISTINCT
144
+ if (this.peekWord().toUpperCase() === 'DISTINCT') {
145
+ this.readWord();
146
+ statement.distinct = true;
147
+ }
148
+
149
+ // 解析列
150
+ statement.columns = this.parseColumnList();
151
+
152
+ // 解析 FROM
153
+ this.skipWhitespace();
154
+ const fromWord = this.readWord().toUpperCase();
155
+ if (fromWord !== 'FROM') {
156
+ throw new Error(`期望 FROM 关键字,得到:${fromWord}`);
157
+ }
158
+
159
+ // 解析表名
160
+ this.skipWhitespace();
161
+ statement.table = this.readIdentifier();
162
+
163
+ // 解析可选子句
164
+ while (this.pos < this.sql.length) {
165
+ this.skipWhitespace();
166
+ if (this.pos >= this.sql.length) break;
167
+
168
+ const keyword = this.peekWord().toUpperCase();
169
+
170
+ switch (keyword) {
171
+ case 'WHERE':
172
+ this.readWord();
173
+ this.skipWhitespace();
174
+ statement.where = this.parseWhereClause();
175
+ break;
176
+ case 'GROUP':
177
+ this.readWord();
178
+ this.skipWhitespace();
179
+ const byWord = this.readWord().toUpperCase();
180
+ if (byWord !== 'BY') {
181
+ throw new Error('期望 GROUP BY');
182
+ }
183
+ this.skipWhitespace();
184
+ statement.groupBy = this.parseColumnList();
185
+ break;
186
+ case 'HAVING':
187
+ this.readWord();
188
+ this.skipWhitespace();
189
+ statement.having = this.parseWhereClause();
190
+ break;
191
+ case 'ORDER':
192
+ this.readWord();
193
+ this.skipWhitespace();
194
+ const orderByWord = this.readWord().toUpperCase();
195
+ if (orderByWord !== 'BY') {
196
+ throw new Error('期望 ORDER BY');
197
+ }
198
+ this.skipWhitespace();
199
+ statement.orderBy = this.parseOrderByList();
200
+ break;
201
+ case 'LIMIT':
202
+ this.readWord();
203
+ this.skipWhitespace();
204
+ statement.limit = this.readNumber();
205
+ break;
206
+ case 'OFFSET':
207
+ this.readWord();
208
+ this.skipWhitespace();
209
+ statement.offset = this.readNumber();
210
+ break;
211
+ default:
212
+ // 未知关键字,跳过
213
+ this.readWord();
214
+ }
215
+ }
216
+
217
+ return statement;
218
+ }
219
+
220
+ /**
221
+ * 解析 INSERT 语句
222
+ */
223
+ private parseInsert(): InsertStatement {
224
+ const statement: InsertStatement = {
225
+ type: 'INSERT',
226
+ table: '',
227
+ columns: [],
228
+ values: []
229
+ };
230
+
231
+ // 解析 INTO (可选)
232
+ const intoWord = this.peekWord().toUpperCase();
233
+ if (intoWord === 'INTO') {
234
+ this.readWord();
235
+ this.skipWhitespace();
236
+ }
237
+
238
+ // 解析表名
239
+ statement.table = this.readIdentifier();
240
+
241
+ // 解析列名
242
+ this.skipWhitespace();
243
+ if (this.currentChar === '(') {
244
+ this.readChar();
245
+ this.skipWhitespace();
246
+ statement.columns = this.parseColumnList();
247
+ this.skipWhitespace();
248
+ // 读取闭合括号
249
+ // @ts-ignore - 类型推断问题
250
+ if (this.sql[this.pos] === ')') {
251
+ this.readChar();
252
+ } else {
253
+ throw new Error('期望闭合括号 )');
254
+ }
255
+ }
256
+
257
+ // 解析 VALUES
258
+ this.skipWhitespace();
259
+ const valuesWord = this.readWord().toUpperCase();
260
+ if (valuesWord !== 'VALUES') {
261
+ throw new Error(`期望 VALUES 关键字,得到:${valuesWord}`);
262
+ }
263
+
264
+ // 解析值列表
265
+ this.skipWhitespace();
266
+ statement.values = this.parseValuesList();
267
+
268
+ return statement;
269
+ }
270
+
271
+ /**
272
+ * 解析 UPDATE 语句
273
+ */
274
+ private parseUpdate(): UpdateStatement {
275
+ const statement: UpdateStatement = {
276
+ type: 'UPDATE',
277
+ table: '',
278
+ set: []
279
+ };
280
+
281
+ // 解析表名
282
+ statement.table = this.readIdentifier();
283
+
284
+ // 解析 SET
285
+ this.skipWhitespace();
286
+ const setWord = this.readWord().toUpperCase();
287
+ if (setWord !== 'SET') {
288
+ throw new Error(`期望 SET 关键字,得到:${setWord}`);
289
+ }
290
+
291
+ // 解析 SET 子句
292
+ this.skipWhitespace();
293
+ statement.set = this.parseSetClause();
294
+
295
+ // 解析可选 WHERE
296
+ this.skipWhitespace();
297
+ if (this.peekWord().toUpperCase() === 'WHERE') {
298
+ this.readWord();
299
+ this.skipWhitespace();
300
+ statement.where = this.parseWhereClause();
301
+ }
302
+
303
+ return statement;
304
+ }
305
+
306
+ /**
307
+ * 解析 DELETE 语句
308
+ */
309
+ private parseDelete(): DeleteStatement {
310
+ const statement: DeleteStatement = {
311
+ type: 'DELETE',
312
+ table: ''
313
+ };
314
+
315
+ // 解析 FROM
316
+ const fromWord = this.peekWord().toUpperCase();
317
+ if (fromWord === 'FROM') {
318
+ this.readWord();
319
+ this.skipWhitespace();
320
+ }
321
+
322
+ // 解析表名
323
+ statement.table = this.readIdentifier();
324
+
325
+ // 解析可选 WHERE
326
+ this.skipWhitespace();
327
+ if (this.peekWord().toUpperCase() === 'WHERE') {
328
+ this.readWord();
329
+ this.skipWhitespace();
330
+ statement.where = this.parseWhereClause();
331
+ }
332
+
333
+ return statement;
334
+ }
335
+
336
+ /**
337
+ * 解析列名列表
338
+ */
339
+ private parseColumnList(): string[] {
340
+ const columns: string[] = [];
341
+
342
+ // 处理 * 情况
343
+ if (this.currentChar === '*') {
344
+ this.readChar();
345
+ return ['*'];
346
+ }
347
+
348
+ columns.push(this.readIdentifier());
349
+
350
+ while (true) {
351
+ this.skipWhitespace();
352
+ if (this.currentChar === ',') {
353
+ this.readChar();
354
+ this.skipWhitespace();
355
+ columns.push(this.readIdentifier());
356
+ } else {
357
+ break;
358
+ }
359
+ }
360
+
361
+ return columns;
362
+ }
363
+
364
+ /**
365
+ * 解析 WHERE 子句
366
+ */
367
+ private parseWhereClause(): WhereClause {
368
+ const conditions = this.parseCondition();
369
+ return conditions;
370
+ }
371
+
372
+ /**
373
+ * 解析条件(支持 AND/OR)
374
+ */
375
+ private parseCondition(): WhereClause {
376
+ const left = this.parseSimpleCondition();
377
+
378
+ this.skipWhitespace();
379
+ const keyword = this.peekWord().toUpperCase();
380
+
381
+ if (keyword === 'AND') {
382
+ this.readWord();
383
+ this.skipWhitespace();
384
+ const right = this.parseCondition();
385
+ return {
386
+ type: 'and',
387
+ conditions: [left, right]
388
+ };
389
+ } else if (keyword === 'OR') {
390
+ this.readWord();
391
+ this.skipWhitespace();
392
+ const right = this.parseCondition();
393
+ return {
394
+ type: 'or',
395
+ conditions: [left, right]
396
+ };
397
+ }
398
+
399
+ return left;
400
+ }
401
+
402
+ /**
403
+ * 解析简单条件
404
+ */
405
+ private parseSimpleCondition(): WhereClause {
406
+ // 处理括号
407
+ this.skipWhitespace();
408
+ if (this.currentChar === '(') {
409
+ this.readChar();
410
+ const condition = this.parseCondition();
411
+ this.skipWhitespace();
412
+ // @ts-ignore - 类型推断问题
413
+ if (this.sql[this.pos] === ')') {
414
+ this.readChar();
415
+ }
416
+ return condition;
417
+ }
418
+
419
+ // 处理 NOT
420
+ if (this.peekWord().toUpperCase() === 'NOT') {
421
+ this.readWord();
422
+ this.skipWhitespace();
423
+ const condition = this.parseSimpleCondition();
424
+ return { type: 'not', condition };
425
+ }
426
+
427
+ const column = this.readIdentifier();
428
+ this.skipWhitespace();
429
+
430
+ // 解析操作符
431
+ let operator = this.readOperator();
432
+ this.skipWhitespace();
433
+
434
+ // 解析值
435
+ const value = this.readValue();
436
+
437
+ return {
438
+ type: 'condition',
439
+ column,
440
+ operator,
441
+ value
442
+ };
443
+ }
444
+
445
+ /**
446
+ * 解析操作符
447
+ */
448
+ private readOperator(): string {
449
+ this.skipWhitespace();
450
+ let op = '';
451
+
452
+ // 双字符操作符
453
+ if (this.currentChar === '=' && this.peekChar(1) !== '=') {
454
+ this.readChar();
455
+ return '=';
456
+ }
457
+ if (this.currentChar === '<' && this.peekChar(1) === '=') {
458
+ this.readChar();
459
+ this.readChar();
460
+ return '<=';
461
+ }
462
+ if (this.currentChar === '>' && this.peekChar(1) === '=') {
463
+ this.readChar();
464
+ this.readChar();
465
+ return '>=';
466
+ }
467
+ if (this.currentChar === '!' && this.peekChar(1) === '=') {
468
+ this.readChar();
469
+ this.readChar();
470
+ return '!=';
471
+ }
472
+ if (this.currentChar === '<' && this.peekChar(1) === '>') {
473
+ this.readChar();
474
+ this.readChar();
475
+ return '<>';
476
+ }
477
+
478
+ // 单字符操作符
479
+ if (['=', '<', '>', '!'].includes(this.currentChar)) {
480
+ op = this.currentChar;
481
+ this.readChar();
482
+ return op;
483
+ }
484
+
485
+ // 单词操作符 (LIKE, IN, IS, BETWEEN)
486
+ // 先检查是否是字母开头,避免遇到引号
487
+ if (/[a-zA-Z]/.test(this.currentChar)) {
488
+ const word = this.readWord().toUpperCase();
489
+ if (['LIKE', 'IN', 'IS', 'BETWEEN'].includes(word)) {
490
+ return word;
491
+ }
492
+ // 如果不是已知操作符,可能是值的一部分,回退
493
+ throw new Error(`未知操作符:${word}`);
494
+ }
495
+
496
+ throw new Error(`未知操作符:${this.currentChar}`);
497
+ }
498
+
499
+ /**
500
+ * 解析值
501
+ */
502
+ private readValue(): unknown {
503
+ this.skipWhitespace();
504
+
505
+ // NULL
506
+ if (this.peekWord().toUpperCase() === 'NULL') {
507
+ this.readWord();
508
+ return null;
509
+ }
510
+
511
+ // TRUE
512
+ if (this.peekWord().toUpperCase() === 'TRUE') {
513
+ this.readWord();
514
+ return true;
515
+ }
516
+
517
+ // FALSE
518
+ if (this.peekWord().toUpperCase() === 'FALSE') {
519
+ this.readWord();
520
+ return false;
521
+ }
522
+
523
+ // 数组 (value1, value2, ...)
524
+ if (this.currentChar === '(') {
525
+ this.readChar();
526
+ this.skipWhitespace();
527
+ const values: unknown[] = [];
528
+
529
+ // @ts-ignore - 类型推断问题
530
+ while (this.sql[this.pos] !== ')') {
531
+ values.push(this.readValue());
532
+ this.skipWhitespace();
533
+ // @ts-ignore - 类型推断问题
534
+ if (this.sql[this.pos] === ',') {
535
+ this.readChar();
536
+ this.skipWhitespace();
537
+ }
538
+ }
539
+
540
+ // @ts-ignore - 类型推断问题
541
+ if (this.sql[this.pos] === ')') {
542
+ this.readChar();
543
+ }
544
+
545
+ return values;
546
+ }
547
+
548
+ // 字符串
549
+ if (this.currentChar === "'" || this.currentChar === '"') {
550
+ return this.readString();
551
+ }
552
+
553
+ // 数字
554
+ if (this.isDigit(this.currentChar) || (this.currentChar === '-' && this.isDigit(this.peekChar(1)))) {
555
+ return this.readNumber();
556
+ }
557
+
558
+ // 标识符
559
+ return this.readIdentifier();
560
+ }
561
+
562
+ /**
563
+ * 解析 SET 子句
564
+ */
565
+ private parseSetClause(): { column: string; value: unknown }[] {
566
+ const set: { column: string; value: unknown }[] = [];
567
+
568
+ set.push({
569
+ column: this.readIdentifier(),
570
+ value: this.parseSetValue()
571
+ });
572
+
573
+ while (true) {
574
+ this.skipWhitespace();
575
+ if (this.currentChar === ',') {
576
+ this.readChar();
577
+ this.skipWhitespace();
578
+ set.push({
579
+ column: this.readIdentifier(),
580
+ value: this.parseSetValue()
581
+ });
582
+ } else {
583
+ break;
584
+ }
585
+ }
586
+
587
+ return set;
588
+ }
589
+
590
+ /**
591
+ * 解析 SET 值
592
+ */
593
+ private parseSetValue(): unknown {
594
+ this.skipWhitespace();
595
+ if (this.currentChar === '=') {
596
+ this.readChar();
597
+ }
598
+ this.skipWhitespace();
599
+ return this.readValue();
600
+ }
601
+
602
+ /**
603
+ * 解析值列表
604
+ */
605
+ private parseValuesList(): unknown[][] {
606
+ const values: unknown[][] = [];
607
+
608
+ values.push(this.parseValueRow());
609
+
610
+ while (true) {
611
+ this.skipWhitespace();
612
+ if (this.currentChar === ',') {
613
+ this.readChar();
614
+ this.skipWhitespace();
615
+ values.push(this.parseValueRow());
616
+ } else {
617
+ break;
618
+ }
619
+ }
620
+
621
+ return values;
622
+ }
623
+
624
+ /**
625
+ * 解析单行值
626
+ */
627
+ private parseValueRow(): unknown[] {
628
+ const row: unknown[] = [];
629
+
630
+ this.skipWhitespace();
631
+ if (this.currentChar === '(') {
632
+ this.readChar();
633
+ this.skipWhitespace();
634
+ row.push(this.readValue());
635
+
636
+ while (true) {
637
+ this.skipWhitespace();
638
+ // @ts-ignore - 类型推断问题
639
+ if (this.sql[this.pos] === ',') {
640
+ this.readChar();
641
+ this.skipWhitespace();
642
+ row.push(this.readValue());
643
+ } else {
644
+ break;
645
+ }
646
+ }
647
+
648
+ this.skipWhitespace();
649
+ // @ts-ignore - 类型推断问题
650
+ if (this.sql[this.pos] === ')') {
651
+ this.readChar();
652
+ } else {
653
+ throw new Error('期望闭合括号 )');
654
+ }
655
+ }
656
+
657
+ return row;
658
+ }
659
+
660
+ /**
661
+ * 解析 ORDER BY 列表
662
+ */
663
+ private parseOrderByList(): OrderByClause[] {
664
+ const orderBy: OrderByClause[] = [];
665
+
666
+ orderBy.push(this.parseOrderByItem());
667
+
668
+ while (true) {
669
+ this.skipWhitespace();
670
+ if (this.currentChar === ',') {
671
+ this.readChar();
672
+ this.skipWhitespace();
673
+ orderBy.push(this.parseOrderByItem());
674
+ } else {
675
+ break;
676
+ }
677
+ }
678
+
679
+ return orderBy;
680
+ }
681
+
682
+ /**
683
+ * 解析单个 ORDER BY
684
+ */
685
+ private parseOrderByItem(): OrderByClause {
686
+ const column = this.readIdentifier();
687
+ this.skipWhitespace();
688
+
689
+ let direction: 'ASC' | 'DESC' = 'ASC';
690
+ const dirWord = this.peekWord().toUpperCase();
691
+ if (dirWord === 'ASC' || dirWord === 'DESC') {
692
+ this.readWord();
693
+ direction = dirWord as 'ASC' | 'DESC';
694
+ }
695
+
696
+ return { column, direction };
697
+ }
698
+
699
+ // ========== 词法分析辅助方法 ==========
700
+
701
+ private skipWhitespace(): void {
702
+ while (this.isWhitespace(this.currentChar)) {
703
+ this.pos++;
704
+ this.currentChar = this.sql[this.pos] || '';
705
+ }
706
+ }
707
+
708
+ private readChar(): string {
709
+ const char = this.currentChar;
710
+ this.pos++;
711
+ this.currentChar = this.sql[this.pos] || '';
712
+ return char;
713
+ }
714
+
715
+ private peekChar(offset: number = 0): string {
716
+ return this.sql[this.pos + offset] || '';
717
+ }
718
+
719
+ private readWord(): string {
720
+ let word = '';
721
+ while (this.isWordChar(this.currentChar)) {
722
+ word += this.readChar();
723
+ }
724
+ return word;
725
+ }
726
+
727
+ private peekWord(): string {
728
+ const savedPos = this.pos;
729
+ const word = this.readWord();
730
+ this.pos = savedPos;
731
+ this.currentChar = this.sql[this.pos] || '';
732
+ return word;
733
+ }
734
+
735
+ private readIdentifier(): string {
736
+ this.skipWhitespace();
737
+
738
+ // 处理引号标识符
739
+ if (this.currentChar === '`' || this.currentChar === '"') {
740
+ const quote = this.readChar();
741
+ let identifier = '';
742
+ while (this.currentChar !== quote && this.pos < this.sql.length) {
743
+ identifier += this.readChar();
744
+ }
745
+ if (this.currentChar === quote) {
746
+ this.readChar();
747
+ }
748
+ return identifier;
749
+ }
750
+
751
+ return this.readWord();
752
+ }
753
+
754
+ private readString(): string {
755
+ const quote = this.readChar();
756
+ let str = '';
757
+ while (this.currentChar !== quote && this.pos < this.sql.length) {
758
+ if (this.currentChar === '\\' && this.peekChar(1) === quote) {
759
+ this.readChar();
760
+ str += this.readChar();
761
+ } else {
762
+ str += this.readChar();
763
+ }
764
+ }
765
+ if (this.currentChar === quote) {
766
+ this.readChar();
767
+ }
768
+ return str;
769
+ }
770
+
771
+ private readNumber(): number {
772
+ let numStr = '';
773
+
774
+ // 处理负数
775
+ if (this.currentChar === '-') {
776
+ numStr += this.readChar();
777
+ }
778
+
779
+ // 整数部分
780
+ while (this.isDigit(this.currentChar)) {
781
+ numStr += this.readChar();
782
+ }
783
+
784
+ // 小数部分
785
+ if (this.currentChar === '.' && this.isDigit(this.peekChar(1))) {
786
+ numStr += this.readChar();
787
+ while (this.isDigit(this.currentChar)) {
788
+ numStr += this.readChar();
789
+ }
790
+ }
791
+
792
+ return parseFloat(numStr);
793
+ }
794
+
795
+ private isWhitespace(char: string): boolean {
796
+ return char === ' ' || char === '\t' || char === '\n' || char === '\r';
797
+ }
798
+
799
+ private isWordChar(char: string): boolean {
800
+ return /[a-zA-Z0-9_]/.test(char);
801
+ }
802
+
803
+ private isDigit(char: string): boolean {
804
+ return /[0-9]/.test(char);
805
+ }
806
+ }
807
+
808
+ /**
809
+ * 解析 SQL 语句
810
+ */
811
+ export function parseSQL(sql: string): SQLParseResult {
812
+ const parser = new SQLParser();
813
+ return parser.parse(sql);
814
+ }