happy-sql 2.0.8 → 2.1.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.
Files changed (145) hide show
  1. package/ChangeLog +17 -0
  2. package/lib/parser/visitors/clause/count/count.js +4 -0
  3. package/lib/parser/visitors/clause/delete/fixture/delete-where-between-fix.js +14 -0
  4. package/lib/parser/visitors/clause/delete/fixture/delete-where-between.sql +1 -0
  5. package/lib/parser/visitors/clause/from/fixture/generate-series-fix.js +12 -0
  6. package/lib/parser/visitors/clause/from/fixture/generate-series.sql +1 -0
  7. package/lib/parser/visitors/clause/from/fixture/group-by-fix.js +14 -0
  8. package/lib/parser/visitors/clause/from/fixture/group-by-having-fix.js +22 -0
  9. package/lib/parser/visitors/clause/from/fixture/group-by-having.sql +1 -0
  10. package/lib/parser/visitors/clause/from/fixture/group-by-multi-fix.js +13 -0
  11. package/lib/parser/visitors/clause/from/fixture/group-by-multi.sql +1 -0
  12. package/lib/parser/visitors/clause/from/fixture/group-by-order-by-fix.js +17 -0
  13. package/lib/parser/visitors/clause/from/fixture/group-by-order-by.sql +1 -0
  14. package/lib/parser/visitors/clause/from/fixture/group-by-sum-fix.js +14 -0
  15. package/lib/parser/visitors/clause/from/fixture/group-by-sum-having-fix.js +19 -0
  16. package/lib/parser/visitors/clause/from/fixture/group-by-sum-having.sql +1 -0
  17. package/lib/parser/visitors/clause/from/fixture/group-by-sum.sql +1 -0
  18. package/lib/parser/visitors/clause/from/fixture/group-by.sql +1 -0
  19. package/lib/parser/visitors/clause/from/fixture/json-each-fix.js +10 -0
  20. package/lib/parser/visitors/clause/from/fixture/json-each.sql +1 -0
  21. package/lib/parser/visitors/clause/from/fixture/limit-fix.js +11 -0
  22. package/lib/parser/visitors/clause/from/fixture/limit-offset-fix.js +12 -0
  23. package/lib/parser/visitors/clause/from/fixture/limit-offset.sql +1 -0
  24. package/lib/parser/visitors/clause/from/fixture/limit.sql +1 -0
  25. package/lib/parser/visitors/clause/from/fixture/order-by-desc-fix.js +13 -0
  26. package/lib/parser/visitors/clause/from/fixture/order-by-desc.sql +1 -0
  27. package/lib/parser/visitors/clause/from/fixture/order-by-fix.js +11 -0
  28. package/lib/parser/visitors/clause/from/fixture/order-by-multi-fix.js +14 -0
  29. package/lib/parser/visitors/clause/from/fixture/order-by-multi.sql +1 -0
  30. package/lib/parser/visitors/clause/from/fixture/order-by.sql +1 -0
  31. package/lib/parser/visitors/clause/from/fixture/unnest-fix.js +10 -0
  32. package/lib/parser/visitors/clause/from/fixture/unnest.sql +1 -0
  33. package/lib/parser/visitors/clause/from/from.js +37 -1
  34. package/lib/parser/visitors/clause/from/group-by.js +6 -0
  35. package/lib/parser/visitors/clause/from/having.js +8 -0
  36. package/lib/parser/visitors/clause/from/limit.js +18 -0
  37. package/lib/parser/visitors/clause/from/order-by.js +20 -0
  38. package/lib/parser/visitors/clause/from/table-func.js +28 -0
  39. package/lib/parser/visitors/clause/index.js +12 -1
  40. package/lib/parser/visitors/clause/operand.js +14 -0
  41. package/lib/parser/visitors/clause/select/fixture/select-abs-fix.js +8 -0
  42. package/lib/parser/visitors/clause/select/fixture/select-abs.sql +1 -0
  43. package/lib/parser/visitors/clause/select/fixture/select-avg-fix.js +10 -0
  44. package/lib/parser/visitors/clause/select/fixture/select-avg.sql +1 -0
  45. package/lib/parser/visitors/clause/select/fixture/select-count-col-fix.js +10 -0
  46. package/lib/parser/visitors/clause/select/fixture/select-count-col.sql +1 -0
  47. package/lib/parser/visitors/clause/select/fixture/select-distinct-fix.js +10 -0
  48. package/lib/parser/visitors/clause/select/fixture/select-distinct-multi-fix.js +11 -0
  49. package/lib/parser/visitors/clause/select/fixture/select-distinct-multi.sql +1 -0
  50. package/lib/parser/visitors/clause/select/fixture/select-distinct.sql +1 -0
  51. package/lib/parser/visitors/clause/select/fixture/select-min-max-fix.js +13 -0
  52. package/lib/parser/visitors/clause/select/fixture/select-min-max.sql +1 -0
  53. package/lib/parser/visitors/clause/select/fixture/select-sum-fix.js +10 -0
  54. package/lib/parser/visitors/clause/select/fixture/select-sum.sql +1 -0
  55. package/lib/parser/visitors/clause/select/select.js +47 -2
  56. package/lib/parser/visitors/clause/union/fixture/union-all-fix.js +10 -0
  57. package/lib/parser/visitors/clause/union/fixture/union-all.sql +1 -0
  58. package/lib/parser/visitors/clause/union/union.js +11 -0
  59. package/lib/parser/visitors/clause/update/fixture/update-where-not-in-fix.js +16 -0
  60. package/lib/parser/visitors/clause/update/fixture/update-where-not-in.sql +1 -0
  61. package/lib/parser/visitors/clause/where/fixture/where-between-fix.js +15 -0
  62. package/lib/parser/visitors/clause/where/fixture/where-between.sql +1 -0
  63. package/lib/parser/visitors/clause/where/fixture/where-not-in-fix.js +16 -0
  64. package/lib/parser/visitors/clause/where/fixture/where-not-in.sql +1 -0
  65. package/lib/parser/visitors/clause/where/where.js +19 -1
  66. package/lib/parser/visitors/clause/with-named/fixture/with-named-select-fix.js +19 -0
  67. package/lib/parser/visitors/clause/with-named/fixture/with-named-select.sql +1 -0
  68. package/lib/parser/visitors/clause/with-named/fixture/with-recursive-fix.js +27 -0
  69. package/lib/parser/visitors/clause/with-named/fixture/with-recursive-multi-fix.js +38 -0
  70. package/lib/parser/visitors/clause/with-named/fixture/with-recursive-multi.sql +1 -0
  71. package/lib/parser/visitors/clause/with-named/fixture/with-recursive-no-columns-fix.js +20 -0
  72. package/lib/parser/visitors/clause/with-named/fixture/with-recursive-no-columns.sql +1 -0
  73. package/lib/parser/visitors/clause/with-named/fixture/with-recursive.sql +1 -0
  74. package/lib/parser/visitors/clause/with-named/with-named.js +15 -2
  75. package/lib/printer/visitors/call-expression/clauses/avg/avg.js +5 -0
  76. package/lib/printer/visitors/call-expression/clauses/avg/fixture/avg-fix.sql +2 -0
  77. package/lib/printer/visitors/call-expression/clauses/avg/fixture/avg.js +1 -0
  78. package/lib/printer/visitors/call-expression/clauses/between/between.js +9 -0
  79. package/lib/printer/visitors/call-expression/clauses/between/fixture/between-fix.sql +3 -0
  80. package/lib/printer/visitors/call-expression/clauses/between/fixture/between.js +3 -0
  81. package/lib/printer/visitors/call-expression/clauses/clauses.js +28 -0
  82. package/lib/printer/visitors/call-expression/clauses/desc/desc.js +4 -0
  83. package/lib/printer/visitors/call-expression/clauses/desc/fixture/desc-fix.sql +3 -0
  84. package/lib/printer/visitors/call-expression/clauses/desc/fixture/desc.js +13 -0
  85. package/lib/printer/visitors/call-expression/clauses/distinct/distinct.js +12 -0
  86. package/lib/printer/visitors/call-expression/clauses/distinct/fixture/distinct-fix.sql +2 -0
  87. package/lib/printer/visitors/call-expression/clauses/distinct/fixture/distinct-multi-fix.sql +2 -0
  88. package/lib/printer/visitors/call-expression/clauses/distinct/fixture/distinct-multi.js +11 -0
  89. package/lib/printer/visitors/call-expression/clauses/distinct/fixture/distinct.js +10 -0
  90. package/lib/printer/visitors/call-expression/clauses/from/fixture/generate-series-fix.sql +2 -0
  91. package/lib/printer/visitors/call-expression/clauses/from/fixture/generate-series.js +3 -0
  92. package/lib/printer/visitors/call-expression/clauses/from/fixture/group-by-having-fix.sql +5 -0
  93. package/lib/printer/visitors/call-expression/clauses/from/fixture/group-by-having.js +22 -0
  94. package/lib/printer/visitors/call-expression/clauses/from/from.js +58 -11
  95. package/lib/printer/visitors/call-expression/clauses/group-by/fixture/group-by-fix.sql +3 -0
  96. package/lib/printer/visitors/call-expression/clauses/group-by/fixture/group-by-multi-fix.sql +3 -0
  97. package/lib/printer/visitors/call-expression/clauses/group-by/fixture/group-by-multi.js +13 -0
  98. package/lib/printer/visitors/call-expression/clauses/group-by/fixture/group-by-sum-fix.sql +4 -0
  99. package/lib/printer/visitors/call-expression/clauses/group-by/fixture/group-by-sum.js +19 -0
  100. package/lib/printer/visitors/call-expression/clauses/group-by/fixture/group-by.js +14 -0
  101. package/lib/printer/visitors/call-expression/clauses/group-by/group-by.js +12 -0
  102. package/lib/printer/visitors/call-expression/clauses/having/fixture/having-fix.sql +3 -0
  103. package/lib/printer/visitors/call-expression/clauses/having/fixture/having.js +16 -0
  104. package/lib/printer/visitors/call-expression/clauses/having/having.js +4 -0
  105. package/lib/printer/visitors/call-expression/clauses/insert/insert.js +1 -1
  106. package/lib/printer/visitors/call-expression/clauses/join/join.js +6 -4
  107. package/lib/printer/visitors/call-expression/clauses/limit/fixture/limit-fix.sql +3 -0
  108. package/lib/printer/visitors/call-expression/clauses/limit/fixture/limit-offset-fix.sql +4 -0
  109. package/lib/printer/visitors/call-expression/clauses/limit/fixture/limit-offset.js +12 -0
  110. package/lib/printer/visitors/call-expression/clauses/limit/fixture/limit.js +11 -0
  111. package/lib/printer/visitors/call-expression/clauses/limit/limit.js +12 -0
  112. package/lib/printer/visitors/call-expression/clauses/max/fixture/max-fix.sql +2 -0
  113. package/lib/printer/visitors/call-expression/clauses/max/fixture/max.js +1 -0
  114. package/lib/printer/visitors/call-expression/clauses/max/max.js +5 -0
  115. package/lib/printer/visitors/call-expression/clauses/min/fixture/min-fix.sql +2 -0
  116. package/lib/printer/visitors/call-expression/clauses/min/fixture/min.js +1 -0
  117. package/lib/printer/visitors/call-expression/clauses/min/min.js +5 -0
  118. package/lib/printer/visitors/call-expression/clauses/not-in-list/fixture/not-in-list-fix.sql +3 -0
  119. package/lib/printer/visitors/call-expression/clauses/not-in-list/fixture/not-in-list.js +3 -0
  120. package/lib/printer/visitors/call-expression/clauses/not-in-list/not-in-list.js +15 -0
  121. package/lib/printer/visitors/call-expression/clauses/order-by/fixture/order-by-fix.sql +3 -0
  122. package/lib/printer/visitors/call-expression/clauses/order-by/fixture/order-by-multi-fix.sql +3 -0
  123. package/lib/printer/visitors/call-expression/clauses/order-by/fixture/order-by-multi.js +14 -0
  124. package/lib/printer/visitors/call-expression/clauses/order-by/fixture/order-by.js +11 -0
  125. package/lib/printer/visitors/call-expression/clauses/order-by/order-by.js +12 -0
  126. package/lib/printer/visitors/call-expression/clauses/returning/returning.js +5 -3
  127. package/lib/printer/visitors/call-expression/clauses/select/select.js +10 -9
  128. package/lib/printer/visitors/call-expression/clauses/sum/fixture/sum-fix.sql +2 -0
  129. package/lib/printer/visitors/call-expression/clauses/sum/fixture/sum.js +1 -0
  130. package/lib/printer/visitors/call-expression/clauses/sum/sum.js +5 -0
  131. package/lib/printer/visitors/call-expression/clauses/union-all/fixture/union-all-fix.sql +3 -0
  132. package/lib/printer/visitors/call-expression/clauses/union-all/fixture/union-all.js +1 -0
  133. package/lib/printer/visitors/call-expression/clauses/union-all/union-all.js +9 -0
  134. package/lib/printer/visitors/call-expression/clauses/with-named/fixture/with-named-insert-fix.sql +3 -3
  135. package/lib/printer/visitors/call-expression/clauses/with-named/fixture/with-named-select-fix.sql +8 -0
  136. package/lib/printer/visitors/call-expression/clauses/with-named/fixture/with-named-select.js +19 -0
  137. package/lib/printer/visitors/call-expression/clauses/with-named/fixture/withNamed-fix.sql +3 -3
  138. package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-fix.sql +10 -0
  139. package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-multi-fix.sql +14 -0
  140. package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-multi.js +38 -0
  141. package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-no-columns-fix.sql +8 -0
  142. package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive-no-columns.js +20 -0
  143. package/lib/printer/visitors/call-expression/clauses/with-recursive/fixture/with-recursive.js +27 -0
  144. package/lib/printer/visitors/call-expression/clauses/with-recursive/with-recursive.js +57 -0
  145. package/package.json +2 -1
package/ChangeLog CHANGED
@@ -1,3 +1,20 @@
1
+ 2026.08.22, v2.1.1
2
+
3
+ feature:
4
+ - e2feb52 happy-sql: ctx -> printer
5
+ - 515f571 happy-sql: generate_series — table-valued function in FROM
6
+ - 39f51e3 parser/printer: where: between: add + test: happy-sql: roundtrip: full groupBy integration test
7
+ - 6a22942 parser/printer: where: not-in: add
8
+ - c1461ac parser/printer: distinct: add
9
+ - 8885f47 parser/printer: limit, offset: add
10
+ - 48f567c parser/printer: order-by: add
11
+ - 33a852e parser/printer: aggregate functions: sum, avg, min, max, count(col)
12
+
13
+ 2026.08.22, v2.1.0
14
+
15
+ feature:
16
+ - 533076c parser: WITH RECURSIVE: add
17
+
1
18
  2026.08.21, v2.0.8
2
19
 
3
20
  fix:
@@ -27,7 +27,11 @@ export const convertCount = (column) => {
27
27
  if (isNumericLiteral(item)) {
28
28
  const {value} = item;
29
29
  args.push(numericLiteral(value));
30
+ continue;
30
31
  }
32
+
33
+ // column reference: COUNT(id)
34
+ args.push(identifier(item.name));
31
35
  }
32
36
 
33
37
  return callExpression(identifier('count'), args);
@@ -0,0 +1,14 @@
1
+ [
2
+ deleteFrom(
3
+ from(
4
+ t,
5
+ ),
6
+ where(
7
+ between(
8
+ id,
9
+ 10,
10
+ 20,
11
+ ),
12
+ ),
13
+ ),
14
+ ];
@@ -0,0 +1 @@
1
+ DELETE FROM t WHERE id BETWEEN 10 AND 20
@@ -0,0 +1,12 @@
1
+ [
2
+ select(
3
+ '*',
4
+ from(
5
+ generateSeries(
6
+ 1,
7
+ 10,
8
+ 2,
9
+ ),
10
+ ),
11
+ ),
12
+ ];
@@ -0,0 +1 @@
1
+ SELECT * FROM generate_series(1, 10, 2)
@@ -0,0 +1,14 @@
1
+ [
2
+ select(
3
+ kind,
4
+ count(
5
+ '*',
6
+ ),
7
+ from(
8
+ VariableDeclaration,
9
+ groupBy(
10
+ kind,
11
+ ),
12
+ ),
13
+ ),
14
+ ];
@@ -0,0 +1,22 @@
1
+ [
2
+ select(
3
+ kind,
4
+ count(
5
+ '*',
6
+ ),
7
+ from(
8
+ VariableDeclaration,
9
+ where(
10
+ kind === 'const',
11
+ ),
12
+ groupBy(
13
+ kind,
14
+ ),
15
+ having(
16
+ count(
17
+ '*',
18
+ ) > 1,
19
+ ),
20
+ ),
21
+ ),
22
+ ];
@@ -0,0 +1 @@
1
+ SELECT kind, COUNT(*) FROM VariableDeclaration WHERE kind = 'const' GROUP BY kind HAVING COUNT(*) > 1
@@ -0,0 +1,13 @@
1
+ [
2
+ select(
3
+ kind,
4
+ name,
5
+ from(
6
+ VariableDeclaration,
7
+ groupBy(
8
+ kind,
9
+ name,
10
+ ),
11
+ ),
12
+ ),
13
+ ];
@@ -0,0 +1 @@
1
+ SELECT kind, name FROM VariableDeclaration GROUP BY kind, name
@@ -0,0 +1,17 @@
1
+ [
2
+ select(
3
+ dept,
4
+ count(
5
+ '*',
6
+ ),
7
+ from(
8
+ emp,
9
+ groupBy(
10
+ dept,
11
+ ),
12
+ orderBy(
13
+ dept,
14
+ ),
15
+ ),
16
+ ),
17
+ ];
@@ -0,0 +1 @@
1
+ SELECT dept, COUNT(*) FROM emp GROUP BY dept ORDER BY dept
@@ -0,0 +1,14 @@
1
+ [
2
+ select(
3
+ dept,
4
+ sum(
5
+ salary,
6
+ ),
7
+ from(
8
+ emp,
9
+ groupBy(
10
+ dept,
11
+ ),
12
+ ),
13
+ ),
14
+ ];
@@ -0,0 +1,19 @@
1
+ [
2
+ select(
3
+ dept,
4
+ sum(
5
+ salary,
6
+ ),
7
+ from(
8
+ emp,
9
+ groupBy(
10
+ dept,
11
+ ),
12
+ having(
13
+ sum(
14
+ salary,
15
+ ) > 1000,
16
+ ),
17
+ ),
18
+ ),
19
+ ];
@@ -0,0 +1 @@
1
+ SELECT dept, SUM(salary) FROM emp GROUP BY dept HAVING SUM(salary) > 1000
@@ -0,0 +1 @@
1
+ SELECT dept, SUM(salary) FROM emp GROUP BY dept
@@ -0,0 +1 @@
1
+ SELECT kind, COUNT(*) FROM VariableDeclaration GROUP BY kind
@@ -0,0 +1,10 @@
1
+ [
2
+ select(
3
+ '*',
4
+ from(
5
+ jsonEach(
6
+ '[1,2]',
7
+ ),
8
+ ),
9
+ ),
10
+ ];
@@ -0,0 +1 @@
1
+ SELECT * FROM json_each('[1,2]')
@@ -0,0 +1,11 @@
1
+ [
2
+ select(
3
+ id,
4
+ from(
5
+ users,
6
+ limit(
7
+ 10,
8
+ ),
9
+ ),
10
+ ),
11
+ ];
@@ -0,0 +1,12 @@
1
+ [
2
+ select(
3
+ id,
4
+ from(
5
+ users,
6
+ limit(
7
+ 10,
8
+ 5,
9
+ ),
10
+ ),
11
+ ),
12
+ ];
@@ -0,0 +1 @@
1
+ SELECT id FROM users LIMIT 10 OFFSET 5
@@ -0,0 +1 @@
1
+ SELECT id FROM users LIMIT 10
@@ -0,0 +1,13 @@
1
+ [
2
+ select(
3
+ id,
4
+ from(
5
+ users,
6
+ orderBy(
7
+ desc(
8
+ name,
9
+ ),
10
+ ),
11
+ ),
12
+ ),
13
+ ];
@@ -0,0 +1 @@
1
+ SELECT id FROM users ORDER BY name DESC
@@ -0,0 +1,11 @@
1
+ [
2
+ select(
3
+ id,
4
+ from(
5
+ users,
6
+ orderBy(
7
+ name,
8
+ ),
9
+ ),
10
+ ),
11
+ ];
@@ -0,0 +1,14 @@
1
+ [
2
+ select(
3
+ id,
4
+ from(
5
+ users,
6
+ orderBy(
7
+ name,
8
+ desc(
9
+ id,
10
+ ),
11
+ ),
12
+ ),
13
+ ),
14
+ ];
@@ -0,0 +1 @@
1
+ SELECT id FROM users ORDER BY name ASC, id DESC
@@ -0,0 +1 @@
1
+ SELECT id FROM users ORDER BY name
@@ -0,0 +1,10 @@
1
+ [
2
+ select(
3
+ '*',
4
+ from(
5
+ unnest(
6
+ arr,
7
+ ),
8
+ ),
9
+ ),
10
+ ];
@@ -0,0 +1 @@
1
+ SELECT * FROM unnest(arr)
@@ -1,5 +1,11 @@
1
1
  import {types} from '@putout/babel';
2
2
  import {convertOperand} from '#parser/clause/operand';
3
+ import {convertBetween} from '#parser/clause/where';
4
+ import {convertGroupBy} from './group-by.js';
5
+ import {convertHaving} from './having.js';
6
+ import {convertOrderBy} from './order-by.js';
7
+ import {convertLimit} from './limit.js';
8
+ import {convertTableFunc} from './table-func.js';
3
9
 
4
10
  const isString = (a) => typeof a === 'string';
5
11
 
@@ -62,6 +68,15 @@ const convertBinary = (node) => {
62
68
  ]);
63
69
  }
64
70
 
71
+ if (op === 'NOT IN') {
72
+ const items = node.right.expr.items.map(convertOperand);
73
+
74
+ return callExpression(identifier('notInList'), [
75
+ convertOperand(node.left),
76
+ ...items,
77
+ ]);
78
+ }
79
+
65
80
  const jsOp = SQL_TO_JS_OP[op] ?? '===';
66
81
 
67
82
  return binaryExpression(
@@ -78,6 +93,9 @@ const convertCondition = (node) => {
78
93
  if (node.operator?.name === 'OR')
79
94
  return logicalExpression('||', convertCondition(node.left), convertCondition(node.right));
80
95
 
96
+ if (node.type === 'between_expr')
97
+ return convertBetween(node);
98
+
81
99
  return convertBinary(node);
82
100
  };
83
101
 
@@ -108,7 +126,7 @@ const flattenJoins = (node, joins = []) => {
108
126
  return joins;
109
127
  };
110
128
 
111
- export const convertFrom = ({expr, whereClause}) => {
129
+ export const convertFrom = ({expr, whereClause, groupByClause, havingClause, orderByClause, limitClause}) => {
112
130
  const fromArgs = [];
113
131
 
114
132
  if (whereClause)
@@ -116,6 +134,18 @@ export const convertFrom = ({expr, whereClause}) => {
116
134
  convertCondition(whereClause.expr),
117
135
  ]));
118
136
 
137
+ if (groupByClause)
138
+ fromArgs.push(convertGroupBy(groupByClause));
139
+
140
+ if (havingClause)
141
+ fromArgs.push(convertHaving(havingClause));
142
+
143
+ if (orderByClause)
144
+ fromArgs.push(convertOrderBy(orderByClause));
145
+
146
+ if (limitClause)
147
+ fromArgs.push(convertLimit(limitClause));
148
+
119
149
  if (expr.type === 'join_expr') {
120
150
  const parts = flattenJoins(expr);
121
151
  return callExpression(identifier('from'), parts);
@@ -127,6 +157,12 @@ export const convertFrom = ({expr, whereClause}) => {
127
157
  ...fromArgs,
128
158
  ]);
129
159
 
160
+ if (expr.type === 'func_call')
161
+ return callExpression(identifier('from'), [
162
+ convertTableFunc(expr),
163
+ ...fromArgs,
164
+ ]);
165
+
130
166
  return callExpression(identifier('from'), [
131
167
  identifier(expr.name),
132
168
  ...fromArgs,
@@ -0,0 +1,6 @@
1
+ import {types} from '@putout/babel';
2
+ import {convertOperand} from '#parser/clause/operand';
3
+
4
+ const {callExpression, identifier} = types;
5
+
6
+ export const convertGroupBy = (clause) => callExpression(identifier('groupBy'), clause.columns.items.map(convertOperand));
@@ -0,0 +1,8 @@
1
+ import {types} from '@putout/babel';
2
+ import {convertCondition} from '#parser/clause/where';
3
+
4
+ const {callExpression, identifier} = types;
5
+
6
+ export const convertHaving = (clause) => callExpression(identifier('having'), [
7
+ convertCondition(clause.expr),
8
+ ]);
@@ -0,0 +1,18 @@
1
+ import {types} from '@putout/babel';
2
+
3
+ const {
4
+ callExpression,
5
+ identifier,
6
+ numericLiteral,
7
+ } = types;
8
+
9
+ export const convertLimit = (limitClause) => {
10
+ const args = [
11
+ numericLiteral(limitClause.count.value),
12
+ ];
13
+
14
+ if (limitClause.offset)
15
+ args.push(numericLiteral(limitClause.offset.value));
16
+
17
+ return callExpression(identifier('limit'), args);
18
+ };
@@ -0,0 +1,20 @@
1
+ import {types} from '@putout/babel';
2
+ import {convertOperand} from '#parser/clause/operand';
3
+
4
+ const {callExpression, identifier} = types;
5
+
6
+ const convertOrderItem = (item) => {
7
+ if (item.type !== 'sort_specification')
8
+ return convertOperand(item);
9
+
10
+ const col = convertOperand(item.expr);
11
+ const {direction} = item;
12
+
13
+ if (direction.type === 'sort_direction_desc')
14
+ return callExpression(identifier('desc'), [col]);
15
+
16
+ // ASC is default — no wrapper
17
+ return col;
18
+ };
19
+
20
+ export const convertOrderBy = (clause) => callExpression(identifier('orderBy'), clause.specifications.items.map(convertOrderItem));
@@ -0,0 +1,28 @@
1
+ import {types} from '@putout/babel';
2
+
3
+ const {
4
+ callExpression,
5
+ identifier,
6
+ numericLiteral,
7
+ stringLiteral,
8
+ } = types;
9
+
10
+ const SNAKE_RE = /_([a-z])/g;
11
+ const toCamel = (s) => s.replace(SNAKE_RE, (_, c) => c.toUpperCase());
12
+
13
+ const convertArg = (arg) => {
14
+ if (arg.type === 'number_literal')
15
+ return numericLiteral(arg.value);
16
+
17
+ if (arg.type === 'string_literal')
18
+ return stringLiteral(arg.value);
19
+
20
+ return identifier(arg.name);
21
+ };
22
+
23
+ export const convertTableFunc = (expr) => {
24
+ const name = toCamel(expr.name.name);
25
+ const args = expr.args.expr.args.items.map(convertArg);
26
+
27
+ return callExpression(identifier(name), args);
28
+ };
@@ -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: convertSelect,
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,
@@ -7,9 +8,22 @@ const {
7
8
  booleanLiteral,
8
9
  nullLiteral,
9
10
  memberExpression,
11
+ callExpression,
10
12
  } = types;
11
13
 
14
+ const isFuncCall = ({type}) => type === 'func_call';
15
+
12
16
  export const convertOperand = (node) => {
17
+ if (isCount(node))
18
+ return convertCount(node);
19
+
20
+ if (isFuncCall(node)) {
21
+ const lower = node.name.name.toLowerCase();
22
+ const {items} = node.args.expr.args;
23
+
24
+ return callExpression(identifier(lower), items.map(convertOperand));
25
+ }
26
+
13
27
  if (node.type === 'member_expr')
14
28
  return memberExpression(identifier(node.object.name), identifier(node.property.name));
15
29
 
@@ -0,0 +1,8 @@
1
+ [
2
+ select(
3
+ ABS(),
4
+ from(
5
+ t,
6
+ ),
7
+ ),
8
+ ];
@@ -0,0 +1 @@
1
+ SELECT ABS(x) FROM t
@@ -0,0 +1,10 @@
1
+ [
2
+ select(
3
+ avg(
4
+ score,
5
+ ),
6
+ from(
7
+ results,
8
+ ),
9
+ ),
10
+ ];
@@ -0,0 +1 @@
1
+ SELECT AVG(score) FROM results
@@ -0,0 +1,10 @@
1
+ [
2
+ select(
3
+ count(
4
+ id,
5
+ ),
6
+ from(
7
+ users,
8
+ ),
9
+ ),
10
+ ];
@@ -0,0 +1 @@
1
+ SELECT COUNT(id) FROM users
@@ -0,0 +1,10 @@
1
+ [
2
+ select(
3
+ distinct(
4
+ name,
5
+ ),
6
+ from(
7
+ users,
8
+ ),
9
+ ),
10
+ ];
@@ -0,0 +1,11 @@
1
+ [
2
+ select(
3
+ distinct(
4
+ name,
5
+ age,
6
+ ),
7
+ from(
8
+ users,
9
+ ),
10
+ ),
11
+ ];
@@ -0,0 +1 @@
1
+ SELECT DISTINCT name, age FROM users
@@ -0,0 +1 @@
1
+ SELECT DISTINCT name FROM users
@@ -0,0 +1,13 @@
1
+ [
2
+ select(
3
+ min(
4
+ price,
5
+ ),
6
+ max(
7
+ price,
8
+ ),
9
+ from(
10
+ products,
11
+ ),
12
+ ),
13
+ ];
@@ -0,0 +1 @@
1
+ SELECT MIN(price), MAX(price) FROM products
@@ -0,0 +1,10 @@
1
+ [
2
+ select(
3
+ sum(
4
+ amount,
5
+ ),
6
+ from(
7
+ orders,
8
+ ),
9
+ ),
10
+ ];
@@ -0,0 +1 @@
1
+ SELECT SUM(amount) FROM orders