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 +2 -2
- package/src/execute/aggregates.js +3 -2
- package/src/execute/execute.js +3 -2
- package/src/execute/utils.js +1 -40
- package/src/expression/alias.js +42 -0
- package/src/expression/evaluate.js +5 -4
- package/src/index.d.ts +10 -1
- package/src/index.js +1 -0
- package/src/types.d.ts +5 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "squirreling",
|
|
3
|
-
"version": "0.9.
|
|
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.
|
|
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 ??
|
|
35
|
+
const alias = col.alias ?? derivedAlias(col.expr)
|
|
35
36
|
columns.push(alias)
|
|
36
37
|
cells[alias] = () => evaluateExpr({
|
|
37
38
|
node: col.expr,
|
package/src/execute/execute.js
CHANGED
|
@@ -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 {
|
|
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 ??
|
|
211
|
+
const alias = col.alias ?? derivedAlias(col.expr)
|
|
211
212
|
columns.push(alias)
|
|
212
213
|
cells[alias] = () => evaluateExpr({
|
|
213
214
|
node: col.expr,
|
package/src/execute/utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @import { AsyncCells, AsyncRow,
|
|
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 {
|
|
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
|
|
108
|
-
if (row.columns.includes(
|
|
109
|
-
return row.cells[
|
|
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
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
|