squirreling 0.8.0 → 0.9.0
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 +3 -3
- package/src/execute/aggregates.js +18 -30
- package/src/execute/execute.js +22 -35
- package/src/execute/join.js +15 -31
- package/src/execute/sort.js +5 -10
- package/src/expression/evaluate.js +56 -60
- package/src/index.d.ts +24 -2
- package/src/index.js +2 -2
- package/src/parse/comparison.js +7 -7
- package/src/parse/expression.js +14 -14
- package/src/parse/functions.js +23 -6
- package/src/parse/parse.js +55 -68
- package/src/parse/state.js +0 -9
- package/src/parse/tokenize.js +2 -2
- package/src/parse/types.d.ts +1 -1
- package/src/parseErrors.js +5 -4
- package/src/plan/columns.js +149 -0
- package/src/plan/plan.js +116 -46
- package/src/plan/types.d.ts +44 -47
- package/src/types.d.ts +19 -0
- package/src/validationErrors.js +10 -5
- package/src/execute/columns.js +0 -102
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "squirreling",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Squirreling Async SQL Engine",
|
|
5
5
|
"author": "Hyperparam",
|
|
6
6
|
"homepage": "https://hyperparam.app",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"test": "vitest run"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@types/node": "25.2.
|
|
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.
|
|
43
|
+
"eslint-plugin-jsdoc": "62.5.5",
|
|
44
44
|
"typescript": "5.9.3",
|
|
45
45
|
"vitest": "4.0.18"
|
|
46
46
|
}
|
|
@@ -3,8 +3,8 @@ import { defaultDerivedAlias, stringify } from './utils.js'
|
|
|
3
3
|
import { executePlan } from './execute.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @import { AsyncCells,
|
|
7
|
-
* @import {
|
|
6
|
+
* @import { AsyncCells, AsyncRow, ExecuteContext, SelectColumn } from '../types.js'
|
|
7
|
+
* @import { HashAggregateNode, ScalarAggregateNode } from '../plan/types.js'
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -12,12 +12,10 @@ import { executePlan } from './execute.js'
|
|
|
12
12
|
*
|
|
13
13
|
* @param {SelectColumn[]} selectColumns
|
|
14
14
|
* @param {AsyncRow[]} group
|
|
15
|
-
* @param {
|
|
16
|
-
* @param {Record<string, UserDefinedFunction>} [functions]
|
|
17
|
-
* @param {AbortSignal} [signal]
|
|
15
|
+
* @param {ExecuteContext} context
|
|
18
16
|
* @returns {AsyncRow}
|
|
19
17
|
*/
|
|
20
|
-
function projectAggregateColumns(selectColumns, group,
|
|
18
|
+
function projectAggregateColumns(selectColumns, group, context) {
|
|
21
19
|
/** @type {string[]} */
|
|
22
20
|
const columns = []
|
|
23
21
|
/** @type {AsyncCells} */
|
|
@@ -38,10 +36,8 @@ function projectAggregateColumns(selectColumns, group, tables, functions, signal
|
|
|
38
36
|
cells[alias] = () => evaluateExpr({
|
|
39
37
|
node: col.expr,
|
|
40
38
|
row: group[0] ?? { columns: [], cells: {} },
|
|
41
|
-
tables,
|
|
42
|
-
functions,
|
|
43
39
|
rows: group,
|
|
44
|
-
|
|
40
|
+
context,
|
|
45
41
|
})
|
|
46
42
|
}
|
|
47
43
|
}
|
|
@@ -57,13 +53,11 @@ function projectAggregateColumns(selectColumns, group, tables, functions, signal
|
|
|
57
53
|
* @yields {AsyncRow}
|
|
58
54
|
*/
|
|
59
55
|
export async function* executeHashAggregate(plan, context) {
|
|
60
|
-
const { tables, functions, signal } = context
|
|
61
|
-
|
|
62
56
|
// Collect all rows
|
|
63
57
|
/** @type {AsyncRow[]} */
|
|
64
58
|
const allRows = []
|
|
65
|
-
for await (const row of executePlan(plan.child, context)) {
|
|
66
|
-
if (signal?.aborted) return
|
|
59
|
+
for await (const row of executePlan({ plan: plan.child, context })) {
|
|
60
|
+
if (context.signal?.aborted) return
|
|
67
61
|
allRows.push(row)
|
|
68
62
|
}
|
|
69
63
|
|
|
@@ -77,7 +71,7 @@ export async function* executeHashAggregate(plan, context) {
|
|
|
77
71
|
/** @type {string[]} */
|
|
78
72
|
const keyParts = []
|
|
79
73
|
for (const expr of plan.groupBy) {
|
|
80
|
-
const v = await evaluateExpr({ node: expr, row,
|
|
74
|
+
const v = await evaluateExpr({ node: expr, row, context })
|
|
81
75
|
keyParts.push(stringify(v))
|
|
82
76
|
}
|
|
83
77
|
const key = keyParts.join('|')
|
|
@@ -92,18 +86,16 @@ export async function* executeHashAggregate(plan, context) {
|
|
|
92
86
|
|
|
93
87
|
// Yield one row per group
|
|
94
88
|
for (const group of groups) {
|
|
95
|
-
const asyncRow = projectAggregateColumns(plan.columns, group,
|
|
89
|
+
const asyncRow = projectAggregateColumns(plan.columns, group, context)
|
|
96
90
|
|
|
97
91
|
// Apply HAVING filter
|
|
98
92
|
if (plan.having) {
|
|
99
|
-
const
|
|
93
|
+
const havingRow = { ...group[0], ...asyncRow }
|
|
100
94
|
const passes = await evaluateExpr({
|
|
101
95
|
node: plan.having,
|
|
102
|
-
row:
|
|
96
|
+
row: havingRow,
|
|
103
97
|
rows: group,
|
|
104
|
-
|
|
105
|
-
functions,
|
|
106
|
-
signal,
|
|
98
|
+
context,
|
|
107
99
|
})
|
|
108
100
|
if (!passes) continue
|
|
109
101
|
}
|
|
@@ -120,28 +112,24 @@ export async function* executeHashAggregate(plan, context) {
|
|
|
120
112
|
* @yields {AsyncRow}
|
|
121
113
|
*/
|
|
122
114
|
export async function* executeScalarAggregate(plan, context) {
|
|
123
|
-
const { tables, functions, signal } = context
|
|
124
|
-
|
|
125
115
|
// Collect all rows into single group
|
|
126
116
|
/** @type {AsyncRow[]} */
|
|
127
117
|
const group = []
|
|
128
|
-
for await (const row of executePlan(plan.child, context)) {
|
|
129
|
-
if (signal?.aborted) return
|
|
118
|
+
for await (const row of executePlan({ plan: plan.child, context })) {
|
|
119
|
+
if (context.signal?.aborted) return
|
|
130
120
|
group.push(row)
|
|
131
121
|
}
|
|
132
122
|
|
|
133
|
-
const asyncRow = projectAggregateColumns(plan.columns, group,
|
|
123
|
+
const asyncRow = projectAggregateColumns(plan.columns, group, context)
|
|
134
124
|
|
|
135
125
|
// Apply HAVING filter
|
|
136
126
|
if (plan.having) {
|
|
137
|
-
const
|
|
127
|
+
const havingRow = { ...group[0], ...asyncRow }
|
|
138
128
|
const passes = await evaluateExpr({
|
|
139
129
|
node: plan.having,
|
|
140
|
-
row:
|
|
130
|
+
row: havingRow,
|
|
141
131
|
rows: group,
|
|
142
|
-
|
|
143
|
-
functions,
|
|
144
|
-
signal,
|
|
132
|
+
context,
|
|
145
133
|
})
|
|
146
134
|
if (!passes) return
|
|
147
135
|
}
|
package/src/execute/execute.js
CHANGED
|
@@ -2,35 +2,26 @@ import { memorySource } from '../backend/dataSource.js'
|
|
|
2
2
|
import { tableNotFoundError } from '../executionErrors.js'
|
|
3
3
|
import { evaluateExpr } from '../expression/evaluate.js'
|
|
4
4
|
import { parseSql } from '../parse/parse.js'
|
|
5
|
-
import {
|
|
6
|
-
import { queryPlan } from '../plan/plan.js'
|
|
5
|
+
import { planSql } from '../plan/plan.js'
|
|
7
6
|
import { executeHashAggregate, executeScalarAggregate } from './aggregates.js'
|
|
8
7
|
import { executeHashJoin, executeNestedLoopJoin, executePositionalJoin } from './join.js'
|
|
9
8
|
import { executeSort } from './sort.js'
|
|
10
9
|
import { defaultDerivedAlias, stableRowKey } from './utils.js'
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
|
-
* @import { AsyncCells, AsyncDataSource, AsyncRow, ExecuteSqlOptions, ExprNode, SelectStatement
|
|
14
|
-
* @import { DistinctNode,
|
|
12
|
+
* @import { AsyncCells, AsyncDataSource, AsyncRow, ExecuteContext, ExecuteSqlOptions, ExprNode, SelectStatement } from '../types.js'
|
|
13
|
+
* @import { DistinctNode, FilterNode, LimitNode, ProjectNode, QueryPlan, ScanNode } from '../plan/types.js'
|
|
15
14
|
*/
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
|
-
* Executes a SQL SELECT query against
|
|
17
|
+
* Executes a SQL SELECT query against tables
|
|
19
18
|
*
|
|
20
|
-
* @param {ExecuteSqlOptions} options
|
|
21
|
-
* @yields {AsyncRow}
|
|
19
|
+
* @param {ExecuteSqlOptions} options
|
|
20
|
+
* @yields {AsyncRow}
|
|
22
21
|
*/
|
|
23
22
|
export async function* executeSql({ tables, query, functions, signal }) {
|
|
24
23
|
const select = typeof query === 'string' ? parseSql({ query, functions }) : query
|
|
25
24
|
|
|
26
|
-
// Check for unsupported operations
|
|
27
|
-
if (!select.from) {
|
|
28
|
-
throw missingClauseError({
|
|
29
|
-
missing: 'FROM clause',
|
|
30
|
-
context: 'SELECT statement',
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
|
|
34
25
|
// Normalize tables: convert arrays to AsyncDataSource
|
|
35
26
|
/** @type {Record<string, AsyncDataSource>} */
|
|
36
27
|
const normalizedTables = {}
|
|
@@ -42,7 +33,7 @@ export async function* executeSql({ tables, query, functions, signal }) {
|
|
|
42
33
|
}
|
|
43
34
|
}
|
|
44
35
|
|
|
45
|
-
yield* executeSelect({ select, tables: normalizedTables, functions, signal })
|
|
36
|
+
yield* executeSelect({ select, context: { tables: normalizedTables, functions, signal } })
|
|
46
37
|
}
|
|
47
38
|
|
|
48
39
|
/**
|
|
@@ -50,24 +41,23 @@ export async function* executeSql({ tables, query, functions, signal }) {
|
|
|
50
41
|
*
|
|
51
42
|
* @param {Object} options
|
|
52
43
|
* @param {SelectStatement} options.select
|
|
53
|
-
* @param {
|
|
54
|
-
* @param {Record<string, UserDefinedFunction>} [options.functions]
|
|
55
|
-
* @param {AbortSignal} [options.signal]
|
|
44
|
+
* @param {ExecuteContext} options.context
|
|
56
45
|
* @yields {AsyncRow}
|
|
57
46
|
*/
|
|
58
|
-
export async function* executeSelect({ select,
|
|
59
|
-
const plan =
|
|
60
|
-
yield* executePlan(
|
|
47
|
+
export async function* executeSelect({ select, context }) {
|
|
48
|
+
const plan = planSql({ query: select, functions: context.functions })
|
|
49
|
+
yield* executePlan({ plan, context })
|
|
61
50
|
}
|
|
62
51
|
|
|
63
52
|
/**
|
|
64
53
|
* Executes a query plan and yields result rows
|
|
65
54
|
*
|
|
66
|
-
* @param {
|
|
67
|
-
* @param {
|
|
55
|
+
* @param {Object} options
|
|
56
|
+
* @param {QueryPlan} options.plan - the query plan to execute
|
|
57
|
+
* @param {ExecuteContext} options.context - execution context
|
|
68
58
|
* @returns {AsyncGenerator<AsyncRow>}
|
|
69
59
|
*/
|
|
70
|
-
export async function* executePlan(plan, context) {
|
|
60
|
+
export async function* executePlan({ plan, context }) {
|
|
71
61
|
if (plan.type === 'Scan') {
|
|
72
62
|
yield* executeScan(plan, context)
|
|
73
63
|
} else if (plan.type === 'Filter') {
|
|
@@ -147,7 +137,7 @@ async function* filterRows(rows, condition, context) {
|
|
|
147
137
|
for await (const row of rows) {
|
|
148
138
|
if (context.signal?.aborted) return
|
|
149
139
|
rowIndex++
|
|
150
|
-
const pass = await evaluateExpr({ node: condition, row, rowIndex,
|
|
140
|
+
const pass = await evaluateExpr({ node: condition, row, rowIndex, context })
|
|
151
141
|
if (pass) yield row
|
|
152
142
|
}
|
|
153
143
|
}
|
|
@@ -187,7 +177,7 @@ async function* limitRows(rows, limit, offset, signal) {
|
|
|
187
177
|
* @yields {AsyncRow}
|
|
188
178
|
*/
|
|
189
179
|
async function* executeFilter(plan, context) {
|
|
190
|
-
yield* filterRows(executePlan(plan.child, context), plan.condition, context)
|
|
180
|
+
yield* filterRows(executePlan({ plan: plan.child, context }), plan.condition, context)
|
|
191
181
|
}
|
|
192
182
|
|
|
193
183
|
/**
|
|
@@ -198,11 +188,10 @@ async function* executeFilter(plan, context) {
|
|
|
198
188
|
* @yields {AsyncRow}
|
|
199
189
|
*/
|
|
200
190
|
async function* executeProject(plan, context) {
|
|
201
|
-
const { tables, functions, signal } = context
|
|
202
191
|
let rowIndex = 0
|
|
203
192
|
|
|
204
|
-
for await (const row of executePlan(plan.child, context)) {
|
|
205
|
-
if (signal?.aborted) return
|
|
193
|
+
for await (const row of executePlan({ plan: plan.child, context })) {
|
|
194
|
+
if (context.signal?.aborted) return
|
|
206
195
|
rowIndex++
|
|
207
196
|
const currentRowIndex = rowIndex
|
|
208
197
|
|
|
@@ -223,10 +212,8 @@ async function* executeProject(plan, context) {
|
|
|
223
212
|
cells[alias] = () => evaluateExpr({
|
|
224
213
|
node: col.expr,
|
|
225
214
|
row,
|
|
226
|
-
tables,
|
|
227
|
-
functions,
|
|
228
215
|
rowIndex: currentRowIndex,
|
|
229
|
-
|
|
216
|
+
context,
|
|
230
217
|
})
|
|
231
218
|
}
|
|
232
219
|
}
|
|
@@ -248,7 +235,7 @@ async function* executeDistinct(plan, context) {
|
|
|
248
235
|
/** @type {Set<string>} */
|
|
249
236
|
const seen = new Set()
|
|
250
237
|
|
|
251
|
-
for await (const row of executePlan(plan.child, context)) {
|
|
238
|
+
for await (const row of executePlan({ plan: plan.child, context })) {
|
|
252
239
|
if (signal?.aborted) return
|
|
253
240
|
|
|
254
241
|
const key = await stableRowKey(row.cells)
|
|
@@ -267,5 +254,5 @@ async function* executeDistinct(plan, context) {
|
|
|
267
254
|
* @yields {AsyncRow}
|
|
268
255
|
*/
|
|
269
256
|
async function* executeLimit(plan, context) {
|
|
270
|
-
yield* limitRows(executePlan(plan.child, context), plan.limit, plan.offset, context.signal)
|
|
257
|
+
yield* limitRows(executePlan({ plan: plan.child, context }), plan.limit, plan.offset, context.signal)
|
|
271
258
|
}
|
package/src/execute/join.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { evaluateExpr } from '../expression/evaluate.js'
|
|
2
|
-
import { missingClauseError } from '../parseErrors.js'
|
|
3
2
|
import { stringify } from './utils.js'
|
|
4
3
|
import { executePlan } from './execute.js'
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
|
-
* @import { AsyncCells, AsyncRow } from '../types.js'
|
|
8
|
-
* @import {
|
|
6
|
+
* @import { AsyncCells, AsyncRow, ExecuteContext } from '../types.js'
|
|
7
|
+
* @import { HashJoinNode, NestedLoopJoinNode, PositionalJoinNode } from '../plan/types.js'
|
|
9
8
|
*/
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -16,22 +15,14 @@ import { executePlan } from './execute.js'
|
|
|
16
15
|
* @yields {AsyncRow}
|
|
17
16
|
*/
|
|
18
17
|
export async function* executeNestedLoopJoin(plan, context) {
|
|
19
|
-
const { tables, functions, signal } = context
|
|
20
18
|
const leftTable = plan.leftAlias
|
|
21
19
|
const rightTable = plan.rightAlias
|
|
22
20
|
|
|
23
|
-
if (!plan.condition) {
|
|
24
|
-
throw missingClauseError({
|
|
25
|
-
missing: 'ON condition',
|
|
26
|
-
context: 'JOIN',
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
|
-
|
|
30
21
|
// Buffer right rows
|
|
31
22
|
/** @type {AsyncRow[]} */
|
|
32
23
|
const rightRows = []
|
|
33
|
-
for await (const row of executePlan(plan.right, context)) {
|
|
34
|
-
if (signal?.aborted) return
|
|
24
|
+
for await (const row of executePlan({ plan: plan.right, context })) {
|
|
25
|
+
if (context.signal?.aborted) return
|
|
35
26
|
rightRows.push(row)
|
|
36
27
|
}
|
|
37
28
|
|
|
@@ -43,8 +34,8 @@ export async function* executeNestedLoopJoin(plan, context) {
|
|
|
43
34
|
/** @type {Set<AsyncRow> | null} */
|
|
44
35
|
const matchedRightRows = plan.joinType === 'RIGHT' || plan.joinType === 'FULL' ? new Set() : null
|
|
45
36
|
|
|
46
|
-
for await (const leftRow of executePlan(plan.left, context)) {
|
|
47
|
-
if (signal?.aborted) break
|
|
37
|
+
for await (const leftRow of executePlan({ plan: plan.left, context })) {
|
|
38
|
+
if (context.signal?.aborted) break
|
|
48
39
|
|
|
49
40
|
if (!leftPrefixedCols) {
|
|
50
41
|
leftPrefixedCols = prefixColumns(leftRow.columns, leftTable)
|
|
@@ -57,9 +48,7 @@ export async function* executeNestedLoopJoin(plan, context) {
|
|
|
57
48
|
const matches = await evaluateExpr({
|
|
58
49
|
node: plan.condition,
|
|
59
50
|
row: tempMerged,
|
|
60
|
-
|
|
61
|
-
functions,
|
|
62
|
-
signal,
|
|
51
|
+
context,
|
|
63
52
|
})
|
|
64
53
|
|
|
65
54
|
if (matches) {
|
|
@@ -101,14 +90,14 @@ export async function* executePositionalJoin(plan, context) {
|
|
|
101
90
|
// Buffer both sides (required for positional join)
|
|
102
91
|
/** @type {AsyncRow[]} */
|
|
103
92
|
const leftRows = []
|
|
104
|
-
for await (const row of executePlan(plan.left, context)) {
|
|
93
|
+
for await (const row of executePlan({ plan: plan.left, context })) {
|
|
105
94
|
if (signal?.aborted) return
|
|
106
95
|
leftRows.push(row)
|
|
107
96
|
}
|
|
108
97
|
|
|
109
98
|
/** @type {AsyncRow[]} */
|
|
110
99
|
const rightRows = []
|
|
111
|
-
for await (const row of executePlan(plan.right, context)) {
|
|
100
|
+
for await (const row of executePlan({ plan: plan.right, context })) {
|
|
112
101
|
if (signal?.aborted) return
|
|
113
102
|
rightRows.push(row)
|
|
114
103
|
}
|
|
@@ -135,15 +124,14 @@ export async function* executePositionalJoin(plan, context) {
|
|
|
135
124
|
* @yields {AsyncRow}
|
|
136
125
|
*/
|
|
137
126
|
export async function* executeHashJoin(plan, context) {
|
|
138
|
-
const { tables, functions, signal } = context
|
|
139
127
|
const leftTable = plan.leftAlias
|
|
140
128
|
const rightTable = plan.rightAlias
|
|
141
129
|
|
|
142
130
|
// Buffer right rows and build hash map
|
|
143
131
|
/** @type {AsyncRow[]} */
|
|
144
132
|
const rightRows = []
|
|
145
|
-
for await (const row of executePlan(plan.right, context)) {
|
|
146
|
-
if (signal?.aborted) return
|
|
133
|
+
for await (const row of executePlan({ plan: plan.right, context })) {
|
|
134
|
+
if (context.signal?.aborted) return
|
|
147
135
|
rightRows.push(row)
|
|
148
136
|
}
|
|
149
137
|
|
|
@@ -153,9 +141,7 @@ export async function* executeHashJoin(plan, context) {
|
|
|
153
141
|
const keyValue = await evaluateExpr({
|
|
154
142
|
node: plan.rightKey,
|
|
155
143
|
row: rightRow,
|
|
156
|
-
|
|
157
|
-
functions,
|
|
158
|
-
signal,
|
|
144
|
+
context,
|
|
159
145
|
})
|
|
160
146
|
if (keyValue == null) continue
|
|
161
147
|
const keyStr = stringify(keyValue)
|
|
@@ -177,8 +163,8 @@ export async function* executeHashJoin(plan, context) {
|
|
|
177
163
|
const matchedRightRows = plan.joinType === 'RIGHT' || plan.joinType === 'FULL' ? new Set() : null
|
|
178
164
|
|
|
179
165
|
// Probe phase: stream left rows
|
|
180
|
-
for await (const leftRow of executePlan(plan.left, context)) {
|
|
181
|
-
if (signal?.aborted) break
|
|
166
|
+
for await (const leftRow of executePlan({ plan: plan.left, context })) {
|
|
167
|
+
if (context.signal?.aborted) break
|
|
182
168
|
|
|
183
169
|
if (!leftPrefixedCols) {
|
|
184
170
|
leftPrefixedCols = prefixColumns(leftRow.columns, leftTable)
|
|
@@ -187,9 +173,7 @@ export async function* executeHashJoin(plan, context) {
|
|
|
187
173
|
const keyValue = await evaluateExpr({
|
|
188
174
|
node: plan.leftKey,
|
|
189
175
|
row: leftRow,
|
|
190
|
-
|
|
191
|
-
functions,
|
|
192
|
-
signal,
|
|
176
|
+
context,
|
|
193
177
|
})
|
|
194
178
|
const keyStr = stringify(keyValue)
|
|
195
179
|
const matchingRightRows = hashMap.get(keyStr)
|
package/src/execute/sort.js
CHANGED
|
@@ -3,8 +3,8 @@ import { executePlan } from './execute.js'
|
|
|
3
3
|
import { compareForTerm } from './utils.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @import { AsyncRow, SqlPrimitive } from '../types.js'
|
|
7
|
-
* @import {
|
|
6
|
+
* @import { AsyncRow, ExecuteContext, SqlPrimitive } from '../types.js'
|
|
7
|
+
* @import { SortNode } from '../plan/types.js'
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -15,13 +15,11 @@ import { compareForTerm } from './utils.js'
|
|
|
15
15
|
* @yields {AsyncRow}
|
|
16
16
|
*/
|
|
17
17
|
export async function* executeSort(plan, context) {
|
|
18
|
-
const { tables, functions, signal } = context
|
|
19
|
-
|
|
20
18
|
// Buffer all rows
|
|
21
19
|
/** @type {AsyncRow[]} */
|
|
22
20
|
const rows = []
|
|
23
|
-
for await (const row of executePlan(plan.child, context)) {
|
|
24
|
-
if (signal?.aborted) return
|
|
21
|
+
for await (const row of executePlan({ plan: plan.child, context })) {
|
|
22
|
+
if (context.signal?.aborted) return
|
|
25
23
|
rows.push(row)
|
|
26
24
|
}
|
|
27
25
|
|
|
@@ -51,10 +49,7 @@ export async function* executeSort(plan, context) {
|
|
|
51
49
|
evaluatedValues[idx][orderByIdx] = await evaluateExpr({
|
|
52
50
|
node: term.expr,
|
|
53
51
|
row: rows[idx],
|
|
54
|
-
|
|
55
|
-
functions,
|
|
56
|
-
aliases: plan.aliases,
|
|
57
|
-
signal,
|
|
52
|
+
context,
|
|
58
53
|
})
|
|
59
54
|
}
|
|
60
55
|
}
|