@checkdigit/eslint-athena-plugin 1.0.0-PR.2-dcdf

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 (66) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +17 -0
  3. package/SECURITY.md +13 -0
  4. package/dist-mjs/athena/api-locator.mjs +66 -0
  5. package/dist-mjs/athena/api-matcher.mjs +206 -0
  6. package/dist-mjs/athena/athena.mjs +165 -0
  7. package/dist-mjs/athena/column.mjs +1 -0
  8. package/dist-mjs/athena/context.mjs +21 -0
  9. package/dist-mjs/athena/index.mjs +1 -0
  10. package/dist-mjs/athena/service-table.mjs +45 -0
  11. package/dist-mjs/athena/sql-file.mjs +123 -0
  12. package/dist-mjs/athena/types.mjs +1 -0
  13. package/dist-mjs/athena/validate.mjs +619 -0
  14. package/dist-mjs/athena/visitor.mjs +291 -0
  15. package/dist-mjs/get-documentation-url.mjs +9 -0
  16. package/dist-mjs/index.mjs +56 -0
  17. package/dist-mjs/openapi/deref-schema.mjs +20 -0
  18. package/dist-mjs/openapi/generate-schema.mjs +375 -0
  19. package/dist-mjs/openapi/service-schema-generator.mjs +176 -0
  20. package/dist-mjs/peggy/athena-peggy.mjs +20700 -0
  21. package/dist-mjs/service.mjs +9 -0
  22. package/dist-mjs/sql-parser.mjs +28 -0
  23. package/dist-types/athena/api-locator.d.ts +2 -0
  24. package/dist-types/athena/api-matcher.d.ts +14 -0
  25. package/dist-types/athena/athena.d.ts +5 -0
  26. package/dist-types/athena/column.d.ts +1 -0
  27. package/dist-types/athena/context.d.ts +21 -0
  28. package/dist-types/athena/index.d.ts +8 -0
  29. package/dist-types/athena/service-table.d.ts +8 -0
  30. package/dist-types/athena/sql-file.d.ts +5 -0
  31. package/dist-types/athena/types.d.ts +493 -0
  32. package/dist-types/athena/validate.d.ts +14 -0
  33. package/dist-types/athena/visitor.d.ts +75 -0
  34. package/dist-types/get-documentation-url.d.ts +1 -0
  35. package/dist-types/index.d.ts +5 -0
  36. package/dist-types/openapi/deref-schema.d.ts +1 -0
  37. package/dist-types/openapi/generate-schema.d.ts +33 -0
  38. package/dist-types/openapi/service-schema-generator.d.ts +5 -0
  39. package/dist-types/peggy/athena-peggy.d.ts +13 -0
  40. package/dist-types/service.d.ts +2 -0
  41. package/dist-types/sql-parser.d.ts +25 -0
  42. package/package.json +1 -0
  43. package/src/api/v1/swagger.yml +619 -0
  44. package/src/api/v2/swagger.yml +477 -0
  45. package/src/athena/api-locator.ts +78 -0
  46. package/src/athena/api-matcher.ts +323 -0
  47. package/src/athena/athena.ts +224 -0
  48. package/src/athena/column.ts +4 -0
  49. package/src/athena/context.ts +47 -0
  50. package/src/athena/index.ts +13 -0
  51. package/src/athena/service-table.ts +78 -0
  52. package/src/athena/sql-file.ts +161 -0
  53. package/src/athena/types.ts +568 -0
  54. package/src/athena/validate.ts +902 -0
  55. package/src/athena/visitor.ts +406 -0
  56. package/src/get-documentation-url.ts +7 -0
  57. package/src/index.ts +67 -0
  58. package/src/openapi/deref-schema.ts +20 -0
  59. package/src/openapi/generate-schema.ts +553 -0
  60. package/src/openapi/service-schema-generator.ts +241 -0
  61. package/src/peggy/athena-peggy.ts +22149 -0
  62. package/src/peggy/athena.peggy +2971 -0
  63. package/src/service.ts +11 -0
  64. package/src/services/eslintAthenaPlugin/v1/swagger.schema.deref.json +1931 -0
  65. package/src/services/eslintAthenaPlugin/v2/swagger.schema.deref.json +978 -0
  66. package/src/sql-parser.ts +53 -0
@@ -0,0 +1,161 @@
1
+ // athena/sql-file.ts
2
+
3
+ /*
4
+ * Copyright (c) 2021-2026 Check Digit, LLC
5
+ *
6
+ * This code is licensed under the MIT license (see LICENSE.txt for details).
7
+ */
8
+
9
+ import debug from 'debug';
10
+ import { ESLintUtils } from '@typescript-eslint/utils';
11
+
12
+ import { parse } from '../peggy/athena-peggy.ts';
13
+ import type { AST } from './types';
14
+ import { createRootContext } from './context.ts';
15
+ import {
16
+ ATHENA_ERROR,
17
+ AthenaError,
18
+ checkAthenaAst,
19
+ offsetToLoc,
20
+ SYNTAXT_ERROR,
21
+ } from './validate.ts';
22
+
23
+ export const ruleId = 'sql-file';
24
+
25
+ const log = debug('eslint-athena-plugin:sql-file');
26
+ const createRule = ESLintUtils.RuleCreator((name) => name);
27
+
28
+ const rule: ESLintUtils.RuleModule<typeof SYNTAXT_ERROR | typeof ATHENA_ERROR> =
29
+ createRule({
30
+ name: ruleId,
31
+ meta: {
32
+ type: 'problem',
33
+ docs: {
34
+ description:
35
+ 'Validate plain .sql files against OpenAPI schemas at lint time',
36
+ },
37
+ schema: [],
38
+ messages: {
39
+ [SYNTAXT_ERROR]: `SyntaxError {{ errorMessage }}`,
40
+ [ATHENA_ERROR]: `AthenaError {{ errorMessage }}`,
41
+ },
42
+ },
43
+ defaultOptions: [],
44
+ create(context) {
45
+ return {
46
+ // Program fires once per file; the entire source text is the SQL to validate.
47
+ Program() {
48
+ const sql = context.sourceCode.getText();
49
+
50
+ if (
51
+ !/^\s*(?:SELECT\b[\s\S]*\bFROM\b|WITH\b[\s\S]*\bSELECT\b[\s\S]*\b)/iu.test(
52
+ sql,
53
+ )
54
+ ) {
55
+ log('skipping non-SELECT SQL', { filename: context.filename });
56
+ return;
57
+ }
58
+
59
+ let ast: AST;
60
+ try {
61
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
62
+ ({ ast } = parse(sql, { includeLocations: true }));
63
+ } catch (error) {
64
+ log('error parsing SQL', { error, filename: context.filename });
65
+ const pegLoc = (
66
+ error as {
67
+ location?: {
68
+ start: { offset: number };
69
+ end: { offset: number };
70
+ };
71
+ }
72
+ ).location;
73
+ if (pegLoc !== undefined) {
74
+ // SQL offsets equal file offsets — no template-literal mapping needed.
75
+ context.report({
76
+ loc: {
77
+ start: offsetToLoc(sql, pegLoc.start.offset),
78
+ end: offsetToLoc(sql, pegLoc.end.offset),
79
+ },
80
+ messageId: SYNTAXT_ERROR,
81
+ data: { errorMessage: (error as Error).message },
82
+ });
83
+ } else {
84
+ context.report({
85
+ loc: {
86
+ start: { line: 1, column: 0 },
87
+ end: { line: 1, column: 0 },
88
+ },
89
+ messageId: SYNTAXT_ERROR,
90
+ data: { errorMessage: (error as Error).message },
91
+ });
92
+ }
93
+ return;
94
+ }
95
+
96
+ const athenaCtx = createRootContext();
97
+ try {
98
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
99
+ checkAthenaAst(Array.isArray(ast) ? ast[0] : ast, athenaCtx);
100
+ } catch (error) {
101
+ log('error checking SQL AST', {
102
+ error,
103
+ filename: context.filename,
104
+ });
105
+ if (error instanceof AthenaError) {
106
+ const astLoc = (
107
+ error.ast as
108
+ | {
109
+ loc?: {
110
+ start: { offset: number };
111
+ end: { offset: number };
112
+ };
113
+ }
114
+ | undefined
115
+ )?.loc;
116
+ if (astLoc !== undefined) {
117
+ context.report({
118
+ loc: {
119
+ start: offsetToLoc(sql, astLoc.start.offset),
120
+ end: offsetToLoc(sql, astLoc.end.offset),
121
+ },
122
+ messageId: ATHENA_ERROR,
123
+ data: { errorMessage: error.message },
124
+ });
125
+ } else {
126
+ context.report({
127
+ loc: {
128
+ start: { line: 1, column: 0 },
129
+ end: { line: 1, column: 0 },
130
+ },
131
+ messageId: ATHENA_ERROR,
132
+ data: { errorMessage: error.message },
133
+ });
134
+ }
135
+ } else {
136
+ // eslint-disable-next-line no-console
137
+ console.error(
138
+ `Failed to apply ${ruleId} rule for "${context.filename}":`,
139
+ error,
140
+ );
141
+ context.report({
142
+ loc: {
143
+ start: { line: 1, column: 0 },
144
+ end: { line: 1, column: 0 },
145
+ },
146
+ messageId: ATHENA_ERROR,
147
+ data: {
148
+ errorMessage:
149
+ error instanceof Error
150
+ ? String(error)
151
+ : JSON.stringify(error, undefined, 2),
152
+ },
153
+ });
154
+ }
155
+ }
156
+ },
157
+ };
158
+ },
159
+ });
160
+
161
+ export default rule;
@@ -0,0 +1,568 @@
1
+ // athena/types.ts
2
+
3
+ /* eslint-disable max-lines */
4
+
5
+ // Type definitions for node-sql-parser 1.0
6
+ // Project: https://github.com/taozhi8833998/node-sql-parser#readme
7
+ // Definitions by: taozhi8833998 <https://github.com/taozhi8833998>
8
+ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
9
+ // TypeScript Version: 2.4
10
+
11
+ /* eslint-disable @typescript-eslint/no-explicit-any */
12
+ /* eslint-disable @typescript-eslint/no-redundant-type-constituents */
13
+
14
+ export interface With {
15
+ name: { value: string };
16
+ stmt: {
17
+ _parentheses?: boolean;
18
+ tableList: string[];
19
+ columnList: string[];
20
+ ast: Select;
21
+ };
22
+ columns?: any[];
23
+ }
24
+ interface Location {
25
+ line: number;
26
+ column: number;
27
+ offset: number;
28
+ }
29
+
30
+ interface LocationRange {
31
+ start: Location;
32
+ end: Location;
33
+ }
34
+
35
+ export type WhilteListCheckMode = 'table' | 'column';
36
+ export interface ParseOptions {
37
+ includeLocations?: boolean;
38
+ }
39
+ export interface Option {
40
+ database?: string;
41
+ type?: string;
42
+ trimQuery?: boolean;
43
+ parseOptions?: ParseOptions;
44
+ }
45
+ export interface TableColumnAst {
46
+ tableList: string[];
47
+ columnList: string[];
48
+ ast: AST[] | AST;
49
+ loc?: LocationRange;
50
+ }
51
+ export interface BaseFrom {
52
+ db: string | null;
53
+ table: string;
54
+ as: string | null;
55
+ schema?: string;
56
+ loc?: LocationRange;
57
+ }
58
+ export interface Join extends BaseFrom {
59
+ join: 'INNER JOIN' | 'LEFT JOIN' | 'RIGHT JOIN';
60
+ using?: string[];
61
+ on?: Binary;
62
+ }
63
+ export interface TableExpr {
64
+ expr: {
65
+ ast: Select;
66
+ };
67
+ as?: string | null;
68
+ parentheses: boolean | { length: number };
69
+ }
70
+ export interface Dual {
71
+ type: 'dual';
72
+ loc?: LocationRange;
73
+ }
74
+ // Represents: (VALUES (...), ...) alias(col1, col2, ...)
75
+ export interface ValuesFrom {
76
+ expr: { type: 'values' };
77
+ as: {
78
+ type: 'function';
79
+ name: { name: { value: string }[] };
80
+ args: { type: 'expr_list'; value: { column: string }[] };
81
+ };
82
+ }
83
+ export type From = BaseFrom | Join | TableExpr | ValuesFrom | Dual;
84
+ export interface LimitValue {
85
+ type: string;
86
+ value: number;
87
+ loc?: LocationRange;
88
+ }
89
+ export interface Limit {
90
+ seperator: string;
91
+ value: LimitValue[];
92
+ loc?: LocationRange;
93
+ }
94
+ export interface OrderBy {
95
+ type: 'ASC' | 'DESC';
96
+ expr: any;
97
+ loc?: LocationRange;
98
+ }
99
+
100
+ export interface ValueExpr<T = string | number | boolean> {
101
+ type:
102
+ | 'backticks_quote_string'
103
+ | 'string'
104
+ | 'regex_string'
105
+ | 'hex_string'
106
+ | 'full_hex_string'
107
+ | 'natural_string'
108
+ | 'bit_string'
109
+ | 'double_quote_string'
110
+ | 'single_quote_string'
111
+ | 'boolean'
112
+ | 'bool'
113
+ | 'null'
114
+ | 'star'
115
+ | 'param'
116
+ | 'origin'
117
+ | 'date'
118
+ | 'datetime'
119
+ | 'default'
120
+ | 'time'
121
+ | 'timestamp'
122
+ | 'var_string';
123
+ value: T;
124
+ }
125
+
126
+ export interface ColumnRefItem {
127
+ type: 'column_ref';
128
+ table: string | null;
129
+ column: string | { expr: ValueExpr };
130
+ options?: ExprList;
131
+ loc?: LocationRange;
132
+ }
133
+ export interface ColumnRefExpr {
134
+ type: 'expr';
135
+ expr: ColumnRefItem;
136
+ as: string | null;
137
+ }
138
+
139
+ export type ColumnRef = ColumnRefItem | ColumnRefExpr;
140
+ export interface SetList {
141
+ column: string;
142
+ value: any;
143
+ table: string | null;
144
+ loc?: LocationRange;
145
+ }
146
+ export interface InsertReplaceValue {
147
+ type: 'expr_list';
148
+ value: any[];
149
+ loc?: LocationRange;
150
+ }
151
+
152
+ export interface Star {
153
+ type: 'star';
154
+ value: '*' | '';
155
+ loc?: LocationRange;
156
+ }
157
+ export interface Case {
158
+ type: 'case';
159
+ expr: null;
160
+ args: (
161
+ | {
162
+ cond: Binary;
163
+ result: ExpressionValue;
164
+ type: 'when';
165
+ }
166
+ | {
167
+ result: ExpressionValue;
168
+ type: 'else';
169
+ }
170
+ )[];
171
+ }
172
+ export interface Cast {
173
+ type: 'cast';
174
+ keyword: 'cast';
175
+ expr: ExpressionValue;
176
+ symbol: 'as';
177
+ target: {
178
+ dataType: string;
179
+ suffix: unknown[];
180
+ };
181
+ }
182
+ export interface AggrFunc {
183
+ type: 'aggr_func';
184
+ name: string;
185
+ args: {
186
+ expr: ExpressionValue;
187
+ distinct: 'DISTINCT' | null;
188
+ orderby: OrderBy[] | null;
189
+ parentheses?: boolean;
190
+ };
191
+ loc?: LocationRange;
192
+ }
193
+
194
+ export interface FunctionName {
195
+ schema?: { value: string; type: string };
196
+ name: ValueExpr<string>[];
197
+ }
198
+ export interface Function {
199
+ type: 'function';
200
+ name: FunctionName;
201
+ args?: ExprList;
202
+ suffix?: any;
203
+ loc?: LocationRange;
204
+ }
205
+ export interface Column {
206
+ expr: ExpressionValue;
207
+ as: ValueExpr<string> | string | null;
208
+ type?: string;
209
+ loc?: LocationRange;
210
+ }
211
+
212
+ export interface Interval {
213
+ type: 'interval';
214
+ unit: string;
215
+ expr: ValueExpr & { loc?: LocationRange };
216
+ }
217
+
218
+ export interface Param {
219
+ type: 'param';
220
+ value: string;
221
+ loc?: LocationRange;
222
+ }
223
+
224
+ export interface Value {
225
+ type: string;
226
+ value: any;
227
+ loc?: LocationRange;
228
+ }
229
+
230
+ export interface Binary {
231
+ type: 'binary_expr';
232
+ operator: string;
233
+ left: ExpressionValue | ExprList;
234
+ right: ExpressionValue | ExprList;
235
+ loc?: LocationRange;
236
+ parentheses?: boolean;
237
+ }
238
+
239
+ export type Expr = Binary;
240
+
241
+ export type ExpressionValue =
242
+ | ColumnRef
243
+ | Param
244
+ | Function
245
+ | Case
246
+ | AggrFunc
247
+ | Value
248
+ | Binary
249
+ | Cast
250
+ | Interval;
251
+
252
+ export interface ExprList {
253
+ type: 'expr_list';
254
+ value: ExpressionValue[];
255
+ loc?: LocationRange;
256
+ parentheses?: boolean;
257
+ separator?: string;
258
+ }
259
+
260
+ export type PartitionBy = {
261
+ type: 'expr';
262
+ expr: ColumnRef[];
263
+ }[];
264
+
265
+ export interface WindowSpec {
266
+ name: null;
267
+ partitionby: PartitionBy;
268
+ orderby: OrderBy[] | null;
269
+ window_frame_clause: string | null;
270
+ }
271
+
272
+ export type AsWindowSpec =
273
+ | string
274
+ | { window_specification: WindowSpec; parentheses: boolean };
275
+
276
+ export interface NamedWindowExpr {
277
+ name: string;
278
+ as_window_specification: AsWindowSpec;
279
+ }
280
+
281
+ export interface WindowExpr {
282
+ keyword: 'window';
283
+ type: 'window';
284
+ expr: NamedWindowExpr[];
285
+ }
286
+
287
+ export interface Select {
288
+ with: With[] | null;
289
+ type: 'select';
290
+ options: any[] | null;
291
+ distinct: 'DISTINCT' | null;
292
+ columns: any[] | Column[];
293
+ from: From[] | TableExpr | null;
294
+ where: Binary | Function | null;
295
+ groupby:
296
+ | { columns: ColumnRef[] | undefined; modifiers: ValueExpr<string>[] }
297
+ | undefined;
298
+ having: any[] | null;
299
+ orderby: OrderBy[] | null;
300
+ limit: Limit | null;
301
+ window?: WindowExpr;
302
+ qualify?: any[] | null;
303
+ _orderby?: OrderBy[] | null;
304
+ _limit?: Limit | null;
305
+ parentheses_symbol?: boolean;
306
+ _parentheses?: boolean;
307
+ loc?: LocationRange;
308
+ _next?: Select;
309
+ set_op?: string;
310
+ }
311
+ export interface Insert_Replace {
312
+ type: 'replace' | 'insert';
313
+ table: any;
314
+ columns: string[] | null;
315
+ values: InsertReplaceValue[] | Select;
316
+ partition: any[];
317
+ prefix: string;
318
+ on_duplicate_update: {
319
+ keyword: 'on duplicate key update';
320
+ set: SetList[];
321
+ };
322
+ loc?: LocationRange;
323
+ }
324
+ export interface Update {
325
+ type: 'update';
326
+ db: string | null;
327
+ table: (From | Dual)[] | null;
328
+ set: SetList[];
329
+ where: Binary | Function | null;
330
+ loc?: LocationRange;
331
+ }
332
+ export interface Delete {
333
+ type: 'delete';
334
+ table: any;
335
+ from: (From | Dual)[];
336
+ where: Binary | Function | null;
337
+ loc?: LocationRange;
338
+ }
339
+
340
+ export interface Alter {
341
+ type: 'alter';
342
+ table: From[];
343
+ expr: any;
344
+ loc?: LocationRange;
345
+ }
346
+
347
+ export interface Use {
348
+ type: 'use';
349
+ db: string;
350
+ loc?: LocationRange;
351
+ }
352
+
353
+ type KW_UNSIGNED = 'UNSIGNED';
354
+ type KW_ZEROFILL = 'ZEROFILL';
355
+
356
+ type Timezone = ['WITHOUT' | 'WITH', 'TIME', 'ZONE'];
357
+
358
+ interface KeywordComment {
359
+ type: 'comment';
360
+ keyword: 'comment';
361
+ symbol?: '=';
362
+ value: string;
363
+ }
364
+
365
+ interface CollateExpr {
366
+ type: 'collate';
367
+ symbol?: '=';
368
+ value: string;
369
+ }
370
+
371
+ interface DataType {
372
+ dataType: string;
373
+ length?: number;
374
+ parentheses?: true;
375
+ suffix?: Timezone | (KW_UNSIGNED | KW_ZEROFILL)[];
376
+ array?: 'one' | 'two';
377
+ }
378
+
379
+ interface LiteralNotNull {
380
+ type: 'not null';
381
+ value: 'not null';
382
+ }
383
+
384
+ interface LiteralNull {
385
+ type: 'null';
386
+ value: null;
387
+ }
388
+
389
+ type LiteralNumeric = number | { type: 'bigint'; value: string };
390
+
391
+ interface ColumnConstraint {
392
+ default_val: {
393
+ type: 'default';
394
+ value: any;
395
+ };
396
+ nullable: LiteralNotNull | LiteralNull;
397
+ }
398
+
399
+ interface ColumnDefinitionOptList {
400
+ nullable?: ColumnConstraint['nullable'];
401
+ default_val?: ColumnConstraint['default_val'];
402
+ auto_increment?: 'auto_increment';
403
+ unique?: 'unique' | 'unique key';
404
+ primary?: 'key' | 'primary key';
405
+ comment?: KeywordComment;
406
+ collate?: { collate: CollateExpr };
407
+ column_format?: { column_format: any };
408
+ storage?: { storage: any };
409
+ reference_definition?: { reference_definition: any };
410
+ character_set?: { type: 'CHARACTER SET'; value: string; symbol?: '=' };
411
+ }
412
+
413
+ type CreateColumnDefinition = {
414
+ column: ColumnRef;
415
+ definition: DataType;
416
+ resource: 'column';
417
+ } & ColumnDefinitionOptList;
418
+
419
+ interface IndexType {
420
+ keyword: 'using';
421
+ type: 'btree' | 'hash' | 'gist' | 'gin';
422
+ }
423
+
424
+ interface IndexOption {
425
+ type: 'key_block_size';
426
+ symbol?: '=';
427
+ expr: LiteralNumeric;
428
+ }
429
+
430
+ interface CreateIndexDefinition {
431
+ index?: string;
432
+ definition: ColumnRef[];
433
+ keyword: 'index' | 'key';
434
+ index_type?: IndexType;
435
+ resource: 'index';
436
+ index_options?: IndexOption[];
437
+ }
438
+
439
+ interface CreateFulltextSpatialIndexDefinition {
440
+ index?: string;
441
+ definition: ColumnRef[];
442
+ keyword?:
443
+ | 'fulltext'
444
+ | 'spatial'
445
+ | 'fulltext key'
446
+ | 'spatial key'
447
+ | 'fulltext index'
448
+ | 'spatial index';
449
+ index_options?: IndexOption[];
450
+ resource: 'index';
451
+ }
452
+
453
+ interface ConstraintName {
454
+ keyword: 'constraint';
455
+ constraint: string;
456
+ }
457
+
458
+ interface CreateConstraintPrimary {
459
+ constraint?: ConstraintName['constraint'];
460
+ definition: ColumnRef[];
461
+ constraint_type: 'primary key';
462
+ keyword?: ConstraintName['keyword'];
463
+ index_type?: IndexType;
464
+ resource: 'constraint';
465
+ index_options?: IndexOption[];
466
+ }
467
+
468
+ interface CreateConstraintUnique {
469
+ constraint?: ConstraintName['constraint'];
470
+ definition: ColumnRef[];
471
+ constraint_type: 'unique key' | 'unique' | 'unique index';
472
+ keyword?: ConstraintName['keyword'];
473
+ index_type?: IndexType;
474
+ index?: string;
475
+ resource: 'constraint';
476
+ index_options?: IndexOption[];
477
+ }
478
+
479
+ interface CreateConstraintForeign {
480
+ constraint?: ConstraintName['constraint'];
481
+ definition: ColumnRef[];
482
+ constraint_type: 'FOREIGN KEY';
483
+ keyword?: ConstraintName['keyword'];
484
+ index?: string;
485
+ resource: 'constraint';
486
+ reference_definition?: any;
487
+ }
488
+
489
+ interface CreateConstraintCheck {
490
+ constraint?: ConstraintName['constraint'];
491
+ definition: any[];
492
+ constraint_type: 'check';
493
+ keyword?: ConstraintName['keyword'];
494
+ resource: 'constraint';
495
+ }
496
+
497
+ type CreateConstraintDefinition =
498
+ | CreateConstraintPrimary
499
+ | CreateConstraintUnique
500
+ | CreateConstraintForeign
501
+ | CreateConstraintCheck;
502
+
503
+ type CreateDefinition =
504
+ | CreateColumnDefinition
505
+ | CreateIndexDefinition
506
+ | CreateFulltextSpatialIndexDefinition
507
+ | CreateConstraintDefinition;
508
+
509
+ export interface Create {
510
+ type: 'create';
511
+ keyword: 'table' | 'index' | 'database';
512
+ temporary?: 'temporary' | null;
513
+ table?: { db: string; table: string }[];
514
+ if_not_exists?: 'if not exists' | null;
515
+ like?: {
516
+ type: 'like';
517
+ table: string;
518
+ parentheses?: boolean;
519
+ } | null;
520
+ ignore_replace?: 'ignore' | 'replace' | null;
521
+ as?: string | null;
522
+ query_expr?: any | null;
523
+ create_definitions?: CreateDefinition[] | null;
524
+ table_options?: any[] | null;
525
+ index_using?: {
526
+ keyword: 'using';
527
+ type: 'btree' | 'hash';
528
+ } | null;
529
+ index?: string | null;
530
+ on_kw?: 'on' | null;
531
+ index_columns?: any[] | null;
532
+ index_type?: 'unique' | 'fulltext' | 'spatial' | null;
533
+ index_options?: any[] | null;
534
+ algorithm_option?: {
535
+ type: 'alter';
536
+ keyword: 'algorithm';
537
+ resource: 'algorithm';
538
+ symbol: '=' | null;
539
+ algorithm: 'default' | 'instant' | 'inplace' | 'copy';
540
+ } | null;
541
+ lock_option?: {
542
+ type: 'alter';
543
+ keyword: 'lock';
544
+ resource: 'lock';
545
+ symbol: '=' | null;
546
+ lock: 'default' | 'none' | 'shared' | 'exclusive';
547
+ } | null;
548
+ database?: string;
549
+ loc?: LocationRange;
550
+ }
551
+
552
+ export interface Drop {
553
+ type: 'drop';
554
+ keyword: string;
555
+ name: any[];
556
+ }
557
+
558
+ export type AST =
559
+ | Use
560
+ | Select
561
+ | Insert_Replace
562
+ | Update
563
+ | Delete
564
+ | Alter
565
+ | Create
566
+ | Drop;
567
+
568
+ /* eslint-enable max-lines */