squirreling 0.16.3 → 0.16.4
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 +3 -3
- package/package.json +8 -6
- package/src/execute/execute.js +3 -1
- package/src/index.d.ts +3 -1
- package/src/parse/parse.js +34 -5
- package/src/types.d.ts +21 -18
package/README.md
CHANGED
|
@@ -95,10 +95,10 @@ Because Squirreling uses lazy cell evaluation, the `AI_SCORE` function only exec
|
|
|
95
95
|
|
|
96
96
|
### Custom Data Sources
|
|
97
97
|
|
|
98
|
-
Squirreling can work with any data source that implements the `AsyncDataSource` interface.
|
|
98
|
+
Squirreling can work with any data source that implements the `AsyncDataSource` interface. The simplest form is a `ScannableDataSource`: column names plus a row scan.
|
|
99
99
|
|
|
100
100
|
```typescript
|
|
101
|
-
interface
|
|
101
|
+
interface ScannableDataSource {
|
|
102
102
|
numRows?: number
|
|
103
103
|
columns: string[]
|
|
104
104
|
scan(options: ScanOptions): ScanResults
|
|
@@ -144,7 +144,7 @@ Squirreling mostly follows the SQL standard. The following features are supporte
|
|
|
144
144
|
- `WITH` clause for Common Table Expressions (CTEs)
|
|
145
145
|
- Subqueries in `SELECT`, `FROM`, `WHERE`, and correlated subqueries
|
|
146
146
|
- `JOIN` operations: `INNER JOIN`, `LEFT JOIN`, `RIGHT JOIN`, `FULL JOIN`, `CROSS JOIN`, `POSITIONAL JOIN`, `LATERAL VIEW [OUTER] EXPLODE(...)`, with `ON` or `USING (col, ...)` conditions
|
|
147
|
-
- `GROUP BY` and `HAVING` clauses
|
|
147
|
+
- `GROUP BY` and `HAVING` clauses, including `GROUP BY ALL`
|
|
148
148
|
- Set operations: `UNION`, `UNION ALL`, `INTERSECT`, `INTERSECT ALL`, `EXCEPT`, `EXCEPT ALL`
|
|
149
149
|
- Expressions: `CASE`, `CAST`, `TRY_CAST`, `BETWEEN`, `IN`, `LIKE`, `IS NULL`, `IS NOT NULL`, string concatenation `||`
|
|
150
150
|
- Subscript access: zero-based array indexing `col[0]`, struct field access `col['field']`, and chains like `col[0].field`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "squirreling",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.4",
|
|
4
4
|
"description": "Squirreling Async SQL Engine",
|
|
5
5
|
"author": "Hyperparam",
|
|
6
6
|
"homepage": "https://hyperparam.app",
|
|
@@ -39,11 +39,13 @@
|
|
|
39
39
|
"test": "vitest run"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@
|
|
43
|
-
"@
|
|
44
|
-
"
|
|
45
|
-
"eslint
|
|
42
|
+
"@eslint/js": "10.0.1",
|
|
43
|
+
"@types/node": "26.4.1",
|
|
44
|
+
"@vitest/coverage-v8": "5.0.0",
|
|
45
|
+
"eslint": "10.10.0",
|
|
46
|
+
"eslint-plugin-jsdoc": "64.3.6",
|
|
47
|
+
"globals": "17.12.0",
|
|
46
48
|
"typescript": "7.0.2",
|
|
47
|
-
"vitest": "
|
|
49
|
+
"vitest": "5.0.0"
|
|
48
50
|
}
|
|
49
51
|
}
|
package/src/execute/execute.js
CHANGED
|
@@ -588,7 +588,9 @@ function executeCount(plan, context) {
|
|
|
588
588
|
throw new Error(`Data source "${plan.table}" does not implement scan()`)
|
|
589
589
|
}
|
|
590
590
|
let count = 0
|
|
591
|
-
|
|
591
|
+
// Counting needs row presence, not payload columns. Sources may still
|
|
592
|
+
// read columns required for their own visibility or delete filters.
|
|
593
|
+
const { rows } = table.scan({ columns: [], signal })
|
|
592
594
|
// eslint-disable-next-line no-unused-vars
|
|
593
595
|
for await (const _ of rows()) {
|
|
594
596
|
signal?.throwIfAborted()
|
package/src/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { AsyncBatch, AsyncDataSource, AsyncRow, ColumnResult, ColumnVector, ExecuteContext, ExecuteSqlOptions, ExprNode, ParseSqlOptions, PlanSqlOptions, QueryPlan, QueryResults, ReadBatchColumnOptions, RowsToBatchesOptions, RowSelection, SqlPrimitive, Statement, Token } from './types.js'
|
|
1
|
+
import type { AsyncBatch, AsyncDataSource, AsyncRow, PreparableDataSource, ScannableDataSource, ColumnResult, ColumnVector, ExecuteContext, ExecuteSqlOptions, ExprNode, ParseSqlOptions, PlanSqlOptions, QueryPlan, QueryResults, ReadBatchColumnOptions, RowsToBatchesOptions, RowSelection, SqlPrimitive, Statement, Token } from './types.js'
|
|
2
2
|
export type {
|
|
3
3
|
AsyncBatch,
|
|
4
4
|
AsyncCells,
|
|
5
5
|
AsyncDataSource,
|
|
6
|
+
PreparableDataSource,
|
|
7
|
+
ScannableDataSource,
|
|
6
8
|
AsyncRow,
|
|
7
9
|
BatchColumn,
|
|
8
10
|
ColumnDemand,
|
package/src/parse/parse.js
CHANGED
|
@@ -274,11 +274,16 @@ function parseSelect(state) {
|
|
|
274
274
|
|
|
275
275
|
if (match(state, 'keyword', 'GROUP')) {
|
|
276
276
|
expect(state, 'keyword', 'BY')
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
277
|
+
if (current(state).type === 'keyword' && current(state).value === 'ALL') {
|
|
278
|
+
const tok = consume(state)
|
|
279
|
+
groupBy.push(...expandGroupByAll(columns, tok.positionStart, tok.positionEnd))
|
|
280
|
+
} else {
|
|
281
|
+
while (true) {
|
|
282
|
+
const expr = resolvePositionalRef(parseExpression(state), columns, 'GROUP BY')
|
|
283
|
+
expectNoAggregate(expr, 'GROUP BY')
|
|
284
|
+
groupBy.push(expr)
|
|
285
|
+
if (!match(state, 'comma')) break
|
|
286
|
+
}
|
|
282
287
|
}
|
|
283
288
|
}
|
|
284
289
|
|
|
@@ -371,6 +376,30 @@ function parseSelect(state) {
|
|
|
371
376
|
}
|
|
372
377
|
}
|
|
373
378
|
|
|
379
|
+
/**
|
|
380
|
+
* Expand GROUP BY ALL into every SELECT expression that contains no aggregate.
|
|
381
|
+
*
|
|
382
|
+
* @param {SelectColumn[]} columns
|
|
383
|
+
* @param {number} positionStart
|
|
384
|
+
* @param {number} positionEnd
|
|
385
|
+
* @returns {ExprNode[]}
|
|
386
|
+
*/
|
|
387
|
+
function expandGroupByAll(columns, positionStart, positionEnd) {
|
|
388
|
+
/** @type {ExprNode[]} */
|
|
389
|
+
const groupBy = []
|
|
390
|
+
for (const col of columns) {
|
|
391
|
+
if (col.type === 'star') {
|
|
392
|
+
throw new ParseError({
|
|
393
|
+
message: `GROUP BY ALL does not support * at position ${positionStart}`,
|
|
394
|
+
positionStart,
|
|
395
|
+
positionEnd,
|
|
396
|
+
})
|
|
397
|
+
}
|
|
398
|
+
if (!findAggregate(col.expr)) groupBy.push(col.expr)
|
|
399
|
+
}
|
|
400
|
+
return groupBy
|
|
401
|
+
}
|
|
402
|
+
|
|
374
403
|
/**
|
|
375
404
|
* Resolves a positive integer literal in GROUP BY or ORDER BY as a positional
|
|
376
405
|
* reference to the Nth SELECT column. Non-integer and non-literal expressions
|
package/src/types.d.ts
CHANGED
|
@@ -209,30 +209,33 @@ export type AsyncCell = () => Promise<SqlPrimitive>
|
|
|
209
209
|
|
|
210
210
|
export type Row = Record<string, SqlPrimitive>[]
|
|
211
211
|
|
|
212
|
-
/**
|
|
213
|
-
* Async data source for streaming SQL execution. A source must implement
|
|
214
|
-
* either scan() or prepareScan().
|
|
215
|
-
*/
|
|
216
212
|
interface AsyncDataSourceBase {
|
|
217
213
|
numRows?: number
|
|
218
214
|
// Optional method for fast column scans
|
|
219
215
|
scanColumn?(options: ScanColumnOptions): AsyncIterable<ArrayLike<SqlPrimitive>> | ScanColumnResults
|
|
220
216
|
}
|
|
221
217
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
218
|
+
/** A data source that always provides column names and a row scan. */
|
|
219
|
+
export interface ScannableDataSource extends AsyncDataSourceBase {
|
|
220
|
+
columns: string[]
|
|
221
|
+
scan(options: ScanOptions): ScanResults
|
|
222
|
+
schema?: RelationSchema
|
|
223
|
+
prepareScan?: PrepareScan
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** A data source that always provides a schema and a prepared batch scan. */
|
|
227
|
+
export interface PreparableDataSource extends AsyncDataSourceBase {
|
|
228
|
+
columns?: string[]
|
|
229
|
+
scan?(options: ScanOptions): ScanResults
|
|
230
|
+
schema: RelationSchema
|
|
231
|
+
prepareScan: PrepareScan
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Async data source for streaming SQL execution. A source must implement
|
|
236
|
+
* either scan() or prepareScan().
|
|
237
|
+
*/
|
|
238
|
+
export type AsyncDataSource = ScannableDataSource | PreparableDataSource
|
|
236
239
|
|
|
237
240
|
/**
|
|
238
241
|
* Result of a scan: streaming rows and flags indicating which hints were
|