happy-sql 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/ChangeLog +60 -0
  2. package/bin/convert.js +3 -9
  3. package/lib/parser/visitors/clause/alter-table/alter-table.js +21 -0
  4. package/lib/parser/visitors/clause/binary.js +30 -6
  5. package/lib/parser/visitors/clause/column-definition/column-definition.js +49 -8
  6. package/lib/parser/visitors/clause/count/count.js +5 -2
  7. package/lib/parser/visitors/clause/create-extension/create-extension.js +7 -0
  8. package/lib/parser/visitors/clause/create-index/create-index.js +36 -5
  9. package/lib/parser/visitors/clause/create-schema/create-schema.js +7 -0
  10. package/lib/parser/visitors/clause/create-table/create-table.js +58 -7
  11. package/lib/parser/visitors/clause/create-view/create-view.js +17 -0
  12. package/lib/parser/visitors/clause/drop-index/drop-index.js +3 -0
  13. package/lib/parser/visitors/clause/drop-view/drop-view.js +15 -0
  14. package/lib/parser/visitors/clause/explain/explain.js +16 -0
  15. package/lib/parser/visitors/clause/from/from.js +93 -4
  16. package/lib/parser/visitors/clause/from/limit.js +13 -0
  17. package/lib/parser/visitors/clause/from/order-by.js +14 -3
  18. package/lib/parser/visitors/clause/from/table-func.js +5 -18
  19. package/lib/parser/visitors/clause/grant/grant.js +26 -0
  20. package/lib/parser/visitors/clause/index.js +50 -2
  21. package/lib/parser/visitors/clause/insert/insert.js +39 -5
  22. package/lib/parser/visitors/clause/operand.js +55 -1
  23. package/lib/parser/visitors/clause/pragma/pragma.js +52 -2
  24. package/lib/parser/visitors/clause/select/select.js +139 -6
  25. package/lib/parser/visitors/clause/set-param/set-param.js +19 -0
  26. package/lib/parser/visitors/clause/table-constraint.js +27 -0
  27. package/lib/parser/visitors/clause/update/update.js +17 -0
  28. package/lib/parser/visitors/clause/where/where.js +17 -0
  29. package/lib/printer/visitors/call-expression/clauses/access-method/access-method.js +4 -0
  30. package/lib/printer/visitors/call-expression/clauses/analyze/analyze.js +10 -0
  31. package/lib/printer/visitors/call-expression/clauses/array-type/array-type.js +4 -0
  32. package/lib/printer/visitors/call-expression/clauses/clauses.js +132 -2
  33. package/lib/printer/visitors/call-expression/clauses/collate/collate.js +7 -0
  34. package/lib/printer/visitors/call-expression/clauses/concurrently/concurrently.js +2 -0
  35. package/lib/printer/visitors/call-expression/clauses/constraint/constraint.js +11 -0
  36. package/lib/printer/visitors/call-expression/clauses/count-distinct/count-distinct.js +13 -0
  37. package/lib/printer/visitors/call-expression/clauses/create-extension/create-extension.js +4 -0
  38. package/lib/printer/visitors/call-expression/clauses/create-index/create-index.js +43 -9
  39. package/lib/printer/visitors/call-expression/clauses/create-index/create-unique-index.js +5 -19
  40. package/lib/printer/visitors/call-expression/clauses/create-materialized-view/create-materialized-view.js +8 -0
  41. package/lib/printer/visitors/call-expression/clauses/create-schema/create-schema.js +4 -0
  42. package/lib/printer/visitors/call-expression/clauses/create-table/create-table.js +16 -1
  43. package/lib/printer/visitors/call-expression/clauses/create-table-as/create-table-as.js +8 -0
  44. package/lib/printer/visitors/call-expression/clauses/create-temp-table/create-temp-table.js +11 -0
  45. package/lib/printer/visitors/call-expression/clauses/create-view/create-view.js +8 -0
  46. package/lib/printer/visitors/call-expression/clauses/create-virtual-table/create-virtual-table.js +8 -0
  47. package/lib/printer/visitors/call-expression/clauses/{nextval/nextval.js → default-nextval/default-nextval.js} +2 -1
  48. package/lib/printer/visitors/call-expression/clauses/default-values/default-values.js +3 -0
  49. package/lib/printer/visitors/call-expression/clauses/detach/detach.js +6 -0
  50. package/lib/printer/visitors/call-expression/clauses/distinct-on/distinct-on.js +14 -0
  51. package/lib/printer/visitors/call-expression/clauses/do-block/do-block.js +5 -0
  52. package/lib/printer/visitors/call-expression/clauses/drop-index/drop-index.js +13 -1
  53. package/lib/printer/visitors/call-expression/clauses/drop-view/drop-view.js +24 -0
  54. package/lib/printer/visitors/call-expression/clauses/explain/explain.js +4 -0
  55. package/lib/printer/visitors/call-expression/clauses/explain-analyze/explain-analyze.js +4 -0
  56. package/lib/printer/visitors/call-expression/clauses/explain-query-plan/explain-query-plan.js +4 -0
  57. package/lib/printer/visitors/call-expression/clauses/fetch-first/fetch-first.js +5 -0
  58. package/lib/printer/visitors/call-expression/clauses/filter/filter.js +8 -0
  59. package/lib/printer/visitors/call-expression/clauses/for-update/for-update.js +3 -0
  60. package/lib/printer/visitors/call-expression/clauses/from/from.js +34 -3
  61. package/lib/printer/visitors/call-expression/clauses/generated-always-as/generated-always-as.js +10 -0
  62. package/lib/printer/visitors/call-expression/clauses/grant/grant.js +10 -0
  63. package/lib/printer/visitors/call-expression/clauses/grant-on/grant-on.js +10 -0
  64. package/lib/printer/visitors/call-expression/clauses/if-not-exists/if-not-exists.js +2 -0
  65. package/lib/printer/visitors/call-expression/clauses/indexed-by/indexed-by.js +7 -0
  66. package/lib/printer/visitors/call-expression/clauses/into/into.js +30 -2
  67. package/lib/printer/visitors/call-expression/clauses/json-op.js +1 -0
  68. package/lib/printer/visitors/call-expression/clauses/lateral-join/lateral-join.js +26 -3
  69. package/lib/printer/visitors/call-expression/clauses/like/like.js +7 -0
  70. package/lib/printer/visitors/call-expression/clauses/limit-all/limit-all.js +3 -0
  71. package/lib/printer/visitors/call-expression/clauses/limit-clauses.js +4 -0
  72. package/lib/printer/visitors/call-expression/clauses/named-window/named-window.js +16 -0
  73. package/lib/printer/visitors/call-expression/clauses/not/not.js +4 -0
  74. package/lib/printer/visitors/call-expression/clauses/not-indexed/not-indexed.js +4 -0
  75. package/lib/printer/visitors/call-expression/clauses/nulls-order/nulls-order.js +9 -0
  76. package/lib/printer/visitors/call-expression/clauses/offset/offset.js +4 -0
  77. package/lib/printer/visitors/call-expression/clauses/on-conflict/on-conflict.js +16 -1
  78. package/lib/printer/visitors/call-expression/clauses/on-delete/on-delete.js +32 -0
  79. package/lib/printer/visitors/call-expression/clauses/or-abort/or-abort.js +3 -0
  80. package/lib/printer/visitors/call-expression/clauses/or-fail/or-fail.js +3 -0
  81. package/lib/printer/visitors/call-expression/clauses/over/over.js +12 -0
  82. package/lib/printer/visitors/call-expression/clauses/pragma/pragma.js +14 -5
  83. package/lib/printer/visitors/call-expression/clauses/privilege/privilege.js +10 -0
  84. package/lib/printer/visitors/call-expression/clauses/references/references.js +14 -4
  85. package/lib/printer/visitors/call-expression/clauses/reindex/reindex.js +10 -0
  86. package/lib/printer/visitors/call-expression/clauses/release-savepoint/release-savepoint.js +4 -0
  87. package/lib/printer/visitors/call-expression/clauses/rename-table/rename-table.js +4 -0
  88. package/lib/printer/visitors/call-expression/clauses/right-outer-join/right-outer-join.js +8 -0
  89. package/lib/printer/visitors/call-expression/clauses/row-level-security/row-level-security.js +7 -0
  90. package/lib/printer/visitors/call-expression/clauses/select/select.js +37 -9
  91. package/lib/printer/visitors/call-expression/clauses/set-param/set-param.js +14 -0
  92. package/lib/printer/visitors/call-expression/clauses/show-param/show-param.js +4 -0
  93. package/lib/printer/visitors/call-expression/clauses/table-primary-key/table-primary-key.js +13 -0
  94. package/lib/printer/visitors/call-expression/clauses/table-unique/table-unique.js +13 -0
  95. package/lib/printer/visitors/call-expression/clauses/to/to.js +10 -0
  96. package/lib/printer/visitors/call-expression/clauses/truncate/truncate.js +12 -0
  97. package/lib/printer/visitors/call-expression/clauses/unary-minus/unary-minus.js +4 -0
  98. package/lib/printer/visitors/call-expression/clauses/update/update.js +24 -3
  99. package/lib/printer/visitors/call-expression/clauses/using/using.js +13 -0
  100. package/lib/printer/visitors/call-expression/clauses/vacuum/vacuum.js +8 -1
  101. package/lib/printer/visitors/call-expression/clauses/window-frame/window-frame.js +38 -0
  102. package/lib/printer/visitors/call-expression/clauses/with-named/with-named.js +8 -20
  103. package/lib/printer/visitors/call-expression/clauses/without-rowid/without-rowid.js +1 -0
  104. package/lib/printer/visitors/member-expression.js +14 -0
  105. package/lib/printer/visitors/string-literal.js +9 -5
  106. package/package.json +9 -2
package/ChangeLog CHANGED
@@ -1,3 +1,63 @@
1
+ 2026.08.27, v2.4.0
2
+
3
+ fix:
4
+ - 044050d nextval: scope DEFAULT nextval conversion to column defaults
5
+ - 6f9d707 from: rightOuterJoin missing from printer imports
6
+ - ba06223 over: window frame ROWS BETWEEN support
7
+ - 6c35624 create-table: TEMP keyword and WITHOUT ROWID
8
+ - 038cac6 references: ON DELETE and ON UPDATE actions
9
+ - 6cd9a75 drop-view: IF EXISTS support
10
+ - d5bd976 create-index: column sort order and index method
11
+ - 1a6dc5f over: window frame ROWS BETWEEN support
12
+ - e8c9ba6 column-definition: GENERATED ALWAYS AS expression
13
+ - dbaea87 count: preserve DISTINCT modifier
14
+ - 5d9ce53 like: ESCAPE clause support
15
+ - e8322bc analyze: qualified table names
16
+ - d0446af update: SQLite OR ABORT and OR FAIL
17
+ - 1ffd47d order-by: ordinals and NULLS FIRST/LAST
18
+ - 48c9aed alter-table: rename table, add constraint, RLS actions
19
+ - 297b46a create-table: table-level primary key and unique constraints
20
+ - 8f3d71f insert: optional column list, DEFAULT VALUES, table alias
21
+ - 1609515 from: JOIN USING support
22
+ - 4c0bc85 pragma: support get/set/qualified/string forms
23
+ - 3ed2c4f select: support full expression set in select columns
24
+ - 44bf5d7 happy-sql: from: UNNEST and func_call alias support
25
+ - fedfc86 happy-sql: ANALYZE and REINDEX preserve table name
26
+ - fbb7ce6 from: SQLite INDEXED BY and NOT INDEXED table hints
27
+ - 923c7bb vacuum: VACUUM INTO file support
28
+ - d00c4d2 update: SQLite OR REPLACE and OR IGNORE
29
+ - 196eae8 drop-index: IF EXISTS support
30
+ - 0cf9caf create-index: IF NOT EXISTS, CONCURRENTLY, WHERE partial index
31
+ - 15cf3bb with-named: remove extra indentation from CTE body
32
+ - 018e921 lateral-join: alias without AS for subquery
33
+ - e3f4ae8 detach database statement
34
+ - c070d03 window: named WINDOW clause
35
+ - 9792a5e from: subquery alias without AS keyword
36
+ - 4868889 where: ISNULL/NOTNULL postfix
37
+ - 3bea77a create-table: AS SELECT form
38
+ - d5ff74b values: standalone VALUES statement
39
+ - 6f27346 truncate: add statement
40
+ - 5a07d99 select: DISTINCT ON
41
+ - 964f8e6 func-call: FILTER (WHERE ...)
42
+ - 407ff5e binary-expression: || concat
43
+ - ed2b211 operand: :: cast_operator_expr
44
+ - b08cc9f binary-expression: ?? → ?
45
+
46
+ feature:
47
+ - 3fff1e3 happy-sql: putout_processor_sql
48
+ - 97f890f USING
49
+ - 8ccaa46 RIGHT OUTER JOIN
50
+ - 29a5510 happy-sql: DO block
51
+ - a18ac59 reindex, analyze, release-savepoint: add trivial statement types
52
+ - f0fef07 create-virtual-table: SQLite CREATE VIRTUAL TABLE USING
53
+ - dfe2b2c grant: GRANT privilege ON table TO role
54
+ - 2a29916 create-schema: CREATE SCHEMA
55
+ - f272f3b create-extension: CREATE EXTENSION
56
+ - cd61021 drop-view: DROP VIEW
57
+ - aef8f2a create-view: CREATE VIEW and CREATE MATERIALIZED VIEW
58
+ - d2585b8 set-param: SET and SHOW parameter statements
59
+ - 0e734a4 explain: EXPLAIN and EXPLAIN ANALYZE
60
+
1
61
  2026.08.24, v2.3.0
2
62
 
3
63
  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);
@@ -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,22 @@ 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
+
18
+ if (!name)
19
+ return node;
20
+
21
+ return callExpression(identifier('constraint'), [
22
+ identifier(name.name.name),
23
+ node,
24
+ ]);
25
+ };
26
+
10
27
  const convertDropColumn = (action) => callExpression(identifier('dropColumn'), [
11
28
  identifier(action.column.name),
12
29
  ]);
@@ -26,6 +43,10 @@ const ACTION_CONVERTERS = {
26
43
  alter_action_drop_column: convertDropColumn,
27
44
  alter_action_rename_column: convertRenameColumn,
28
45
  alter_action_alter_column: convertAlterColumnType,
46
+ alter_action_rename: convertRenameTable,
47
+ alter_action_add_constraint: convertAddConstraint,
48
+ alter_action_enable: () => callExpression(identifier('enableRowLevelSecurity'), []),
49
+ alter_action_disable: () => callExpression(identifier('disableRowLevelSecurity'), []),
29
50
  };
30
51
 
31
52
  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?.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 = {
@@ -31,14 +31,25 @@ const convertGenerated = (constraint) => {
31
31
  return callExpression(identifier('identity'), []);
32
32
  };
33
33
 
34
+ const isGeneratedExpr = ({expr}) => expr?.type === 'paren_expr';
35
+
36
+ const convertGeneratedExpr = (constraint) => callExpression(identifier('generatedAlwaysAs'), [
37
+ convertBinary(constraint.expr.expr),
38
+ booleanLiteral(constraint.storageKw?.name === 'STORED'),
39
+ ]);
40
+
41
+ const convertDefaultNextval = (expr) => {
42
+ const [seq] = expr.args.expr.args.items;
43
+ const seqName = seq.value ?? seq.name;
44
+
45
+ return callExpression(identifier('defaultNextval'), [
46
+ identifier(seqName),
47
+ ]);
48
+ };
49
+
34
50
  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
- }
51
+ if (expr.type === 'func_call' && expr.name.name === 'nextval')
52
+ return convertDefaultNextval(expr);
42
53
 
43
54
  if (expr.type === 'number_literal')
44
55
  return callExpression(identifier('default_'), [
@@ -69,6 +80,28 @@ const convertCheck = (constraint) => callExpression(identifier('check'), [
69
80
  convertBinary(constraint.expr.expr),
70
81
  ]);
71
82
 
83
+ const ACTION_NAMES = {
84
+ CASCADE: true,
85
+ RESTRICT: true,
86
+ SET_NULL: true,
87
+ SET_DEFAULT: true,
88
+ };
89
+
90
+ const convertReferentialAction = ({eventKw, actionKw}) => {
91
+ const event = eventKw.name === 'DELETE' ? 'onDelete' : 'onUpdate';
92
+ const action = Array.isArray(actionKw) ? actionKw
93
+ .map(({name}) => name)
94
+ .join(' ') : actionKw.name;
95
+
96
+ const name = ACTION_NAMES[action] ? action : action
97
+ .replace(/\s+/g, '_')
98
+ .toUpperCase();
99
+
100
+ return callExpression(identifier(event), [
101
+ identifier(name),
102
+ ]);
103
+ };
104
+
72
105
  const convertReferences = (constraint) => {
73
106
  const refTable = identifier(constraint.table.name);
74
107
  const cols = constraint.columns.expr.items;
@@ -77,12 +110,20 @@ const convertReferences = (constraint) => {
77
110
  for (const col of cols)
78
111
  args.push(identifier(col.name));
79
112
 
113
+ for (const option of constraint.options)
114
+ args.push(convertReferentialAction(option));
115
+
80
116
  return callExpression(identifier('references'), args);
81
117
  };
82
118
 
83
119
  const CONSTRAINT_VISITORS = {
84
120
  constraint_primary_key: () => callExpression(identifier('primaryKey'), []),
85
- constraint_generated: convertGenerated,
121
+ constraint_generated: (constraint) => {
122
+ if (isGeneratedExpr(constraint))
123
+ return convertGeneratedExpr(constraint);
124
+
125
+ return convertGenerated(constraint);
126
+ },
86
127
  constraint_not_null: () => callExpression(identifier('notNull'), []),
87
128
  constraint_default: convertDefault,
88
129
  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?.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,64 @@ 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) => ['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 isWithoutRowid = (options) => options?.items.some(({name}) => name?.some?.(({name}) => name === 'WITHOUT'));
25
+
26
+ const convertTableArgs = (stmt) => {
27
+ const colNodes = stmt.columns.expr.items.map(convertColumnListItem);
28
+
29
+ if (isWithoutRowid(stmt.options))
30
+ colNodes.push(callExpression(identifier('withoutRowid'), []));
31
+
32
+ return [
33
+ identifier(stmt.name.name),
14
34
  arrayExpression(colNodes),
15
35
  ];
36
+ };
37
+
38
+ const convertUsing = ({module}) => {
39
+ const args = [];
40
+
41
+ for (const item of module.args.expr.args.items)
42
+ args.push(identifier(item.name));
43
+
44
+ return callExpression(identifier(module.name.name), args);
45
+ };
46
+
47
+ export const convertCreateTable = (stmt) => {
48
+ if (isVirtual(stmt)) {
49
+ const [usingClause] = stmt.clauses;
50
+
51
+ return callExpression(identifier('createVirtualTable'), [
52
+ identifier(stmt.name.name),
53
+ convertUsing(usingClause),
54
+ ]);
55
+ }
56
+
57
+ const asClause = stmt.clauses?.find(isAsClause);
58
+
59
+ if (asClause)
60
+ return callExpression(identifier('createTableAs'), [
61
+ identifier(stmt.name.name),
62
+ convertClause(asClause.expr),
63
+ ]);
64
+
65
+ const fnName = isTemp(stmt) ? 'createTempTable' : 'createTable';
66
+ const tableArgs = convertTableArgs(stmt);
16
67
 
17
- if (ifNotExistsKw)
18
- return callExpression(identifier('createTableIfNotExists'), tableArgs);
68
+ if (stmt.ifNotExistsKw)
69
+ return callExpression(identifier(`${fnName}IfNotExists`), tableArgs);
19
70
 
20
- return callExpression(identifier('createTable'), tableArgs);
71
+ return callExpression(identifier(fnName), tableArgs);
21
72
  };
@@ -0,0 +1,17 @@
1
+ import {types} from '@putout/babel';
2
+ import {convertClause} from '#parser/clause';
3
+
4
+ const {identifier, callExpression} = types;
5
+
6
+ const isMaterialized = (stmt) => stmt.kinds.some(({kindKw}) => kindKw.name === 'MATERIALIZED');
7
+
8
+ export const convertCreateView = (stmt) => {
9
+ const [asClause] = stmt.clauses;
10
+ const inner = convertClause(asClause.expr);
11
+ const fnName = isMaterialized(stmt) ? 'createMaterializedView' : 'createView';
12
+
13
+ return callExpression(identifier(fnName), [
14
+ identifier(stmt.name.name),
15
+ inner,
16
+ ]);
17
+ };
@@ -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
+ };