@quereus/quereus 0.6.1 → 0.6.3

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.
Files changed (55) hide show
  1. package/dist/src/common/type-inference.d.ts +9 -1
  2. package/dist/src/common/type-inference.d.ts.map +1 -1
  3. package/dist/src/common/type-inference.js +11 -3
  4. package/dist/src/common/type-inference.js.map +1 -1
  5. package/dist/src/core/database.d.ts +27 -1
  6. package/dist/src/core/database.d.ts.map +1 -1
  7. package/dist/src/core/database.js +39 -6
  8. package/dist/src/core/database.js.map +1 -1
  9. package/dist/src/core/param.d.ts +17 -1
  10. package/dist/src/core/param.d.ts.map +1 -1
  11. package/dist/src/core/param.js +23 -1
  12. package/dist/src/core/param.js.map +1 -1
  13. package/dist/src/core/statement.d.ts +10 -1
  14. package/dist/src/core/statement.d.ts.map +1 -1
  15. package/dist/src/core/statement.js +71 -5
  16. package/dist/src/core/statement.js.map +1 -1
  17. package/dist/src/planner/scopes/param.d.ts +2 -2
  18. package/dist/src/planner/scopes/param.d.ts.map +1 -1
  19. package/dist/src/planner/scopes/param.js +9 -9
  20. package/dist/src/planner/scopes/param.js.map +1 -1
  21. package/dist/src/runtime/emit/schema-declarative.js +1 -1
  22. package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
  23. package/dist/src/schema/schema-hasher.d.ts +3 -3
  24. package/dist/src/schema/schema-hasher.d.ts.map +1 -1
  25. package/dist/src/schema/schema-hasher.js +9 -27
  26. package/dist/src/schema/schema-hasher.js.map +1 -1
  27. package/dist/src/types/index.d.ts +1 -1
  28. package/dist/src/types/index.d.ts.map +1 -1
  29. package/dist/src/types/index.js +1 -1
  30. package/dist/src/types/index.js.map +1 -1
  31. package/dist/src/types/logical-type.d.ts +5 -0
  32. package/dist/src/types/logical-type.d.ts.map +1 -1
  33. package/dist/src/types/logical-type.js +15 -0
  34. package/dist/src/types/logical-type.js.map +1 -1
  35. package/dist/src/util/hash.d.ts +19 -0
  36. package/dist/src/util/hash.d.ts.map +1 -0
  37. package/dist/src/util/hash.js +76 -0
  38. package/dist/src/util/hash.js.map +1 -0
  39. package/package.json +1 -1
  40. package/src/common/type-inference.ts +11 -3
  41. package/src/core/database.ts +41 -6
  42. package/src/core/param.ts +23 -1
  43. package/src/core/statement.ts +89 -5
  44. package/src/planner/building/delete.ts +214 -214
  45. package/src/planner/building/insert.ts +428 -428
  46. package/src/planner/building/update.ts +319 -319
  47. package/src/planner/scopes/param.ts +9 -9
  48. package/src/runtime/emit/schema-declarative.ts +1 -1
  49. package/src/schema/schema-hasher.ts +9 -27
  50. package/src/types/index.ts +1 -1
  51. package/src/types/logical-type.ts +16 -0
  52. package/src/util/ast-stringify.ts +864 -864
  53. package/src/util/hash.ts +90 -0
  54. package/src/vtab/memory/table.ts +256 -256
  55. package/src/vtab/table.ts +162 -162
@@ -1,214 +1,214 @@
1
- import type * as AST from '../../parser/ast.js';
2
- import type { PlanningContext } from '../planning-context.js';
3
- import { DeleteNode } from '../nodes/delete-node.js';
4
- import { buildTableReference } from './table.js';
5
- import { buildExpression } from './expression.js';
6
- import { PlanNode, type RelationalPlanNode, type ScalarPlanNode, type Attribute, type RowDescriptor } from '../nodes/plan-node.js';
7
- import { FilterNode } from '../nodes/filter.js';
8
- import { QuereusError } from '../../common/errors.js';
9
- import { StatusCode } from '../../common/types.js';
10
- import { RegisteredScope } from '../scopes/registered.js';
11
- import { ColumnReferenceNode } from '../nodes/reference.js';
12
- import { SinkNode } from '../nodes/sink-node.js';
13
- import { ConstraintCheckNode } from '../nodes/constraint-check-node.js';
14
- import { RowOpFlag } from '../../schema/table.js';
15
- import { ReturningNode } from '../nodes/returning-node.js';
16
- import { buildOldNewRowDescriptors } from '../../util/row-descriptor.js';
17
- import { DmlExecutorNode } from '../nodes/dml-executor-node.js';
18
- import { buildConstraintChecks } from './constraint-builder.js';
19
-
20
- export function buildDeleteStmt(
21
- ctx: PlanningContext,
22
- stmt: AST.DeleteStmt,
23
- ): PlanNode {
24
- const tableRetrieve = buildTableReference({ type: 'table', table: stmt.table }, ctx);
25
- const tableReference = tableRetrieve.tableRef; // Extract the actual TableReferenceNode
26
-
27
- // Process mutation context assignments if present
28
- const mutationContextValues = new Map<string, ScalarPlanNode>();
29
- const contextAttributes: Attribute[] = [];
30
-
31
- if (stmt.contextValues && tableReference.tableSchema.mutationContext) {
32
- // Create context attributes
33
- tableReference.tableSchema.mutationContext.forEach((contextVar) => {
34
- contextAttributes.push({
35
- id: PlanNode.nextAttrId(),
36
- name: contextVar.name,
37
- type: {
38
- typeClass: 'scalar' as const,
39
- logicalType: contextVar.logicalType,
40
- nullable: !contextVar.notNull,
41
- isReadOnly: true
42
- },
43
- sourceRelation: `context.${tableReference.tableSchema.name}`
44
- });
45
- });
46
-
47
- // Build context value expressions (evaluated in the base scope, before table scope)
48
- stmt.contextValues.forEach((assignment) => {
49
- const valueExpr = buildExpression(ctx, assignment.value) as ScalarPlanNode;
50
- mutationContextValues.set(assignment.name, valueExpr);
51
- });
52
- }
53
-
54
- // Plan the source of rows to delete. This is typically the table itself, potentially filtered.
55
- let sourceNode: RelationalPlanNode = tableRetrieve; // Use the RetrieveNode as source
56
-
57
- // Create a new scope with the table columns registered for column resolution
58
- const tableScope = new RegisteredScope(ctx.scope);
59
- const sourceAttributes = sourceNode.getAttributes();
60
- sourceNode.getType().columns.forEach((c, i) => {
61
- const attr = sourceAttributes[i];
62
- tableScope.registerSymbol(c.name.toLowerCase(), (exp, s) =>
63
- new ColumnReferenceNode(s, exp as AST.ColumnExpr, c.type, attr.id, i));
64
- });
65
-
66
- // Create a new planning context with the updated scope for WHERE clause resolution
67
- const deleteCtx = { ...ctx, scope: tableScope };
68
-
69
- if (stmt.where) {
70
- const filterExpression = buildExpression(deleteCtx, stmt.where);
71
- sourceNode = new FilterNode(deleteCtx.scope, sourceNode, filterExpression);
72
- }
73
-
74
- // Create OLD/NEW attributes for DELETE (OLD = actual values being deleted, NEW = all NULL)
75
- const oldAttributes = tableReference.tableSchema.columns.map((col: any) => ({
76
- id: PlanNode.nextAttrId(),
77
- name: col.name,
78
- type: {
79
- typeClass: 'scalar' as const,
80
- logicalType: col.logicalType,
81
- nullable: !col.notNull,
82
- isReadOnly: false
83
- },
84
- sourceRelation: `OLD.${tableReference.tableSchema.name}`
85
- }));
86
-
87
- const newAttributes = tableReference.tableSchema.columns.map((col: any) => ({
88
- id: PlanNode.nextAttrId(),
89
- name: col.name,
90
- type: {
91
- typeClass: 'scalar' as const,
92
- logicalType: col.logicalType,
93
- nullable: true, // NEW values are always NULL for DELETE
94
- isReadOnly: false
95
- },
96
- sourceRelation: `NEW.${tableReference.tableSchema.name}`
97
- }));
98
-
99
- const { oldRowDescriptor, newRowDescriptor, flatRowDescriptor } = buildOldNewRowDescriptors(oldAttributes, newAttributes);
100
-
101
- // Build context descriptor if we have context attributes
102
- const contextDescriptor: RowDescriptor = contextAttributes.length > 0 ? [] : undefined as any;
103
- if (contextDescriptor) {
104
- contextAttributes.forEach((attr, index) => {
105
- contextDescriptor[attr.id] = index;
106
- });
107
- }
108
-
109
- // Build constraint checks at plan time
110
- const constraintChecks = buildConstraintChecks(
111
- deleteCtx,
112
- tableReference.tableSchema,
113
- RowOpFlag.DELETE,
114
- oldAttributes,
115
- newAttributes,
116
- flatRowDescriptor,
117
- contextAttributes
118
- );
119
-
120
- // Always inject ConstraintCheckNode for DELETE operations
121
- const constraintCheckNode = new ConstraintCheckNode(
122
- deleteCtx.scope,
123
- sourceNode,
124
- tableReference,
125
- RowOpFlag.DELETE,
126
- oldRowDescriptor,
127
- newRowDescriptor,
128
- flatRowDescriptor,
129
- constraintChecks,
130
- mutationContextValues.size > 0 ? mutationContextValues : undefined,
131
- contextAttributes.length > 0 ? contextAttributes : undefined,
132
- contextDescriptor
133
- );
134
-
135
- const deleteNode = new DeleteNode(
136
- deleteCtx.scope,
137
- tableReference,
138
- constraintCheckNode,
139
- oldRowDescriptor,
140
- flatRowDescriptor,
141
- mutationContextValues.size > 0 ? mutationContextValues : undefined,
142
- contextAttributes.length > 0 ? contextAttributes : undefined,
143
- contextDescriptor
144
- );
145
-
146
- // Add DML executor node to perform the actual database delete operations
147
- const dmlExecutorNode = new DmlExecutorNode(
148
- deleteCtx.scope,
149
- deleteNode,
150
- tableReference,
151
- 'delete'
152
- );
153
-
154
- const resultNode: RelationalPlanNode = dmlExecutorNode;
155
-
156
- if (stmt.returning && stmt.returning.length > 0) {
157
- // Create returning scope with OLD/NEW attribute access
158
- const returningScope = new RegisteredScope(deleteCtx.scope);
159
-
160
- // Register OLD.* symbols (actual values being deleted)
161
- oldAttributes.forEach((attr: any, columnIndex: any) => {
162
- const tableColumn = tableReference.tableSchema.columns[columnIndex];
163
- returningScope.registerSymbol(`old.${tableColumn.name.toLowerCase()}`, (exp, s) =>
164
- new ColumnReferenceNode(s, exp as AST.ColumnExpr, attr.type, attr.id, columnIndex)
165
- );
166
- });
167
-
168
- // Register NEW.* symbols (always NULL for DELETE) and unqualified column names (default to OLD for DELETE)
169
- newAttributes.forEach((attr: any, columnIndex: any) => {
170
- const tableColumn = tableReference.tableSchema.columns[columnIndex];
171
-
172
- // NEW.column (always NULL for DELETE)
173
- returningScope.registerSymbol(`new.${tableColumn.name.toLowerCase()}`, (exp, s) =>
174
- new ColumnReferenceNode(s, exp as AST.ColumnExpr, attr.type, attr.id, columnIndex)
175
- );
176
-
177
- // Unqualified column (defaults to OLD for DELETE)
178
- const oldAttr = oldAttributes[columnIndex];
179
- returningScope.registerSymbol(tableColumn.name.toLowerCase(), (exp, s) =>
180
- new ColumnReferenceNode(s, exp as AST.ColumnExpr, oldAttr.type, oldAttr.id, columnIndex)
181
- );
182
-
183
- // Table-qualified form (table.column -> OLD for DELETE)
184
- const tblQualified = `${tableReference.tableSchema.name.toLowerCase()}.${tableColumn.name.toLowerCase()}`;
185
- returningScope.registerSymbol(tblQualified, (exp, s) =>
186
- new ColumnReferenceNode(s, exp as AST.ColumnExpr, oldAttr.type, oldAttr.id, columnIndex)
187
- );
188
- });
189
-
190
- // Build RETURNING projections in the OLD/NEW context
191
- const returningProjections = stmt.returning.map(rc => {
192
- // TODO: Support RETURNING *
193
- if (rc.type === 'all') throw new QuereusError('RETURNING * not yet supported', StatusCode.UNSUPPORTED);
194
-
195
- // Infer alias from column name if not explicitly provided
196
- let alias = rc.alias;
197
- if (!alias && rc.expr.type === 'column') {
198
- // For qualified column references like OLD.id, normalize to lowercase
199
- alias = rc.expr.table
200
- ? `${rc.expr.table.toLowerCase()}.${rc.expr.name.toLowerCase()}`
201
- : rc.expr.name.toLowerCase();
202
- }
203
-
204
- return {
205
- node: buildExpression({ ...deleteCtx, scope: returningScope }, rc.expr) as ScalarPlanNode,
206
- alias: alias
207
- };
208
- });
209
-
210
- return new ReturningNode(deleteCtx.scope, dmlExecutorNode, returningProjections);
211
- }
212
-
213
- return new SinkNode(deleteCtx.scope, resultNode, 'delete');
214
- }
1
+ import type * as AST from '../../parser/ast.js';
2
+ import type { PlanningContext } from '../planning-context.js';
3
+ import { DeleteNode } from '../nodes/delete-node.js';
4
+ import { buildTableReference } from './table.js';
5
+ import { buildExpression } from './expression.js';
6
+ import { PlanNode, type RelationalPlanNode, type ScalarPlanNode, type Attribute, type RowDescriptor } from '../nodes/plan-node.js';
7
+ import { FilterNode } from '../nodes/filter.js';
8
+ import { QuereusError } from '../../common/errors.js';
9
+ import { StatusCode } from '../../common/types.js';
10
+ import { RegisteredScope } from '../scopes/registered.js';
11
+ import { ColumnReferenceNode } from '../nodes/reference.js';
12
+ import { SinkNode } from '../nodes/sink-node.js';
13
+ import { ConstraintCheckNode } from '../nodes/constraint-check-node.js';
14
+ import { RowOpFlag } from '../../schema/table.js';
15
+ import { ReturningNode } from '../nodes/returning-node.js';
16
+ import { buildOldNewRowDescriptors } from '../../util/row-descriptor.js';
17
+ import { DmlExecutorNode } from '../nodes/dml-executor-node.js';
18
+ import { buildConstraintChecks } from './constraint-builder.js';
19
+
20
+ export function buildDeleteStmt(
21
+ ctx: PlanningContext,
22
+ stmt: AST.DeleteStmt,
23
+ ): PlanNode {
24
+ const tableRetrieve = buildTableReference({ type: 'table', table: stmt.table }, ctx);
25
+ const tableReference = tableRetrieve.tableRef; // Extract the actual TableReferenceNode
26
+
27
+ // Process mutation context assignments if present
28
+ const mutationContextValues = new Map<string, ScalarPlanNode>();
29
+ const contextAttributes: Attribute[] = [];
30
+
31
+ if (stmt.contextValues && tableReference.tableSchema.mutationContext) {
32
+ // Create context attributes
33
+ tableReference.tableSchema.mutationContext.forEach((contextVar) => {
34
+ contextAttributes.push({
35
+ id: PlanNode.nextAttrId(),
36
+ name: contextVar.name,
37
+ type: {
38
+ typeClass: 'scalar' as const,
39
+ logicalType: contextVar.logicalType,
40
+ nullable: !contextVar.notNull,
41
+ isReadOnly: true
42
+ },
43
+ sourceRelation: `context.${tableReference.tableSchema.name}`
44
+ });
45
+ });
46
+
47
+ // Build context value expressions (evaluated in the base scope, before table scope)
48
+ stmt.contextValues.forEach((assignment) => {
49
+ const valueExpr = buildExpression(ctx, assignment.value) as ScalarPlanNode;
50
+ mutationContextValues.set(assignment.name, valueExpr);
51
+ });
52
+ }
53
+
54
+ // Plan the source of rows to delete. This is typically the table itself, potentially filtered.
55
+ let sourceNode: RelationalPlanNode = tableRetrieve; // Use the RetrieveNode as source
56
+
57
+ // Create a new scope with the table columns registered for column resolution
58
+ const tableScope = new RegisteredScope(ctx.scope);
59
+ const sourceAttributes = sourceNode.getAttributes();
60
+ sourceNode.getType().columns.forEach((c, i) => {
61
+ const attr = sourceAttributes[i];
62
+ tableScope.registerSymbol(c.name.toLowerCase(), (exp, s) =>
63
+ new ColumnReferenceNode(s, exp as AST.ColumnExpr, c.type, attr.id, i));
64
+ });
65
+
66
+ // Create a new planning context with the updated scope for WHERE clause resolution
67
+ const deleteCtx = { ...ctx, scope: tableScope };
68
+
69
+ if (stmt.where) {
70
+ const filterExpression = buildExpression(deleteCtx, stmt.where);
71
+ sourceNode = new FilterNode(deleteCtx.scope, sourceNode, filterExpression);
72
+ }
73
+
74
+ // Create OLD/NEW attributes for DELETE (OLD = actual values being deleted, NEW = all NULL)
75
+ const oldAttributes = tableReference.tableSchema.columns.map((col: any) => ({
76
+ id: PlanNode.nextAttrId(),
77
+ name: col.name,
78
+ type: {
79
+ typeClass: 'scalar' as const,
80
+ logicalType: col.logicalType,
81
+ nullable: !col.notNull,
82
+ isReadOnly: false
83
+ },
84
+ sourceRelation: `OLD.${tableReference.tableSchema.name}`
85
+ }));
86
+
87
+ const newAttributes = tableReference.tableSchema.columns.map((col: any) => ({
88
+ id: PlanNode.nextAttrId(),
89
+ name: col.name,
90
+ type: {
91
+ typeClass: 'scalar' as const,
92
+ logicalType: col.logicalType,
93
+ nullable: true, // NEW values are always NULL for DELETE
94
+ isReadOnly: false
95
+ },
96
+ sourceRelation: `NEW.${tableReference.tableSchema.name}`
97
+ }));
98
+
99
+ const { oldRowDescriptor, newRowDescriptor, flatRowDescriptor } = buildOldNewRowDescriptors(oldAttributes, newAttributes);
100
+
101
+ // Build context descriptor if we have context attributes
102
+ const contextDescriptor: RowDescriptor = contextAttributes.length > 0 ? [] : undefined as any;
103
+ if (contextDescriptor) {
104
+ contextAttributes.forEach((attr, index) => {
105
+ contextDescriptor[attr.id] = index;
106
+ });
107
+ }
108
+
109
+ // Build constraint checks at plan time
110
+ const constraintChecks = buildConstraintChecks(
111
+ deleteCtx,
112
+ tableReference.tableSchema,
113
+ RowOpFlag.DELETE,
114
+ oldAttributes,
115
+ newAttributes,
116
+ flatRowDescriptor,
117
+ contextAttributes
118
+ );
119
+
120
+ // Always inject ConstraintCheckNode for DELETE operations
121
+ const constraintCheckNode = new ConstraintCheckNode(
122
+ deleteCtx.scope,
123
+ sourceNode,
124
+ tableReference,
125
+ RowOpFlag.DELETE,
126
+ oldRowDescriptor,
127
+ newRowDescriptor,
128
+ flatRowDescriptor,
129
+ constraintChecks,
130
+ mutationContextValues.size > 0 ? mutationContextValues : undefined,
131
+ contextAttributes.length > 0 ? contextAttributes : undefined,
132
+ contextDescriptor
133
+ );
134
+
135
+ const deleteNode = new DeleteNode(
136
+ deleteCtx.scope,
137
+ tableReference,
138
+ constraintCheckNode,
139
+ oldRowDescriptor,
140
+ flatRowDescriptor,
141
+ mutationContextValues.size > 0 ? mutationContextValues : undefined,
142
+ contextAttributes.length > 0 ? contextAttributes : undefined,
143
+ contextDescriptor
144
+ );
145
+
146
+ // Add DML executor node to perform the actual database delete operations
147
+ const dmlExecutorNode = new DmlExecutorNode(
148
+ deleteCtx.scope,
149
+ deleteNode,
150
+ tableReference,
151
+ 'delete'
152
+ );
153
+
154
+ const resultNode: RelationalPlanNode = dmlExecutorNode;
155
+
156
+ if (stmt.returning && stmt.returning.length > 0) {
157
+ // Create returning scope with OLD/NEW attribute access
158
+ const returningScope = new RegisteredScope(deleteCtx.scope);
159
+
160
+ // Register OLD.* symbols (actual values being deleted)
161
+ oldAttributes.forEach((attr: any, columnIndex: any) => {
162
+ const tableColumn = tableReference.tableSchema.columns[columnIndex];
163
+ returningScope.registerSymbol(`old.${tableColumn.name.toLowerCase()}`, (exp, s) =>
164
+ new ColumnReferenceNode(s, exp as AST.ColumnExpr, attr.type, attr.id, columnIndex)
165
+ );
166
+ });
167
+
168
+ // Register NEW.* symbols (always NULL for DELETE) and unqualified column names (default to OLD for DELETE)
169
+ newAttributes.forEach((attr: any, columnIndex: any) => {
170
+ const tableColumn = tableReference.tableSchema.columns[columnIndex];
171
+
172
+ // NEW.column (always NULL for DELETE)
173
+ returningScope.registerSymbol(`new.${tableColumn.name.toLowerCase()}`, (exp, s) =>
174
+ new ColumnReferenceNode(s, exp as AST.ColumnExpr, attr.type, attr.id, columnIndex)
175
+ );
176
+
177
+ // Unqualified column (defaults to OLD for DELETE)
178
+ const oldAttr = oldAttributes[columnIndex];
179
+ returningScope.registerSymbol(tableColumn.name.toLowerCase(), (exp, s) =>
180
+ new ColumnReferenceNode(s, exp as AST.ColumnExpr, oldAttr.type, oldAttr.id, columnIndex)
181
+ );
182
+
183
+ // Table-qualified form (table.column -> OLD for DELETE)
184
+ const tblQualified = `${tableReference.tableSchema.name.toLowerCase()}.${tableColumn.name.toLowerCase()}`;
185
+ returningScope.registerSymbol(tblQualified, (exp, s) =>
186
+ new ColumnReferenceNode(s, exp as AST.ColumnExpr, oldAttr.type, oldAttr.id, columnIndex)
187
+ );
188
+ });
189
+
190
+ // Build RETURNING projections in the OLD/NEW context
191
+ const returningProjections = stmt.returning.map(rc => {
192
+ // TODO: Support RETURNING *
193
+ if (rc.type === 'all') throw new QuereusError('RETURNING * not yet supported', StatusCode.UNSUPPORTED);
194
+
195
+ // Infer alias from column name if not explicitly provided
196
+ let alias = rc.alias;
197
+ if (!alias && rc.expr.type === 'column') {
198
+ // For qualified column references like OLD.id, normalize to lowercase
199
+ alias = rc.expr.table
200
+ ? `${rc.expr.table.toLowerCase()}.${rc.expr.name.toLowerCase()}`
201
+ : rc.expr.name.toLowerCase();
202
+ }
203
+
204
+ return {
205
+ node: buildExpression({ ...deleteCtx, scope: returningScope }, rc.expr) as ScalarPlanNode,
206
+ alias: alias
207
+ };
208
+ });
209
+
210
+ return new ReturningNode(deleteCtx.scope, dmlExecutorNode, returningProjections);
211
+ }
212
+
213
+ return new SinkNode(deleteCtx.scope, resultNode, 'delete');
214
+ }