happy-sql 1.0.1 → 1.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.
package/ChangeLog CHANGED
@@ -1,3 +1,13 @@
1
+ 2026.07.27, v1.1.1
2
+
3
+ feature:
4
+ - e88833c happy-sql: count: 1
5
+
6
+ 2026.07.27, v1.1.0
7
+
8
+ feature:
9
+ - f6446c3 happy-sql: COUNT
10
+
1
11
  2026.07.27, v1.0.1
2
12
 
3
13
  feature:
package/README.md CHANGED
@@ -17,6 +17,16 @@ SQL to JS AST parser and printer.
17
17
  npm i happy-sql --save
18
18
  ```
19
19
 
20
+ ## API
21
+
22
+ ```js
23
+ const source = `select(count('*'), from(users))`;
24
+
25
+ convertJsToSql(source);
26
+ // returns
27
+ 'SELECT COUNT(*)\nFROM users\n';
28
+ ```
29
+
20
30
  ## License
21
31
 
22
32
  MIT
@@ -40,14 +40,12 @@ export const parseSqlNode = (source) => {
40
40
 
41
41
  const elements = [];
42
42
 
43
- for (let i = 0; i < cst.statements.length; i++) {
44
- const stmt = cst.statements[i];
45
-
46
- if (stmt.type === 'empty')
43
+ for (const [i, statement] of cst.statements.entries()) {
44
+ if (statement.type === 'empty')
47
45
  continue;
48
46
 
49
- const stmtNode = convertClause(stmt);
50
- const leading = !i ? cst.leading : stmt.leading;
47
+ const stmtNode = convertClause(statement);
48
+ const leading = i ? statement.leading : cst.leading;
51
49
 
52
50
  elements.push(wrapSection(stmtNode, getSectionName(leading)));
53
51
  }
@@ -0,0 +1,34 @@
1
+ import {types} from '@putout/babel';
2
+
3
+ const {
4
+ stringLiteral,
5
+ callExpression,
6
+ identifier,
7
+ numericLiteral,
8
+ } = types;
9
+
10
+ const isAllColumns = ({type}) => type === 'all_columns';
11
+ const isNumericLiteral = ({type}) => type === 'number_literal';
12
+
13
+ export const isCount = (column) => {
14
+ return column.type === 'func_call' && /count/i.test(column.name.name);
15
+ };
16
+
17
+ export const convertCount = (column) => {
18
+ const {items} = column.args.expr.args;
19
+ const args = [];
20
+
21
+ for (const item of items) {
22
+ if (isAllColumns(item)) {
23
+ args.push(stringLiteral('*'));
24
+ continue;
25
+ }
26
+
27
+ if (isNumericLiteral(item)) {
28
+ const {value} = item;
29
+ args.push(numericLiteral(value));
30
+ }
31
+ }
32
+
33
+ return callExpression(identifier('count'), args);
34
+ };
@@ -0,0 +1,3 @@
1
+ [
2
+ select(count('*'), from(users)),
3
+ ];
@@ -0,0 +1,3 @@
1
+ [
2
+ select(count(1), from(users)),
3
+ ];
@@ -0,0 +1 @@
1
+ SELECT COUNT(1) FROM users
@@ -0,0 +1 @@
1
+ SELECT COUNT(*) FROM users
@@ -3,6 +3,7 @@ import {convertOperand} from '#parser/clause/operand';
3
3
  import {convertFrom} from '#parser/clause/from';
4
4
  import {convertWhere} from '#parser/clause/where';
5
5
  import {findClause} from '#parser/clause/find';
6
+ import {convertCount, isCount} from '#parser/clause/count';
6
7
 
7
8
  const {
8
9
  identifier,
@@ -11,11 +12,14 @@ const {
11
12
  callExpression,
12
13
  } = types;
13
14
 
14
- const convertColumn = (col) => {
15
- if (col.type === 'alias')
16
- return assignmentExpression('=', identifier(col.alias.name), convertOperand(col.expr));
15
+ const convertColumn = (column) => {
16
+ if (isCount(column))
17
+ return convertCount(column);
17
18
 
18
- return identifier(col.name);
19
+ if (column.type === 'alias')
20
+ return assignmentExpression('=', identifier(column.alias.name), convertOperand(column.expr));
21
+
22
+ return identifier(column.name);
19
23
  };
20
24
 
21
25
  const convertColumns = (columns) => {
@@ -2,9 +2,10 @@ import {clauses} from './clauses/clauses.js';
2
2
 
3
3
  export const CallExpression = (path, printer) => {
4
4
  const {name} = path.node.callee;
5
+ const visit = clauses[name];
5
6
 
6
- if (!clauses[name])
7
+ if (!visit)
7
8
  throw Error(`${name} not supported yet`);
8
9
 
9
- clauses[name](path, printer);
10
+ visit(path, printer);
10
11
  };
@@ -9,10 +9,12 @@ import {update} from './update/update.js';
9
9
  import {set} from './set/set.js';
10
10
  import {del} from './delete/delete.js';
11
11
  import {section} from './section/section.js';
12
+ import {count} from './count/count.js';
12
13
 
13
14
  export const clauses = {
14
- select,
15
+ count,
15
16
  from,
17
+ select,
16
18
  where,
17
19
  insert,
18
20
  into,
@@ -0,0 +1,7 @@
1
+ export const count = (path, {write, traverse}) => {
2
+ const [first] = path.get('arguments');
3
+ write('COUNT');
4
+ write('(');
5
+ traverse(first);
6
+ write(')');
7
+ };
@@ -0,0 +1,2 @@
1
+ SELECT COUNT(1)
2
+ FROM users
@@ -0,0 +1,2 @@
1
+ SELECT COUNT(*)
2
+ FROM users
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "happy-sql",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "description": "sql to js ast parser and printer",
6
6
  "exports": {
@@ -18,6 +18,7 @@
18
18
  "#parser/test": "./test/create-parser-test.js",
19
19
  "#parser/clause": "./lib/parser/visitors/clause/index.js",
20
20
  "#parser/clause/select": "./lib/parser/visitors/clause/select/select.js",
21
+ "#parser/clause/count": "./lib/parser/visitors/clause/count/count.js",
21
22
  "#parser/clause/from": "./lib/parser/visitors/clause/from/from.js",
22
23
  "#parser/clause/where": "./lib/parser/visitors/clause/where/where.js",
23
24
  "#parser/clause/insert": "./lib/parser/visitors/clause/insert/insert.js",
@@ -79,6 +80,7 @@
79
80
  "@putout/babel": "^5.7.3",
80
81
  "@putout/operator-json": "^3.4.0",
81
82
  "@putout/printer": "^18.17.0",
83
+ "just-camel-case": "^6.2.0",
82
84
  "redstd": "^1.0.2",
83
85
  "sql-parser-cst": "^0.42.1"
84
86
  }