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
|
@@ -2,11 +2,20 @@ import {types} from '@putout/babel';
|
|
|
2
2
|
import {convertBetween} from '#parser/clause/where';
|
|
3
3
|
import {convertClause} from '#parser/clause';
|
|
4
4
|
import {convertBinary} from '#parser/clause/binary';
|
|
5
|
+
import {
|
|
6
|
+
convertOperand,
|
|
7
|
+
convertMemberExpr,
|
|
8
|
+
} from '#parser/clause/operand';
|
|
5
9
|
import {convertGroupBy} from './group-by.js';
|
|
6
10
|
import {convertHaving} from './having.js';
|
|
7
11
|
import {convertOrderBy} from './order-by.js';
|
|
8
|
-
import {convertLimit} from './limit.js';
|
|
9
12
|
import {convertTableFunc} from './table-func.js';
|
|
13
|
+
import {
|
|
14
|
+
convertLimit,
|
|
15
|
+
convertOffset,
|
|
16
|
+
convertFetch,
|
|
17
|
+
convertForUpdate,
|
|
18
|
+
} from './limit.js';
|
|
10
19
|
|
|
11
20
|
const {
|
|
12
21
|
identifier,
|
|
@@ -21,6 +30,20 @@ const isExists = (node) => node.type === 'prefix_op_expr' && node.operator.name
|
|
|
21
30
|
const isNotExists = (node) => node.type === 'prefix_op_expr' && node.operator.name === 'NOT' && isExists(node.expr);
|
|
22
31
|
const isParenExpr = (node) => node.type === 'paren_expr';
|
|
23
32
|
|
|
33
|
+
const POSTFIX_OP = {
|
|
34
|
+
ISNULL: 'isNull',
|
|
35
|
+
NOTNULL: 'isNotNull',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const convertPostfix = (node) => {
|
|
39
|
+
const {name} = node.operator;
|
|
40
|
+
const fn = POSTFIX_OP[name];
|
|
41
|
+
|
|
42
|
+
return callExpression(identifier(fn), [
|
|
43
|
+
convertOperand(node.expr),
|
|
44
|
+
]);
|
|
45
|
+
};
|
|
46
|
+
|
|
24
47
|
const convertCondition = (node) => {
|
|
25
48
|
if (node.operator && node.operator.name === 'AND')
|
|
26
49
|
return logicalExpression('&&', convertCondition(node.left), convertCondition(node.right));
|
|
@@ -31,6 +54,9 @@ const convertCondition = (node) => {
|
|
|
31
54
|
if (node.type === 'between_expr')
|
|
32
55
|
return convertBetween(node);
|
|
33
56
|
|
|
57
|
+
if (node.type === 'postfix_op_expr')
|
|
58
|
+
return convertPostfix(node);
|
|
59
|
+
|
|
34
60
|
if (isNotExists(node))
|
|
35
61
|
return callExpression(identifier('notExists'), [
|
|
36
62
|
convertClause(node.expr.expr.expr),
|
|
@@ -51,7 +77,30 @@ const convertOn = (spec) => callExpression(identifier('on'), [
|
|
|
51
77
|
convertCondition(spec.expr),
|
|
52
78
|
]);
|
|
53
79
|
|
|
80
|
+
const isJoinUsing = ({type}) => type === 'join_using_specification';
|
|
81
|
+
|
|
82
|
+
const convertSpecification = (spec) => {
|
|
83
|
+
if (isJoinUsing(spec))
|
|
84
|
+
return callExpression(identifier('using'), spec.expr.expr.items.map(({name}) => identifier(name)));
|
|
85
|
+
|
|
86
|
+
return convertOn(spec);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const isIndexedTable = ({type}) => type === 'indexed_table';
|
|
90
|
+
const isNotIndexedTable = ({type}) => type === 'not_indexed_table';
|
|
91
|
+
|
|
54
92
|
const convertAlias = (node) => {
|
|
93
|
+
if (isIndexedTable(node))
|
|
94
|
+
return callExpression(identifier('indexedBy'), [
|
|
95
|
+
identifier(node.table.name),
|
|
96
|
+
identifier(node.index.name),
|
|
97
|
+
]);
|
|
98
|
+
|
|
99
|
+
if (isNotIndexedTable(node))
|
|
100
|
+
return callExpression(identifier('notIndexed'), [
|
|
101
|
+
identifier(node.table.name),
|
|
102
|
+
]);
|
|
103
|
+
|
|
55
104
|
if (node.type !== 'alias')
|
|
56
105
|
return identifier(node.name);
|
|
57
106
|
|
|
@@ -75,6 +124,9 @@ const convertAlias = (node) => {
|
|
|
75
124
|
]), tsLiteralType(stringLiteral(aliasName)));
|
|
76
125
|
}
|
|
77
126
|
|
|
127
|
+
if (node.expr.type === 'func_call')
|
|
128
|
+
return tsAsExpression(convertTableFunc(node.expr), tsLiteralType(stringLiteral(node.alias.name)));
|
|
129
|
+
|
|
78
130
|
return tsAsExpression(identifier(node.expr.name), tsLiteralType(stringLiteral(node.alias.name)));
|
|
79
131
|
};
|
|
80
132
|
|
|
@@ -93,6 +145,11 @@ const joinTypeParts = (operator) => {
|
|
|
93
145
|
return parts;
|
|
94
146
|
};
|
|
95
147
|
|
|
148
|
+
const capitalizeWord = (s) => s[0].toUpperCase() +
|
|
149
|
+
s
|
|
150
|
+
.slice(1)
|
|
151
|
+
.toLowerCase();
|
|
152
|
+
|
|
96
153
|
const convertJoinType = (operator) => {
|
|
97
154
|
const parts = joinTypeParts(operator);
|
|
98
155
|
|
|
@@ -103,14 +160,12 @@ const convertJoinType = (operator) => {
|
|
|
103
160
|
return 'join';
|
|
104
161
|
|
|
105
162
|
// 'LEFT OUTER' → 'leftOuter' → 'leftOuterJoin'
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
.toLowerCase())
|
|
113
|
-
.join('');
|
|
163
|
+
const tail = [];
|
|
164
|
+
|
|
165
|
+
for (const part of parts.slice(1))
|
|
166
|
+
tail.push(capitalizeWord(part));
|
|
167
|
+
|
|
168
|
+
const camel = parts[0].toLowerCase() + tail.join('');
|
|
114
169
|
|
|
115
170
|
return `${camel}Join`;
|
|
116
171
|
};
|
|
@@ -152,7 +207,7 @@ const flattenJoins = (node, joins = []) => {
|
|
|
152
207
|
else
|
|
153
208
|
joins.push(callExpression(identifier(fnName), [
|
|
154
209
|
convertAlias(node.right),
|
|
155
|
-
|
|
210
|
+
convertSpecification(node.specification),
|
|
156
211
|
]));
|
|
157
212
|
|
|
158
213
|
return joins;
|
|
@@ -163,7 +218,26 @@ const flattenJoins = (node, joins = []) => {
|
|
|
163
218
|
return joins;
|
|
164
219
|
};
|
|
165
220
|
|
|
166
|
-
|
|
221
|
+
const convertWindow = (node) => {
|
|
222
|
+
const {name} = node;
|
|
223
|
+
const {expr} = node.window;
|
|
224
|
+
|
|
225
|
+
const args = [
|
|
226
|
+
identifier(name.name),
|
|
227
|
+
];
|
|
228
|
+
|
|
229
|
+
const {partitionBy, orderBy} = expr;
|
|
230
|
+
|
|
231
|
+
if (partitionBy)
|
|
232
|
+
args.push(callExpression(identifier('partitionBy'), partitionBy.specifications.items.map(convertOperand)));
|
|
233
|
+
|
|
234
|
+
if (orderBy)
|
|
235
|
+
args.push(convertOrderBy(orderBy));
|
|
236
|
+
|
|
237
|
+
return callExpression(identifier('namedWindow'), args);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
export const convertFrom = ({expr, whereClause, groupByClause, havingClause, orderByClause, windowClause, limitClause, offsetClause, fetchClause, forClause}) => {
|
|
167
241
|
const fromArgs = [];
|
|
168
242
|
|
|
169
243
|
if (whereClause)
|
|
@@ -177,15 +251,31 @@ export const convertFrom = ({expr, whereClause, groupByClause, havingClause, ord
|
|
|
177
251
|
if (havingClause)
|
|
178
252
|
fromArgs.push(convertHaving(havingClause));
|
|
179
253
|
|
|
254
|
+
if (windowClause)
|
|
255
|
+
fromArgs.push(...windowClause.namedWindows.items.map(convertWindow));
|
|
256
|
+
|
|
180
257
|
if (orderByClause)
|
|
181
258
|
fromArgs.push(convertOrderBy(orderByClause));
|
|
182
259
|
|
|
183
260
|
if (limitClause)
|
|
184
261
|
fromArgs.push(convertLimit(limitClause));
|
|
185
262
|
|
|
263
|
+
if (offsetClause)
|
|
264
|
+
fromArgs.push(convertOffset(offsetClause));
|
|
265
|
+
|
|
266
|
+
if (fetchClause)
|
|
267
|
+
fromArgs.push(convertFetch(fetchClause));
|
|
268
|
+
|
|
269
|
+
if (forClause)
|
|
270
|
+
fromArgs.push(convertForUpdate());
|
|
271
|
+
|
|
186
272
|
if (expr.type === 'join_expr') {
|
|
187
273
|
const parts = flattenJoins(expr);
|
|
188
|
-
|
|
274
|
+
|
|
275
|
+
return callExpression(identifier('from'), [
|
|
276
|
+
...parts,
|
|
277
|
+
...fromArgs,
|
|
278
|
+
]);
|
|
189
279
|
}
|
|
190
280
|
|
|
191
281
|
if (expr.type === 'alias')
|
|
@@ -200,8 +290,14 @@ export const convertFrom = ({expr, whereClause, groupByClause, havingClause, ord
|
|
|
200
290
|
...fromArgs,
|
|
201
291
|
]);
|
|
202
292
|
|
|
293
|
+
if (expr.type === 'member_expr')
|
|
294
|
+
return callExpression(identifier('from'), [
|
|
295
|
+
convertMemberExpr(expr),
|
|
296
|
+
...fromArgs,
|
|
297
|
+
]);
|
|
298
|
+
|
|
203
299
|
return callExpression(identifier('from'), [
|
|
204
|
-
|
|
300
|
+
convertAlias(expr),
|
|
205
301
|
...fromArgs,
|
|
206
302
|
]);
|
|
207
303
|
};
|
|
@@ -3,4 +3,11 @@ import {convertOperand} from '#parser/clause/operand';
|
|
|
3
3
|
|
|
4
4
|
const {callExpression, identifier} = types;
|
|
5
5
|
|
|
6
|
-
export const convertGroupBy = (clause) =>
|
|
6
|
+
export const convertGroupBy = (clause) => {
|
|
7
|
+
const args = [];
|
|
8
|
+
|
|
9
|
+
for (const item of clause.columns.items)
|
|
10
|
+
args.push(convertOperand(item));
|
|
11
|
+
|
|
12
|
+
return callExpression(identifier('groupBy'), args);
|
|
13
|
+
};
|
|
@@ -7,6 +7,9 @@ const {
|
|
|
7
7
|
} = types;
|
|
8
8
|
|
|
9
9
|
export const convertLimit = (limitClause) => {
|
|
10
|
+
if (limitClause.count && limitClause.count.type === 'limit_all')
|
|
11
|
+
return callExpression(identifier('limitAll'), []);
|
|
12
|
+
|
|
10
13
|
const args = [
|
|
11
14
|
numericLiteral(limitClause.count.value),
|
|
12
15
|
];
|
|
@@ -16,3 +19,13 @@ export const convertLimit = (limitClause) => {
|
|
|
16
19
|
|
|
17
20
|
return callExpression(identifier('limit'), args);
|
|
18
21
|
};
|
|
22
|
+
|
|
23
|
+
export const convertOffset = (offsetClause) => callExpression(identifier('offset'), [
|
|
24
|
+
numericLiteral(offsetClause.offset.value),
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
export const convertFetch = (fetchClause) => callExpression(identifier('fetchFirst'), [
|
|
28
|
+
numericLiteral(fetchClause.count.value),
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
export const convertForUpdate = () => callExpression(identifier('forUpdate'), []);
|
|
@@ -3,15 +3,27 @@ import {convertOperand} from '#parser/clause/operand';
|
|
|
3
3
|
|
|
4
4
|
const {callExpression, identifier} = types;
|
|
5
5
|
|
|
6
|
+
const isDesc = ({type}) => type === 'sort_direction_desc';
|
|
7
|
+
|
|
8
|
+
const convertNullsOrder = (col, nullHandlingKw) => {
|
|
9
|
+
const isLast = nullHandlingKw.at(-1).name === 'LAST';
|
|
10
|
+
const fnName = isLast ? 'nullsLast' : 'nullsFirst';
|
|
11
|
+
|
|
12
|
+
return callExpression(identifier(fnName), [col]);
|
|
13
|
+
};
|
|
14
|
+
|
|
6
15
|
const convertOrderItem = (item) => {
|
|
7
16
|
if (item.type !== 'sort_specification')
|
|
8
17
|
return convertOperand(item);
|
|
9
18
|
|
|
10
|
-
|
|
19
|
+
let col = convertOperand(item.expr);
|
|
11
20
|
const {direction} = item;
|
|
12
21
|
|
|
13
|
-
if (direction
|
|
14
|
-
|
|
22
|
+
if (direction && isDesc(direction))
|
|
23
|
+
col = callExpression(identifier('desc'), [col]);
|
|
24
|
+
|
|
25
|
+
if (item.nullHandlingKw)
|
|
26
|
+
return convertNullsOrder(col, item.nullHandlingKw);
|
|
15
27
|
|
|
16
28
|
// ASC is default — no wrapper
|
|
17
29
|
return col;
|
|
@@ -1,28 +1,24 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
+
import {convertOperand} from '#parser/clause/operand';
|
|
2
3
|
|
|
3
|
-
const {
|
|
4
|
-
callExpression,
|
|
5
|
-
identifier,
|
|
6
|
-
numericLiteral,
|
|
7
|
-
stringLiteral,
|
|
8
|
-
} = types;
|
|
4
|
+
const {callExpression, identifier} = types;
|
|
9
5
|
|
|
10
6
|
const SNAKE_RE = /_([a-z])/g;
|
|
11
7
|
const toCamel = (s) => s.replace(SNAKE_RE, (_, c) => c.toUpperCase());
|
|
12
8
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
return numericLiteral(arg.value);
|
|
9
|
+
const getRawName = (expr) => {
|
|
10
|
+
const raw = expr.name.name;
|
|
16
11
|
|
|
17
|
-
if (
|
|
18
|
-
return
|
|
12
|
+
if (raw.includes('_'))
|
|
13
|
+
return raw.toLowerCase();
|
|
19
14
|
|
|
20
|
-
return
|
|
15
|
+
return raw;
|
|
21
16
|
};
|
|
22
17
|
|
|
23
18
|
export const convertTableFunc = (expr) => {
|
|
24
|
-
|
|
25
|
-
const
|
|
19
|
+
// multi-word snake_case names are lowercased first (GENERATE_SERIES → generateSeries)
|
|
20
|
+
const name = toCamel(getRawName(expr));
|
|
21
|
+
const args = expr.args.expr.args.items.map(convertOperand);
|
|
26
22
|
|
|
27
23
|
return callExpression(identifier(name), args);
|
|
28
24
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {types} from '@putout/babel';
|
|
2
|
+
|
|
3
|
+
const {identifier, callExpression} = types;
|
|
4
|
+
|
|
5
|
+
export const convertGrant = (stmt) => {
|
|
6
|
+
const privArgs = [];
|
|
7
|
+
|
|
8
|
+
for (const p of stmt.privileges.items)
|
|
9
|
+
privArgs.push(identifier(p.privilegeKw.name));
|
|
10
|
+
|
|
11
|
+
const tableArgs = [];
|
|
12
|
+
|
|
13
|
+
for (const t of stmt.resource.tables.items)
|
|
14
|
+
tableArgs.push(identifier(t.name));
|
|
15
|
+
|
|
16
|
+
const roleArgs = [];
|
|
17
|
+
|
|
18
|
+
for (const r of stmt.roles.items)
|
|
19
|
+
roleArgs.push(identifier(r.name));
|
|
20
|
+
|
|
21
|
+
return callExpression(identifier('grant'), [
|
|
22
|
+
callExpression(identifier('privilege'), privArgs),
|
|
23
|
+
callExpression(identifier('grantOn'), tableArgs),
|
|
24
|
+
callExpression(identifier('to'), roleArgs),
|
|
25
|
+
]);
|
|
26
|
+
};
|
|
@@ -12,8 +12,19 @@ import {convertDropTable} from '#parser/clause/drop-table';
|
|
|
12
12
|
import {convertDropIndex} from '#parser/clause/drop-index';
|
|
13
13
|
import {convertPragma} from '#parser/clause/pragma';
|
|
14
14
|
import {convertAttach} from '#parser/clause/attach';
|
|
15
|
+
import {convertExplain} from '#parser/clause/explain';
|
|
16
|
+
import {
|
|
17
|
+
convertSetParam,
|
|
18
|
+
convertShowParam,
|
|
19
|
+
} from '#parser/clause/set-param';
|
|
20
|
+
import {convertCreateView} from '#parser/clause/create-view';
|
|
21
|
+
import {convertDropView} from '#parser/clause/drop-view';
|
|
22
|
+
import {convertCreateExtension} from '#parser/clause/create-extension';
|
|
23
|
+
import {convertCreateSchema} from '#parser/clause/create-schema';
|
|
24
|
+
import {convertGrant} from '#parser/clause/grant';
|
|
15
25
|
import {convertUnion} from '#parser/clause/union';
|
|
16
26
|
import {findClause} from '#parser/clause/find';
|
|
27
|
+
import {convertMemberExpr} from '#parser/clause/operand';
|
|
17
28
|
import {
|
|
18
29
|
convertBegin,
|
|
19
30
|
convertCommit,
|
|
@@ -21,7 +32,20 @@ import {
|
|
|
21
32
|
convertSavepoint,
|
|
22
33
|
} from '#parser/clause/transaction';
|
|
23
34
|
|
|
24
|
-
const {
|
|
35
|
+
const {
|
|
36
|
+
identifier,
|
|
37
|
+
callExpression,
|
|
38
|
+
stringLiteral,
|
|
39
|
+
} = types;
|
|
40
|
+
|
|
41
|
+
const isMemberExpr = ({type}) => type === 'member_expr';
|
|
42
|
+
|
|
43
|
+
const convertTableName = (table) => {
|
|
44
|
+
if (isMemberExpr(table))
|
|
45
|
+
return convertMemberExpr(table);
|
|
46
|
+
|
|
47
|
+
return identifier(table.name);
|
|
48
|
+
};
|
|
25
49
|
|
|
26
50
|
export const convertClause = (stmt) => {
|
|
27
51
|
const {type} = stmt;
|
|
@@ -51,6 +75,8 @@ const convertSelectOrNamed = (stmt) => {
|
|
|
51
75
|
return convertSelect(stmt);
|
|
52
76
|
};
|
|
53
77
|
|
|
78
|
+
const getAnalyzeTables = ({tables}) => tables.items || tables;
|
|
79
|
+
|
|
54
80
|
const clauseVisitors = {
|
|
55
81
|
select_stmt: convertSelectOrNamed,
|
|
56
82
|
insert_stmt: convertInsertOrNamed,
|
|
@@ -69,5 +95,43 @@ const clauseVisitors = {
|
|
|
69
95
|
pragma_stmt: convertPragma,
|
|
70
96
|
attach_database_stmt: convertAttach,
|
|
71
97
|
create_index_stmt: convertCreateIndex,
|
|
72
|
-
vacuum_stmt: () => callExpression(identifier('vacuum'), [
|
|
98
|
+
vacuum_stmt: ({file}) => callExpression(identifier('vacuum'), file ? [
|
|
99
|
+
stringLiteral(file.value),
|
|
100
|
+
] : []),
|
|
101
|
+
truncate_stmt: ({tables}) => {
|
|
102
|
+
const args = [];
|
|
103
|
+
|
|
104
|
+
for (const table of tables.items)
|
|
105
|
+
args.push(convertTableName(table));
|
|
106
|
+
|
|
107
|
+
return callExpression(identifier('truncate'), args);
|
|
108
|
+
},
|
|
109
|
+
detach_database_stmt: ({schema}) => callExpression(identifier('detach'), [
|
|
110
|
+
identifier(schema.name),
|
|
111
|
+
]),
|
|
112
|
+
explain_stmt: convertExplain,
|
|
113
|
+
set_parameter_stmt: convertSetParam,
|
|
114
|
+
show_parameter_stmt: convertShowParam,
|
|
115
|
+
create_view_stmt: convertCreateView,
|
|
116
|
+
drop_view_stmt: convertDropView,
|
|
117
|
+
create_extension_stmt: convertCreateExtension,
|
|
118
|
+
create_schema_stmt: convertCreateSchema,
|
|
119
|
+
grant_privilege_stmt: convertGrant,
|
|
120
|
+
reindex_stmt: (stmt) => callExpression(identifier('reindex'), stmt.name ? [
|
|
121
|
+
identifier(stmt.name.name),
|
|
122
|
+
] : []),
|
|
123
|
+
analyze_stmt: (stmt) => {
|
|
124
|
+
const args = [];
|
|
125
|
+
|
|
126
|
+
for (const table of getAnalyzeTables(stmt))
|
|
127
|
+
args.push(convertTableName(table));
|
|
128
|
+
|
|
129
|
+
return callExpression(identifier('analyze'), args);
|
|
130
|
+
},
|
|
131
|
+
release_savepoint_stmt: ({savepoint}) => callExpression(identifier('releaseSavepoint'), [
|
|
132
|
+
identifier(savepoint.name),
|
|
133
|
+
]),
|
|
134
|
+
do_stmt: (stmt) => callExpression(identifier('doBlock'), [
|
|
135
|
+
stringLiteral(stmt.body.value),
|
|
136
|
+
]),
|
|
73
137
|
};
|
|
@@ -3,12 +3,16 @@ import {convertOperand} from '#parser/clause/operand';
|
|
|
3
3
|
import {convertSet} from '#parser/clause/set';
|
|
4
4
|
import {convertSelect} from '#parser/clause/select';
|
|
5
5
|
import {convertReturning} from '#parser/clause/returning';
|
|
6
|
+
import {convertCondition} from '#parser/clause/where';
|
|
6
7
|
import {findClause} from '#parser/clause/find';
|
|
7
8
|
|
|
8
9
|
const {
|
|
9
10
|
identifier,
|
|
10
11
|
callExpression,
|
|
11
12
|
arrayExpression,
|
|
13
|
+
stringLiteral,
|
|
14
|
+
tsAsExpression,
|
|
15
|
+
tsLiteralType,
|
|
12
16
|
} = types;
|
|
13
17
|
|
|
14
18
|
const convertExprToIdentifier = ({expr}) => identifier(expr.name);
|
|
@@ -49,24 +53,60 @@ const convertSource = (vc) => {
|
|
|
49
53
|
return callExpression(identifier('values'), rowArgs);
|
|
50
54
|
};
|
|
51
55
|
|
|
56
|
+
const getTargetArgs = (target) => {
|
|
57
|
+
if (!target)
|
|
58
|
+
return [];
|
|
59
|
+
|
|
60
|
+
const args = [];
|
|
61
|
+
|
|
62
|
+
for (const item of target.expr.items)
|
|
63
|
+
args.push(convertExprToIdentifier(item));
|
|
64
|
+
|
|
65
|
+
return args;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const convertUpsertAction = (action) => {
|
|
69
|
+
if (action.type === 'upsert_action_nothing')
|
|
70
|
+
return identifier('nothing');
|
|
71
|
+
|
|
72
|
+
return convertSet(action.set);
|
|
73
|
+
};
|
|
74
|
+
|
|
52
75
|
const convertUpsert = (upsertClause) => {
|
|
53
76
|
const target = upsertClause.conflictTarget;
|
|
54
77
|
const {action} = upsertClause;
|
|
55
78
|
|
|
56
|
-
const targetArgs = target
|
|
57
|
-
const actionNode =
|
|
79
|
+
const targetArgs = getTargetArgs(target);
|
|
80
|
+
const actionNode = convertUpsertAction(action);
|
|
81
|
+
|
|
82
|
+
if (upsertClause.where)
|
|
83
|
+
targetArgs.push(callExpression(identifier('where'), [
|
|
84
|
+
convertCondition(upsertClause.where.expr),
|
|
85
|
+
]));
|
|
58
86
|
|
|
59
87
|
return callExpression(identifier('onConflict'), [...targetArgs, actionNode]);
|
|
60
88
|
};
|
|
61
89
|
|
|
62
|
-
const isReplaceInto = ({insertKw, orAction}) => !orAction && insertKw
|
|
90
|
+
const isReplaceInto = ({insertKw, orAction}) => !orAction && insertKw && insertKw.name === 'REPLACE';
|
|
91
|
+
|
|
92
|
+
const colsToArg = (cols) => {
|
|
93
|
+
if (cols.length === 1)
|
|
94
|
+
return identifier(cols[0].name);
|
|
95
|
+
|
|
96
|
+
const args = [];
|
|
97
|
+
|
|
98
|
+
for (const col of cols)
|
|
99
|
+
args.push(convertColToIdentifier(col));
|
|
100
|
+
|
|
101
|
+
return arrayExpression(args);
|
|
102
|
+
};
|
|
63
103
|
|
|
64
104
|
const convertReplaceInto = ({clauses}) => {
|
|
65
105
|
const ic = findClause(clauses, 'insert_clause');
|
|
66
106
|
const rc = findClause(clauses, 'returning_clause');
|
|
67
107
|
|
|
68
108
|
const cols = ic.columns.expr.items;
|
|
69
|
-
const colArg =
|
|
109
|
+
const colArg = colsToArg(cols);
|
|
70
110
|
const source = convertSource(findClause(clauses, 'values_clause'));
|
|
71
111
|
|
|
72
112
|
return callExpression(identifier('replaceInto'), [
|
|
@@ -79,6 +119,13 @@ const convertReplaceInto = ({clauses}) => {
|
|
|
79
119
|
].filter(Boolean));
|
|
80
120
|
};
|
|
81
121
|
|
|
122
|
+
const getSource = (dc, vc) => {
|
|
123
|
+
if (dc)
|
|
124
|
+
return callExpression(identifier('defaultValues'), []);
|
|
125
|
+
|
|
126
|
+
return convertSource(vc);
|
|
127
|
+
};
|
|
128
|
+
|
|
82
129
|
export const convertInsert = (stmt) => {
|
|
83
130
|
if (isReplaceInto(stmt.clauses[0]))
|
|
84
131
|
return convertReplaceInto(stmt);
|
|
@@ -88,16 +135,16 @@ export const convertInsert = (stmt) => {
|
|
|
88
135
|
const [, vc] = clauses;
|
|
89
136
|
const uc = findClause(clauses, 'upsert_clause');
|
|
90
137
|
const rc = findClause(clauses, 'returning_clause');
|
|
138
|
+
const dc = findClause(clauses, 'default_values');
|
|
91
139
|
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
const source = convertSource(vc);
|
|
140
|
+
const colArgs = convertColumns(ic);
|
|
141
|
+
const source = getSource(dc, vc);
|
|
95
142
|
|
|
96
143
|
const args = [
|
|
97
144
|
ic.orAction && convertOrAction(ic.orAction),
|
|
98
145
|
callExpression(identifier('into'), [
|
|
99
|
-
|
|
100
|
-
|
|
146
|
+
convertTable(ic),
|
|
147
|
+
...colArgs,
|
|
101
148
|
source,
|
|
102
149
|
]),
|
|
103
150
|
uc && convertUpsert(uc),
|
|
@@ -106,3 +153,28 @@ export const convertInsert = (stmt) => {
|
|
|
106
153
|
|
|
107
154
|
return callExpression(identifier('insert'), args);
|
|
108
155
|
};
|
|
156
|
+
|
|
157
|
+
const isAliasTable = ({table}) => table.type === 'alias';
|
|
158
|
+
|
|
159
|
+
const convertTable = (ic) => {
|
|
160
|
+
if (!isAliasTable(ic))
|
|
161
|
+
return identifier(ic.table.name);
|
|
162
|
+
|
|
163
|
+
const {expr, alias} = ic.table;
|
|
164
|
+
|
|
165
|
+
return tsAsExpression(identifier(expr.name), tsLiteralType(stringLiteral(alias.name)));
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const convertColumns = (ic) => {
|
|
169
|
+
const columns = ic.columns || ic.table.columnAliases;
|
|
170
|
+
|
|
171
|
+
if (!columns)
|
|
172
|
+
return [];
|
|
173
|
+
|
|
174
|
+
const cols = columns.expr.items;
|
|
175
|
+
const colArg = colsToArg(cols);
|
|
176
|
+
|
|
177
|
+
return [
|
|
178
|
+
colArg,
|
|
179
|
+
];
|
|
180
|
+
};
|
|
@@ -2,6 +2,7 @@ import {types} from '@putout/babel';
|
|
|
2
2
|
import {convertCount, isCount} from '#parser/clause/count';
|
|
3
3
|
import {convertCaseWhen} from '#parser/clause/case-when';
|
|
4
4
|
import {convertClause} from '#parser/clause';
|
|
5
|
+
import {convertBinary} from '#parser/clause/binary';
|
|
5
6
|
|
|
6
7
|
const {
|
|
7
8
|
identifier,
|
|
@@ -13,17 +14,40 @@ const {
|
|
|
13
14
|
callExpression,
|
|
14
15
|
} = types;
|
|
15
16
|
|
|
17
|
+
const isString = (a) => typeof a === 'string';
|
|
18
|
+
|
|
16
19
|
export const convertMemberExpr = (node) => {
|
|
17
20
|
const object = identifier(node.object.name);
|
|
18
21
|
|
|
19
22
|
if (node.property.type === 'all_columns')
|
|
20
23
|
return memberExpression(object, stringLiteral('*'), true);
|
|
21
24
|
|
|
25
|
+
if (node.property.type === 'array_subscript')
|
|
26
|
+
return memberExpression(object, convertOperand(node.property.expr), true);
|
|
27
|
+
|
|
22
28
|
return memberExpression(object, identifier(node.property.name));
|
|
23
29
|
};
|
|
24
30
|
|
|
25
31
|
const isFuncCall = ({type}) => type === 'func_call';
|
|
26
32
|
|
|
33
|
+
const getDataTypeName = ({name}) => {
|
|
34
|
+
if (isString(name))
|
|
35
|
+
return name;
|
|
36
|
+
|
|
37
|
+
return name.text;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const isArrayDataType = ({type}) => type === 'array_data_type';
|
|
41
|
+
|
|
42
|
+
const convertDataType = (dataType) => {
|
|
43
|
+
if (!isArrayDataType(dataType))
|
|
44
|
+
return identifier(getDataTypeName(dataType));
|
|
45
|
+
|
|
46
|
+
return callExpression(identifier('arrayType'), [
|
|
47
|
+
identifier(getDataTypeName(dataType.dataType)),
|
|
48
|
+
]);
|
|
49
|
+
};
|
|
50
|
+
|
|
27
51
|
const convertQuantifier = (node) => {
|
|
28
52
|
const {name} = node.quantifierKw;
|
|
29
53
|
const inner = node.expr.expr;
|
|
@@ -42,6 +66,25 @@ const convertQuantifier = (node) => {
|
|
|
42
66
|
return callExpression(identifier(name), args);
|
|
43
67
|
};
|
|
44
68
|
|
|
69
|
+
const convertPrefix = (node) => {
|
|
70
|
+
const {operator} = node;
|
|
71
|
+
const name = operator.name || operator;
|
|
72
|
+
|
|
73
|
+
if (name === 'EXISTS')
|
|
74
|
+
return callExpression(identifier('exists'), [
|
|
75
|
+
convertClause(node.expr.expr),
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
if (name === 'NOT')
|
|
79
|
+
return callExpression(identifier('not'), [
|
|
80
|
+
convertOperand(node.expr),
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
return callExpression(identifier('unaryMinus'), [
|
|
84
|
+
convertOperand(node.expr),
|
|
85
|
+
]);
|
|
86
|
+
};
|
|
87
|
+
|
|
45
88
|
export const convertOperand = (node) => {
|
|
46
89
|
if (isCount(node))
|
|
47
90
|
return convertCount(node);
|
|
@@ -74,7 +117,18 @@ export const convertOperand = (node) => {
|
|
|
74
117
|
if (node.type === 'cast_operator_expr')
|
|
75
118
|
return callExpression(identifier('pgCast'), [
|
|
76
119
|
convertOperand(node.left),
|
|
77
|
-
|
|
120
|
+
convertDataType(node.right),
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
if (node.type === 'binary_expr')
|
|
124
|
+
return convertBinary(node);
|
|
125
|
+
|
|
126
|
+
if (node.type === 'prefix_op_expr')
|
|
127
|
+
return convertPrefix(node);
|
|
128
|
+
|
|
129
|
+
if (node.type === 'paren_expr' && node.expr.type === 'select_stmt')
|
|
130
|
+
return callExpression(identifier('subquery'), [
|
|
131
|
+
convertClause(node.expr),
|
|
78
132
|
]);
|
|
79
133
|
|
|
80
134
|
if (node.type === 'parameter')
|