squirreling 0.9.0 → 0.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squirreling",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Squirreling Async SQL Engine",
5
5
  "author": "Hyperparam",
6
6
  "homepage": "https://hyperparam.app",
@@ -40,7 +40,7 @@
40
40
  "@types/node": "25.2.3",
41
41
  "@vitest/coverage-v8": "4.0.18",
42
42
  "eslint": "9.39.2",
43
- "eslint-plugin-jsdoc": "62.5.5",
43
+ "eslint-plugin-jsdoc": "62.6.0",
44
44
  "typescript": "5.9.3",
45
45
  "vitest": "4.0.18"
46
46
  }
@@ -1,6 +1,7 @@
1
+ import { derivedAlias } from '../expression/alias.js'
1
2
  import { evaluateExpr } from '../expression/evaluate.js'
2
- import { defaultDerivedAlias, stringify } from './utils.js'
3
3
  import { executePlan } from './execute.js'
4
+ import { stringify } from './utils.js'
4
5
 
5
6
  /**
6
7
  * @import { AsyncCells, AsyncRow, ExecuteContext, SelectColumn } from '../types.js'
@@ -31,7 +32,7 @@ function projectAggregateColumns(selectColumns, group, context) {
31
32
  }
32
33
  }
33
34
  } else if (col.kind === 'derived') {
34
- const alias = col.alias ?? defaultDerivedAlias(col.expr)
35
+ const alias = col.alias ?? derivedAlias(col.expr)
35
36
  columns.push(alias)
36
37
  cells[alias] = () => evaluateExpr({
37
38
  node: col.expr,
@@ -1,12 +1,13 @@
1
1
  import { memorySource } from '../backend/dataSource.js'
2
2
  import { tableNotFoundError } from '../executionErrors.js'
3
+ import { derivedAlias } from '../expression/alias.js'
3
4
  import { evaluateExpr } from '../expression/evaluate.js'
4
5
  import { parseSql } from '../parse/parse.js'
5
6
  import { planSql } from '../plan/plan.js'
6
7
  import { executeHashAggregate, executeScalarAggregate } from './aggregates.js'
7
8
  import { executeHashJoin, executeNestedLoopJoin, executePositionalJoin } from './join.js'
8
9
  import { executeSort } from './sort.js'
9
- import { defaultDerivedAlias, stableRowKey } from './utils.js'
10
+ import { stableRowKey } from './utils.js'
10
11
 
11
12
  /**
12
13
  * @import { AsyncCells, AsyncDataSource, AsyncRow, ExecuteContext, ExecuteSqlOptions, ExprNode, SelectStatement } from '../types.js'
@@ -207,7 +208,7 @@ async function* executeProject(plan, context) {
207
208
  cells[key] = row.cells[key]
208
209
  }
209
210
  } else if (col.kind === 'derived') {
210
- const alias = col.alias ?? defaultDerivedAlias(col.expr)
211
+ const alias = col.alias ?? derivedAlias(col.expr)
211
212
  columns.push(alias)
212
213
  cells[alias] = () => evaluateExpr({
213
214
  node: col.expr,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @import { AsyncCells, AsyncRow, ExprNode, OrderByItem, SqlPrimitive } from '../types.js'
2
+ * @import { AsyncCells, AsyncRow, OrderByItem, SqlPrimitive } from '../types.js'
3
3
  */
4
4
 
5
5
  /**
@@ -57,45 +57,6 @@ export async function collect(asyncRows) {
57
57
  return results
58
58
  }
59
59
 
60
- /**
61
- * Generates a default alias for a derived column expression
62
- *
63
- * @param {ExprNode} expr - the expression node
64
- * @returns {string} the generated alias
65
- */
66
- export function defaultDerivedAlias(expr) {
67
- if (expr.type === 'identifier') {
68
- // For qualified names like 'users.name', use just the column part as alias
69
- if (expr.name.includes('.')) {
70
- return expr.name.split('.').pop()
71
- }
72
- return expr.name
73
- }
74
- if (expr.type === 'literal') {
75
- return String(expr.value)
76
- }
77
- if (expr.type === 'cast') {
78
- return defaultDerivedAlias(expr.expr) + '_as_' + expr.toType
79
- }
80
- if (expr.type === 'unary') {
81
- return expr.op + '_' + defaultDerivedAlias(expr.argument)
82
- }
83
- if (expr.type === 'binary') {
84
- return defaultDerivedAlias(expr.left) + '_' + expr.op + '_' + defaultDerivedAlias(expr.right)
85
- }
86
- if (expr.type === 'function') {
87
- // Handle aggregate functions with star (COUNT(*) -> count_all)
88
- if (expr.args.length === 1 && expr.args[0].type === 'identifier' && expr.args[0].name === '*') {
89
- return expr.name.toLowerCase() + '_all'
90
- }
91
- return expr.name.toLowerCase() + '_' + expr.args.map(defaultDerivedAlias).join('_')
92
- }
93
- if (expr.type === 'interval') {
94
- return `interval_${expr.value}_${expr.unit.toLowerCase()}`
95
- }
96
- return 'expr'
97
- }
98
-
99
60
  /**
100
61
  * @param {SqlPrimitive} value
101
62
  * @returns {string}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @import { ExprNode } from '../types.js'
3
+ */
4
+
5
+ /**
6
+ * Generates a default alias for a derived column expression
7
+ *
8
+ * @param {ExprNode} expr - the expression node
9
+ * @returns {string} the generated alias
10
+ */
11
+ export function derivedAlias(expr) {
12
+ if (expr.type === 'identifier') {
13
+ // For qualified names like 'users.name', use just the column part as alias
14
+ if (expr.name.includes('.')) {
15
+ return expr.name.split('.').pop()
16
+ }
17
+ return expr.name
18
+ }
19
+ if (expr.type === 'literal') {
20
+ return String(expr.value)
21
+ }
22
+ if (expr.type === 'cast') {
23
+ return derivedAlias(expr.expr) + '_as_' + expr.toType
24
+ }
25
+ if (expr.type === 'unary') {
26
+ return expr.op + '_' + derivedAlias(expr.argument)
27
+ }
28
+ if (expr.type === 'binary') {
29
+ return derivedAlias(expr.left) + '_' + expr.op + '_' + derivedAlias(expr.right)
30
+ }
31
+ if (expr.type === 'function') {
32
+ // Handle aggregate functions with star (COUNT(*) -> count_all)
33
+ if (expr.args.length === 1 && expr.args[0].type === 'identifier' && expr.args[0].name === '*') {
34
+ return expr.name.toLowerCase() + '_all'
35
+ }
36
+ return expr.name.toLowerCase() + '_' + expr.args.map(derivedAlias).join('_')
37
+ }
38
+ if (expr.type === 'interval') {
39
+ return `interval_${expr.value}_${expr.unit.toLowerCase()}`
40
+ }
41
+ return 'expr'
42
+ }
@@ -1,9 +1,10 @@
1
1
  import { executeSelect } from '../execute/execute.js'
2
- import { defaultDerivedAlias, stringify } from '../execute/utils.js'
2
+ import { stringify } from '../execute/utils.js'
3
3
  import { columnNotFoundError, invalidContextError } from '../executionErrors.js'
4
4
  import { unknownFunctionError } from '../parseErrors.js'
5
5
  import { isAggregateFunc, isMathFunc, isRegexpFunc, isStringFunc } from '../validation.js'
6
6
  import { aggregateError, argValueError, castError } from '../validationErrors.js'
7
+ import { derivedAlias } from './alias.js'
7
8
  import { applyBinaryOp } from './binary.js'
8
9
  import { applyIntervalToDate } from './date.js'
9
10
  import { evaluateMathFunc } from './math.js'
@@ -104,9 +105,9 @@ export async function evaluateExpr({ node, row, rowIndex, rows, context }) {
104
105
  if (!rows) {
105
106
  // Aggregate function used outside of aggregate context
106
107
  // This is only allowed if same aggregate was in the SELECT list
107
- const derivedAlias = defaultDerivedAlias(node)
108
- if (row.columns.includes(derivedAlias)) {
109
- return row.cells[derivedAlias]()
108
+ const alias = derivedAlias(node)
109
+ if (row.columns.includes(alias)) {
110
+ return row.cells[alias]()
110
111
  } else {
111
112
  throw aggregateError({
112
113
  funcName,
package/src/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AsyncDataSource, AsyncRow, ExecuteContext, ExecuteSqlOptions, ParseSqlOptions, PlanSqlOptions, QueryPlan, SelectStatement, SqlPrimitive, Token } from './types.js'
1
+ import type { AsyncDataSource, AsyncRow, ExecuteContext, ExecuteSqlOptions, ExprNode, ParseSqlOptions, PlanSqlOptions, QueryPlan, SelectStatement, SqlPrimitive, Token } from './types.js'
2
2
  export type {
3
3
  AsyncCells,
4
4
  AsyncDataSource,
@@ -76,3 +76,12 @@ export function tokenizeSql(sql: string): Token[]
76
76
  export function collect<T>(asyncGen: AsyncGenerator<AsyncRow>): Promise<Record<string, SqlPrimitive>[]>
77
77
 
78
78
  export function cachedDataSource(source: AsyncDataSource): AsyncDataSource
79
+
80
+ /**
81
+ * Generates a default alias for a derived column expression.
82
+ * Useful for generating column names pre-execution.
83
+ *
84
+ * @param expr - the expression node
85
+ * @returns the generated alias
86
+ */
87
+ export function derivedAlias(expr: ExprNode): string
package/src/index.js CHANGED
@@ -4,3 +4,4 @@ export { planSql } from './plan/plan.js'
4
4
  export { tokenizeSql } from './parse/tokenize.js'
5
5
  export { collect } from './execute/utils.js'
6
6
  export { cachedDataSource } from './backend/dataSource.js'
7
+ export { derivedAlias } from './expression/alias.js'
package/src/types.d.ts CHANGED
@@ -228,12 +228,6 @@ export type ExprNode =
228
228
  | SubqueryNode
229
229
  | IntervalNode
230
230
 
231
- export interface StarColumn {
232
- kind: 'star'
233
- table?: string
234
- alias?: string
235
- }
236
-
237
231
  export type AggregateFunc = 'COUNT' | 'SUM' | 'AVG' | 'MIN' | 'MAX' | 'JSON_ARRAYAGG' | 'STDDEV_SAMP' | 'STDDEV_POP'
238
232
 
239
233
  export type MathFunc =
@@ -276,6 +270,11 @@ export type StringFunc =
276
270
  | 'RIGHT'
277
271
  | 'INSTR'
278
272
 
273
+ export interface StarColumn {
274
+ kind: 'star'
275
+ table?: string
276
+ }
277
+
279
278
  export interface DerivedColumn {
280
279
  kind: 'derived'
281
280
  expr: ExprNode