happy-sql 2.4.1 → 2.5.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 +6 -0
- package/lib/parser/visitors/clause/binary.js +15 -6
- package/lib/parser/visitors/clause/from/from.js +5 -51
- package/lib/parser/visitors/clause/operand.js +10 -0
- package/lib/parser/visitors/clause/select/select.js +4 -0
- package/lib/parser/visitors/clause/where/where.js +30 -3
- package/lib/printer/visitors/binary-expression.js +28 -5
- package/lib/printer/visitors/call-expression/clauses/clauses.js +8 -1
- package/lib/printer/visitors/call-expression/clauses/create-index/create-index.js +10 -1
- package/lib/printer/visitors/call-expression/clauses/from/from.js +49 -45
- package/lib/printer/visitors/call-expression/clauses/is-null/is-null.js +14 -0
- package/lib/printer/visitors/call-expression/clauses/lateral-join/lateral-join.js +7 -11
- package/lib/printer/visitors/call-expression/clauses/not/not.js +13 -1
- package/lib/printer/visitors/call-expression/clauses/select/select.js +7 -6
- package/lib/printer/visitors/call-expression/clauses/update/update.js +7 -11
- package/lib/printer/visitors/logical-expression.js +7 -2
- package/lib/printer/visitors/string-literal.js +15 -1
- package/package.json +1 -1
package/ChangeLog
CHANGED
|
@@ -89,13 +89,22 @@ const convertCollate = (node) => callExpression(identifier('collate'), [
|
|
|
89
89
|
convertOperand(node.right),
|
|
90
90
|
]);
|
|
91
91
|
|
|
92
|
-
const
|
|
93
|
-
convertOperand(node.left),
|
|
94
|
-
]);
|
|
92
|
+
const isNullLiteral = ({type}) => type === 'null_literal';
|
|
95
93
|
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
const createIs = (nullName, name) => (node) => {
|
|
95
|
+
if (isNullLiteral(node.right))
|
|
96
|
+
return callExpression(identifier(nullName), [
|
|
97
|
+
convertOperand(node.left),
|
|
98
|
+
]);
|
|
99
|
+
|
|
100
|
+
return callExpression(identifier(name), [
|
|
101
|
+
convertOperand(node.left),
|
|
102
|
+
convertOperand(node.right),
|
|
103
|
+
]);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const convertIsNull = createIs('isNull', 'is');
|
|
107
|
+
const convertIsNotNull = createIs('isNotNull', 'isNot');
|
|
99
108
|
|
|
100
109
|
const convertIn = (node) => {
|
|
101
110
|
const inner = node.right.expr;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
convertCondition,
|
|
4
|
+
convertWhere,
|
|
5
|
+
} from '#parser/clause/where';
|
|
3
6
|
import {convertClause} from '#parser/clause';
|
|
4
|
-
import {convertBinary} from '#parser/clause/binary';
|
|
5
7
|
import {
|
|
6
8
|
convertOperand,
|
|
7
9
|
convertMemberExpr,
|
|
@@ -20,59 +22,13 @@ import {
|
|
|
20
22
|
const {
|
|
21
23
|
identifier,
|
|
22
24
|
callExpression,
|
|
23
|
-
logicalExpression,
|
|
24
25
|
stringLiteral,
|
|
25
26
|
tsAsExpression,
|
|
26
27
|
tsLiteralType,
|
|
27
28
|
} = types;
|
|
28
29
|
|
|
29
|
-
const isExists = (node) => node.type === 'prefix_op_expr' && node.operator.name === 'EXISTS';
|
|
30
|
-
const isNotExists = (node) => node.type === 'prefix_op_expr' && node.operator.name === 'NOT' && isExists(node.expr);
|
|
31
30
|
const isParenExpr = (node) => node.type === 'paren_expr';
|
|
32
31
|
|
|
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
|
-
|
|
47
|
-
const convertCondition = (node) => {
|
|
48
|
-
if (node.operator && node.operator.name === 'AND')
|
|
49
|
-
return logicalExpression('&&', convertCondition(node.left), convertCondition(node.right));
|
|
50
|
-
|
|
51
|
-
if (node.operator && node.operator.name === 'OR')
|
|
52
|
-
return logicalExpression('||', convertCondition(node.left), convertCondition(node.right));
|
|
53
|
-
|
|
54
|
-
if (node.type === 'between_expr')
|
|
55
|
-
return convertBetween(node);
|
|
56
|
-
|
|
57
|
-
if (node.type === 'postfix_op_expr')
|
|
58
|
-
return convertPostfix(node);
|
|
59
|
-
|
|
60
|
-
if (isNotExists(node))
|
|
61
|
-
return callExpression(identifier('notExists'), [
|
|
62
|
-
convertClause(node.expr.expr.expr),
|
|
63
|
-
]);
|
|
64
|
-
|
|
65
|
-
if (isExists(node))
|
|
66
|
-
return callExpression(identifier('exists'), [
|
|
67
|
-
convertClause(node.expr.expr),
|
|
68
|
-
]);
|
|
69
|
-
|
|
70
|
-
if (isParenExpr(node))
|
|
71
|
-
return convertCondition(node.expr);
|
|
72
|
-
|
|
73
|
-
return convertBinary(node);
|
|
74
|
-
};
|
|
75
|
-
|
|
76
32
|
const convertOn = (spec) => callExpression(identifier('on'), [
|
|
77
33
|
convertCondition(spec.expr),
|
|
78
34
|
]);
|
|
@@ -241,9 +197,7 @@ export const convertFrom = ({expr, whereClause, groupByClause, havingClause, ord
|
|
|
241
197
|
const fromArgs = [];
|
|
242
198
|
|
|
243
199
|
if (whereClause)
|
|
244
|
-
fromArgs.push(
|
|
245
|
-
convertCondition(whereClause.expr),
|
|
246
|
-
]));
|
|
200
|
+
fromArgs.push(convertWhere(whereClause));
|
|
247
201
|
|
|
248
202
|
if (groupByClause)
|
|
249
203
|
fromArgs.push(convertGroupBy(groupByClause));
|
|
@@ -131,6 +131,16 @@ export const convertOperand = (node) => {
|
|
|
131
131
|
convertClause(node.expr),
|
|
132
132
|
]);
|
|
133
133
|
|
|
134
|
+
if (node.type === 'paren_expr') {
|
|
135
|
+
const inner = convertOperand(node.expr);
|
|
136
|
+
|
|
137
|
+
inner.extra = {
|
|
138
|
+
parenthesized: true,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return inner;
|
|
142
|
+
}
|
|
143
|
+
|
|
134
144
|
if (node.type === 'parameter')
|
|
135
145
|
return stringLiteral(node.text);
|
|
136
146
|
|
|
@@ -10,6 +10,7 @@ import {convertBinary} from '#parser/clause/binary';
|
|
|
10
10
|
import {
|
|
11
11
|
convertCondition,
|
|
12
12
|
convertBetween,
|
|
13
|
+
convertWhere,
|
|
13
14
|
} from '#parser/clause/where';
|
|
14
15
|
import {findClause} from '#parser/clause/find';
|
|
15
16
|
import {convertOrderBy} from '../from/order-by.js';
|
|
@@ -312,6 +313,9 @@ export const convertSelect = ({clauses}) => {
|
|
|
312
313
|
].filter(Boolean);
|
|
313
314
|
|
|
314
315
|
if (!fromClause) {
|
|
316
|
+
if (whereClause)
|
|
317
|
+
args.push(convertWhere(whereClause));
|
|
318
|
+
|
|
315
319
|
if (limitClause)
|
|
316
320
|
args.push(convertLimit(limitClause));
|
|
317
321
|
|
|
@@ -7,11 +7,22 @@ const {
|
|
|
7
7
|
logicalExpression,
|
|
8
8
|
identifier,
|
|
9
9
|
callExpression,
|
|
10
|
+
isLogicalExpression,
|
|
10
11
|
} = types;
|
|
11
12
|
|
|
12
13
|
const convertAnd = (node) => logicalExpression('&&', convertCondition(node.left), convertCondition(node.right));
|
|
13
14
|
const convertOr = (node) => logicalExpression('||', convertCondition(node.left), convertCondition(node.right));
|
|
14
15
|
|
|
16
|
+
const isNot = (node) => node.type === 'prefix_op_expr' && node.operator.name === 'NOT';
|
|
17
|
+
|
|
18
|
+
const keepParens = (node) => {
|
|
19
|
+
node.extra = {
|
|
20
|
+
parenthesized: true,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return node;
|
|
24
|
+
};
|
|
25
|
+
|
|
15
26
|
const isNotBetween = (node) => Array.isArray(node.betweenKw) && node.betweenKw[0].name === 'NOT';
|
|
16
27
|
|
|
17
28
|
export const convertBetween = (node) => {
|
|
@@ -68,12 +79,28 @@ export const convertCondition = (node) => {
|
|
|
68
79
|
convertClause(node.expr.expr),
|
|
69
80
|
]);
|
|
70
81
|
|
|
71
|
-
if (isParenExpr(node))
|
|
72
|
-
return
|
|
82
|
+
if (isNot(node) && isParenExpr(node.expr))
|
|
83
|
+
return callExpression(identifier('not'), [
|
|
84
|
+
convertCondition(node.expr.expr),
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
if (isParenExpr(node)) {
|
|
88
|
+
const result = convertCondition(node.expr);
|
|
89
|
+
|
|
90
|
+
if (isLogicalExpression(result))
|
|
91
|
+
return keepParens(result);
|
|
92
|
+
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
73
95
|
|
|
74
96
|
return convertBinary(node);
|
|
75
97
|
};
|
|
76
98
|
|
|
99
|
+
const stripParens = (node) => {
|
|
100
|
+
delete node.extra;
|
|
101
|
+
return node;
|
|
102
|
+
};
|
|
103
|
+
|
|
77
104
|
export const convertWhere = (node) => callExpression(identifier('where'), [
|
|
78
|
-
convertCondition(node.expr),
|
|
105
|
+
stripParens(convertCondition(node.expr)),
|
|
79
106
|
]);
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {types} from '@putout/babel';
|
|
2
|
+
|
|
3
|
+
const {isBinaryExpression} = types;
|
|
4
|
+
|
|
1
5
|
const JS_TO_SQL_OP = {
|
|
2
6
|
'===': '=',
|
|
3
7
|
'!==': '!=',
|
|
@@ -7,11 +11,30 @@ const JS_TO_SQL_OP = {
|
|
|
7
11
|
'<': '<',
|
|
8
12
|
};
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
const ADDITIVE = ['+', '-'];
|
|
15
|
+
const MULTIPLICATIVE = ['*', '/', '%'];
|
|
16
|
+
|
|
17
|
+
const needsParens = (node, operator) => {
|
|
18
|
+
if (!isBinaryExpression(node))
|
|
19
|
+
return false;
|
|
20
|
+
|
|
21
|
+
return MULTIPLICATIVE.includes(operator) && ADDITIVE.includes(node.operator);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const print = (path, operator, {write, traverse}) => {
|
|
25
|
+
if (!needsParens(path.node, operator))
|
|
26
|
+
return traverse(path);
|
|
12
27
|
|
|
13
|
-
|
|
28
|
+
write('(');
|
|
29
|
+
traverse(path);
|
|
30
|
+
write(')');
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const BinaryExpression = (path, printer) => {
|
|
34
|
+
const {write} = printer;
|
|
35
|
+
const {operator} = path.node;
|
|
14
36
|
|
|
15
|
-
|
|
16
|
-
|
|
37
|
+
print(path.get('left'), operator, printer);
|
|
38
|
+
write(` ${JS_TO_SQL_OP[operator] || operator} `);
|
|
39
|
+
print(path.get('right'), operator, printer);
|
|
17
40
|
};
|
|
@@ -138,10 +138,15 @@ import {lastInsertRowid} from './last-insert-rowid/last-insert-rowid.js';
|
|
|
138
138
|
import {lastval} from './lastval/lastval.js';
|
|
139
139
|
import {defaultNextval} from './default-nextval/default-nextval.js';
|
|
140
140
|
import {like} from './like/like.js';
|
|
141
|
-
import {isNull, isNotNull} from './is-null/is-null.js';
|
|
142
141
|
import {orReplace} from './or-replace/or-replace.js';
|
|
143
142
|
import {orIgnore} from './or-ignore/or-ignore.js';
|
|
144
143
|
import {inList} from './in-list/in-list.js';
|
|
144
|
+
import {
|
|
145
|
+
isNull,
|
|
146
|
+
isNotNull,
|
|
147
|
+
is,
|
|
148
|
+
isNot,
|
|
149
|
+
} from './is-null/is-null.js';
|
|
145
150
|
import {
|
|
146
151
|
identity,
|
|
147
152
|
identityByDefault,
|
|
@@ -315,6 +320,8 @@ export const clauses = {
|
|
|
315
320
|
isDistinctFrom,
|
|
316
321
|
collate,
|
|
317
322
|
isNull,
|
|
323
|
+
is,
|
|
324
|
+
isNot,
|
|
318
325
|
isNotNull,
|
|
319
326
|
inList,
|
|
320
327
|
identity,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
+
import {createTypeChecker} from '@putout/printer/type-checker';
|
|
2
3
|
|
|
3
4
|
const {isCallExpression} = types;
|
|
4
5
|
|
|
@@ -6,7 +7,15 @@ const isConcurrently = (arg) => isCallExpression(arg.node) && arg.node.callee.na
|
|
|
6
7
|
const isIfNotExists = (arg) => isCallExpression(arg.node) && arg.node.callee.name === 'ifNotExists';
|
|
7
8
|
const isWhere = (arg) => isCallExpression(arg.node) && arg.node.callee.name === 'where';
|
|
8
9
|
const isAccessMethod = (arg) => isCallExpression(arg.node) && arg.node.callee.name === 'accessMethod';
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
const isOption = createTypeChecker([
|
|
12
|
+
['+: node.callee.name', '=', 'concurrently'],
|
|
13
|
+
['+: node.callee.name', '=', 'ifNotExists'],
|
|
14
|
+
['+: node.callee.name', '=', 'where'],
|
|
15
|
+
['+: node.callee.name', '=', 'accessMethod'],
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
const isCol = (arg) => !isOption(arg);
|
|
10
19
|
|
|
11
20
|
export const printIndexBody = (path, {write, traverse}) => {
|
|
12
21
|
const [name, table, ...rest] = path.get('arguments');
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
+
import {createTypeChecker} from '@putout/printer/type-checker';
|
|
2
3
|
|
|
3
|
-
const {
|
|
4
|
-
isTSAsExpression,
|
|
5
|
-
isCallExpression,
|
|
6
|
-
} = types;
|
|
4
|
+
const {isTSAsExpression} = types;
|
|
7
5
|
|
|
8
6
|
const printAsExpression = (path, {write, traverse}) => {
|
|
9
7
|
const expr = path.get('expression');
|
|
10
8
|
|
|
11
|
-
if (isTableFunc(expr
|
|
9
|
+
if (isTableFunc(expr))
|
|
12
10
|
printTableFunc(expr, {
|
|
13
11
|
write,
|
|
14
12
|
traverse,
|
|
@@ -16,7 +14,7 @@ const printAsExpression = (path, {write, traverse}) => {
|
|
|
16
14
|
else
|
|
17
15
|
traverse(expr);
|
|
18
16
|
|
|
19
|
-
if (isSubqueryAlias(
|
|
17
|
+
if (isSubqueryAlias(expr))
|
|
20
18
|
write(' ');
|
|
21
19
|
else
|
|
22
20
|
write(' AS ');
|
|
@@ -24,44 +22,52 @@ const printAsExpression = (path, {write, traverse}) => {
|
|
|
24
22
|
write(path.node.typeAnnotation.literal.value);
|
|
25
23
|
};
|
|
26
24
|
|
|
27
|
-
const isSubqueryAlias = (
|
|
28
|
-
'subquery',
|
|
29
|
-
'lateralSubquery',
|
|
30
|
-
]
|
|
25
|
+
const isSubqueryAlias = createTypeChecker([
|
|
26
|
+
['+: node.callee.name', '=', 'subquery'],
|
|
27
|
+
['+: node.callee.name', '=', 'lateralSubquery'],
|
|
28
|
+
]);
|
|
31
29
|
|
|
32
|
-
const
|
|
33
|
-
'where',
|
|
34
|
-
'groupBy',
|
|
35
|
-
'having',
|
|
36
|
-
'namedWindow',
|
|
37
|
-
'orderBy',
|
|
38
|
-
'limit',
|
|
39
|
-
'limitAll',
|
|
40
|
-
'offset',
|
|
41
|
-
'fetchFirst',
|
|
42
|
-
'forUpdate',
|
|
43
|
-
]
|
|
30
|
+
const isTableFunc = createTypeChecker([
|
|
31
|
+
['-: node.callee.name', '=', 'where'],
|
|
32
|
+
['-: node.callee.name', '=', 'groupBy'],
|
|
33
|
+
['-: node.callee.name', '=', 'having'],
|
|
34
|
+
['-: node.callee.name', '=', 'namedWindow'],
|
|
35
|
+
['-: node.callee.name', '=', 'orderBy'],
|
|
36
|
+
['-: node.callee.name', '=', 'limit'],
|
|
37
|
+
['-: node.callee.name', '=', 'limitAll'],
|
|
38
|
+
['-: node.callee.name', '=', 'offset'],
|
|
39
|
+
['-: node.callee.name', '=', 'fetchFirst'],
|
|
40
|
+
['-: node.callee.name', '=', 'forUpdate'],
|
|
41
|
+
['-: node.callee.name', '=', 'join'],
|
|
42
|
+
['-: node.callee.name', '=', 'leftJoin'],
|
|
43
|
+
['-: node.callee.name', '=', 'rightJoin'],
|
|
44
|
+
['-: node.callee.name', '=', 'rightOuterJoin'],
|
|
45
|
+
['-: node.callee.name', '=', 'innerJoin'],
|
|
46
|
+
['-: node.callee.name', '=', 'leftOuterJoin'],
|
|
47
|
+
['-: node.callee.name', '=', 'fullOuterJoin'],
|
|
48
|
+
['-: node.callee.name', '=', 'naturalJoin'],
|
|
49
|
+
['-: node.callee.name', '=', 'crossJoin'],
|
|
50
|
+
['-: node.callee.name', '=', 'on'],
|
|
51
|
+
['-: node.callee.name', '=', 'subquery'],
|
|
52
|
+
['-: node.callee.name', '=', 'lateralJoin'],
|
|
53
|
+
['-: node.callee.name', '=', 'lateralSubquery'],
|
|
54
|
+
['-: node.callee.name', '=', 'indexedBy'],
|
|
55
|
+
['-: node.callee.name', '=', 'notIndexed'],
|
|
56
|
+
'+: node -> CallExpression',
|
|
57
|
+
]);
|
|
44
58
|
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
'
|
|
48
|
-
'
|
|
49
|
-
'
|
|
50
|
-
'
|
|
51
|
-
'
|
|
52
|
-
'
|
|
53
|
-
'
|
|
54
|
-
'
|
|
55
|
-
'
|
|
56
|
-
|
|
57
|
-
'subquery',
|
|
58
|
-
'lateralJoin',
|
|
59
|
-
'lateralSubquery',
|
|
60
|
-
'indexedBy',
|
|
61
|
-
'notIndexed',
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
const isClause = ({node}) => isCallExpression(node) && CLAUSE_NAMES.includes(node.callee.name);
|
|
59
|
+
const isClause = createTypeChecker([
|
|
60
|
+
['+: node.callee.name', '=', 'where'],
|
|
61
|
+
['+: node.callee.name', '=', 'groupBy'],
|
|
62
|
+
['+: node.callee.name', '=', 'having'],
|
|
63
|
+
['+: node.callee.name', '=', 'namedWindow'],
|
|
64
|
+
['+: node.callee.name', '=', 'orderBy'],
|
|
65
|
+
['+: node.callee.name', '=', 'limit'],
|
|
66
|
+
['+: node.callee.name', '=', 'limitAll'],
|
|
67
|
+
['+: node.callee.name', '=', 'offset'],
|
|
68
|
+
['+: node.callee.name', '=', 'fetchFirst'],
|
|
69
|
+
['+: node.callee.name', '=', 'forUpdate'],
|
|
70
|
+
]);
|
|
65
71
|
|
|
66
72
|
const CAMEL_RE = /([A-Z])/g;
|
|
67
73
|
const toSnake = (a) => a.replace(CAMEL_RE, (_, c) => `_${c.toLowerCase()}`);
|
|
@@ -76,8 +82,6 @@ const toFuncName = (name) => {
|
|
|
76
82
|
return toSnake(name);
|
|
77
83
|
};
|
|
78
84
|
|
|
79
|
-
const isTableFunc = (node) => isCallExpression(node) && !TABLE_ARG_NAMES.includes(node.callee.name);
|
|
80
|
-
|
|
81
85
|
const printTableFunc = (path, {write, traverse}) => {
|
|
82
86
|
const {name} = path.node.callee;
|
|
83
87
|
const args = path.get('arguments');
|
|
@@ -102,7 +106,7 @@ const printArg = (path, printer) => {
|
|
|
102
106
|
if (isTSAsExpression(node))
|
|
103
107
|
return printAsExpression(path, printer);
|
|
104
108
|
|
|
105
|
-
if (isTableFunc(
|
|
109
|
+
if (isTableFunc(path))
|
|
106
110
|
return printTableFunc(path, printer);
|
|
107
111
|
|
|
108
112
|
traverse(path);
|
|
@@ -9,3 +9,17 @@ export const isNotNull = (path, {write, traverse}) => {
|
|
|
9
9
|
traverse(args[0]);
|
|
10
10
|
write(' IS NOT NULL');
|
|
11
11
|
};
|
|
12
|
+
|
|
13
|
+
export const is = (path, {write, traverse}) => {
|
|
14
|
+
const args = path.get('arguments');
|
|
15
|
+
traverse(args[0]);
|
|
16
|
+
write(' IS ');
|
|
17
|
+
traverse(args[1]);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const isNot = (path, {write, traverse}) => {
|
|
21
|
+
const args = path.get('arguments');
|
|
22
|
+
traverse(args[0]);
|
|
23
|
+
write(' IS NOT ');
|
|
24
|
+
traverse(args[1]);
|
|
25
|
+
};
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
+
import {createTypeChecker} from '@putout/printer/type-checker';
|
|
2
3
|
|
|
3
|
-
const {
|
|
4
|
-
isTSAsExpression,
|
|
5
|
-
isCallExpression,
|
|
6
|
-
} = types;
|
|
4
|
+
const {isTSAsExpression} = types;
|
|
7
5
|
|
|
8
|
-
const isSubqueryAlias = (
|
|
9
|
-
'subquery',
|
|
10
|
-
'lateralSubquery',
|
|
11
|
-
]
|
|
6
|
+
const isSubqueryAlias = createTypeChecker([
|
|
7
|
+
['+: node.callee.name', '=', 'subquery'],
|
|
8
|
+
['+: node.callee.name', '=', 'lateralSubquery'],
|
|
9
|
+
]);
|
|
12
10
|
|
|
13
11
|
const printAsExpression = (path, {write, traverse}) => {
|
|
14
|
-
const {expression} = path.node;
|
|
15
|
-
|
|
16
12
|
traverse(path.get('expression'));
|
|
17
13
|
|
|
18
|
-
if (isSubqueryAlias(expression))
|
|
14
|
+
if (isSubqueryAlias(path.get('expression')))
|
|
19
15
|
write(' ');
|
|
20
16
|
else
|
|
21
17
|
write(' AS ');
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
+
import {types} from '@putout/babel';
|
|
2
|
+
|
|
3
|
+
const {isLogicalExpression} = types;
|
|
4
|
+
|
|
1
5
|
export const not = (path, {write, traverse}) => {
|
|
6
|
+
const [arg] = path.get('arguments');
|
|
7
|
+
|
|
2
8
|
write('NOT ');
|
|
3
|
-
|
|
9
|
+
|
|
10
|
+
if (!isLogicalExpression(arg.node))
|
|
11
|
+
return traverse(arg);
|
|
12
|
+
|
|
13
|
+
write('(');
|
|
14
|
+
traverse(arg);
|
|
15
|
+
write(')');
|
|
4
16
|
};
|
|
@@ -29,12 +29,13 @@ const isFrom = createTypeChecker([
|
|
|
29
29
|
['+: node.callee.name', '=', 'from'],
|
|
30
30
|
]);
|
|
31
31
|
|
|
32
|
-
const isClauseName = (
|
|
33
|
-
'limitAll',
|
|
34
|
-
'offset',
|
|
35
|
-
'fetchFirst',
|
|
36
|
-
'forUpdate',
|
|
37
|
-
|
|
32
|
+
const isClauseName = createTypeChecker([
|
|
33
|
+
['+: node.callee.name', '=', 'limitAll'],
|
|
34
|
+
['+: node.callee.name', '=', 'offset'],
|
|
35
|
+
['+: node.callee.name', '=', 'fetchFirst'],
|
|
36
|
+
['+: node.callee.name', '=', 'forUpdate'],
|
|
37
|
+
['+: node.callee.name', '=', 'where'],
|
|
38
|
+
]);
|
|
38
39
|
|
|
39
40
|
const isDistinctOn = (path) => isCallExpression(path.node) && path.node.callee.name === 'distinctOn';
|
|
40
41
|
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {createTypeChecker} from '@putout/printer/type-checker';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
'
|
|
7
|
-
'
|
|
8
|
-
|
|
9
|
-
'orFail',
|
|
10
|
-
];
|
|
11
|
-
|
|
12
|
-
const isOrAction = (arg) => isCallExpression(arg.node) && OR_ACTION_NAMES.includes(arg.node.callee.name);
|
|
3
|
+
const isOrAction = createTypeChecker([
|
|
4
|
+
['+: node.callee.name', '=', 'orReplace'],
|
|
5
|
+
['+: node.callee.name', '=', 'orIgnore'],
|
|
6
|
+
['+: node.callee.name', '=', 'orAbort'],
|
|
7
|
+
['+: node.callee.name', '=', 'orFail'],
|
|
8
|
+
]);
|
|
13
9
|
|
|
14
10
|
export const update = (path, {write, traverse}) => {
|
|
15
11
|
const args = path.get('arguments');
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const {
|
|
4
|
+
isLogicalExpression,
|
|
5
|
+
isCallExpression,
|
|
6
|
+
} = types;
|
|
7
|
+
|
|
8
|
+
const isInNot = ({parent}) => isCallExpression(parent) && parent.callee.name === 'not';
|
|
4
9
|
const needsParensIn = (node, op) => op === '&&' && isLogicalExpression(node) && node.operator === '||';
|
|
5
10
|
|
|
6
11
|
const printNestedOr = (node, printer) => {
|
|
@@ -18,7 +23,7 @@ export const LogicalExpression = (path, {write, traverse}) => {
|
|
|
18
23
|
const left = path.get('left');
|
|
19
24
|
const right = path.get('right');
|
|
20
25
|
const hasNestedParen = needsParensIn(left.node, node.operator) || needsParensIn(right.node, node.operator);
|
|
21
|
-
const separator = hasNestedParen ? ` ${op} ` : `\n${op} `;
|
|
26
|
+
const separator = hasNestedParen || isInNot(path) ? ` ${op} ` : `\n${op} `;
|
|
22
27
|
|
|
23
28
|
if (needsParensIn(left.node, node.operator))
|
|
24
29
|
printNestedOr(left, {
|
|
@@ -1,7 +1,21 @@
|
|
|
1
|
+
import {createTypeChecker} from '@putout/printer/type-checker';
|
|
2
|
+
|
|
3
|
+
const isValueContext = createTypeChecker([
|
|
4
|
+
'+: parent -> BinaryExpression',
|
|
5
|
+
[
|
|
6
|
+
'+: parent.callee.name',
|
|
7
|
+
'=',
|
|
8
|
+
'inList',
|
|
9
|
+
],
|
|
10
|
+
]);
|
|
11
|
+
|
|
1
12
|
export const StringLiteral = (path, {write}) => {
|
|
2
13
|
const {value} = path.node;
|
|
3
14
|
|
|
4
|
-
if (value === '*'
|
|
15
|
+
if (value === '*' && !isValueContext(path))
|
|
16
|
+
return write(value);
|
|
17
|
+
|
|
18
|
+
if (value.startsWith(':'))
|
|
5
19
|
return write(value);
|
|
6
20
|
|
|
7
21
|
// quoted identifier like "weird col" — written as is
|