happy-sql 2.0.0 → 2.0.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.
Files changed (41) 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 +3 -4
  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/select.js +3 -2
  15. package/lib/printer/visitors/call-expression/clauses/clauses.js +0 -2
  16. package/lib/printer/visitors/call-expression/clauses/from/from.js +24 -2
  17. package/lib/printer/visitors/call-expression/clauses/insert/fixture/insert-fix.sql +1 -1
  18. package/lib/printer/visitors/call-expression/clauses/into/fixture/single-column-fix.sql +1 -1
  19. package/lib/printer/visitors/call-expression/clauses/join/fixture/join-fix.sql +2 -2
  20. package/lib/printer/visitors/call-expression/clauses/join/fixture/join-multi-fix.sql +3 -3
  21. package/lib/printer/visitors/call-expression/clauses/join/fixture/join-multi.js +1 -1
  22. package/lib/printer/visitors/call-expression/clauses/join/fixture/join.js +1 -1
  23. package/lib/printer/visitors/call-expression/clauses/join/join.js +20 -1
  24. package/lib/printer/visitors/call-expression/clauses/on-conflict/fixture/on-conflict-fix.sql +1 -1
  25. package/lib/printer/visitors/call-expression/clauses/on-conflict/fixture/on-conflict-multi-fix.sql +1 -1
  26. package/lib/printer/visitors/call-expression/clauses/returning/fixture/returning-conflict-fix.sql +1 -1
  27. package/lib/printer/visitors/call-expression/clauses/returning/fixture/returning-fix.sql +1 -1
  28. package/lib/printer/visitors/call-expression/clauses/returning/fixture/returning-id-fix.sql +1 -1
  29. package/lib/printer/visitors/call-expression/clauses/returning/fixture/returning-multi-fix.sql +1 -1
  30. package/lib/printer/visitors/call-expression/clauses/returning/fixture/returning.js +1 -1
  31. package/lib/printer/visitors/call-expression/clauses/returning/returning.js +20 -1
  32. package/lib/printer/visitors/call-expression/clauses/select/select.js +20 -2
  33. package/lib/printer/visitors/call-expression/clauses/values/fixture/values-fix.sql +1 -1
  34. package/lib/printer/visitors/call-expression/clauses/values/fixture/values-quoted-fix.sql +1 -1
  35. package/lib/printer/visitors/call-expression/clauses/values/values.js +1 -10
  36. package/lib/printer/visitors/call-expression/clauses/with-named/fixture/with-named-insert-fix.sql +1 -1
  37. package/lib/printer/visitors/call-expression/clauses/with-named/fixture/withNamed-fix.sql +1 -1
  38. package/lib/printer/visitors/index.js +0 -2
  39. package/package.json +1 -1
  40. package/lib/printer/visitors/assignment-expression.js +0 -5
  41. 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.2
2
+
3
+ fix:
4
+ - e7b456f happy-sql: drop as(), use TSAsExpression aliases; round-trip specs; 100% coverage
5
+
6
+ 2026.08.19, v2.0.1
7
+
8
+ fix:
9
+ - c1629b0 happy-sql: keep :x unquoted
10
+
1
11
  2026.08.19, v2.0.0
2
12
 
3
13
  feature:
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
  };
@@ -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
  ];
@@ -8,7 +8,8 @@ import {convertCount, isCount} from '#parser/clause/count';
8
8
  const {
9
9
  identifier,
10
10
  stringLiteral,
11
- assignmentExpression,
11
+ tsAsExpression,
12
+ tsLiteralType,
12
13
  callExpression,
13
14
  memberExpression,
14
15
  } = types;
@@ -21,7 +22,7 @@ const convertColumn = (column) => {
21
22
  return convertFuncCall(column);
22
23
 
23
24
  if (column.type === 'alias')
24
- return assignmentExpression('=', identifier(column.alias.name), convertOperand(column.expr));
25
+ return tsAsExpression(convertOperand(column.expr), tsLiteralType(stringLiteral(column.alias.name)));
25
26
 
26
27
  if (column.type === 'string_literal')
27
28
  return stringLiteral(column.value);
@@ -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,
@@ -1,9 +1,31 @@
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');
3
19
 
4
20
  write('FROM ');
5
- traverse(args[0]);
21
+ printArg(args[0], {
22
+ write,
23
+ traverse,
24
+ });
6
25
 
7
26
  for (let i = 1; i < args.length; i++)
8
- traverse(args[i]);
27
+ printArg(args[i], {
28
+ write,
29
+ traverse,
30
+ });
9
31
  };
@@ -1 +1 @@
1
- INSERT INTO t (x) VALUES (':x')
1
+ INSERT INTO t (x) VALUES (:x)
@@ -1 +1 @@
1
- INSERT INTO t (x) VALUES (':x')
1
+ INSERT INTO t (x) VALUES (:x)
@@ -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 @@
1
- INSERT INTO t (x) VALUES (':x') ON CONFLICT (x) DO UPDATE SET x = :x
1
+ INSERT INTO t (x) VALUES (:x) ON CONFLICT (x) DO UPDATE SET x = :x
@@ -1 +1 @@
1
- INSERT INTO t (x) VALUES (':x') ON CONFLICT (x, y) DO UPDATE SET x = :x
1
+ INSERT INTO t (x) VALUES (:x) ON CONFLICT (x, y) DO UPDATE SET x = :x
@@ -1 +1 @@
1
- INSERT INTO t (x) VALUES (':x') ON CONFLICT (x) DO UPDATE SET y = :y RETURNING id
1
+ INSERT INTO t (x) VALUES (:x) ON CONFLICT (x) DO UPDATE SET y = :y RETURNING id
@@ -1 +1 @@
1
- INSERT INTO CallExpression (parent_id) VALUES (':parent_id') RETURNING id AS call_id
1
+ INSERT INTO CallExpression (parent_id) VALUES (:parent_id) RETURNING id AS call_id
@@ -1 +1 @@
1
- INSERT INTO CallExpression (parent_id) VALUES (':parent_id') RETURNING id
1
+ INSERT INTO CallExpression (parent_id) VALUES (:parent_id) RETURNING id
@@ -1 +1 @@
1
- INSERT INTO t (x) VALUES (':x') RETURNING id, created_at
1
+ INSERT INTO t (x) VALUES (:x) 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,6 +1,21 @@
1
1
  import {types} from '@putout/babel';
2
2
 
3
- const {isStringLiteral} = types;
3
+ const {
4
+ isTSAsExpression,
5
+ isStringLiteral,
6
+ } = types;
7
+
8
+ const printAsExpression = (path, {write, traverse}) => {
9
+ traverse(path.get('expression'));
10
+ write(` AS ${path.node.typeAnnotation.literal.value}`);
11
+ };
12
+
13
+ const printItem = (path, ctx) => {
14
+ if (isTSAsExpression(path.node))
15
+ return printAsExpression(path, ctx);
16
+
17
+ ctx.traverse(path);
18
+ };
4
19
 
5
20
  export const select = (path, {write, traverse}) => {
6
21
  const args = path.get('arguments');
@@ -13,7 +28,10 @@ export const select = (path, {write, traverse}) => {
13
28
  if (i > 0)
14
29
  write(', ');
15
30
 
16
- traverse(cols[i]);
31
+ printItem(cols[i], {
32
+ write,
33
+ traverse,
34
+ });
17
35
  }
18
36
 
19
37
  if (rest.length === 1 && isStringLiteral(rest[0])) {
@@ -1 +1 @@
1
- VALUES (':x')
1
+ VALUES (:x)
@@ -1 +1 @@
1
- VALUES (':file', ':parent_id')
1
+ VALUES (:file, :parent_id)
@@ -1,7 +1,3 @@
1
- import {types} from '@putout/babel';
2
-
3
- const {isStringLiteral} = types;
4
-
5
1
  export const values = (path, {write, traverse}) => {
6
2
  const args = path.get('arguments');
7
3
  write('VALUES (');
@@ -9,12 +5,7 @@ export const values = (path, {write, traverse}) => {
9
5
  if (i > 0)
10
6
  write(', ');
11
7
 
12
- const arg = args[i];
13
-
14
- if (isStringLiteral(arg.node))
15
- write(`'${arg.node.value}'`);
16
- else
17
- traverse(arg);
8
+ traverse(args[i]);
18
9
  }
19
10
 
20
11
  write(')');
@@ -1,6 +1,6 @@
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) RETURNING id
4
4
  ),
5
5
  member AS (
6
6
  INSERT INTO MemberExpression (file, parent_id) SELECT :file, id
@@ -1,6 +1,6 @@
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) RETURNING id
4
4
  ),
5
5
  member AS (
6
6
  INSERT INTO MemberExpression (parent_id) SELECT id
@@ -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.0",
3
+ "version": "2.0.2",
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
- };