happy-sql 1.5.0 → 1.5.2
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 +11 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-in-fix.js +3 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-in.sql +1 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-is-not-null-fix.js +3 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-is-not-null.sql +1 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-is-null-fix.js +3 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-is-null.sql +1 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-like-fix.js +3 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-like.sql +1 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-not-eq-fix.js +6 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-not-eq.sql +1 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-number-fix.js +6 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-number.sql +1 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-or-fix.js +6 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-or.sql +1 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-param-fix.js +6 -0
- package/lib/parser/visitors/clause/from/fixture/join-on-param.sql +1 -0
- package/lib/parser/visitors/clause/from/from.js +68 -1
- package/lib/parser/visitors/clause/insert/insert.js +2 -4
- package/lib/parser/visitors/clause/operand.js +8 -0
- package/lib/parser/visitors/clause/select/fixture/select-param-fix.js +3 -0
- package/lib/parser/visitors/clause/select/fixture/select-param.sql +1 -0
- package/lib/parser/visitors/clause/select/select.js +3 -0
- package/lib/parser/visitors/clause/where/fixture/where-compare-fix.js +3 -0
- package/lib/parser/visitors/clause/where/fixture/where-compare.sql +1 -0
- package/lib/parser/visitors/clause/where/fixture/where-gte-fix.js +3 -0
- package/lib/parser/visitors/clause/where/fixture/where-gte.sql +1 -0
- package/lib/parser/visitors/clause/where/fixture/where-in-fix.js +3 -0
- package/lib/parser/visitors/clause/where/fixture/where-in.sql +1 -0
- package/lib/parser/visitors/clause/where/fixture/where-is-not-null-fix.js +3 -0
- package/lib/parser/visitors/clause/where/fixture/where-is-not-null.sql +1 -0
- package/lib/parser/visitors/clause/where/fixture/where-is-null-fix.js +3 -0
- package/lib/parser/visitors/clause/where/fixture/where-is-null.sql +1 -0
- package/lib/parser/visitors/clause/where/fixture/where-like-fix.js +3 -0
- package/lib/parser/visitors/clause/where/fixture/where-like.sql +1 -0
- package/lib/parser/visitors/clause/where/fixture/where-not-eq-fix.js +3 -0
- package/lib/parser/visitors/clause/where/fixture/where-not-eq.sql +1 -0
- package/lib/parser/visitors/clause/where/where.js +59 -4
- package/lib/printer/visitors/array-expression.js +1 -1
- package/lib/printer/visitors/binary-expression.js +9 -1
- package/lib/printer/visitors/call-expression/clauses/clauses.js +7 -0
- package/lib/printer/visitors/call-expression/clauses/in-list/in-list.js +15 -0
- package/lib/printer/visitors/call-expression/clauses/is-null/is-null.js +11 -0
- package/lib/printer/visitors/call-expression/clauses/like/like.js +6 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-gte-fix.sql +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-gte.js +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-in-fix.sql +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-in.js +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-is-not-null-fix.sql +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-is-not-null.js +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-is-null-fix.sql +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-is-null.js +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-like-fix.sql +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-like.js +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-ne-fix.sql +3 -0
- package/lib/printer/visitors/call-expression/clauses/where/fixture/where-ne.js +3 -0
- package/package.json +1 -1
package/ChangeLog
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT u.id FROM t JOIN u ON u.id IN (1, 2, 3)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT u.id FROM t JOIN u ON u.x IS NOT NULL
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT u.id FROM t JOIN u ON u.x IS NULL
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT u.id FROM t JOIN u ON u.x LIKE :p
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT bin.id FROM BinaryExpression bin JOIN Identifier arg_id ON arg_id.parent_id = bin.id AND arg_id.id != bin.id
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT bin.id FROM BinaryExpression bin JOIN Identifier nan_id ON nan_id.parent_id = 1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT bin.id FROM BinaryExpression bin JOIN Identifier nan_id ON nan_id.parent_id = bin.id OR nan_id.name = 'NaN'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT bin.id FROM BinaryExpression bin JOIN Identifier nan_id ON nan_id.parent_id = :param_id
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
2
|
|
|
3
|
+
const isString = (a) => typeof a === 'string';
|
|
4
|
+
|
|
3
5
|
const {
|
|
4
6
|
identifier,
|
|
5
7
|
callExpression,
|
|
@@ -8,6 +10,8 @@ const {
|
|
|
8
10
|
logicalExpression,
|
|
9
11
|
stringLiteral,
|
|
10
12
|
numericLiteral,
|
|
13
|
+
booleanLiteral,
|
|
14
|
+
nullLiteral,
|
|
11
15
|
} = types;
|
|
12
16
|
|
|
13
17
|
const convertOperand = (node) => {
|
|
@@ -23,9 +27,72 @@ const convertOperand = (node) => {
|
|
|
23
27
|
if (node.type === 'string_literal')
|
|
24
28
|
return stringLiteral(node.value);
|
|
25
29
|
|
|
30
|
+
if (node.type === 'boolean_literal')
|
|
31
|
+
return booleanLiteral(node.value);
|
|
32
|
+
|
|
33
|
+
if (node.type === 'null_literal')
|
|
34
|
+
return nullLiteral(node.value);
|
|
35
|
+
|
|
26
36
|
return identifier(node.name);
|
|
27
37
|
};
|
|
28
38
|
|
|
39
|
+
const opName = (op) => {
|
|
40
|
+
if (Array.isArray(op))
|
|
41
|
+
return op
|
|
42
|
+
.map((k) => k.name)
|
|
43
|
+
.join(' ');
|
|
44
|
+
|
|
45
|
+
if (isString(op))
|
|
46
|
+
return op;
|
|
47
|
+
|
|
48
|
+
return op?.name ?? '';
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const SQL_TO_JS_OP = {
|
|
52
|
+
'=': '===',
|
|
53
|
+
'!=': '!==',
|
|
54
|
+
'>=': '>=',
|
|
55
|
+
'<=': '<=',
|
|
56
|
+
'>': '>',
|
|
57
|
+
'<': '<',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const convertBinary = (node) => {
|
|
61
|
+
const op = opName(node.operator);
|
|
62
|
+
|
|
63
|
+
if (op === 'LIKE')
|
|
64
|
+
return callExpression(identifier('like'), [
|
|
65
|
+
convertOperand(node.left),
|
|
66
|
+
convertOperand(node.right),
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
if (op === 'IS')
|
|
70
|
+
return callExpression(identifier('isNull'), [
|
|
71
|
+
convertOperand(node.left),
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
if (op === 'IS NOT')
|
|
75
|
+
return callExpression(identifier('isNotNull'), [
|
|
76
|
+
convertOperand(node.left),
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
if (op === 'IN') {
|
|
80
|
+
const items = node.right.expr.items.map(convertOperand);
|
|
81
|
+
return callExpression(identifier('inList'), [
|
|
82
|
+
convertOperand(node.left),
|
|
83
|
+
...items,
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const jsOp = SQL_TO_JS_OP[op] ?? '===';
|
|
88
|
+
|
|
89
|
+
return binaryExpression(
|
|
90
|
+
jsOp,
|
|
91
|
+
convertOperand(node.left),
|
|
92
|
+
convertOperand(node.right),
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
29
96
|
const convertCondition = (node) => {
|
|
30
97
|
if (node.operator?.name === 'AND')
|
|
31
98
|
return logicalExpression('&&', convertCondition(node.left), convertCondition(node.right));
|
|
@@ -33,7 +100,7 @@ const convertCondition = (node) => {
|
|
|
33
100
|
if (node.operator?.name === 'OR')
|
|
34
101
|
return logicalExpression('||', convertCondition(node.left), convertCondition(node.right));
|
|
35
102
|
|
|
36
|
-
return
|
|
103
|
+
return convertBinary(node);
|
|
37
104
|
};
|
|
38
105
|
|
|
39
106
|
const convertOn = (spec) => callExpression(identifier('on'), [
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
+
import {convertOperand} from '#parser/clause/operand';
|
|
2
3
|
import {convertSet} from '#parser/clause/set';
|
|
3
4
|
import {convertSelect} from '#parser/clause/select';
|
|
4
5
|
import {findClause} from '#parser/clause/find';
|
|
@@ -38,10 +39,7 @@ const convertSource = (vc) => {
|
|
|
38
39
|
return convertSelect(vc);
|
|
39
40
|
|
|
40
41
|
const vals = vc.values.items[0].expr.items;
|
|
41
|
-
const valArgs =
|
|
42
|
-
|
|
43
|
-
for (const p of vals)
|
|
44
|
-
valArgs.push(stringLiteral(p.text));
|
|
42
|
+
const valArgs = vals.map(convertOperand);
|
|
45
43
|
|
|
46
44
|
return callExpression(identifier('values'), valArgs);
|
|
47
45
|
};
|
|
@@ -4,6 +4,8 @@ const {
|
|
|
4
4
|
identifier,
|
|
5
5
|
stringLiteral,
|
|
6
6
|
numericLiteral,
|
|
7
|
+
booleanLiteral,
|
|
8
|
+
nullLiteral,
|
|
7
9
|
memberExpression,
|
|
8
10
|
} = types;
|
|
9
11
|
|
|
@@ -20,5 +22,11 @@ export const convertOperand = (node) => {
|
|
|
20
22
|
if (node.type === 'string_literal')
|
|
21
23
|
return stringLiteral(node.value);
|
|
22
24
|
|
|
25
|
+
if (node.type === 'boolean_literal')
|
|
26
|
+
return booleanLiteral(node.value);
|
|
27
|
+
|
|
28
|
+
if (node.type === 'null_literal')
|
|
29
|
+
return nullLiteral(node.value);
|
|
30
|
+
|
|
23
31
|
return identifier(node.name);
|
|
24
32
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT :arg_name, id FROM t
|
|
@@ -29,6 +29,9 @@ const convertColumn = (column) => {
|
|
|
29
29
|
if (column.type === 'member_expr')
|
|
30
30
|
return memberExpression(identifier(column.object.name), identifier(column.property.name));
|
|
31
31
|
|
|
32
|
+
if (column.type === 'parameter')
|
|
33
|
+
return stringLiteral(column.text);
|
|
34
|
+
|
|
32
35
|
return identifier(column.name);
|
|
33
36
|
};
|
|
34
37
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT * FROM t WHERE x > 1 AND y < 2
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT * FROM t WHERE x >= 1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT * FROM t WHERE x IN (1, 2, 3)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT * FROM t WHERE x IS NOT NULL
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT * FROM t WHERE x IS NULL
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT * FROM t WHERE x LIKE :pattern
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SELECT * FROM t WHERE x != :y
|
|
@@ -1,18 +1,73 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
2
|
import {convertOperand} from '#parser/clause/operand';
|
|
3
3
|
|
|
4
|
+
const isString = (a) => typeof a === 'string';
|
|
5
|
+
|
|
4
6
|
const {
|
|
5
7
|
logicalExpression,
|
|
6
8
|
identifier,
|
|
7
9
|
callExpression,
|
|
10
|
+
binaryExpression,
|
|
8
11
|
} = types;
|
|
9
12
|
|
|
13
|
+
const opName = (op) => {
|
|
14
|
+
if (Array.isArray(op))
|
|
15
|
+
return op
|
|
16
|
+
.map((k) => k.name)
|
|
17
|
+
.join(' ');
|
|
18
|
+
|
|
19
|
+
if (isString(op))
|
|
20
|
+
return op;
|
|
21
|
+
|
|
22
|
+
return op?.name ?? '';
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const SQL_TO_JS_OP = {
|
|
26
|
+
'=': '===',
|
|
27
|
+
'!=': '!==',
|
|
28
|
+
'>=': '>=',
|
|
29
|
+
'<=': '<=',
|
|
30
|
+
'>': '>',
|
|
31
|
+
'<': '<',
|
|
32
|
+
};
|
|
33
|
+
|
|
10
34
|
const convertAnd = (node) => logicalExpression('&&', convertCondition(node.left), convertCondition(node.right));
|
|
11
35
|
const convertOr = (node) => logicalExpression('||', convertCondition(node.left), convertCondition(node.right));
|
|
12
36
|
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
37
|
+
const convertBinary = (node) => {
|
|
38
|
+
const op = opName(node.operator);
|
|
39
|
+
|
|
40
|
+
if (op === 'LIKE')
|
|
41
|
+
return callExpression(identifier('like'), [
|
|
42
|
+
convertOperand(node.left),
|
|
43
|
+
convertOperand(node.right),
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
if (op === 'IS')
|
|
47
|
+
return callExpression(identifier('isNull'), [
|
|
48
|
+
convertOperand(node.left),
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
if (op === 'IS NOT')
|
|
52
|
+
return callExpression(identifier('isNotNull'), [
|
|
53
|
+
convertOperand(node.left),
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
if (op === 'IN') {
|
|
57
|
+
const items = node.right.expr.items.map(convertOperand);
|
|
58
|
+
return callExpression(identifier('inList'), [
|
|
59
|
+
convertOperand(node.left),
|
|
60
|
+
...items,
|
|
61
|
+
]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const jsOp = SQL_TO_JS_OP[op] ?? '===';
|
|
65
|
+
|
|
66
|
+
return binaryExpression(
|
|
67
|
+
jsOp,
|
|
68
|
+
convertOperand(node.left),
|
|
69
|
+
convertOperand(node.right),
|
|
70
|
+
);
|
|
16
71
|
};
|
|
17
72
|
|
|
18
73
|
const convertCondition = (node) => {
|
|
@@ -22,7 +77,7 @@ const convertCondition = (node) => {
|
|
|
22
77
|
if (node.operator?.name === 'OR')
|
|
23
78
|
return convertOr(node);
|
|
24
79
|
|
|
25
|
-
return
|
|
80
|
+
return convertBinary(node);
|
|
26
81
|
};
|
|
27
82
|
|
|
28
83
|
export const convertWhere = (node) => callExpression(identifier('where'), [
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
const JS_TO_SQL_OP = {
|
|
2
|
+
'===': '=',
|
|
3
|
+
'!==': '!=',
|
|
4
|
+
};
|
|
5
|
+
|
|
1
6
|
export const BinaryExpression = (path, {write, traverse}) => {
|
|
2
7
|
traverse(path.get('left'));
|
|
3
|
-
|
|
8
|
+
|
|
9
|
+
const op = path.node.operator;
|
|
10
|
+
|
|
11
|
+
write(` ${JS_TO_SQL_OP[op] ?? op} `);
|
|
4
12
|
traverse(path.get('right'));
|
|
5
13
|
};
|
|
@@ -22,6 +22,9 @@ import {serial} from './serial/serial.js';
|
|
|
22
22
|
import {primaryKey} from './primary-key/primary-key.js';
|
|
23
23
|
import {lastInsertRowid} from './last-insert-rowid/last-insert-rowid.js';
|
|
24
24
|
import {lastval} from './lastval/lastval.js';
|
|
25
|
+
import {like} from './like/like.js';
|
|
26
|
+
import {isNull, isNotNull} from './is-null/is-null.js';
|
|
27
|
+
import {inList} from './in-list/in-list.js';
|
|
25
28
|
|
|
26
29
|
export const clauses = {
|
|
27
30
|
join,
|
|
@@ -48,4 +51,8 @@ export const clauses = {
|
|
|
48
51
|
primaryKey,
|
|
49
52
|
lastInsertRowid,
|
|
50
53
|
lastval,
|
|
54
|
+
like,
|
|
55
|
+
isNull,
|
|
56
|
+
isNotNull,
|
|
57
|
+
inList,
|
|
51
58
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const inList = (path, {write, traverse}) => {
|
|
2
|
+
const [head, ...items] = path.get('arguments');
|
|
3
|
+
|
|
4
|
+
traverse(head);
|
|
5
|
+
write(' IN (');
|
|
6
|
+
|
|
7
|
+
for (let i = 0; i < items.length; i++) {
|
|
8
|
+
if (i > 0)
|
|
9
|
+
write(', ');
|
|
10
|
+
|
|
11
|
+
traverse(items[i]);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
write(')');
|
|
15
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const isNull = (path, {write, traverse}) => {
|
|
2
|
+
const args = path.get('arguments');
|
|
3
|
+
traverse(args[0]);
|
|
4
|
+
write(' IS NULL');
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const isNotNull = (path, {write, traverse}) => {
|
|
8
|
+
const args = path.get('arguments');
|
|
9
|
+
traverse(args[0]);
|
|
10
|
+
write(' IS NOT NULL');
|
|
11
|
+
};
|