happy-sql 2.0.8 → 2.1.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.
- package/ChangeLog +5 -0
- package/lib/parser/visitors/clause/from/fixture/group-by-fix.js +14 -0
- package/lib/parser/visitors/clause/from/fixture/group-by-having-fix.js +22 -0
- package/lib/parser/visitors/clause/from/fixture/group-by-having.sql +1 -0
- package/lib/parser/visitors/clause/from/fixture/group-by-multi-fix.js +13 -0
- package/lib/parser/visitors/clause/from/fixture/group-by-multi.sql +1 -0
- package/lib/parser/visitors/clause/from/fixture/group-by.sql +1 -0
- package/lib/parser/visitors/clause/from/from.js +9 -1
- package/lib/parser/visitors/clause/from/group-by.js +6 -0
- package/lib/parser/visitors/clause/from/having.js +8 -0
- package/lib/parser/visitors/clause/index.js +12 -1
- package/lib/parser/visitors/clause/operand.js +4 -0
- package/lib/parser/visitors/clause/select/select.js +16 -0
- package/lib/parser/visitors/clause/union/fixture/union-all-fix.js +10 -0
- package/lib/parser/visitors/clause/union/fixture/union-all.sql +1 -0
- package/lib/parser/visitors/clause/union/union.js +11 -0
- package/lib/parser/visitors/clause/where/where.js +1 -1
- package/lib/parser/visitors/clause/with-named/fixture/with-named-select-fix.js +19 -0
- package/lib/parser/visitors/clause/with-named/fixture/with-named-select.sql +1 -0
- package/lib/parser/visitors/clause/with-named/fixture/with-recursive-fix.js +27 -0
- package/lib/parser/visitors/clause/with-named/fixture/with-recursive-multi-fix.js +38 -0
- package/lib/parser/visitors/clause/with-named/fixture/with-recursive-multi.sql +1 -0
- package/lib/parser/visitors/clause/with-named/fixture/with-recursive-no-columns-fix.js +20 -0
- package/lib/parser/visitors/clause/with-named/fixture/with-recursive-no-columns.sql +1 -0
- package/lib/parser/visitors/clause/with-named/fixture/with-recursive.sql +1 -0
- package/lib/parser/visitors/clause/with-named/with-named.js +15 -2
- package/lib/printer/visitors/call-expression/clauses/clauses.js +8 -0
- package/lib/printer/visitors/call-expression/clauses/from/fixture/group-by-having-fix.sql +5 -0
- package/lib/printer/visitors/call-expression/clauses/from/fixture/group-by-having.js +22 -0
- package/lib/printer/visitors/call-expression/clauses/from/from.js +13 -6
- package/lib/printer/visitors/call-expression/clauses/group-by/fixture/group-by-fix.sql +3 -0
- package/lib/printer/visitors/call-expression/clauses/group-by/fixture/group-by-multi-fix.sql +3 -0
- package/lib/printer/visitors/call-expression/clauses/group-by/fixture/group-by-multi.js +13 -0
- package/lib/printer/visitors/call-expression/clauses/group-by/fixture/group-by.js +14 -0
- package/lib/printer/visitors/call-expression/clauses/group-by/group-by.js +12 -0
- package/lib/printer/visitors/call-expression/clauses/having/fixture/having-fix.sql +3 -0
- package/lib/printer/visitors/call-expression/clauses/having/fixture/having.js +16 -0
- package/lib/printer/visitors/call-expression/clauses/having/having.js +4 -0
- package/lib/printer/visitors/call-expression/clauses/insert/insert.js +1 -1
- package/lib/printer/visitors/call-expression/clauses/join/join.js +1 -1
- package/lib/printer/visitors/call-expression/clauses/select/select.js +1 -1
- package/lib/printer/visitors/call-expression/clauses/union-all/fixture/union-all-fix.sql +3 -0
- package/lib/printer/visitors/call-expression/clauses/union-all/fixture/union-all.js +1 -0
- package/lib/printer/visitors/call-expression/clauses/union-all/union-all.js +9 -0
- package/lib/printer/visitors/call-expression/clauses/with-named/fixture/with-named-insert-fix.sql +3 -3
- package/lib/printer/visitors/call-expression/clauses/with-named/fixture/with-named-select-fix.sql +8 -0
- package/lib/printer/visitors/call-expression/clauses/with-named/fixture/with-named-select.js +19 -0
- package/lib/printer/visitors/call-expression/clauses/with-named/fixture/withNamed-fix.sql +3 -3
- package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-fix.sql +10 -0
- package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-multi-fix.sql +14 -0
- package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-multi.js +38 -0
- package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-no-columns-fix.sql +8 -0
- package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-no-columns.js +20 -0
- package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive.js +27 -0
- package/lib/printer/visitors/call-expression/clauses/with-recursive/with-recursive.js +57 -0
- package/package.json +2 -1
package/ChangeLog
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT kind, COUNT(*) FROM VariableDeclaration WHERE kind = 'const' GROUP BY kind HAVING COUNT(*) > 1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT kind, name FROM VariableDeclaration GROUP BY kind, name
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT kind, COUNT(*) FROM VariableDeclaration GROUP BY kind
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
2
|
import {convertOperand} from '#parser/clause/operand';
|
|
3
|
+
import {convertGroupBy} from './group-by.js';
|
|
4
|
+
import {convertHaving} from './having.js';
|
|
3
5
|
|
|
4
6
|
const isString = (a) => typeof a === 'string';
|
|
5
7
|
|
|
@@ -108,7 +110,7 @@ const flattenJoins = (node, joins = []) => {
|
|
|
108
110
|
return joins;
|
|
109
111
|
};
|
|
110
112
|
|
|
111
|
-
export const convertFrom = ({expr, whereClause}) => {
|
|
113
|
+
export const convertFrom = ({expr, whereClause, groupByClause, havingClause}) => {
|
|
112
114
|
const fromArgs = [];
|
|
113
115
|
|
|
114
116
|
if (whereClause)
|
|
@@ -116,6 +118,12 @@ export const convertFrom = ({expr, whereClause}) => {
|
|
|
116
118
|
convertCondition(whereClause.expr),
|
|
117
119
|
]));
|
|
118
120
|
|
|
121
|
+
if (groupByClause)
|
|
122
|
+
fromArgs.push(convertGroupBy(groupByClause));
|
|
123
|
+
|
|
124
|
+
if (havingClause)
|
|
125
|
+
fromArgs.push(convertHaving(havingClause));
|
|
126
|
+
|
|
119
127
|
if (expr.type === 'join_expr') {
|
|
120
128
|
const parts = flattenJoins(expr);
|
|
121
129
|
return callExpression(identifier('from'), parts);
|
|
@@ -5,6 +5,7 @@ import {convertDelete} from '#parser/clause/delete';
|
|
|
5
5
|
import {convertWithNamed} from '#parser/clause/with-named';
|
|
6
6
|
import {convertCreateTable} from '#parser/clause/create-table';
|
|
7
7
|
import {convertCreateSequence} from '#parser/clause/create-sequence';
|
|
8
|
+
import {convertUnionAll} from '#parser/clause/union';
|
|
8
9
|
import {findClause} from '#parser/clause/find';
|
|
9
10
|
|
|
10
11
|
export const convertClause = (stmt) => {
|
|
@@ -26,11 +27,21 @@ const convertInsertOrNamed = (stmt) => {
|
|
|
26
27
|
return convertInsert(stmt);
|
|
27
28
|
};
|
|
28
29
|
|
|
30
|
+
const convertSelectOrNamed = (stmt) => {
|
|
31
|
+
const {clauses} = stmt;
|
|
32
|
+
|
|
33
|
+
if (findClause(clauses, 'with_clause'))
|
|
34
|
+
return convertWithNamed(stmt);
|
|
35
|
+
|
|
36
|
+
return convertSelect(stmt);
|
|
37
|
+
};
|
|
38
|
+
|
|
29
39
|
const clauseVisitors = {
|
|
30
|
-
select_stmt:
|
|
40
|
+
select_stmt: convertSelectOrNamed,
|
|
31
41
|
insert_stmt: convertInsertOrNamed,
|
|
32
42
|
update_stmt: convertUpdate,
|
|
33
43
|
delete_stmt: convertDelete,
|
|
34
44
|
create_table_stmt: convertCreateTable,
|
|
35
45
|
create_sequence_stmt: convertCreateSequence,
|
|
46
|
+
compound_select_stmt: convertUnionAll,
|
|
36
47
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
+
import {convertCount, isCount} from '#parser/clause/count';
|
|
2
3
|
|
|
3
4
|
const {
|
|
4
5
|
identifier,
|
|
@@ -10,6 +11,9 @@ const {
|
|
|
10
11
|
} = types;
|
|
11
12
|
|
|
12
13
|
export const convertOperand = (node) => {
|
|
14
|
+
if (isCount(node))
|
|
15
|
+
return convertCount(node);
|
|
16
|
+
|
|
13
17
|
if (node.type === 'member_expr')
|
|
14
18
|
return memberExpression(identifier(node.object.name), identifier(node.property.name));
|
|
15
19
|
|
|
@@ -11,6 +11,8 @@ const {
|
|
|
11
11
|
tsLiteralType,
|
|
12
12
|
callExpression,
|
|
13
13
|
memberExpression,
|
|
14
|
+
numericLiteral,
|
|
15
|
+
binaryExpression,
|
|
14
16
|
} = types;
|
|
15
17
|
|
|
16
18
|
const convertColumn = (column) => {
|
|
@@ -32,6 +34,16 @@ const convertColumn = (column) => {
|
|
|
32
34
|
if (column.type === 'parameter')
|
|
33
35
|
return stringLiteral(column.text);
|
|
34
36
|
|
|
37
|
+
if (column.type === 'number_literal')
|
|
38
|
+
return numericLiteral(column.value);
|
|
39
|
+
|
|
40
|
+
if (column.type === 'binary_expr')
|
|
41
|
+
return binaryExpression(
|
|
42
|
+
column.operator,
|
|
43
|
+
convertOperand(column.left),
|
|
44
|
+
convertOperand(column.right),
|
|
45
|
+
);
|
|
46
|
+
|
|
35
47
|
return identifier(column.name);
|
|
36
48
|
};
|
|
37
49
|
|
|
@@ -57,12 +69,16 @@ export const convertSelect = ({clauses}) => {
|
|
|
57
69
|
const selectClause = findClause(clauses, 'select_clause');
|
|
58
70
|
const fromClause = findClause(clauses, 'from_clause');
|
|
59
71
|
const whereClause = findClause(clauses, 'where_clause');
|
|
72
|
+
const groupByClause = findClause(clauses, 'group_by_clause');
|
|
73
|
+
const havingClause = findClause(clauses, 'having_clause');
|
|
60
74
|
|
|
61
75
|
const args = [
|
|
62
76
|
...convertColumns(selectClause.columns),
|
|
63
77
|
fromClause && convertFrom({
|
|
64
78
|
expr: fromClause.expr,
|
|
65
79
|
whereClause,
|
|
80
|
+
groupByClause,
|
|
81
|
+
havingClause,
|
|
66
82
|
}),
|
|
67
83
|
].filter(Boolean);
|
|
68
84
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT 1 UNION ALL SELECT 2
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {types} from '@putout/babel';
|
|
2
|
+
import {convertClause} from '#parser/clause';
|
|
3
|
+
|
|
4
|
+
const {callExpression, identifier} = types;
|
|
5
|
+
|
|
6
|
+
export const convertUnionAll = (stmt) => {
|
|
7
|
+
return callExpression(identifier('unionAll'), [
|
|
8
|
+
convertClause(stmt.left),
|
|
9
|
+
convertClause(stmt.right),
|
|
10
|
+
]);
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
WITH recent AS (SELECT id FROM users WHERE kind = 'const') SELECT id FROM recent
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[
|
|
2
|
+
withRecursive(
|
|
3
|
+
numbers(
|
|
4
|
+
'value',
|
|
5
|
+
unionAll(
|
|
6
|
+
select(
|
|
7
|
+
1,
|
|
8
|
+
),
|
|
9
|
+
select(
|
|
10
|
+
value + 1,
|
|
11
|
+
from(
|
|
12
|
+
numbers,
|
|
13
|
+
where(
|
|
14
|
+
value < 10,
|
|
15
|
+
),
|
|
16
|
+
),
|
|
17
|
+
),
|
|
18
|
+
),
|
|
19
|
+
),
|
|
20
|
+
select(
|
|
21
|
+
value,
|
|
22
|
+
from(
|
|
23
|
+
numbers,
|
|
24
|
+
),
|
|
25
|
+
),
|
|
26
|
+
),
|
|
27
|
+
];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[
|
|
2
|
+
withRecursive(
|
|
3
|
+
t(
|
|
4
|
+
unionAll(
|
|
5
|
+
select(
|
|
6
|
+
1,
|
|
7
|
+
),
|
|
8
|
+
select(
|
|
9
|
+
2,
|
|
10
|
+
),
|
|
11
|
+
),
|
|
12
|
+
),
|
|
13
|
+
u(
|
|
14
|
+
'a',
|
|
15
|
+
'b',
|
|
16
|
+
unionAll(
|
|
17
|
+
select(
|
|
18
|
+
1,
|
|
19
|
+
2,
|
|
20
|
+
),
|
|
21
|
+
select(
|
|
22
|
+
a,
|
|
23
|
+
b,
|
|
24
|
+
from(
|
|
25
|
+
t,
|
|
26
|
+
),
|
|
27
|
+
),
|
|
28
|
+
),
|
|
29
|
+
),
|
|
30
|
+
select(
|
|
31
|
+
a,
|
|
32
|
+
b,
|
|
33
|
+
from(
|
|
34
|
+
u,
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
WITH RECURSIVE t AS (SELECT 1 UNION ALL SELECT 2), u(a, b) AS (SELECT 1, 2 UNION ALL SELECT a, b FROM t) SELECT a, b FROM u
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
WITH RECURSIVE t AS (SELECT 1 UNION ALL SELECT 2) SELECT * FROM t
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
WITH RECURSIVE numbers(value) AS (SELECT 1 UNION ALL SELECT value + 1 FROM numbers WHERE value < 10) SELECT value FROM numbers
|
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
identifier,
|
|
7
7
|
assignmentExpression,
|
|
8
8
|
callExpression,
|
|
9
|
+
stringLiteral,
|
|
9
10
|
} = types;
|
|
10
11
|
|
|
11
12
|
const isWithClause = (clause) => clause.type !== 'with_clause';
|
|
@@ -14,18 +15,30 @@ const convertTable = ({table, expr}) => {
|
|
|
14
15
|
return assignmentExpression('=', identifier(table.name), convertClause(expr.expr));
|
|
15
16
|
};
|
|
16
17
|
|
|
18
|
+
// recursive CTE: numbers('value', unionAll(...))
|
|
19
|
+
const convertRecursiveTable = ({table, columns, expr}) => {
|
|
20
|
+
const colArgs = columns ? columns.expr.items.map((column) => stringLiteral(column.name)) : [];
|
|
21
|
+
const body = convertClause(expr.expr);
|
|
22
|
+
|
|
23
|
+
return callExpression(identifier(table.name), [...colArgs, body]);
|
|
24
|
+
};
|
|
25
|
+
|
|
17
26
|
export const convertWithNamed = (stmt) => {
|
|
18
27
|
const withClause = findClause(stmt.clauses, 'with_clause');
|
|
28
|
+
const isRecursive = Boolean(withClause.recursiveKw);
|
|
29
|
+
const fnName = isRecursive ? 'withRecursive' : 'withNamed';
|
|
19
30
|
|
|
20
31
|
const finalStatement = convertClause({
|
|
21
32
|
...stmt,
|
|
22
33
|
clauses: stmt.clauses.filter(isWithClause),
|
|
23
34
|
});
|
|
24
35
|
|
|
36
|
+
const convertCte = isRecursive ? convertRecursiveTable : convertTable;
|
|
37
|
+
|
|
25
38
|
const args = [
|
|
26
|
-
...withClause.tables.items.map(
|
|
39
|
+
...withClause.tables.items.map(convertCte),
|
|
27
40
|
finalStatement,
|
|
28
41
|
];
|
|
29
42
|
|
|
30
|
-
return callExpression(identifier(
|
|
43
|
+
return callExpression(identifier(fnName), args);
|
|
31
44
|
};
|
|
@@ -14,6 +14,10 @@ import {section} from './section/section.js';
|
|
|
14
14
|
import {count} from './count/count.js';
|
|
15
15
|
import {returning} from './returning/returning.js';
|
|
16
16
|
import {withNamed} from './with-named/with-named.js';
|
|
17
|
+
import {withRecursive} from './with-recursive/with-recursive.js';
|
|
18
|
+
import {unionAll} from './union-all/union-all.js';
|
|
19
|
+
import {groupBy} from './group-by/group-by.js';
|
|
20
|
+
import {having} from './having/having.js';
|
|
17
21
|
import {createTable} from './create-table/create-table.js';
|
|
18
22
|
import {createSequence} from './create-sequence/create-sequence.js';
|
|
19
23
|
import {column} from './column/column.js';
|
|
@@ -48,6 +52,10 @@ export const clauses = {
|
|
|
48
52
|
section,
|
|
49
53
|
returning,
|
|
50
54
|
withNamed,
|
|
55
|
+
withRecursive,
|
|
56
|
+
unionAll,
|
|
57
|
+
groupBy,
|
|
58
|
+
having,
|
|
51
59
|
createTable,
|
|
52
60
|
createSequence,
|
|
53
61
|
column,
|
|
@@ -7,6 +7,14 @@ const printAsExpression = (path, {write, traverse}) => {
|
|
|
7
7
|
write(` AS ${path.node.typeAnnotation.literal.value}`);
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
const CLAUSE_NAMES = [
|
|
11
|
+
'where',
|
|
12
|
+
'groupBy',
|
|
13
|
+
'having',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const isClause = ({node}) => node.type === 'CallExpression' && CLAUSE_NAMES.includes(node.callee?.name);
|
|
17
|
+
|
|
10
18
|
const printArg = (path, ctx) => {
|
|
11
19
|
if (isTSAsExpression(path.node))
|
|
12
20
|
return printAsExpression(path, ctx);
|
|
@@ -16,9 +24,8 @@ const printArg = (path, ctx) => {
|
|
|
16
24
|
|
|
17
25
|
export const from = (path, {write, traverse}) => {
|
|
18
26
|
const args = path.get('arguments');
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const tableArgs = hasWhere ? args.slice(0, -1) : args;
|
|
27
|
+
const tableArgs = args.filter((arg) => !isClause(arg));
|
|
28
|
+
const clauseArgs = args.filter(isClause);
|
|
22
29
|
|
|
23
30
|
write('FROM ');
|
|
24
31
|
printArg(tableArgs[0], {
|
|
@@ -32,8 +39,8 @@ export const from = (path, {write, traverse}) => {
|
|
|
32
39
|
traverse,
|
|
33
40
|
});
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
write.
|
|
37
|
-
traverse(
|
|
42
|
+
for (const clause of clauseArgs) {
|
|
43
|
+
write.breakline();
|
|
44
|
+
traverse(clause);
|
|
38
45
|
}
|
|
39
46
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[unionAll(select(1), select(2))];
|
package/lib/printer/visitors/call-expression/clauses/with-named/fixture/with-named-insert-fix.sql
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
WITH
|
|
2
2
|
call AS (
|
|
3
3
|
INSERT INTO CallExpression (file, parent_id) VALUES (:file, :parent_id)
|
|
4
|
-
RETURNING id
|
|
4
|
+
RETURNING id
|
|
5
5
|
),
|
|
6
6
|
member AS (
|
|
7
7
|
INSERT INTO MemberExpression (file, parent_id) SELECT :file, id
|
|
8
|
-
FROM call
|
|
9
|
-
RETURNING id
|
|
8
|
+
FROM call
|
|
9
|
+
RETURNING id
|
|
10
10
|
)
|
|
11
11
|
INSERT INTO Identifier (file, name, parent_id) SELECT :file, 'isNaN', id
|
|
12
12
|
FROM member
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
WITH
|
|
2
2
|
call AS (
|
|
3
3
|
INSERT INTO CallExpression (parent_id) VALUES (:parent_id)
|
|
4
|
-
RETURNING id
|
|
4
|
+
RETURNING id
|
|
5
5
|
),
|
|
6
6
|
member AS (
|
|
7
7
|
INSERT INTO MemberExpression (parent_id) SELECT id
|
|
8
|
-
FROM call
|
|
9
|
-
RETURNING id
|
|
8
|
+
FROM call
|
|
9
|
+
RETURNING id
|
|
10
10
|
)
|
|
11
11
|
INSERT INTO Identifier (name, parent_id) SELECT 'x', id
|
|
12
12
|
FROM member
|
package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-multi.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[
|
|
2
|
+
withRecursive(
|
|
3
|
+
t(
|
|
4
|
+
unionAll(
|
|
5
|
+
select(
|
|
6
|
+
1,
|
|
7
|
+
),
|
|
8
|
+
select(
|
|
9
|
+
2,
|
|
10
|
+
),
|
|
11
|
+
),
|
|
12
|
+
),
|
|
13
|
+
u(
|
|
14
|
+
'a',
|
|
15
|
+
'b',
|
|
16
|
+
unionAll(
|
|
17
|
+
select(
|
|
18
|
+
1,
|
|
19
|
+
2,
|
|
20
|
+
),
|
|
21
|
+
select(
|
|
22
|
+
a,
|
|
23
|
+
b,
|
|
24
|
+
from(
|
|
25
|
+
t,
|
|
26
|
+
),
|
|
27
|
+
),
|
|
28
|
+
),
|
|
29
|
+
),
|
|
30
|
+
select(
|
|
31
|
+
a,
|
|
32
|
+
b,
|
|
33
|
+
from(
|
|
34
|
+
u,
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[
|
|
2
|
+
withRecursive(
|
|
3
|
+
numbers(
|
|
4
|
+
'value',
|
|
5
|
+
unionAll(
|
|
6
|
+
select(
|
|
7
|
+
1,
|
|
8
|
+
),
|
|
9
|
+
select(
|
|
10
|
+
value + 1,
|
|
11
|
+
from(
|
|
12
|
+
numbers,
|
|
13
|
+
where(
|
|
14
|
+
value < 10,
|
|
15
|
+
),
|
|
16
|
+
),
|
|
17
|
+
),
|
|
18
|
+
),
|
|
19
|
+
),
|
|
20
|
+
select(
|
|
21
|
+
value,
|
|
22
|
+
from(
|
|
23
|
+
numbers,
|
|
24
|
+
),
|
|
25
|
+
),
|
|
26
|
+
),
|
|
27
|
+
];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const isStringLiteral = ({type}) => type === 'StringLiteral';
|
|
2
|
+
|
|
3
|
+
export const withRecursive = (path, {write, indent, traverse}) => {
|
|
4
|
+
const args = path.get('arguments');
|
|
5
|
+
const ctes = args.slice(0, -1);
|
|
6
|
+
const finalStatement = args.at(-1);
|
|
7
|
+
|
|
8
|
+
write('WITH RECURSIVE');
|
|
9
|
+
write.newline();
|
|
10
|
+
|
|
11
|
+
const last = ctes.length - 1;
|
|
12
|
+
|
|
13
|
+
for (const [i, cte] of ctes.entries()) {
|
|
14
|
+
const {name} = cte.node.callee;
|
|
15
|
+
const cteArgs = cte.get('arguments');
|
|
16
|
+
const colArgs = cteArgs.filter(isStringLiteral);
|
|
17
|
+
|
|
18
|
+
indent.inc();
|
|
19
|
+
write.indent();
|
|
20
|
+
indent.dec();
|
|
21
|
+
write(name);
|
|
22
|
+
|
|
23
|
+
if (colArgs.length) {
|
|
24
|
+
write('(');
|
|
25
|
+
|
|
26
|
+
for (const [j, col] of colArgs.entries()) {
|
|
27
|
+
if (j > 0)
|
|
28
|
+
write(', ');
|
|
29
|
+
|
|
30
|
+
write(col.node.value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
write(')');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
write(' AS (');
|
|
37
|
+
write.newline();
|
|
38
|
+
indent.inc();
|
|
39
|
+
indent.inc();
|
|
40
|
+
write.indent();
|
|
41
|
+
traverse(cteArgs.at(-1));
|
|
42
|
+
indent.dec();
|
|
43
|
+
indent.dec();
|
|
44
|
+
write.newline();
|
|
45
|
+
indent.inc();
|
|
46
|
+
write.indent();
|
|
47
|
+
indent.dec();
|
|
48
|
+
write(')');
|
|
49
|
+
|
|
50
|
+
if (i < last)
|
|
51
|
+
write(',');
|
|
52
|
+
|
|
53
|
+
write.newline();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
traverse(finalStatement);
|
|
57
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "happy-sql",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "sql to js ast parser and printer",
|
|
6
6
|
"exports": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"#parser/clause/update": "./lib/parser/visitors/clause/update/update.js",
|
|
26
26
|
"#parser/clause/delete": "./lib/parser/visitors/clause/delete/delete.js",
|
|
27
27
|
"#parser/clause/with-named": "./lib/parser/visitors/clause/with-named/with-named.js",
|
|
28
|
+
"#parser/clause/union": "./lib/parser/visitors/clause/union/union.js",
|
|
28
29
|
"#parser/clause/create-table": "./lib/parser/visitors/clause/create-table/create-table.js",
|
|
29
30
|
"#parser/clause/create-sequence": "./lib/parser/visitors/clause/create-sequence/create-sequence.js",
|
|
30
31
|
"#parser/clause/column-definition": "./lib/parser/visitors/clause/column-definition/column-definition.js",
|