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.
@@ -1,30 +1,26 @@
1
- import { AsyncDataSource, ExprNode, JoinType, OrderByItem, ScanOptions, SelectColumn, UserDefinedFunction } from '../types.js'
2
-
3
- export interface ExecuteContext {
4
- tables: Record<string, AsyncDataSource>
5
- functions?: Record<string, UserDefinedFunction>
6
- signal?: AbortSignal
7
- }
1
+ import { ExprNode, JoinType, OrderByItem, ScanOptions, SelectColumn } from '../types.js'
8
2
 
9
3
  export type QueryPlan =
10
4
  | ScanNode
11
5
  | FilterNode
12
6
  | ProjectNode
13
- | HashJoinNode
14
- | NestedLoopJoinNode
15
- | PositionalJoinNode
16
- | HashAggregateNode
17
- | ScalarAggregateNode
18
7
  | SortNode
19
8
  | DistinctNode
20
9
  | LimitNode
10
+ | HashAggregateNode
11
+ | ScalarAggregateNode
12
+ | HashJoinNode
13
+ | NestedLoopJoinNode
14
+ | PositionalJoinNode
21
15
 
16
+ // Scan node
22
17
  export interface ScanNode {
23
18
  type: 'Scan'
24
19
  table: string
25
- hints?: ScanOptions
20
+ hints: ScanOptions
26
21
  }
27
22
 
23
+ // Single-child nodes
28
24
  export interface FilterNode {
29
25
  type: 'Filter'
30
26
  condition: ExprNode
@@ -37,6 +33,41 @@ export interface ProjectNode {
37
33
  child: QueryPlan
38
34
  }
39
35
 
36
+ export interface SortNode {
37
+ type: 'Sort'
38
+ orderBy: OrderByItem[]
39
+ child: QueryPlan
40
+ }
41
+
42
+ export interface DistinctNode {
43
+ type: 'Distinct'
44
+ child: QueryPlan
45
+ }
46
+
47
+ export interface LimitNode {
48
+ type: 'Limit'
49
+ limit?: number
50
+ offset?: number
51
+ child: QueryPlan
52
+ }
53
+
54
+ // Aggregate nodes
55
+ export interface HashAggregateNode {
56
+ type: 'HashAggregate'
57
+ groupBy: ExprNode[]
58
+ columns: SelectColumn[]
59
+ having?: ExprNode
60
+ child: QueryPlan
61
+ }
62
+
63
+ export interface ScalarAggregateNode {
64
+ type: 'ScalarAggregate'
65
+ columns: SelectColumn[]
66
+ having?: ExprNode
67
+ child: QueryPlan
68
+ }
69
+
70
+ // Join nodes
40
71
  export interface HashJoinNode {
41
72
  type: 'HashJoin'
42
73
  joinType: JoinType
@@ -65,37 +96,3 @@ export interface PositionalJoinNode {
65
96
  left: QueryPlan
66
97
  right: QueryPlan
67
98
  }
68
-
69
- export interface HashAggregateNode {
70
- type: 'HashAggregate'
71
- groupBy: ExprNode[]
72
- columns: SelectColumn[]
73
- having?: ExprNode
74
- child: QueryPlan
75
- }
76
-
77
- export interface ScalarAggregateNode {
78
- type: 'ScalarAggregate'
79
- columns: SelectColumn[]
80
- having?: ExprNode
81
- child: QueryPlan
82
- }
83
-
84
- export interface SortNode {
85
- type: 'Sort'
86
- orderBy: OrderByItem[]
87
- aliases?: Map<string, ExprNode>
88
- child: QueryPlan
89
- }
90
-
91
- export interface DistinctNode {
92
- type: 'Distinct'
93
- child: QueryPlan
94
- }
95
-
96
- export interface LimitNode {
97
- type: 'Limit'
98
- limit?: number
99
- offset?: number
100
- child: QueryPlan
101
- }
package/src/types.d.ts CHANGED
@@ -15,6 +15,19 @@ export interface ExecuteSqlOptions {
15
15
  signal?: AbortSignal
16
16
  }
17
17
 
18
+ // planSql(options)
19
+ export interface PlanSqlOptions {
20
+ query: string | SelectStatement
21
+ functions?: Record<string, UserDefinedFunction>
22
+ }
23
+
24
+ // executePlan(plan, context)
25
+ export interface ExecuteContext {
26
+ tables: Record<string, AsyncDataSource>
27
+ functions?: Record<string, UserDefinedFunction>
28
+ signal?: AbortSignal
29
+ }
30
+
18
31
  // AsyncRow represents a row with async cell values
19
32
  export interface AsyncRow {
20
33
  columns: string[]
@@ -285,3 +298,9 @@ export interface JoinClause {
285
298
  alias?: string
286
299
  on?: ExprNode
287
300
  }
301
+
302
+ export interface ExecuteContext {
303
+ tables: Record<string, AsyncDataSource>
304
+ functions?: Record<string, UserDefinedFunction>
305
+ signal?: AbortSignal
306
+ }
@@ -89,15 +89,20 @@ export function argValueError({ funcName, message, positionStart, positionEnd, h
89
89
  }
90
90
 
91
91
  /**
92
- * Error for aggregate function misuse (e.g., SUM(*)).
92
+ * Error for aggregate function misuse.
93
93
  *
94
94
  * @param {Object} options
95
95
  * @param {string} options.funcName - The aggregate function
96
- * @param {string} options.issue - What's wrong (e.g., "(*) is not supported")
97
- * @returns {Error}
96
+ * @param {number} options.positionStart - Start position in query
97
+ * @param {number} options.positionEnd - End position in query
98
+ * @returns {ExecutionError}
98
99
  */
99
- export function aggregateError({ funcName, issue }) {
100
- return new Error(`${funcName}${issue}`)
100
+ export function aggregateError({ funcName, positionStart, positionEnd }) {
101
+ return new ExecutionError({
102
+ message: `Aggregate function ${funcName} must exist in a GROUP BY clause or be part of an aggregate SELECT list`,
103
+ positionStart,
104
+ positionEnd,
105
+ })
101
106
  }
102
107
 
103
108
  /**
@@ -1,102 +0,0 @@
1
- /**
2
- * @import { ExprNode, SelectStatement, SelectColumn } from '../types.js'
3
- */
4
-
5
- /**
6
- * Extracts column names needed from a SELECT statement.
7
- *
8
- * @param {SelectStatement} select
9
- * @returns {string[] | undefined} array of column names, or undefined if all columns needed
10
- */
11
- export function extractColumns(select) {
12
- // If any column is SELECT *, we need all columns
13
- if (select.columns.some(col => col.kind === 'star')) {
14
- return undefined
15
- }
16
-
17
- /** @type {Set<string>} */
18
- const columns = new Set()
19
-
20
- // Columns from SELECT list
21
- for (const col of select.columns) {
22
- collectColumnsFromSelectColumn(col, columns)
23
- }
24
-
25
- // Columns from WHERE
26
- collectColumnsFromExpr(select.where, columns)
27
-
28
- // Columns from ORDER BY
29
- for (const item of select.orderBy) {
30
- collectColumnsFromExpr(item.expr, columns)
31
- }
32
-
33
- // Columns from GROUP BY
34
- for (const expr of select.groupBy) {
35
- collectColumnsFromExpr(expr, columns)
36
- }
37
-
38
- // Columns from HAVING
39
- collectColumnsFromExpr(select.having, columns)
40
-
41
- return [...columns]
42
- }
43
-
44
- /**
45
- * Collects column names from a SELECT column
46
- *
47
- * @param {SelectColumn} col
48
- * @param {Set<string>} columns
49
- */
50
- function collectColumnsFromSelectColumn(col, columns) {
51
- if (col.kind === 'derived') {
52
- collectColumnsFromExpr(col.expr, columns)
53
- }
54
- // 'star' columns handled separately (returns undefined for all columns)
55
- }
56
-
57
- /**
58
- * Recursively collects column names (identifiers) from an expression
59
- *
60
- * @param {ExprNode | undefined} expr
61
- * @param {Set<string>} columns
62
- */
63
- function collectColumnsFromExpr(expr, columns) {
64
- if (!expr) return
65
- if (expr.type === 'identifier' && expr.name !== '*') {
66
- columns.add(expr.name)
67
- } else if (expr.type === 'literal') {
68
- // No columns
69
- } else if (expr.type === 'binary') {
70
- collectColumnsFromExpr(expr.left, columns)
71
- collectColumnsFromExpr(expr.right, columns)
72
- } else if (expr.type === 'unary') {
73
- collectColumnsFromExpr(expr.argument, columns)
74
- } else if (expr.type === 'function') {
75
- for (const arg of expr.args) {
76
- collectColumnsFromExpr(arg, columns)
77
- }
78
- } else if (expr.type === 'cast') {
79
- collectColumnsFromExpr(expr.expr, columns)
80
- } else if (expr.type === 'in valuelist') {
81
- collectColumnsFromExpr(expr.expr, columns)
82
- for (const val of expr.values) {
83
- collectColumnsFromExpr(val, columns)
84
- }
85
- } else if (expr.type === 'in') {
86
- collectColumnsFromExpr(expr.expr, columns)
87
- // Subquery columns are from a different scope, don't collect
88
- } else if (expr.type === 'exists' || expr.type === 'not exists') {
89
- // Subquery columns are from a different scope, don't collect
90
- } else if (expr.type === 'case') {
91
- if (expr.caseExpr) {
92
- collectColumnsFromExpr(expr.caseExpr, columns)
93
- }
94
- for (const when of expr.whenClauses) {
95
- collectColumnsFromExpr(when.condition, columns)
96
- collectColumnsFromExpr(when.result, columns)
97
- }
98
- if (expr.elseResult) {
99
- collectColumnsFromExpr(expr.elseResult, columns)
100
- }
101
- }
102
- }