squirreling 0.1.0 → 0.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/README.md CHANGED
@@ -1,7 +1,11 @@
1
1
  # Squirreling SQL Engine
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/squirreling)](https://www.npmjs.com/package/squirreling)
4
+ [![downloads](https://img.shields.io/npm/dt/squirreling)](https://www.npmjs.com/package/squirreling)
5
+ [![minzipped](https://img.shields.io/bundlephobia/minzip/squirreling)](https://www.npmjs.com/package/squirreling)
6
+ [![workflow status](https://github.com/hyparam/squirreling/actions/workflows/ci.yml/badge.svg)](https://github.com/hyparam/squirreling/actions)
3
7
  [![mit license](https://img.shields.io/badge/License-MIT-orange.svg)](https://opensource.org/licenses/MIT)
4
-
8
+ [![dependencies](https://img.shields.io/badge/Dependencies-0-blueviolet)](https://www.npmjs.com/package/squirreling?activeTab=dependencies)
5
9
  Squirreling is a lightweight SQL engine for JavaScript applications, designed to provide efficient and easy-to-use database functionalities in the browser.
6
10
 
7
11
  ## Features
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "squirreling",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "author": "Hyperparam",
5
5
  "homepage": "https://hyperparam.app",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/hyparam/squirrel.git"
9
+ "url": "git+https://github.com/hyparam/squirreling.git"
10
10
  },
11
11
  "type": "module",
12
12
  "sideEffects": false,
@@ -1,8 +1,9 @@
1
+ import { evaluateExpr } from './expression.js'
1
2
 
2
3
  /**
3
4
  * Evaluates an aggregate function over a set of rows
4
5
  *
5
- * @import { AggregateColumn, Row } from '../types.js'
6
+ * @import { AggregateColumn, ExprNode, Row } from '../types.js'
6
7
  * @param {AggregateColumn} col - aggregate column definition
7
8
  * @param {Row[]} rows - rows to aggregate
8
9
  * @returns {number | null} aggregated result
@@ -12,10 +13,9 @@ export function evaluateAggregate(col, rows) {
12
13
 
13
14
  if (func === 'COUNT') {
14
15
  if (arg.kind === 'star') return rows.length
15
- const field = arg.column
16
16
  let count = 0
17
17
  for (let i = 0; i < rows.length; i += 1) {
18
- const v = rows[i][field]
18
+ const v = evaluateExpr(arg.expr, rows[i])
19
19
  if (v !== null && v !== undefined) {
20
20
  count += 1
21
21
  }
@@ -27,7 +27,6 @@ export function evaluateAggregate(col, rows) {
27
27
  if (arg.kind === 'star') {
28
28
  throw new Error(func + '(*) is not supported, use a column name')
29
29
  }
30
- const field = arg.column
31
30
  let sum = 0
32
31
  let count = 0
33
32
  /** @type {number | null} */
@@ -36,7 +35,7 @@ export function evaluateAggregate(col, rows) {
36
35
  let max = null
37
36
 
38
37
  for (let i = 0; i < rows.length; i += 1) {
39
- const raw = rows[i][field]
38
+ const raw = evaluateExpr(arg.expr, rows[i])
40
39
  if (raw == null) continue
41
40
  const num = Number(raw)
42
41
  if (!Number.isFinite(num)) continue
@@ -63,11 +62,39 @@ export function evaluateAggregate(col, rows) {
63
62
 
64
63
  /**
65
64
  * Generates a default alias name for an aggregate function
66
- * @param {AggregateColumn} col - The aggregate column definition
67
- * @returns {string} The generated alias (e.g., "count_all", "sum_amount")
65
+ * (e.g., "count_all", "sum_amount")
66
+ *
67
+ * @param {AggregateColumn} col
68
+ * @returns {string}
68
69
  */
69
70
  export function defaultAggregateAlias(col) {
70
71
  const base = col.func.toLowerCase()
71
72
  if (col.arg.kind === 'star') return base + '_all'
72
- return base + '_' + col.arg.column
73
+ return base + '_' + defaultAggregateAliasExpr(col.arg.expr)
74
+ }
75
+
76
+ /**
77
+ * @param {ExprNode} expr
78
+ * @returns {string}
79
+ */
80
+ export
81
+ function defaultAggregateAliasExpr(expr) {
82
+ if (expr.type === 'identifier') {
83
+ return expr.name
84
+ }
85
+ if (expr.type === 'literal') {
86
+ return String(expr.value)
87
+ }
88
+ if (expr.type === 'cast') {
89
+ return defaultAggregateAliasExpr(expr.expr) + '_as_' + expr.toType
90
+ }
91
+ if (expr.type === 'unary') {
92
+ return expr.op + '_' + defaultAggregateAliasExpr(expr.argument)
93
+ }
94
+ if (expr.type === 'binary') {
95
+ return defaultAggregateAliasExpr(expr.left) + '_' + expr.op + '_' + defaultAggregateAliasExpr(expr.right)
96
+ }
97
+ if (expr.type === 'function') {
98
+ return expr.name.toLowerCase() + '_' + expr.args.map(defaultAggregateAliasExpr).join('_')
99
+ }
73
100
  }
@@ -226,11 +226,24 @@ function parseAggregateItem(state, func) {
226
226
  if (cur.type === 'operator' && cur.value === '*') {
227
227
  consume(state)
228
228
  arg = { kind: 'star' }
229
+ } else if (cur.type === 'identifier' && cur.value === 'CAST') {
230
+ // Handle CAST inside aggregate: SUM(CAST(x AS type))
231
+ expectIdentifier(state) // consume CAST
232
+ expect(state, 'paren', '(')
233
+ const cursor = createExprCursor(state)
234
+ const expr = parseExpression(cursor)
235
+ expect(state, 'keyword', 'AS')
236
+ const typeTok = expectIdentifier(state)
237
+ expect(state, 'paren', ')')
238
+ arg = {
239
+ kind: 'expression',
240
+ expr: { type: 'cast', expr, toType: typeTok.value },
241
+ }
229
242
  } else {
230
243
  const colTok = expectIdentifier(state)
231
244
  arg = {
232
- kind: 'column',
233
- column: colTok.value,
245
+ kind: 'expression',
246
+ expr: { type: 'identifier', name: colTok.value },
234
247
  }
235
248
  }
236
249
 
package/src/types.d.ts CHANGED
@@ -102,12 +102,12 @@ export interface AggregateArgStar {
102
102
  kind: 'star'
103
103
  }
104
104
 
105
- export interface AggregateArgColumn {
106
- kind: 'column'
107
- column: string
105
+ export interface AggregateArgExpression {
106
+ kind: 'expression'
107
+ expr: ExprNode
108
108
  }
109
109
 
110
- export type AggregateArg = AggregateArgStar | AggregateArgColumn
110
+ export type AggregateArg = AggregateArgStar | AggregateArgExpression
111
111
 
112
112
  export interface AggregateColumn {
113
113
  kind: 'aggregate'