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.
- package/ChangeLog +88 -0
- package/bin/convert.js +3 -9
- package/lib/parser/parser.js +11 -11
- package/lib/parser/visitors/clause/alter-table/alter-table.js +24 -0
- package/lib/parser/visitors/clause/binary.js +31 -7
- package/lib/parser/visitors/clause/column-definition/column-definition.js +62 -8
- package/lib/parser/visitors/clause/count/count.js +5 -2
- package/lib/parser/visitors/clause/create-extension/create-extension.js +7 -0
- package/lib/parser/visitors/clause/create-index/create-index.js +36 -5
- package/lib/parser/visitors/clause/create-schema/create-schema.js +7 -0
- package/lib/parser/visitors/clause/create-table/create-table.js +63 -7
- package/lib/parser/visitors/clause/create-view/create-view.js +18 -0
- package/lib/parser/visitors/clause/drop-index/drop-index.js +3 -0
- package/lib/parser/visitors/clause/drop-view/drop-view.js +15 -0
- package/lib/parser/visitors/clause/explain/explain.js +16 -0
- package/lib/parser/visitors/clause/from/from.js +109 -13
- package/lib/parser/visitors/clause/from/group-by.js +8 -1
- package/lib/parser/visitors/clause/from/limit.js +13 -0
- package/lib/parser/visitors/clause/from/order-by.js +15 -3
- package/lib/parser/visitors/clause/from/table-func.js +10 -14
- package/lib/parser/visitors/clause/grant/grant.js +26 -0
- package/lib/parser/visitors/clause/index.js +66 -2
- package/lib/parser/visitors/clause/insert/insert.js +81 -9
- package/lib/parser/visitors/clause/operand.js +55 -1
- package/lib/parser/visitors/clause/pragma/pragma.js +52 -2
- package/lib/parser/visitors/clause/select/select.js +149 -9
- package/lib/parser/visitors/clause/set-param/set-param.js +19 -0
- package/lib/parser/visitors/clause/table-constraint.js +27 -0
- package/lib/parser/visitors/clause/update/update.js +17 -0
- package/lib/parser/visitors/clause/where/where.js +17 -0
- package/lib/parser/visitors/clause/with-named/with-named.js +15 -1
- package/lib/printer/visitors/call-expression/clauses/access-method/access-method.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/add-constraint/add-constraint.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/analyze/analyze.js +10 -0
- package/lib/printer/visitors/call-expression/clauses/array-type/array-type.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/clauses.js +134 -2
- package/lib/printer/visitors/call-expression/clauses/collate/collate.js +7 -0
- package/lib/printer/visitors/call-expression/clauses/concurrently/concurrently.js +2 -0
- package/lib/printer/visitors/call-expression/clauses/constraint/constraint.js +11 -0
- package/lib/printer/visitors/call-expression/clauses/count-distinct/count-distinct.js +13 -0
- package/lib/printer/visitors/call-expression/clauses/create-extension/create-extension.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/create-index/create-index.js +43 -9
- package/lib/printer/visitors/call-expression/clauses/create-index/create-unique-index.js +5 -19
- package/lib/printer/visitors/call-expression/clauses/create-materialized-view/create-materialized-view.js +8 -0
- package/lib/printer/visitors/call-expression/clauses/create-schema/create-schema.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/create-table/create-table.js +16 -1
- package/lib/printer/visitors/call-expression/clauses/create-table-as/create-table-as.js +8 -0
- package/lib/printer/visitors/call-expression/clauses/create-temp-table/create-temp-table.js +11 -0
- package/lib/printer/visitors/call-expression/clauses/create-view/create-view.js +8 -0
- package/lib/printer/visitors/call-expression/clauses/create-virtual-table/create-virtual-table.js +8 -0
- package/lib/printer/visitors/call-expression/clauses/{nextval/nextval.js → default-nextval/default-nextval.js} +2 -1
- package/lib/printer/visitors/call-expression/clauses/default-values/default-values.js +3 -0
- package/lib/printer/visitors/call-expression/clauses/detach/detach.js +6 -0
- package/lib/printer/visitors/call-expression/clauses/distinct-on/distinct-on.js +14 -0
- package/lib/printer/visitors/call-expression/clauses/do-block/do-block.js +5 -0
- package/lib/printer/visitors/call-expression/clauses/drop-index/drop-index.js +13 -1
- package/lib/printer/visitors/call-expression/clauses/drop-view/drop-view.js +24 -0
- package/lib/printer/visitors/call-expression/clauses/explain/explain.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/explain-analyze/explain-analyze.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/explain-query-plan/explain-query-plan.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/fetch-first/fetch-first.js +5 -0
- package/lib/printer/visitors/call-expression/clauses/filter/filter.js +8 -0
- package/lib/printer/visitors/call-expression/clauses/for-update/for-update.js +3 -0
- package/lib/printer/visitors/call-expression/clauses/from/from.js +49 -5
- package/lib/printer/visitors/call-expression/clauses/generated-always-as/generated-always-as.js +10 -0
- package/lib/printer/visitors/call-expression/clauses/grant/grant.js +10 -0
- package/lib/printer/visitors/call-expression/clauses/grant-on/grant-on.js +10 -0
- package/lib/printer/visitors/call-expression/clauses/if-not-exists/if-not-exists.js +2 -0
- package/lib/printer/visitors/call-expression/clauses/indexed-by/indexed-by.js +7 -0
- package/lib/printer/visitors/call-expression/clauses/into/into.js +34 -3
- package/lib/printer/visitors/call-expression/clauses/json-op.js +9 -1
- package/lib/printer/visitors/call-expression/clauses/lateral-join/lateral-join.js +26 -3
- package/lib/printer/visitors/call-expression/clauses/like/like.js +7 -0
- package/lib/printer/visitors/call-expression/clauses/limit-all/limit-all.js +3 -0
- package/lib/printer/visitors/call-expression/clauses/limit-clauses.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/named-window/named-window.js +16 -0
- package/lib/printer/visitors/call-expression/clauses/not/not.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/not-indexed/not-indexed.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/nulls-order/nulls-order.js +9 -0
- package/lib/printer/visitors/call-expression/clauses/offset/offset.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/on-conflict/on-conflict.js +24 -2
- package/lib/printer/visitors/call-expression/clauses/on-delete/on-delete.js +32 -0
- package/lib/printer/visitors/call-expression/clauses/or-abort/or-abort.js +3 -0
- package/lib/printer/visitors/call-expression/clauses/or-fail/or-fail.js +3 -0
- package/lib/printer/visitors/call-expression/clauses/over/over.js +12 -0
- package/lib/printer/visitors/call-expression/clauses/pragma/pragma.js +14 -5
- package/lib/printer/visitors/call-expression/clauses/privilege/privilege.js +10 -0
- package/lib/printer/visitors/call-expression/clauses/references/references.js +26 -4
- package/lib/printer/visitors/call-expression/clauses/reindex/reindex.js +10 -0
- package/lib/printer/visitors/call-expression/clauses/release-savepoint/release-savepoint.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/rename-table/rename-table.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/right-outer-join/right-outer-join.js +8 -0
- package/lib/printer/visitors/call-expression/clauses/row-level-security/row-level-security.js +7 -0
- package/lib/printer/visitors/call-expression/clauses/section/section.js +5 -1
- package/lib/printer/visitors/call-expression/clauses/select/select.js +37 -9
- package/lib/printer/visitors/call-expression/clauses/set-param/set-param.js +14 -0
- package/lib/printer/visitors/call-expression/clauses/show-param/show-param.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/table-primary-key/table-primary-key.js +13 -0
- package/lib/printer/visitors/call-expression/clauses/table-unique/table-unique.js +13 -0
- package/lib/printer/visitors/call-expression/clauses/to/to.js +10 -0
- package/lib/printer/visitors/call-expression/clauses/truncate/truncate.js +12 -0
- package/lib/printer/visitors/call-expression/clauses/unary-minus/unary-minus.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/update/update.js +24 -3
- package/lib/printer/visitors/call-expression/clauses/using/using.js +13 -0
- package/lib/printer/visitors/call-expression/clauses/vacuum/vacuum.js +8 -1
- package/lib/printer/visitors/call-expression/clauses/window-frame/window-frame.js +38 -0
- package/lib/printer/visitors/call-expression/clauses/with-named/with-named.js +8 -20
- package/lib/printer/visitors/call-expression/clauses/without-rowid/without-rowid.js +1 -0
- package/lib/printer/visitors/logical-expression.js +4 -1
- package/lib/printer/visitors/member-expression.js +14 -0
- package/lib/printer/visitors/string-literal.js +9 -5
- 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(
|
|
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);
|
package/lib/parser/parser.js
CHANGED
|
@@ -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(
|
|
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
|
|
51
|
-
.
|
|
52
|
-
|
|
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
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
61
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
38
|
+
const name = funcArgs.distinctKw ? 'countDistinct' : 'count';
|
|
39
|
+
|
|
40
|
+
return callExpression(identifier(name), args);
|
|
38
41
|
};
|
|
@@ -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
|
-
|
|
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
|
-
|
|
34
|
+
const args = [
|
|
25
35
|
identifier(name.name),
|
|
26
36
|
identifier(table.name),
|
|
27
|
-
|
|
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
|
};
|
|
@@ -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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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(
|
|
73
|
+
if (stmt.ifNotExistsKw)
|
|
74
|
+
return callExpression(identifier(`${fnName}IfNotExists`), tableArgs);
|
|
19
75
|
|
|
20
|
-
return callExpression(identifier(
|
|
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
|
+
};
|