happy-sql 2.3.0 → 2.4.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 (112) hide show
  1. package/ChangeLog +88 -0
  2. package/bin/convert.js +3 -9
  3. package/lib/parser/parser.js +11 -11
  4. package/lib/parser/visitors/clause/alter-table/alter-table.js +24 -0
  5. package/lib/parser/visitors/clause/binary.js +31 -7
  6. package/lib/parser/visitors/clause/column-definition/column-definition.js +62 -8
  7. package/lib/parser/visitors/clause/count/count.js +5 -2
  8. package/lib/parser/visitors/clause/create-extension/create-extension.js +7 -0
  9. package/lib/parser/visitors/clause/create-index/create-index.js +36 -5
  10. package/lib/parser/visitors/clause/create-schema/create-schema.js +7 -0
  11. package/lib/parser/visitors/clause/create-table/create-table.js +63 -7
  12. package/lib/parser/visitors/clause/create-view/create-view.js +18 -0
  13. package/lib/parser/visitors/clause/drop-index/drop-index.js +3 -0
  14. package/lib/parser/visitors/clause/drop-view/drop-view.js +15 -0
  15. package/lib/parser/visitors/clause/explain/explain.js +16 -0
  16. package/lib/parser/visitors/clause/from/from.js +109 -13
  17. package/lib/parser/visitors/clause/from/group-by.js +8 -1
  18. package/lib/parser/visitors/clause/from/limit.js +13 -0
  19. package/lib/parser/visitors/clause/from/order-by.js +15 -3
  20. package/lib/parser/visitors/clause/from/table-func.js +10 -14
  21. package/lib/parser/visitors/clause/grant/grant.js +26 -0
  22. package/lib/parser/visitors/clause/index.js +66 -2
  23. package/lib/parser/visitors/clause/insert/insert.js +81 -9
  24. package/lib/parser/visitors/clause/operand.js +55 -1
  25. package/lib/parser/visitors/clause/pragma/pragma.js +52 -2
  26. package/lib/parser/visitors/clause/select/select.js +149 -9
  27. package/lib/parser/visitors/clause/set-param/set-param.js +19 -0
  28. package/lib/parser/visitors/clause/table-constraint.js +27 -0
  29. package/lib/parser/visitors/clause/update/update.js +17 -0
  30. package/lib/parser/visitors/clause/where/where.js +17 -0
  31. package/lib/parser/visitors/clause/with-named/with-named.js +15 -1
  32. package/lib/printer/visitors/call-expression/clauses/access-method/access-method.js +4 -0
  33. package/lib/printer/visitors/call-expression/clauses/add-constraint/add-constraint.js +4 -0
  34. package/lib/printer/visitors/call-expression/clauses/analyze/analyze.js +10 -0
  35. package/lib/printer/visitors/call-expression/clauses/array-type/array-type.js +4 -0
  36. package/lib/printer/visitors/call-expression/clauses/clauses.js +134 -2
  37. package/lib/printer/visitors/call-expression/clauses/collate/collate.js +7 -0
  38. package/lib/printer/visitors/call-expression/clauses/concurrently/concurrently.js +2 -0
  39. package/lib/printer/visitors/call-expression/clauses/constraint/constraint.js +11 -0
  40. package/lib/printer/visitors/call-expression/clauses/count-distinct/count-distinct.js +13 -0
  41. package/lib/printer/visitors/call-expression/clauses/create-extension/create-extension.js +4 -0
  42. package/lib/printer/visitors/call-expression/clauses/create-index/create-index.js +43 -9
  43. package/lib/printer/visitors/call-expression/clauses/create-index/create-unique-index.js +5 -19
  44. package/lib/printer/visitors/call-expression/clauses/create-materialized-view/create-materialized-view.js +8 -0
  45. package/lib/printer/visitors/call-expression/clauses/create-schema/create-schema.js +4 -0
  46. package/lib/printer/visitors/call-expression/clauses/create-table/create-table.js +16 -1
  47. package/lib/printer/visitors/call-expression/clauses/create-table-as/create-table-as.js +8 -0
  48. package/lib/printer/visitors/call-expression/clauses/create-temp-table/create-temp-table.js +11 -0
  49. package/lib/printer/visitors/call-expression/clauses/create-view/create-view.js +8 -0
  50. package/lib/printer/visitors/call-expression/clauses/create-virtual-table/create-virtual-table.js +8 -0
  51. package/lib/printer/visitors/call-expression/clauses/{nextval/nextval.js → default-nextval/default-nextval.js} +2 -1
  52. package/lib/printer/visitors/call-expression/clauses/default-values/default-values.js +3 -0
  53. package/lib/printer/visitors/call-expression/clauses/detach/detach.js +6 -0
  54. package/lib/printer/visitors/call-expression/clauses/distinct-on/distinct-on.js +14 -0
  55. package/lib/printer/visitors/call-expression/clauses/do-block/do-block.js +5 -0
  56. package/lib/printer/visitors/call-expression/clauses/drop-index/drop-index.js +13 -1
  57. package/lib/printer/visitors/call-expression/clauses/drop-view/drop-view.js +24 -0
  58. package/lib/printer/visitors/call-expression/clauses/explain/explain.js +4 -0
  59. package/lib/printer/visitors/call-expression/clauses/explain-analyze/explain-analyze.js +4 -0
  60. package/lib/printer/visitors/call-expression/clauses/explain-query-plan/explain-query-plan.js +4 -0
  61. package/lib/printer/visitors/call-expression/clauses/fetch-first/fetch-first.js +5 -0
  62. package/lib/printer/visitors/call-expression/clauses/filter/filter.js +8 -0
  63. package/lib/printer/visitors/call-expression/clauses/for-update/for-update.js +3 -0
  64. package/lib/printer/visitors/call-expression/clauses/from/from.js +49 -5
  65. package/lib/printer/visitors/call-expression/clauses/generated-always-as/generated-always-as.js +10 -0
  66. package/lib/printer/visitors/call-expression/clauses/grant/grant.js +10 -0
  67. package/lib/printer/visitors/call-expression/clauses/grant-on/grant-on.js +10 -0
  68. package/lib/printer/visitors/call-expression/clauses/if-not-exists/if-not-exists.js +2 -0
  69. package/lib/printer/visitors/call-expression/clauses/indexed-by/indexed-by.js +7 -0
  70. package/lib/printer/visitors/call-expression/clauses/into/into.js +34 -3
  71. package/lib/printer/visitors/call-expression/clauses/json-op.js +9 -1
  72. package/lib/printer/visitors/call-expression/clauses/lateral-join/lateral-join.js +26 -3
  73. package/lib/printer/visitors/call-expression/clauses/like/like.js +7 -0
  74. package/lib/printer/visitors/call-expression/clauses/limit-all/limit-all.js +3 -0
  75. package/lib/printer/visitors/call-expression/clauses/limit-clauses.js +4 -0
  76. package/lib/printer/visitors/call-expression/clauses/named-window/named-window.js +16 -0
  77. package/lib/printer/visitors/call-expression/clauses/not/not.js +4 -0
  78. package/lib/printer/visitors/call-expression/clauses/not-indexed/not-indexed.js +4 -0
  79. package/lib/printer/visitors/call-expression/clauses/nulls-order/nulls-order.js +9 -0
  80. package/lib/printer/visitors/call-expression/clauses/offset/offset.js +4 -0
  81. package/lib/printer/visitors/call-expression/clauses/on-conflict/on-conflict.js +24 -2
  82. package/lib/printer/visitors/call-expression/clauses/on-delete/on-delete.js +32 -0
  83. package/lib/printer/visitors/call-expression/clauses/or-abort/or-abort.js +3 -0
  84. package/lib/printer/visitors/call-expression/clauses/or-fail/or-fail.js +3 -0
  85. package/lib/printer/visitors/call-expression/clauses/over/over.js +12 -0
  86. package/lib/printer/visitors/call-expression/clauses/pragma/pragma.js +14 -5
  87. package/lib/printer/visitors/call-expression/clauses/privilege/privilege.js +10 -0
  88. package/lib/printer/visitors/call-expression/clauses/references/references.js +26 -4
  89. package/lib/printer/visitors/call-expression/clauses/reindex/reindex.js +10 -0
  90. package/lib/printer/visitors/call-expression/clauses/release-savepoint/release-savepoint.js +4 -0
  91. package/lib/printer/visitors/call-expression/clauses/rename-table/rename-table.js +4 -0
  92. package/lib/printer/visitors/call-expression/clauses/right-outer-join/right-outer-join.js +8 -0
  93. package/lib/printer/visitors/call-expression/clauses/row-level-security/row-level-security.js +7 -0
  94. package/lib/printer/visitors/call-expression/clauses/section/section.js +5 -1
  95. package/lib/printer/visitors/call-expression/clauses/select/select.js +37 -9
  96. package/lib/printer/visitors/call-expression/clauses/set-param/set-param.js +14 -0
  97. package/lib/printer/visitors/call-expression/clauses/show-param/show-param.js +4 -0
  98. package/lib/printer/visitors/call-expression/clauses/table-primary-key/table-primary-key.js +13 -0
  99. package/lib/printer/visitors/call-expression/clauses/table-unique/table-unique.js +13 -0
  100. package/lib/printer/visitors/call-expression/clauses/to/to.js +10 -0
  101. package/lib/printer/visitors/call-expression/clauses/truncate/truncate.js +12 -0
  102. package/lib/printer/visitors/call-expression/clauses/unary-minus/unary-minus.js +4 -0
  103. package/lib/printer/visitors/call-expression/clauses/update/update.js +24 -3
  104. package/lib/printer/visitors/call-expression/clauses/using/using.js +13 -0
  105. package/lib/printer/visitors/call-expression/clauses/vacuum/vacuum.js +8 -1
  106. package/lib/printer/visitors/call-expression/clauses/window-frame/window-frame.js +38 -0
  107. package/lib/printer/visitors/call-expression/clauses/with-named/with-named.js +8 -20
  108. package/lib/printer/visitors/call-expression/clauses/without-rowid/without-rowid.js +1 -0
  109. package/lib/printer/visitors/logical-expression.js +4 -1
  110. package/lib/printer/visitors/member-expression.js +14 -0
  111. package/lib/printer/visitors/string-literal.js +9 -5
  112. package/package.json +11 -4
package/ChangeLog CHANGED
@@ -1,3 +1,91 @@
1
+ 2026.11.14, v2.4.1
2
+
3
+ fix:
4
+ - 10d5818 happy-sql: join
5
+ - 7510903 alter-table: rename table, add constraint, RLS actions
6
+ - a4e14a1 references: ON DELETE and ON UPDATE actions
7
+ - 60cbd74 from: extract capitalizeWord, remove inlined arrow
8
+ - 3ebbea9 with-named: extract convertColumn, remove inlined arrow
9
+ - 8848396 printer/from: remove inlined arrows and ternary
10
+ - 0cc326c window-frame: remove optional chaining
11
+ - 652387a references: remove optional chaining
12
+ - 344f7c3 clause/index: remove optional chaining, nullish coalescing, inlined arrows
13
+ - 313fa5f binary: remove optional chaining and nullish coalescing
14
+ - 12b6f3c insert: remove optional chaining and inlined arrows/ternaries
15
+ - 652bcad create-index: remove optional chaining
16
+ - b5b40ac limit: remove optional chaining
17
+ - 5eb1732 create-table: remove optional chaining and inlined arrows
18
+ - f078532 create-view: extract isMaterializedKind predicate
19
+ - 472e627 order-by: extract nulls order fn name
20
+ - ddcb389 group-by: remove inlined arrow in map
21
+ - 1be75b4 table-func: extract getRawName, remove inlined ternary
22
+ - 10a0b35 column-definition: remove optional chaining, nullish coalescing, inlined arrows
23
+ - 9108d3e operand: remove optional chaining and nullish coalescing
24
+
25
+ feature:
26
+ - ffaef07 happy-sql: sql-parser-cst v0.44.1
27
+ - 981cf13 happy-sql: @putout/plugin-printer v9.0.0
28
+
29
+ 2026.08.27, v2.4.0
30
+
31
+ fix:
32
+ - 044050d nextval: scope DEFAULT nextval conversion to column defaults
33
+ - 6f9d707 from: rightOuterJoin missing from printer imports
34
+ - ba06223 over: window frame ROWS BETWEEN support
35
+ - 6c35624 create-table: TEMP keyword and WITHOUT ROWID
36
+ - 038cac6 references: ON DELETE and ON UPDATE actions
37
+ - 6cd9a75 drop-view: IF EXISTS support
38
+ - d5bd976 create-index: column sort order and index method
39
+ - 1a6dc5f over: window frame ROWS BETWEEN support
40
+ - e8c9ba6 column-definition: GENERATED ALWAYS AS expression
41
+ - dbaea87 count: preserve DISTINCT modifier
42
+ - 5d9ce53 like: ESCAPE clause support
43
+ - e8322bc analyze: qualified table names
44
+ - d0446af update: SQLite OR ABORT and OR FAIL
45
+ - 1ffd47d order-by: ordinals and NULLS FIRST/LAST
46
+ - 48c9aed alter-table: rename table, add constraint, RLS actions
47
+ - 297b46a create-table: table-level primary key and unique constraints
48
+ - 8f3d71f insert: optional column list, DEFAULT VALUES, table alias
49
+ - 1609515 from: JOIN USING support
50
+ - 4c0bc85 pragma: support get/set/qualified/string forms
51
+ - 3ed2c4f select: support full expression set in select columns
52
+ - 44bf5d7 happy-sql: from: UNNEST and func_call alias support
53
+ - fedfc86 happy-sql: ANALYZE and REINDEX preserve table name
54
+ - fbb7ce6 from: SQLite INDEXED BY and NOT INDEXED table hints
55
+ - 923c7bb vacuum: VACUUM INTO file support
56
+ - d00c4d2 update: SQLite OR REPLACE and OR IGNORE
57
+ - 196eae8 drop-index: IF EXISTS support
58
+ - 0cf9caf create-index: IF NOT EXISTS, CONCURRENTLY, WHERE partial index
59
+ - 15cf3bb with-named: remove extra indentation from CTE body
60
+ - 018e921 lateral-join: alias without AS for subquery
61
+ - e3f4ae8 detach database statement
62
+ - c070d03 window: named WINDOW clause
63
+ - 9792a5e from: subquery alias without AS keyword
64
+ - 4868889 where: ISNULL/NOTNULL postfix
65
+ - 3bea77a create-table: AS SELECT form
66
+ - d5ff74b values: standalone VALUES statement
67
+ - 6f27346 truncate: add statement
68
+ - 5a07d99 select: DISTINCT ON
69
+ - 964f8e6 func-call: FILTER (WHERE ...)
70
+ - 407ff5e binary-expression: || concat
71
+ - ed2b211 operand: :: cast_operator_expr
72
+ - b08cc9f binary-expression: ?? → ?
73
+
74
+ feature:
75
+ - 3fff1e3 happy-sql: putout_processor_sql
76
+ - 97f890f USING
77
+ - 8ccaa46 RIGHT OUTER JOIN
78
+ - 29a5510 happy-sql: DO block
79
+ - a18ac59 reindex, analyze, release-savepoint: add trivial statement types
80
+ - f0fef07 create-virtual-table: SQLite CREATE VIRTUAL TABLE USING
81
+ - dfe2b2c grant: GRANT privilege ON table TO role
82
+ - 2a29916 create-schema: CREATE SCHEMA
83
+ - f272f3b create-extension: CREATE EXTENSION
84
+ - cd61021 drop-view: DROP VIEW
85
+ - aef8f2a create-view: CREATE VIEW and CREATE MATERIALIZED VIEW
86
+ - d2585b8 set-param: SET and SHOW parameter statements
87
+ - 0e734a4 explain: EXPLAIN and EXPLAIN ANALYZE
88
+
1
89
  2026.08.24, v2.3.0
2
90
 
3
91
  fix:
package/bin/convert.js CHANGED
@@ -1,15 +1,9 @@
1
- import {
2
- __markdown_name,
3
- fromJS,
4
- } from '@putout/operator-json';
1
+ import {__sql_name, fromJS} from '@putout/operator-json';
5
2
  import {convertJsToSql, convertSqlToJs} from '#happy-sql';
6
3
 
7
4
  export function convert(source) {
8
- if (source.startsWith(__markdown_name))
9
- return convertJsToSql(fromJS(
10
- source,
11
- __markdown_name,
12
- ));
5
+ if (source.startsWith(__sql_name))
6
+ return convertJsToSql(fromJS(source, __sql_name));
13
7
 
14
8
  if (source.startsWith('['))
15
9
  return convertJsToSql(source);
@@ -18,19 +18,17 @@ const DIALECTS = [
18
18
  'sqlite',
19
19
  ];
20
20
 
21
- const parseCstDialect = (source, dialect) => parseCst(source, {
22
- dialect,
23
- paramTypes: [':name'],
24
- includeRange: true,
25
- includeComments: true,
26
- });
27
-
28
21
  export const parseSql = (source) => {
29
22
  let cst;
30
23
  let error;
31
24
 
32
25
  for (const dialect of DIALECTS) {
33
- [error, cst] = tryCatch(parseCstDialect, source, dialect);
26
+ [error, cst] = tryCatch(parseCst, source, {
27
+ dialect,
28
+ paramTypes: [':name'],
29
+ includeRange: true,
30
+ includeComments: true,
31
+ });
34
32
 
35
33
  if (cst)
36
34
  return convertSource(cst);
@@ -47,9 +45,11 @@ const getSectionName = (leading) => {
47
45
 
48
46
  const comment = leading.find(isComment);
49
47
 
50
- return comment ? comment.text
51
- .slice(2)
52
- .trim() : null;
48
+ return comment
49
+ ? comment.text
50
+ .slice(2)
51
+ .trim()
52
+ : null;
53
53
  };
54
54
 
55
55
  const convertSource = (cst) => {
@@ -1,5 +1,6 @@
1
1
  import {types} from '@putout/babel';
2
2
  import {convertColumnDefinition} from '#parser/clause/column-definition';
3
+ import {convertTableConstraint} from '../table-constraint.js';
3
4
 
4
5
  const {identifier, callExpression} = types;
5
6
 
@@ -7,6 +8,25 @@ const convertAddColumn = (action) => callExpression(identifier('addColumn'), [
7
8
  convertColumnDefinition(action.column),
8
9
  ]);
9
10
 
11
+ const convertRenameTable = (action) => callExpression(identifier('renameTable'), [
12
+ identifier(action.newName.name),
13
+ ]);
14
+
15
+ const convertAddConstraint = ({name, constraint}) => {
16
+ const node = convertTableConstraint(constraint);
17
+ const args = [];
18
+
19
+ if (name)
20
+ args.push(callExpression(identifier('constraint'), [
21
+ identifier(name.name.name),
22
+ node,
23
+ ]));
24
+ else
25
+ args.push(node);
26
+
27
+ return callExpression(identifier('addConstraint'), args);
28
+ };
29
+
10
30
  const convertDropColumn = (action) => callExpression(identifier('dropColumn'), [
11
31
  identifier(action.column.name),
12
32
  ]);
@@ -26,6 +46,10 @@ const ACTION_CONVERTERS = {
26
46
  alter_action_drop_column: convertDropColumn,
27
47
  alter_action_rename_column: convertRenameColumn,
28
48
  alter_action_alter_column: convertAlterColumnType,
49
+ alter_action_rename: convertRenameTable,
50
+ alter_action_add_constraint: convertAddConstraint,
51
+ alter_action_enable: () => callExpression(identifier('enableRowLevelSecurity'), []),
52
+ alter_action_disable: () => callExpression(identifier('disableRowLevelSecurity'), []),
29
53
  };
30
54
 
31
55
  export const convertAlterTable = ({table, actions}) => {
@@ -31,10 +31,20 @@ export const opName = (op) => {
31
31
  return op.name;
32
32
  };
33
33
 
34
- const convertLike = (node) => callExpression(identifier('like'), [
35
- convertOperand(node.left),
36
- convertOperand(node.right),
37
- ]);
34
+ const isEscape = (node) => node && node.type === 'binary_expr' && opName(node.operator) === 'ESCAPE';
35
+
36
+ const convertLike = (node) => {
37
+ const args = [
38
+ convertOperand(node.left),
39
+ ];
40
+
41
+ if (isEscape(node.right))
42
+ args.push(convertOperand(node.right.left), convertOperand(node.right.right));
43
+ else
44
+ args.push(convertOperand(node.right));
45
+
46
+ return callExpression(identifier('like'), args);
47
+ };
38
48
 
39
49
  const convertNotLike = (node) => callExpression(identifier('notLike'), [
40
50
  convertOperand(node.left),
@@ -56,9 +66,16 @@ const convertIsDistinctFrom = (node) => callExpression(identifier('isDistinctFro
56
66
  convertOperand(node.right),
57
67
  ]);
58
68
 
69
+ const convertConcatOperand = (node) => {
70
+ if (node.operator && opName(node.operator) === '||')
71
+ return convertConcat(node);
72
+
73
+ return convertOperand(node);
74
+ };
75
+
59
76
  const convertConcat = (node) => callExpression(identifier('concat'), [
60
- convertOperand(node.left),
61
- convertOperand(node.right),
77
+ convertConcatOperand(node.left),
78
+ convertConcatOperand(node.right),
62
79
  ]);
63
80
 
64
81
  const convertJsonTuple = (op) => (node) => arrayExpression([
@@ -67,6 +84,11 @@ const convertJsonTuple = (op) => (node) => arrayExpression([
67
84
  convertOperand(node.right),
68
85
  ]);
69
86
 
87
+ const convertCollate = (node) => callExpression(identifier('collate'), [
88
+ convertOperand(node.left),
89
+ convertOperand(node.right),
90
+ ]);
91
+
70
92
  const convertIsNull = (node) => callExpression(identifier('isNull'), [
71
93
  convertOperand(node.left),
72
94
  ]);
@@ -118,6 +140,7 @@ const OP_CONVERTERS = {
118
140
  '?': convertJsonTuple('?'),
119
141
  '?|': convertJsonTuple('?|'),
120
142
  '?&': convertJsonTuple('?&'),
143
+ '??': convertJsonTuple('??'),
121
144
  '@>': convertJsonTuple('@>'),
122
145
  '<@': convertJsonTuple('<@'),
123
146
  '||': convertConcat,
@@ -125,6 +148,7 @@ const OP_CONVERTERS = {
125
148
  'IS NOT': convertIsNotNull,
126
149
  'IN': convertIn,
127
150
  'NOT IN': convertNotIn,
151
+ 'COLLATE': convertCollate,
128
152
  };
129
153
 
130
154
  export const SQL_TO_JS_OP = {
@@ -148,7 +172,7 @@ export const convertBinary = (node) => {
148
172
  if (convert)
149
173
  return convert(node);
150
174
 
151
- const jsOp = SQL_TO_JS_OP[op] ?? '===';
175
+ const jsOp = SQL_TO_JS_OP[op] || '===';
152
176
 
153
177
  return binaryExpression(
154
178
  jsOp,
@@ -31,14 +31,27 @@ const convertGenerated = (constraint) => {
31
31
  return callExpression(identifier('identity'), []);
32
32
  };
33
33
 
34
+ const isGeneratedExpr = ({expr}) => expr && expr.type === 'paren_expr';
35
+
36
+ const isStored = (constraint) => Boolean(constraint.storageKw) && constraint.storageKw.name === 'STORED';
37
+
38
+ const convertGeneratedExpr = (constraint) => callExpression(identifier('generatedAlwaysAs'), [
39
+ convertBinary(constraint.expr.expr),
40
+ booleanLiteral(isStored(constraint)),
41
+ ]);
42
+
43
+ const convertDefaultNextval = (expr) => {
44
+ const [seq] = expr.args.expr.args.items;
45
+ const seqName = seq.value || seq.name;
46
+
47
+ return callExpression(identifier('defaultNextval'), [
48
+ identifier(seqName),
49
+ ]);
50
+ };
51
+
34
52
  const convertDefault = ({expr}) => {
35
- if (expr.type === 'func_call' && expr.name.name === 'nextval') {
36
- const seqName = expr.args.expr.args.items[0].value;
37
-
38
- return callExpression(identifier('nextval'), [
39
- identifier(seqName),
40
- ]);
41
- }
53
+ if (expr.type === 'func_call' && expr.name.name === 'nextval')
54
+ return convertDefaultNextval(expr);
42
55
 
43
56
  if (expr.type === 'number_literal')
44
57
  return callExpression(identifier('default_'), [
@@ -69,6 +82,39 @@ const convertCheck = (constraint) => callExpression(identifier('check'), [
69
82
  convertBinary(constraint.expr.expr),
70
83
  ]);
71
84
 
85
+ const ACTION_NAMES = {
86
+ CASCADE: true,
87
+ RESTRICT: true,
88
+ SET_NULL: true,
89
+ SET_DEFAULT: true,
90
+ };
91
+
92
+ const getActionName = (kw) => kw.name;
93
+
94
+ const normalizeAction = (a) => {
95
+ if (ACTION_NAMES[a])
96
+ return a;
97
+
98
+ return a
99
+ .replace(/\s+/g, '_')
100
+ .toUpperCase();
101
+ };
102
+
103
+ const convertReferentialAction = ({eventKw, actionKw}) => {
104
+ const event = eventKw.name === 'DELETE' ? 'onDelete' : 'onUpdate';
105
+ const action = Array.isArray(actionKw)
106
+ ? actionKw
107
+ .map(getActionName)
108
+ .join(' ')
109
+ : actionKw.name;
110
+
111
+ const name = normalizeAction(action);
112
+
113
+ return callExpression(identifier(event), [
114
+ identifier(name),
115
+ ]);
116
+ };
117
+
72
118
  const convertReferences = (constraint) => {
73
119
  const refTable = identifier(constraint.table.name);
74
120
  const cols = constraint.columns.expr.items;
@@ -77,12 +123,20 @@ const convertReferences = (constraint) => {
77
123
  for (const col of cols)
78
124
  args.push(identifier(col.name));
79
125
 
126
+ for (const option of constraint.options)
127
+ args.push(convertReferentialAction(option));
128
+
80
129
  return callExpression(identifier('references'), args);
81
130
  };
82
131
 
83
132
  const CONSTRAINT_VISITORS = {
84
133
  constraint_primary_key: () => callExpression(identifier('primaryKey'), []),
85
- constraint_generated: convertGenerated,
134
+ constraint_generated: (constraint) => {
135
+ if (isGeneratedExpr(constraint))
136
+ return convertGeneratedExpr(constraint);
137
+
138
+ return convertGenerated(constraint);
139
+ },
86
140
  constraint_not_null: () => callExpression(identifier('notNull'), []),
87
141
  constraint_default: convertDefault,
88
142
  constraint_unique: convertUnique,
@@ -15,7 +15,8 @@ export const isCount = (column) => {
15
15
  };
16
16
 
17
17
  export const convertCount = (column) => {
18
- const {items} = column.args.expr.args;
18
+ const funcArgs = column.args.expr;
19
+ const {items} = funcArgs.args;
19
20
  const args = [];
20
21
 
21
22
  for (const item of items) {
@@ -34,5 +35,7 @@ export const convertCount = (column) => {
34
35
  args.push(identifier(item.name));
35
36
  }
36
37
 
37
- return callExpression(identifier('count'), args);
38
+ const name = funcArgs.distinctKw ? 'countDistinct' : 'count';
39
+
40
+ return callExpression(identifier(name), args);
38
41
  };
@@ -0,0 +1,7 @@
1
+ import {types} from '@putout/babel';
2
+
3
+ const {identifier, callExpression} = types;
4
+
5
+ export const convertCreateExtension = (stmt) => callExpression(identifier('createExtension'), [
6
+ identifier(stmt.name.name),
7
+ ]);
@@ -1,13 +1,23 @@
1
1
  import {types} from '@putout/babel';
2
+ import {convertCondition} from '#parser/clause/where';
3
+ import {findClause} from '#parser/clause/find';
2
4
 
3
5
  const {identifier, callExpression} = types;
4
6
 
7
+ const isDesc = (item) => item.direction && item.direction.type === 'sort_direction_desc';
8
+
5
9
  const convertColumns = (columns) => {
6
10
  const {items} = columns.expr;
7
11
  const cols = [];
8
12
 
9
- for (const item of items)
10
- cols.push(identifier(item.expr.name));
13
+ for (const item of items) {
14
+ if (isDesc(item))
15
+ cols.push(callExpression(identifier('desc'), [
16
+ identifier(item.expr.name),
17
+ ]));
18
+ else
19
+ cols.push(identifier(item.expr.name));
20
+ }
11
21
 
12
22
  return cols;
13
23
  };
@@ -21,9 +31,30 @@ export const convertCreateIndex = (stmt) => {
21
31
 
22
32
  const isUnique = stmt.indexTypeKw && stmt.indexTypeKw.name === 'UNIQUE';
23
33
 
24
- return callExpression(identifier(isUnique ? 'createUniqueIndex' : 'createIndex'), [
34
+ const args = [
25
35
  identifier(name.name),
26
36
  identifier(table.name),
27
- ...convertColumns(columns),
28
- ]);
37
+ ];
38
+
39
+ if (stmt.using)
40
+ args.push(callExpression(identifier('accessMethod'), [
41
+ identifier(stmt.using.method.name),
42
+ ]));
43
+
44
+ args.push(...convertColumns(columns));
45
+
46
+ const whereClause = findClause(stmt.clauses, 'where_clause');
47
+
48
+ if (stmt.ifNotExistsKw)
49
+ args.push(callExpression(identifier('ifNotExists'), []));
50
+
51
+ if (stmt.concurrentlyKw)
52
+ args.push(callExpression(identifier('concurrently'), []));
53
+
54
+ if (whereClause)
55
+ args.push(callExpression(identifier('where'), [
56
+ convertCondition(whereClause.expr),
57
+ ]));
58
+
59
+ return callExpression(identifier(isUnique ? 'createUniqueIndex' : 'createIndex'), args);
29
60
  };
@@ -0,0 +1,7 @@
1
+ import {types} from '@putout/babel';
2
+
3
+ const {identifier, callExpression} = types;
4
+
5
+ export const convertCreateSchema = (stmt) => callExpression(identifier('createSchema'), [
6
+ identifier(stmt.name.name),
7
+ ]);
@@ -1,5 +1,7 @@
1
1
  import {types} from '@putout/babel';
2
2
  import {convertColumnDefinition} from '#parser/clause/column-definition';
3
+ import {convertClause} from '#parser/clause';
4
+ import {convertTableConstraint} from '../table-constraint.js';
3
5
 
4
6
  const {
5
7
  identifier,
@@ -7,15 +9,69 @@ const {
7
9
  arrayExpression,
8
10
  } = types;
9
11
 
10
- export const convertCreateTable = ({name, columns, ifNotExistsKw}) => {
11
- const colNodes = columns.expr.items.map(convertColumnDefinition);
12
- const tableArgs = [
13
- identifier(name.name),
12
+ const isAsClause = ({type}) => type === 'as_clause';
13
+ const isVirtual = (stmt) => stmt.kind && stmt.kind.kindKw.name === 'VIRTUAL';
14
+ const isColumnDefinition = ({type}) => type === 'column_definition';
15
+ const isTemp = (stmt) => stmt.kind && ['TEMP', 'TEMPORARY'].includes(stmt.kind.kindKw.name);
16
+
17
+ const convertColumnListItem = (item) => {
18
+ if (isColumnDefinition(item))
19
+ return convertColumnDefinition(item);
20
+
21
+ return convertTableConstraint(item);
22
+ };
23
+
24
+ const isWithoutName = ({name}) => name === 'WITHOUT';
25
+ const isWithoutKeyword = ({name}) => Array.isArray(name) && name.some(isWithoutName);
26
+ const isWithoutRowid = (options) => options && options.items.some(isWithoutKeyword);
27
+
28
+ const convertTableArgs = (stmt) => {
29
+ const colNodes = [];
30
+
31
+ for (const item of stmt.columns.expr.items)
32
+ colNodes.push(convertColumnListItem(item));
33
+
34
+ if (isWithoutRowid(stmt.options))
35
+ colNodes.push(callExpression(identifier('withoutRowid'), []));
36
+
37
+ return [
38
+ identifier(stmt.name.name),
14
39
  arrayExpression(colNodes),
15
40
  ];
41
+ };
42
+
43
+ const convertUsing = ({module}) => {
44
+ const args = [];
45
+
46
+ for (const item of module.args.expr.args.items)
47
+ args.push(identifier(item.name));
48
+
49
+ return callExpression(identifier(module.name.name), args);
50
+ };
51
+
52
+ export const convertCreateTable = (stmt) => {
53
+ if (isVirtual(stmt)) {
54
+ const [usingClause] = stmt.clauses;
55
+
56
+ return callExpression(identifier('createVirtualTable'), [
57
+ identifier(stmt.name.name),
58
+ convertUsing(usingClause),
59
+ ]);
60
+ }
61
+
62
+ const asClause = stmt.clauses && stmt.clauses.find(isAsClause);
63
+
64
+ if (asClause)
65
+ return callExpression(identifier('createTableAs'), [
66
+ identifier(stmt.name.name),
67
+ convertClause(asClause.expr),
68
+ ]);
69
+
70
+ const fnName = isTemp(stmt) ? 'createTempTable' : 'createTable';
71
+ const tableArgs = convertTableArgs(stmt);
16
72
 
17
- if (ifNotExistsKw)
18
- return callExpression(identifier('createTableIfNotExists'), tableArgs);
73
+ if (stmt.ifNotExistsKw)
74
+ return callExpression(identifier(`${fnName}IfNotExists`), tableArgs);
19
75
 
20
- return callExpression(identifier('createTable'), tableArgs);
76
+ return callExpression(identifier(fnName), tableArgs);
21
77
  };
@@ -0,0 +1,18 @@
1
+ import {types} from '@putout/babel';
2
+ import {convertClause} from '#parser/clause';
3
+
4
+ const {identifier, callExpression} = types;
5
+
6
+ const isMaterializedKind = ({kindKw}) => kindKw.name === 'MATERIALIZED';
7
+ const isMaterialized = (stmt) => stmt.kinds.some(isMaterializedKind);
8
+
9
+ export const convertCreateView = (stmt) => {
10
+ const [asClause] = stmt.clauses;
11
+ const inner = convertClause(asClause.expr);
12
+ const fnName = isMaterialized(stmt) ? 'createMaterializedView' : 'createView';
13
+
14
+ return callExpression(identifier(fnName), [
15
+ identifier(stmt.name.name),
16
+ inner,
17
+ ]);
18
+ };
@@ -5,6 +5,9 @@ const {identifier, callExpression} = types;
5
5
  export const convertDropIndex = (stmt) => {
6
6
  const args = [];
7
7
 
8
+ if (stmt.ifExistsKw)
9
+ args.push(callExpression(identifier('ifExists'), []));
10
+
8
11
  for (const idx of stmt.indexes.items)
9
12
  args.push(identifier(idx.name));
10
13
 
@@ -0,0 +1,15 @@
1
+ import {types} from '@putout/babel';
2
+
3
+ const {identifier, callExpression} = types;
4
+
5
+ export const convertDropView = (stmt) => {
6
+ const args = [];
7
+
8
+ if (stmt.ifExistsKw)
9
+ args.push(callExpression(identifier('ifExists'), []));
10
+
11
+ for (const view of stmt.views.items)
12
+ args.push(identifier(view.name));
13
+
14
+ return callExpression(identifier('dropView'), args);
15
+ };
@@ -0,0 +1,16 @@
1
+ import {types} from '@putout/babel';
2
+ import {convertClause} from '#parser/clause';
3
+
4
+ const {identifier, callExpression} = types;
5
+
6
+ export const convertExplain = (stmt) => {
7
+ const inner = convertClause(stmt.statement);
8
+
9
+ if (stmt.analyzeKw)
10
+ return callExpression(identifier('explainAnalyze'), [inner]);
11
+
12
+ if (stmt.queryPlanKw)
13
+ return callExpression(identifier('explainQueryPlan'), [inner]);
14
+
15
+ return callExpression(identifier('explain'), [inner]);
16
+ };