happy-sql 2.0.1 → 2.0.3

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 (68) hide show
  1. package/ChangeLog +10 -0
  2. package/lib/happy-sql.js +5 -1
  3. package/lib/parser/visitors/clause/from/fixture/join-fix.js +1 -4
  4. package/lib/parser/visitors/clause/from/fixture/join-multi-fix.js +1 -4
  5. package/lib/parser/visitors/clause/from/fixture/join-on-not-eq-fix.js +1 -4
  6. package/lib/parser/visitors/clause/from/fixture/join-on-number-fix.js +1 -4
  7. package/lib/parser/visitors/clause/from/fixture/join-on-or-fix.js +1 -4
  8. package/lib/parser/visitors/clause/from/fixture/join-on-param-fix.js +1 -4
  9. package/lib/parser/visitors/clause/from/from.js +13 -7
  10. package/lib/parser/visitors/clause/insert/fixture/insert-returning-fix.js +1 -1
  11. package/lib/parser/visitors/clause/insert/insert.js +3 -4
  12. package/lib/parser/visitors/clause/select/fixture/select-alias-fix.js +1 -1
  13. package/lib/parser/visitors/clause/select/fixture/select-alias-param-fix.js +1 -1
  14. package/lib/parser/visitors/clause/select/fixture/select-number-fix.js +1 -1
  15. package/lib/parser/visitors/clause/select/select.js +8 -6
  16. package/lib/parser/visitors/clause/where/fixture/where-compare-fix.js +1 -1
  17. package/lib/parser/visitors/clause/where/fixture/where-fix.js +1 -1
  18. package/lib/parser/visitors/clause/where/fixture/where-gte-fix.js +1 -1
  19. package/lib/parser/visitors/clause/where/fixture/where-in-fix.js +1 -1
  20. package/lib/parser/visitors/clause/where/fixture/where-is-not-null-fix.js +1 -1
  21. package/lib/parser/visitors/clause/where/fixture/where-is-null-fix.js +1 -1
  22. package/lib/parser/visitors/clause/where/fixture/where-like-fix.js +1 -1
  23. package/lib/parser/visitors/clause/where/fixture/where-not-eq-fix.js +1 -1
  24. package/lib/parser/visitors/clause/where/fixture/where-number-fix.js +1 -1
  25. package/lib/parser/visitors/clause/where/fixture/where-or-fix.js +1 -1
  26. package/lib/printer/visitors/array-expression.js +1 -1
  27. package/lib/printer/visitors/call-expression/clauses/clauses.js +0 -2
  28. package/lib/printer/visitors/call-expression/clauses/create-table/create-table.js +2 -2
  29. package/lib/printer/visitors/call-expression/clauses/create-table/fixture/createTable-fix.sql +2 -1
  30. package/lib/printer/visitors/call-expression/clauses/create-table/fixture/createTableIdentity-fix.sql +2 -1
  31. package/lib/printer/visitors/call-expression/clauses/create-table/fixture/createTableIdentityByDefault-fix.sql +2 -1
  32. package/lib/printer/visitors/call-expression/clauses/create-table/fixture/createTableSerial-fix.sql +2 -1
  33. package/lib/printer/visitors/call-expression/clauses/from/from.js +33 -3
  34. package/lib/printer/visitors/call-expression/clauses/insert/insert.js +1 -1
  35. package/lib/printer/visitors/call-expression/clauses/into/into.js +6 -2
  36. package/lib/printer/visitors/call-expression/clauses/join/fixture/join-fix.sql +2 -2
  37. package/lib/printer/visitors/call-expression/clauses/join/fixture/join-multi-fix.sql +3 -3
  38. package/lib/printer/visitors/call-expression/clauses/join/fixture/join-multi.js +1 -1
  39. package/lib/printer/visitors/call-expression/clauses/join/fixture/join.js +1 -1
  40. package/lib/printer/visitors/call-expression/clauses/join/join.js +20 -1
  41. package/lib/printer/visitors/call-expression/clauses/nextval/fixture/nextval-fix.sql +3 -1
  42. package/lib/printer/visitors/call-expression/clauses/on-conflict/fixture/on-conflict-fix.sql +2 -1
  43. package/lib/printer/visitors/call-expression/clauses/on-conflict/fixture/on-conflict-multi-fix.sql +2 -1
  44. package/lib/printer/visitors/call-expression/clauses/returning/fixture/returning-conflict-fix.sql +3 -1
  45. package/lib/printer/visitors/call-expression/clauses/returning/fixture/returning-fix.sql +2 -1
  46. package/lib/printer/visitors/call-expression/clauses/returning/fixture/returning-id-fix.sql +2 -1
  47. package/lib/printer/visitors/call-expression/clauses/returning/fixture/returning-multi-fix.sql +2 -1
  48. package/lib/printer/visitors/call-expression/clauses/returning/fixture/returning.js +1 -1
  49. package/lib/printer/visitors/call-expression/clauses/returning/returning.js +20 -1
  50. package/lib/printer/visitors/call-expression/clauses/section/fixture/section-fix.sql +1 -1
  51. package/lib/printer/visitors/call-expression/clauses/section/fixture/section-multi-fix.sql +3 -2
  52. package/lib/printer/visitors/call-expression/clauses/section/section.js +3 -2
  53. package/lib/printer/visitors/call-expression/clauses/select/fixture/string-fix.sql +1 -1
  54. package/lib/printer/visitors/call-expression/clauses/select/select.js +24 -14
  55. package/lib/printer/visitors/call-expression/clauses/where/fixture/where-fix.sql +1 -3
  56. package/lib/printer/visitors/call-expression/clauses/where/fixture/where-gte-fix.sql +1 -3
  57. package/lib/printer/visitors/call-expression/clauses/where/fixture/where-in-fix.sql +1 -3
  58. package/lib/printer/visitors/call-expression/clauses/where/fixture/where-is-not-null-fix.sql +1 -3
  59. package/lib/printer/visitors/call-expression/clauses/where/fixture/where-is-null-fix.sql +1 -3
  60. package/lib/printer/visitors/call-expression/clauses/where/fixture/where-like-fix.sql +1 -3
  61. package/lib/printer/visitors/call-expression/clauses/where/fixture/where-ne-fix.sql +1 -3
  62. package/lib/printer/visitors/call-expression/clauses/with-named/fixture/with-named-insert-fix.sql +4 -2
  63. package/lib/printer/visitors/call-expression/clauses/with-named/fixture/withNamed-fix.sql +4 -2
  64. package/lib/printer/visitors/fixture/binary-expression-fix.sql +1 -3
  65. package/lib/printer/visitors/index.js +0 -2
  66. package/package.json +1 -1
  67. package/lib/printer/visitors/assignment-expression.js +0 -5
  68. package/lib/printer/visitors/call-expression/clauses/as/as.js +0 -15
package/ChangeLog CHANGED
@@ -1,3 +1,13 @@
1
+ 2026.08.20, v2.0.3
2
+
3
+ feature:
4
+ - 894a345 from
5
+
6
+ 2026.08.20, v2.0.2
7
+
8
+ fix:
9
+ - e7b456f happy-sql: drop as(), use TSAsExpression aliases; round-trip specs; 100% coverage
10
+
1
11
  2026.08.19, v2.0.1
2
12
 
3
13
  fix:
package/lib/happy-sql.js CHANGED
@@ -8,4 +8,8 @@ export {parseSql} from '#parser';
8
8
 
9
9
  export const convertSqlToJs = (sql) => print(parseSql(sql));
10
10
 
11
- export const convertJsToSql = (js) => printSql(parse(js));
11
+ export const convertJsToSql = (js) => printSql(parse(js, {
12
+ plugins: [
13
+ ['typescript'],
14
+ ],
15
+ }));
@@ -1,6 +1,3 @@
1
1
  [
2
- select(bin.id, from(as(
3
- BinaryExpression,
4
- bin,
5
- ), join(as(Identifier, nan_id), on(nan_id.parent_id === bin.id && nan_id.name === 'NaN')))),
2
+ select(bin.id, from(BinaryExpression as 'bin', join(Identifier as 'nan_id', on(nan_id.parent_id === bin.id && nan_id.name === 'NaN')))),
6
3
  ];
@@ -1,6 +1,3 @@
1
1
  [
2
- select(bin.id, arg_id.name, from(as(
3
- BinaryExpression,
4
- bin,
5
- ), join(as(Identifier, nan_id), on(nan_id.parent_id === bin.id)), join(as(Identifier, arg_id), on(arg_id.parent_id === bin.id)))),
2
+ select(bin.id, arg_id.name, from(BinaryExpression as 'bin', join(Identifier as 'nan_id', on(nan_id.parent_id === bin.id)), join(Identifier as 'arg_id', on(arg_id.parent_id === bin.id)))),
6
3
  ];
@@ -1,6 +1,3 @@
1
1
  [
2
- select(bin.id, from(as(
3
- BinaryExpression,
4
- bin,
5
- ), join(as(Identifier, arg_id), on(arg_id.parent_id === bin.id && arg_id.id !== bin.id)))),
2
+ select(bin.id, from(BinaryExpression as 'bin', join(Identifier as 'arg_id', on(arg_id.parent_id === bin.id && arg_id.id !== bin.id)))),
6
3
  ];
@@ -1,6 +1,3 @@
1
1
  [
2
- select(bin.id, from(as(
3
- BinaryExpression,
4
- bin,
5
- ), join(as(Identifier, nan_id), on(nan_id.parent_id === 1)))),
2
+ select(bin.id, from(BinaryExpression as 'bin', join(Identifier as 'nan_id', on(nan_id.parent_id === 1)))),
6
3
  ];
@@ -1,6 +1,3 @@
1
1
  [
2
- select(bin.id, from(as(
3
- BinaryExpression,
4
- bin,
5
- ), join(as(Identifier, nan_id), on(nan_id.parent_id === bin.id || nan_id.name === 'NaN')))),
2
+ select(bin.id, from(BinaryExpression as 'bin', join(Identifier as 'nan_id', on(nan_id.parent_id === bin.id || nan_id.name === 'NaN')))),
6
3
  ];
@@ -1,6 +1,3 @@
1
1
  [
2
- select(bin.id, from(as(
3
- BinaryExpression,
4
- bin,
5
- ), join(as(Identifier, nan_id), on(nan_id.parent_id === ':param_id')))),
2
+ select(bin.id, from(BinaryExpression as 'bin', join(Identifier as 'nan_id', on(nan_id.parent_id === ':param_id')))),
6
3
  ];
@@ -12,6 +12,8 @@ const {
12
12
  numericLiteral,
13
13
  booleanLiteral,
14
14
  nullLiteral,
15
+ tsAsExpression,
16
+ tsLiteralType,
15
17
  } = types;
16
18
 
17
19
  const convertOperand = (node) => {
@@ -110,10 +112,7 @@ const convertOn = (spec) => callExpression(identifier('on'), [
110
112
 
111
113
  const convertAlias = (node) => {
112
114
  if (node.type === 'alias')
113
- return callExpression(identifier('as'), [
114
- identifier(node.expr.name),
115
- identifier(node.alias.name),
116
- ]);
115
+ return tsAsExpression(identifier(node.expr.name), tsLiteralType(stringLiteral(node.alias.name)));
117
116
 
118
117
  return identifier(node.name);
119
118
  };
@@ -134,7 +133,7 @@ const flattenJoins = (node, joins = []) => {
134
133
  return joins;
135
134
  };
136
135
 
137
- export const convertFrom = ({expr}) => {
136
+ export const convertFrom = ({expr, whereClause}) => {
138
137
  if (expr.type === 'join_expr') {
139
138
  const parts = flattenJoins(expr);
140
139
  return callExpression(identifier('from'), parts);
@@ -145,7 +144,14 @@ export const convertFrom = ({expr}) => {
145
144
  convertAlias(expr),
146
145
  ]);
147
146
 
148
- return callExpression(identifier('from'), [
147
+ const fromArgs = [
149
148
  identifier(expr.name),
150
- ]);
149
+ ];
150
+
151
+ if (whereClause)
152
+ fromArgs.push(callExpression(identifier('where'), [
153
+ convertCondition(whereClause.expr),
154
+ ]));
155
+
156
+ return callExpression(identifier('from'), fromArgs);
151
157
  };
@@ -3,5 +3,5 @@
3
3
  CallExpression,
4
4
  parent_id,
5
5
  values(':parent_id'),
6
- ), returning(as(id, 'call_id'))),
6
+ ), returning(id as 'call_id')),
7
7
  ];
@@ -9,6 +9,8 @@ const {
9
9
  callExpression,
10
10
  arrayExpression,
11
11
  stringLiteral,
12
+ tsAsExpression,
13
+ tsLiteralType,
12
14
  } = types;
13
15
 
14
16
  const convertExprToIdentifier = ({expr}) => identifier(expr.name);
@@ -19,10 +21,7 @@ const convertReturningItem = (item) => {
19
21
  const {name} = item.expr;
20
22
  const aliasName = item.alias.name;
21
23
 
22
- return callExpression(identifier('as'), [
23
- identifier(name),
24
- stringLiteral(aliasName),
25
- ]);
24
+ return tsAsExpression(identifier(name), tsLiteralType(stringLiteral(aliasName)));
26
25
  }
27
26
 
28
27
  return identifier(item.name);
@@ -1,3 +1,3 @@
1
1
  [
2
- select(message = 'msg', num = 42, from(t)),
2
+ select('msg' as 'message', 42 as 'num', from(t)),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select(file = ':file', from(t)),
2
+ select(':file' as 'file', from(t)),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(t), where(num === 42)),
2
+ select('*', from(t, where(num === 42))),
3
3
  ];
@@ -1,14 +1,14 @@
1
1
  import {types} from '@putout/babel';
2
2
  import {convertOperand} from '#parser/clause/operand';
3
3
  import {convertFrom} from '#parser/clause/from';
4
- import {convertWhere} from '#parser/clause/where';
5
- import {findClause} from '#parser/clause/find';
6
4
  import {convertCount, isCount} from '#parser/clause/count';
5
+ import {findClause} from '#parser/clause/find';
7
6
 
8
7
  const {
9
8
  identifier,
10
9
  stringLiteral,
11
- assignmentExpression,
10
+ tsAsExpression,
11
+ tsLiteralType,
12
12
  callExpression,
13
13
  memberExpression,
14
14
  } = types;
@@ -21,7 +21,7 @@ const convertColumn = (column) => {
21
21
  return convertFuncCall(column);
22
22
 
23
23
  if (column.type === 'alias')
24
- return assignmentExpression('=', identifier(column.alias.name), convertOperand(column.expr));
24
+ return tsAsExpression(convertOperand(column.expr), tsLiteralType(stringLiteral(column.alias.name)));
25
25
 
26
26
  if (column.type === 'string_literal')
27
27
  return stringLiteral(column.value);
@@ -60,8 +60,10 @@ export const convertSelect = ({clauses}) => {
60
60
 
61
61
  const args = [
62
62
  ...convertColumns(selectClause.columns),
63
- fromClause && convertFrom(fromClause),
64
- whereClause && convertWhere(whereClause),
63
+ fromClause && convertFrom({
64
+ expr: fromClause.expr,
65
+ whereClause,
66
+ }),
65
67
  ].filter(Boolean);
66
68
 
67
69
  return callExpression(identifier('select'), args);
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(t), where(x > 1 && y < 2)),
2
+ select('*', from(t, where(x > 1 && y < 2))),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(users), where(id === ':id')),
2
+ select('*', from(users, where(id === ':id'))),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(t), where(x >= 1)),
2
+ select('*', from(t, where(x >= 1))),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(t), where(inList(x, 1, 2, 3))),
2
+ select('*', from(t, where(inList(x, 1, 2, 3)))),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(t), where(isNotNull(x))),
2
+ select('*', from(t, where(isNotNull(x)))),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(t), where(isNull(x))),
2
+ select('*', from(t, where(isNull(x)))),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(t), where(like(x, ':pattern'))),
2
+ select('*', from(t, where(like(x, ':pattern')))),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(t), where(x !== ':y')),
2
+ select('*', from(t, where(x !== ':y'))),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(t), where(id === 42)),
2
+ select('*', from(t, where(id === 42))),
3
3
  ];
@@ -1,3 +1,3 @@
1
1
  [
2
- select('*', from(t), where(x === ':x' || y === ':y')),
2
+ select('*', from(t, where(x === ':x' || y === ':y'))),
3
3
  ];
@@ -6,6 +6,6 @@ export const ArrayExpression = (path, {write, traverse}) => {
6
6
  traverse(el);
7
7
 
8
8
  if (i < n)
9
- write(';\n');
9
+ write('\n\n');
10
10
  }
11
11
  };
@@ -13,7 +13,6 @@ import {deleteFrom} from './delete/delete.js';
13
13
  import {section} from './section/section.js';
14
14
  import {count} from './count/count.js';
15
15
  import {returning} from './returning/returning.js';
16
- import {as} from './as/as.js';
17
16
  import {withNamed} from './with-named/with-named.js';
18
17
  import {createTable} from './create-table/create-table.js';
19
18
  import {createSequence} from './create-sequence/create-sequence.js';
@@ -48,7 +47,6 @@ export const clauses = {
48
47
  deleteFrom,
49
48
  section,
50
49
  returning,
51
- as,
52
50
  withNamed,
53
51
  createTable,
54
52
  createSequence,
@@ -3,13 +3,13 @@ export const createTable = (path, {write, traverse}) => {
3
3
 
4
4
  write('CREATE TABLE ');
5
5
  traverse(name);
6
- write(' (');
6
+ write(' (\n');
7
7
 
8
8
  const elements = columns.get('elements');
9
9
 
10
10
  for (const [i, element] of elements.entries()) {
11
11
  if (i > 0)
12
- write(', ');
12
+ write(',\n');
13
13
 
14
14
  traverse(element);
15
15
  }
@@ -1 +1,2 @@
1
- CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT)
1
+ CREATE TABLE t (
2
+ id INTEGER PRIMARY KEY AUTOINCREMENT)
@@ -1 +1,2 @@
1
- CREATE TABLE t (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY)
1
+ CREATE TABLE t (
2
+ id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY)
@@ -1 +1,2 @@
1
- CREATE TABLE t (id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY)
1
+ CREATE TABLE t (
2
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY)
@@ -1 +1,2 @@
1
- CREATE TABLE t (id SERIAL PRIMARY KEY)
1
+ CREATE TABLE t (
2
+ id SERIAL PRIMARY KEY)
@@ -1,9 +1,39 @@
1
+ import {types} from '@putout/babel';
2
+
3
+ const {isTSAsExpression} = types;
4
+
5
+ const printAsExpression = (path, {write, traverse}) => {
6
+ traverse(path.get('expression'));
7
+ write(` AS ${path.node.typeAnnotation.literal.value}`);
8
+ };
9
+
10
+ const printArg = (path, ctx) => {
11
+ if (isTSAsExpression(path.node))
12
+ return printAsExpression(path, ctx);
13
+
14
+ ctx.traverse(path);
15
+ };
16
+
1
17
  export const from = (path, {write, traverse}) => {
2
18
  const args = path.get('arguments');
19
+ const lastArg = args.at(-1);
20
+ const hasWhere = lastArg?.node?.callee?.name === 'where';
21
+ const tableArgs = hasWhere ? args.slice(0, -1) : args;
3
22
 
4
23
  write('FROM ');
5
- traverse(args[0]);
24
+ printArg(tableArgs[0], {
25
+ write,
26
+ traverse,
27
+ });
28
+
29
+ for (let i = 1; i < tableArgs.length; i++)
30
+ printArg(tableArgs[i], {
31
+ write,
32
+ traverse,
33
+ });
6
34
 
7
- for (let i = 1; i < args.length; i++)
8
- traverse(args[i]);
35
+ if (hasWhere) {
36
+ write('\n');
37
+ traverse(lastArg);
38
+ }
9
39
  };
@@ -6,7 +6,7 @@ export const insert = (path, {write, traverse}) => {
6
6
  traverse(intoArg);
7
7
 
8
8
  for (const arg of rest) {
9
- write(' ');
9
+ write('\n');
10
10
  traverse(arg);
11
11
  }
12
12
  };
@@ -21,6 +21,10 @@ export const into = (path, {write, traverse}) => {
21
21
  traverse(columns);
22
22
  }
23
23
 
24
- write(') ');
25
- traverse(values);
24
+ write(')');
25
+
26
+ if (values) {
27
+ write(' ');
28
+ traverse(values);
29
+ }
26
30
  };
@@ -1,4 +1,4 @@
1
1
  SELECT bin.id
2
- FROM BinaryExpression bin
3
- JOIN Identifier nan_id ON nan_id.parent_id = bin.id
2
+ FROM BinaryExpression AS bin
3
+ JOIN Identifier AS nan_id ON nan_id.parent_id = bin.id
4
4
  AND nan_id.name = 'NaN'
@@ -1,4 +1,4 @@
1
1
  SELECT bin.id, arg_id.name
2
- FROM BinaryExpression bin
3
- JOIN Identifier nan_id ON nan_id.parent_id = bin.id
4
- JOIN Identifier arg_id ON arg_id.parent_id = bin.id
2
+ FROM BinaryExpression AS bin
3
+ JOIN Identifier AS nan_id ON nan_id.parent_id = bin.id
4
+ JOIN Identifier AS arg_id ON arg_id.parent_id = bin.id
@@ -1 +1 @@
1
- [select(bin.id, arg_id.name, from(as(BinaryExpression, bin), join(as(Identifier, nan_id), on(nan_id.parent_id === bin.id)), join(as(Identifier, arg_id), on(arg_id.parent_id === bin.id))))];
1
+ [select(bin.id, arg_id.name, from(BinaryExpression as 'bin', join(Identifier as 'nan_id', on(nan_id.parent_id === bin.id)), join(Identifier as 'arg_id', on(arg_id.parent_id === bin.id))))];
@@ -1 +1 @@
1
- [select(bin.id, from(as(BinaryExpression, bin), join(as(Identifier, nan_id), on(nan_id.parent_id === bin.id && nan_id.name === 'NaN'))))];
1
+ [select(bin.id, from(BinaryExpression as 'bin', join(Identifier as 'nan_id', on(nan_id.parent_id === bin.id && nan_id.name === 'NaN'))))];
@@ -1,8 +1,27 @@
1
+ import {types} from '@putout/babel';
2
+
3
+ const {isTSAsExpression} = types;
4
+
5
+ const printAsExpression = (path, {write, traverse}) => {
6
+ traverse(path.get('expression'));
7
+ write(` AS ${path.node.typeAnnotation.literal.value}`);
8
+ };
9
+
10
+ const printTable = (path, ctx) => {
11
+ if (isTSAsExpression(path.node))
12
+ return printAsExpression(path, ctx);
13
+
14
+ ctx.traverse(path);
15
+ };
16
+
1
17
  export const join = (path, {write, traverse}) => {
2
18
  const [table, onClause] = path.get('arguments');
3
19
 
4
20
  write('\nJOIN ');
5
- traverse(table);
21
+ printTable(table, {
22
+ write,
23
+ traverse,
24
+ });
6
25
  write(' ');
7
26
  traverse(onClause);
8
27
  };
@@ -1 +1,3 @@
1
- CREATE TABLE users (id INTEGER DEFAULT nextval('users_id_seq') PRIMARY KEY, name TEXT)
1
+ CREATE TABLE users (
2
+ id INTEGER DEFAULT nextval('users_id_seq') PRIMARY KEY,
3
+ name TEXT)
@@ -1 +1,2 @@
1
- INSERT INTO t (x) VALUES (:x) ON CONFLICT (x) DO UPDATE SET x = :x
1
+ INSERT INTO t (x) VALUES (:x)
2
+ ON CONFLICT (x) DO UPDATE SET x = :x
@@ -1 +1,2 @@
1
- INSERT INTO t (x) VALUES (:x) ON CONFLICT (x, y) DO UPDATE SET x = :x
1
+ INSERT INTO t (x) VALUES (:x)
2
+ ON CONFLICT (x, y) DO UPDATE SET x = :x
@@ -1 +1,3 @@
1
- INSERT INTO t (x) VALUES (:x) ON CONFLICT (x) DO UPDATE SET y = :y RETURNING id
1
+ INSERT INTO t (x) VALUES (:x)
2
+ ON CONFLICT (x) DO UPDATE SET y = :y
3
+ RETURNING id
@@ -1 +1,2 @@
1
- INSERT INTO CallExpression (parent_id) VALUES (:parent_id) RETURNING id AS call_id
1
+ INSERT INTO CallExpression (parent_id) VALUES (:parent_id)
2
+ RETURNING id AS call_id
@@ -1 +1,2 @@
1
- INSERT INTO CallExpression (parent_id) VALUES (:parent_id) RETURNING id
1
+ INSERT INTO CallExpression (parent_id) VALUES (:parent_id)
2
+ RETURNING id
@@ -1 +1,2 @@
1
- INSERT INTO t (x) VALUES (:x) RETURNING id, created_at
1
+ INSERT INTO t (x) VALUES (:x)
2
+ RETURNING id, created_at
@@ -3,5 +3,5 @@
3
3
  CallExpression,
4
4
  parent_id,
5
5
  values(':parent_id'),
6
- ), returning(as(id, 'call_id'))),
6
+ ), returning(id as 'call_id')),
7
7
  ];
@@ -1,3 +1,19 @@
1
+ import {types} from '@putout/babel';
2
+
3
+ const {isTSAsExpression} = types;
4
+
5
+ const printAsExpression = (path, {write, traverse}) => {
6
+ traverse(path.get('expression'));
7
+ write(` AS ${path.node.typeAnnotation.literal.value}`);
8
+ };
9
+
10
+ const printItem = (path, ctx) => {
11
+ if (isTSAsExpression(path.node))
12
+ return printAsExpression(path, ctx);
13
+
14
+ ctx.traverse(path);
15
+ };
16
+
1
17
  export const returning = (path, {write, traverse}) => {
2
18
  write('RETURNING ');
3
19
  const args = path.get('arguments');
@@ -6,6 +22,9 @@ export const returning = (path, {write, traverse}) => {
6
22
  if (i > 0)
7
23
  write(', ');
8
24
 
9
- traverse(arg);
25
+ printItem(arg, {
26
+ write,
27
+ traverse,
28
+ });
10
29
  }
11
30
  };
@@ -1,3 +1,3 @@
1
1
  -- @select
2
2
  SELECT *
3
- FROM users;
3
+ FROM users
@@ -1,7 +1,8 @@
1
1
  -- @fix
2
2
  UPDATE Identifier
3
3
  SET name = 'isNaN'
4
- WHERE id = :nan_id;
4
+ WHERE id = :nan_id
5
+
5
6
  UPDATE BinaryExpression
6
7
  SET operator = '==='
7
- WHERE id = :id;
8
+ WHERE id = :id
@@ -8,12 +8,13 @@ export const section = (path, {write, traverse}) => {
8
8
 
9
9
  for (const [i, element] of elements.entries()) {
10
10
  traverse(element);
11
- write(i < lastIndex ? ';\n' : ';');
11
+
12
+ if (i < lastIndex)
13
+ write('\n\n');
12
14
  }
13
15
 
14
16
  return;
15
17
  }
16
18
 
17
19
  traverse(stmt);
18
- write(';');
19
20
  };
@@ -1 +1 @@
1
- SELECT 'hello';
1
+ SELECT 'hello'
@@ -1,30 +1,40 @@
1
1
  import {types} from '@putout/babel';
2
2
 
3
- const {isStringLiteral} = types;
3
+ const {isTSAsExpression} = types;
4
+
5
+ const printAsExpression = (path, {write, traverse}) => {
6
+ traverse(path.get('expression'));
7
+ write(` AS ${path.node.typeAnnotation.literal.value}`);
8
+ };
9
+
10
+ const printItem = (path, ctx) => {
11
+ if (isTSAsExpression(path.node))
12
+ return printAsExpression(path, ctx);
13
+
14
+ ctx.traverse(path);
15
+ };
4
16
 
5
17
  export const select = (path, {write, traverse}) => {
6
18
  const args = path.get('arguments');
7
- const fromIdx = args.findIndex((a) => a.node.callee?.name === 'from');
8
- const cols = args.slice(0, fromIdx);
9
- const rest = args.slice(fromIdx);
19
+ const lastArg = args.at(-1);
20
+ const hasFrom = lastArg?.node?.callee?.name === 'from';
21
+ const fromArg = hasFrom ? lastArg : null;
22
+ const cols = hasFrom ? args.slice(0, -1) : args;
10
23
 
11
24
  write('SELECT ');
25
+
12
26
  for (let i = 0; i < cols.length; i++) {
13
27
  if (i > 0)
14
28
  write(', ');
15
29
 
16
- traverse(cols[i]);
17
- }
18
-
19
- if (rest.length === 1 && isStringLiteral(rest[0])) {
20
- traverse(rest[0]);
21
- write(';');
22
-
23
- return;
30
+ printItem(cols[i], {
31
+ write,
32
+ traverse,
33
+ });
24
34
  }
25
35
 
26
- for (const arg of rest) {
36
+ if (fromArg) {
27
37
  write('\n');
28
- traverse(arg);
38
+ traverse(fromArg);
29
39
  }
30
40
  };
@@ -1,3 +1 @@
1
- SELECT *
2
- FROM users
3
- WHERE id = :id
1
+ SELECT *, FROM users, WHERE id = :id
@@ -1,3 +1 @@
1
- SELECT *
2
- FROM t
3
- WHERE x >= 1
1
+ SELECT *, FROM t, WHERE x >= 1
@@ -1,3 +1 @@
1
- SELECT *
2
- FROM t
3
- WHERE x IN (1, 2, 3)
1
+ SELECT *, FROM t, WHERE x IN (1, 2, 3)
@@ -1,3 +1 @@
1
- SELECT *
2
- FROM t
3
- WHERE x IS NOT NULL
1
+ SELECT *, FROM t, WHERE x IS NOT NULL
@@ -1,3 +1 @@
1
- SELECT *
2
- FROM t
3
- WHERE x IS NULL
1
+ SELECT *, FROM t, WHERE x IS NULL
@@ -1,3 +1 @@
1
- SELECT *
2
- FROM t
3
- WHERE x LIKE :pattern
1
+ SELECT *, FROM t, WHERE x LIKE :pattern
@@ -1,3 +1 @@
1
- SELECT *
2
- FROM t
3
- WHERE x != :y
1
+ SELECT *, FROM t, WHERE x != :y
@@ -1,10 +1,12 @@
1
1
  WITH
2
2
  call AS (
3
- INSERT INTO CallExpression (file, parent_id) VALUES (:file, :parent_id) RETURNING id
3
+ INSERT INTO CallExpression (file, parent_id) VALUES (:file, :parent_id)
4
+ RETURNING id
4
5
  ),
5
6
  member AS (
6
7
  INSERT INTO MemberExpression (file, parent_id) SELECT :file, id
7
- FROM call RETURNING id
8
+ FROM call
9
+ RETURNING id
8
10
  )
9
11
  INSERT INTO Identifier (file, name, parent_id) SELECT :file, 'isNaN', id
10
12
  FROM member
@@ -1,10 +1,12 @@
1
1
  WITH
2
2
  call AS (
3
- INSERT INTO CallExpression (parent_id) VALUES (:parent_id) RETURNING id
3
+ INSERT INTO CallExpression (parent_id) VALUES (:parent_id)
4
+ RETURNING id
4
5
  ),
5
6
  member AS (
6
7
  INSERT INTO MemberExpression (parent_id) SELECT id
7
- FROM call RETURNING id
8
+ FROM call
9
+ RETURNING id
8
10
  )
9
11
  INSERT INTO Identifier (name, parent_id) SELECT 'x', id
10
12
  FROM member
@@ -1,3 +1 @@
1
- SELECT *
2
- FROM t
3
- WHERE x % 2
1
+ SELECT *, FROM t, WHERE x % 2
@@ -4,7 +4,6 @@ import {CallExpression} from './call-expression/call-expression.js';
4
4
  import {ArrayExpression} from './array-expression.js';
5
5
  import {BinaryExpression} from './binary-expression.js';
6
6
  import {LogicalExpression} from './logical-expression.js';
7
- import {AssignmentExpression} from './assignment-expression.js';
8
7
  import {MemberExpression} from './member-expression.js';
9
8
 
10
9
  export const visitors = {
@@ -14,6 +13,5 @@ export const visitors = {
14
13
  ExpressionStatement,
15
14
  BinaryExpression,
16
15
  LogicalExpression,
17
- AssignmentExpression,
18
16
  MemberExpression,
19
17
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "happy-sql",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "type": "module",
5
5
  "description": "sql to js ast parser and printer",
6
6
  "exports": {
@@ -1,5 +0,0 @@
1
- export const AssignmentExpression = (path, {write, traverse}) => {
2
- traverse(path.get('right'));
3
- write(' AS ');
4
- traverse(path.get('left'));
5
- };
@@ -1,15 +0,0 @@
1
- export const as = (path, {write, traverse}) => {
2
- const [column, alias] = path.get('arguments');
3
-
4
- traverse(column);
5
-
6
- if (alias.node.type === 'StringLiteral') {
7
- write(' AS ');
8
- write(alias.node.value);
9
-
10
- return;
11
- }
12
-
13
- write(' ');
14
- traverse(alias);
15
- };