@quereus/quereus 0.5.2 → 0.6.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/README.md +5 -1
- package/dist/src/common/datatype.d.ts +4 -5
- package/dist/src/common/datatype.d.ts.map +1 -1
- package/dist/src/common/datatype.js.map +1 -1
- package/dist/src/common/type-inference.d.ts +3 -6
- package/dist/src/common/type-inference.d.ts.map +1 -1
- package/dist/src/common/type-inference.js +17 -22
- package/dist/src/common/type-inference.js.map +1 -1
- package/dist/src/core/param.d.ts.map +1 -1
- package/dist/src/core/param.js +3 -18
- package/dist/src/core/param.js.map +1 -1
- package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
- package/dist/src/func/builtins/aggregate.js +24 -2
- package/dist/src/func/builtins/aggregate.js.map +1 -1
- package/dist/src/func/builtins/builtin-window-functions.js +10 -10
- package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
- package/dist/src/func/builtins/conversion.d.ts +10 -0
- package/dist/src/func/builtins/conversion.d.ts.map +1 -1
- package/dist/src/func/builtins/conversion.js +20 -1
- package/dist/src/func/builtins/conversion.js.map +1 -1
- package/dist/src/func/builtins/explain.js +53 -53
- package/dist/src/func/builtins/explain.js.map +1 -1
- package/dist/src/func/builtins/generation.js +2 -2
- package/dist/src/func/builtins/generation.js.map +1 -1
- package/dist/src/func/builtins/index.d.ts.map +1 -1
- package/dist/src/func/builtins/index.js +16 -1
- package/dist/src/func/builtins/index.js.map +1 -1
- package/dist/src/func/builtins/json-tvf.js +17 -17
- package/dist/src/func/builtins/json-tvf.js.map +1 -1
- package/dist/src/func/builtins/scalar.d.ts.map +1 -1
- package/dist/src/func/builtins/scalar.js +202 -13
- package/dist/src/func/builtins/scalar.js.map +1 -1
- package/dist/src/func/builtins/schema.js +18 -18
- package/dist/src/func/builtins/schema.js.map +1 -1
- package/dist/src/func/builtins/string.d.ts.map +1 -1
- package/dist/src/func/builtins/string.js +56 -47
- package/dist/src/func/builtins/string.js.map +1 -1
- package/dist/src/func/builtins/timespan.d.ts +45 -0
- package/dist/src/func/builtins/timespan.d.ts.map +1 -0
- package/dist/src/func/builtins/timespan.js +147 -0
- package/dist/src/func/builtins/timespan.js.map +1 -0
- package/dist/src/func/registration.d.ts +26 -0
- package/dist/src/func/registration.d.ts.map +1 -1
- package/dist/src/func/registration.js +9 -5
- package/dist/src/func/registration.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/parser.js +2 -2
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/planner/building/constraint-builder.js +2 -2
- package/dist/src/planner/building/constraint-builder.js.map +1 -1
- package/dist/src/planner/building/delete.js +3 -3
- package/dist/src/planner/building/delete.js.map +1 -1
- package/dist/src/planner/building/function-call.d.ts.map +1 -1
- package/dist/src/planner/building/function-call.js +24 -4
- package/dist/src/planner/building/function-call.js.map +1 -1
- package/dist/src/planner/building/insert.js +3 -3
- package/dist/src/planner/building/insert.js.map +1 -1
- package/dist/src/planner/building/select.d.ts.map +1 -1
- package/dist/src/planner/building/select.js +3 -2
- package/dist/src/planner/building/select.js.map +1 -1
- package/dist/src/planner/building/update.js +7 -7
- package/dist/src/planner/building/update.js.map +1 -1
- package/dist/src/planner/nodes/aggregate-function.d.ts +2 -1
- package/dist/src/planner/nodes/aggregate-function.d.ts.map +1 -1
- package/dist/src/planner/nodes/aggregate-function.js +10 -3
- package/dist/src/planner/nodes/aggregate-function.js.map +1 -1
- package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cte-node.js +2 -2
- package/dist/src/planner/nodes/cte-node.js.map +1 -1
- package/dist/src/planner/nodes/declarative-schema.js +3 -3
- package/dist/src/planner/nodes/declarative-schema.js.map +1 -1
- package/dist/src/planner/nodes/function.d.ts +2 -1
- package/dist/src/planner/nodes/function.d.ts.map +1 -1
- package/dist/src/planner/nodes/function.js +6 -3
- package/dist/src/planner/nodes/function.js.map +1 -1
- package/dist/src/planner/nodes/insert-node.js +1 -1
- package/dist/src/planner/nodes/insert-node.js.map +1 -1
- package/dist/src/planner/nodes/pragma.d.ts +1 -1
- package/dist/src/planner/nodes/pragma.d.ts.map +1 -1
- package/dist/src/planner/nodes/pragma.js +3 -3
- package/dist/src/planner/nodes/pragma.js.map +1 -1
- package/dist/src/planner/nodes/reference.js +1 -1
- package/dist/src/planner/nodes/reference.js.map +1 -1
- package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
- package/dist/src/planner/nodes/scalar.js +55 -101
- package/dist/src/planner/nodes/scalar.js.map +1 -1
- package/dist/src/planner/nodes/sequencing-node.js +2 -2
- package/dist/src/planner/nodes/sequencing-node.js.map +1 -1
- package/dist/src/planner/nodes/sink-node.js +2 -2
- package/dist/src/planner/nodes/sink-node.js.map +1 -1
- package/dist/src/planner/nodes/subquery.d.ts.map +1 -1
- package/dist/src/planner/nodes/subquery.js +4 -7
- package/dist/src/planner/nodes/subquery.js.map +1 -1
- package/dist/src/planner/nodes/view-reference-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/view-reference-node.js +2 -2
- package/dist/src/planner/nodes/view-reference-node.js.map +1 -1
- package/dist/src/planner/nodes/window-function.js +3 -3
- package/dist/src/planner/nodes/window-function.js.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
- package/dist/src/planner/scopes/global.js +3 -3
- package/dist/src/planner/scopes/global.js.map +1 -1
- package/dist/src/planner/scopes/param.d.ts.map +1 -1
- package/dist/src/planner/scopes/param.js +2 -2
- package/dist/src/planner/scopes/param.js.map +1 -1
- package/dist/src/planner/type-utils.d.ts +2 -12
- package/dist/src/planner/type-utils.d.ts.map +1 -1
- package/dist/src/planner/type-utils.js +6 -21
- package/dist/src/planner/type-utils.js.map +1 -1
- package/dist/src/runtime/emit/binary.d.ts.map +1 -1
- package/dist/src/runtime/emit/binary.js +40 -2
- package/dist/src/runtime/emit/binary.js.map +1 -1
- package/dist/src/runtime/emit/temporal-arithmetic.d.ts +33 -0
- package/dist/src/runtime/emit/temporal-arithmetic.d.ts.map +1 -0
- package/dist/src/runtime/emit/temporal-arithmetic.js +269 -0
- package/dist/src/runtime/emit/temporal-arithmetic.js.map +1 -0
- package/dist/src/runtime/emit/unary.d.ts.map +1 -1
- package/dist/src/runtime/emit/unary.js +12 -0
- package/dist/src/runtime/emit/unary.js.map +1 -1
- package/dist/src/schema/catalog.js +3 -3
- package/dist/src/schema/catalog.js.map +1 -1
- package/dist/src/schema/column.d.ts +0 -3
- package/dist/src/schema/column.d.ts.map +1 -1
- package/dist/src/schema/column.js +0 -2
- package/dist/src/schema/column.js.map +1 -1
- package/dist/src/schema/function.d.ts +29 -1
- package/dist/src/schema/function.d.ts.map +1 -1
- package/dist/src/schema/function.js.map +1 -1
- package/dist/src/schema/table.d.ts +3 -3
- package/dist/src/schema/table.d.ts.map +1 -1
- package/dist/src/schema/table.js +4 -6
- package/dist/src/schema/table.js.map +1 -1
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +1 -1
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/registry.d.ts.map +1 -1
- package/dist/src/types/registry.js +5 -1
- package/dist/src/types/registry.js.map +1 -1
- package/dist/src/types/temporal-types.d.ts +5 -0
- package/dist/src/types/temporal-types.d.ts.map +1 -1
- package/dist/src/types/temporal-types.js +122 -0
- package/dist/src/types/temporal-types.js.map +1 -1
- package/dist/src/util/plan-formatter.d.ts.map +1 -1
- package/dist/src/util/plan-formatter.js +1 -5
- package/dist/src/util/plan-formatter.js.map +1 -1
- package/dist/src/util/row-descriptor.js +2 -2
- package/dist/src/util/row-descriptor.js.map +1 -1
- package/dist/src/vtab/best-access-plan.d.ts +4 -3
- package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
- package/dist/src/vtab/best-access-plan.js.map +1 -1
- package/dist/src/vtab/memory/module.js +1 -1
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/package.json +1 -1
- package/src/common/datatype.ts +4 -5
- package/src/common/type-inference.ts +13 -22
- package/src/core/param.ts +4 -11
- package/src/func/builtins/aggregate.ts +24 -2
- package/src/func/builtins/builtin-window-functions.ts +10 -10
- package/src/func/builtins/conversion.ts +26 -1
- package/src/func/builtins/explain.ts +53 -53
- package/src/func/builtins/generation.ts +2 -2
- package/src/func/builtins/index.ts +20 -1
- package/src/func/builtins/json-tvf.ts +17 -17
- package/src/func/builtins/scalar.ts +205 -14
- package/src/func/builtins/schema.ts +18 -18
- package/src/func/builtins/string.ts +91 -78
- package/src/func/builtins/timespan.ts +179 -0
- package/src/func/registration.ts +35 -5
- package/src/index.ts +2 -1
- package/src/parser/parser.ts +2 -2
- package/src/planner/building/constraint-builder.ts +2 -2
- package/src/planner/building/delete.ts +3 -3
- package/src/planner/building/function-call.ts +44 -3
- package/src/planner/building/insert.ts +3 -3
- package/src/planner/building/select.ts +3 -2
- package/src/planner/building/update.ts +7 -7
- package/src/planner/nodes/aggregate-function.ts +13 -3
- package/src/planner/nodes/cte-node.ts +2 -2
- package/src/planner/nodes/declarative-schema.ts +3 -3
- package/src/planner/nodes/function.ts +8 -3
- package/src/planner/nodes/insert-node.ts +1 -1
- package/src/planner/nodes/pragma.ts +4 -3
- package/src/planner/nodes/reference.ts +1 -1
- package/src/planner/nodes/scalar.ts +54 -102
- package/src/planner/nodes/sequencing-node.ts +2 -2
- package/src/planner/nodes/sink-node.ts +2 -2
- package/src/planner/nodes/subquery.ts +5 -7
- package/src/planner/nodes/view-reference-node.ts +2 -2
- package/src/planner/nodes/window-function.ts +3 -3
- package/src/planner/rules/access/rule-select-access-path.ts +1 -1
- package/src/planner/rules/retrieve/rule-grow-retrieve.ts +1 -1
- package/src/planner/scopes/global.ts +3 -3
- package/src/planner/scopes/param.ts +2 -2
- package/src/planner/type-utils.ts +6 -14
- package/src/runtime/emit/binary.ts +48 -2
- package/src/runtime/emit/temporal-arithmetic.ts +302 -0
- package/src/runtime/emit/unary.ts +13 -0
- package/src/schema/catalog.ts +3 -3
- package/src/schema/column.ts +0 -3
- package/src/schema/function.ts +29 -1
- package/src/schema/table.ts +5 -7
- package/src/types/index.ts +1 -1
- package/src/types/registry.ts +5 -1
- package/src/types/temporal-types.ts +123 -0
- package/src/util/plan-formatter.ts +1 -4
- package/src/util/row-descriptor.ts +2 -2
- package/src/vtab/best-access-plan.ts +4 -3
- package/src/vtab/memory/module.ts +1 -1
package/src/schema/catalog.ts
CHANGED
|
@@ -101,7 +101,7 @@ function tableSchemaToCatalog(tableSchema: TableSchema): CatalogTable {
|
|
|
101
101
|
|
|
102
102
|
const columns = tableSchema.columns.map(col => ({
|
|
103
103
|
name: col.name,
|
|
104
|
-
type: col.
|
|
104
|
+
type: col.logicalType.name,
|
|
105
105
|
notNull: col.notNull,
|
|
106
106
|
primaryKey: col.primaryKey
|
|
107
107
|
}));
|
|
@@ -165,8 +165,8 @@ function generateTableDDL(tableSchema: TableSchema): string {
|
|
|
165
165
|
const columnDefs: string[] = [];
|
|
166
166
|
for (const col of tableSchema.columns) {
|
|
167
167
|
let colDef = `"${col.name}"`;
|
|
168
|
-
if (col.
|
|
169
|
-
colDef += ` ${col.
|
|
168
|
+
if (col.logicalType) {
|
|
169
|
+
colDef += ` ${col.logicalType.name}`;
|
|
170
170
|
}
|
|
171
171
|
if (col.notNull) {
|
|
172
172
|
colDef += ' NOT NULL';
|
package/src/schema/column.ts
CHANGED
|
@@ -10,8 +10,6 @@ export interface ColumnSchema {
|
|
|
10
10
|
name: string;
|
|
11
11
|
/** Logical type definition */
|
|
12
12
|
logicalType: LogicalType;
|
|
13
|
-
/** Data type affinity (TEXT, INTEGER, REAL, BLOB, NUMERIC) - kept for backward compatibility during transition */
|
|
14
|
-
affinity: SqlDataType;
|
|
15
13
|
/** Whether the column has a NOT NULL constraint */
|
|
16
14
|
notNull: boolean;
|
|
17
15
|
/** Whether the column is part of the primary key */
|
|
@@ -43,7 +41,6 @@ export function createDefaultColumnSchema(name: string, defaultNotNull: boolean
|
|
|
43
41
|
return {
|
|
44
42
|
name: name,
|
|
45
43
|
logicalType: TEXT_TYPE,
|
|
46
|
-
affinity: SqlDataType.TEXT,
|
|
47
44
|
notNull: defaultNotNull, // Third Manifesto: default to NOT NULL
|
|
48
45
|
primaryKey: false,
|
|
49
46
|
pkOrder: 0,
|
package/src/schema/function.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { MaybePromise, Row, SqlValue } from '../common/types.js';
|
|
1
|
+
import type { MaybePromise, Row, SqlValue, DeepReadonly } from '../common/types.js';
|
|
2
2
|
import { FunctionFlags } from '../common/constants.js';
|
|
3
3
|
import { SqlDataType } from '../common/types.js';
|
|
4
4
|
import type { Database } from '../core/database.js';
|
|
5
5
|
import type { BaseType, ScalarType, RelationType } from '../common/datatype.js';
|
|
6
6
|
import type { AggValue } from '../func/registration.js';
|
|
7
|
+
import type { LogicalType } from '../types/logical-type.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Type for a scalar function implementation.
|
|
@@ -74,6 +75,21 @@ export interface ScalarFunctionSchema extends BaseFunctionSchema {
|
|
|
74
75
|
returnType: ScalarType;
|
|
75
76
|
/** Direct scalar function implementation */
|
|
76
77
|
implementation: ScalarFunc;
|
|
78
|
+
/**
|
|
79
|
+
* Optional type inference function for polymorphic functions.
|
|
80
|
+
* If provided, this function will be called at planning time to determine
|
|
81
|
+
* the return type based on the actual argument types.
|
|
82
|
+
* This allows functions like abs() to return INTEGER when given INTEGER,
|
|
83
|
+
* and REAL when given REAL.
|
|
84
|
+
*/
|
|
85
|
+
inferReturnType?: (argTypes: ReadonlyArray<DeepReadonly<LogicalType>>) => ScalarType;
|
|
86
|
+
/**
|
|
87
|
+
* Optional argument type validation function.
|
|
88
|
+
* If provided, this function will be called at planning time to validate
|
|
89
|
+
* that the argument types are acceptable for this function.
|
|
90
|
+
* Should return true if types are valid, false otherwise.
|
|
91
|
+
*/
|
|
92
|
+
validateArgTypes?: (argTypes: ReadonlyArray<DeepReadonly<LogicalType>>) => boolean;
|
|
77
93
|
}
|
|
78
94
|
|
|
79
95
|
/**
|
|
@@ -98,6 +114,18 @@ export interface AggregateFunctionSchema extends BaseFunctionSchema {
|
|
|
98
114
|
finalizeFunction: AggregateFinalizer;
|
|
99
115
|
/** Initial accumulator value for aggregates */
|
|
100
116
|
initialValue?: AggValue;
|
|
117
|
+
/**
|
|
118
|
+
* Optional type inference function for polymorphic aggregate functions.
|
|
119
|
+
* If provided, this function will be called at planning time to determine
|
|
120
|
+
* the return type based on the actual argument types.
|
|
121
|
+
*/
|
|
122
|
+
inferReturnType?: (argTypes: ReadonlyArray<DeepReadonly<LogicalType>>) => ScalarType;
|
|
123
|
+
/**
|
|
124
|
+
* Optional argument type validation function.
|
|
125
|
+
* If provided, this function will be called at planning time to validate
|
|
126
|
+
* that the argument types are acceptable for this function.
|
|
127
|
+
*/
|
|
128
|
+
validateArgTypes?: (argTypes: ReadonlyArray<DeepReadonly<LogicalType>>) => boolean;
|
|
101
129
|
}
|
|
102
130
|
|
|
103
131
|
/**
|
package/src/schema/table.ts
CHANGED
|
@@ -3,7 +3,6 @@ import type { AnyVirtualTableModule } from '../vtab/module.js';
|
|
|
3
3
|
import { MemoryTableModule } from '../vtab/memory/module.js';
|
|
4
4
|
import type { Expression } from '../parser/ast.js';
|
|
5
5
|
import { type ColumnDef, type TableConstraint } from '../parser/ast.js';
|
|
6
|
-
import { getAffinity } from '../common/type-inference.js';
|
|
7
6
|
import { RowOp, SqlDataType, StatusCode, type SqlValue } from '../common/types.js';
|
|
8
7
|
import type * as AST from '../parser/ast.js';
|
|
9
8
|
import { quereusError, QuereusError } from '../common/errors.js';
|
|
@@ -99,7 +98,6 @@ export function columnDefToSchema(def: ColumnDef, defaultNotNull: boolean = true
|
|
|
99
98
|
const schema: Partial<ColumnSchema> & { name: string } = {
|
|
100
99
|
name: def.name,
|
|
101
100
|
logicalType: logicalType,
|
|
102
|
-
affinity: getAffinity(def.dataType), // Keep for backward compatibility during transition
|
|
103
101
|
notNull: defaultNotNull, // Default based on Third Manifesto principles
|
|
104
102
|
primaryKey: false,
|
|
105
103
|
pkOrder: 0,
|
|
@@ -166,8 +164,8 @@ export function columnDefToSchema(def: ColumnDef, defaultNotNull: boolean = true
|
|
|
166
164
|
export interface MutationContextDefinition {
|
|
167
165
|
/** Variable name */
|
|
168
166
|
name: string;
|
|
169
|
-
/**
|
|
170
|
-
|
|
167
|
+
/** Logical type of the variable */
|
|
168
|
+
logicalType: import('../types/logical-type.js').LogicalType;
|
|
171
169
|
/** Whether the variable is NOT NULL */
|
|
172
170
|
notNull: boolean;
|
|
173
171
|
}
|
|
@@ -182,7 +180,7 @@ export interface MutationContextDefinition {
|
|
|
182
180
|
export function mutationContextVarToSchema(varDef: AST.MutationContextVar, defaultNotNull: boolean = true): MutationContextDefinition {
|
|
183
181
|
return {
|
|
184
182
|
name: varDef.name,
|
|
185
|
-
|
|
183
|
+
logicalType: inferType(varDef.dataType),
|
|
186
184
|
notNull: varDef.notNull !== undefined ? varDef.notNull : defaultNotNull,
|
|
187
185
|
};
|
|
188
186
|
}
|
|
@@ -403,8 +401,8 @@ function findColumnPKDefinition(columns: ReadonlyArray<ColumnSchema>): ReadonlyA
|
|
|
403
401
|
|
|
404
402
|
return Object.freeze(pkCols.map(col => ({
|
|
405
403
|
index: col.originalIndex,
|
|
406
|
-
desc: col.
|
|
407
|
-
autoIncrement: col.
|
|
404
|
+
desc: col.logicalType.name === 'INTEGER' && col.pkDirection === 'desc',
|
|
405
|
+
autoIncrement: col.logicalType.name === 'INTEGER',
|
|
408
406
|
collation: col.collation || 'BINARY'
|
|
409
407
|
})));
|
|
410
408
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { PhysicalType, type LogicalType, getPhysicalType } from './logical-type.
|
|
|
5
5
|
export { NULL_TYPE, INTEGER_TYPE, REAL_TYPE, TEXT_TYPE, BLOB_TYPE, BOOLEAN_TYPE, NUMERIC_TYPE, ANY_TYPE } from './builtin-types.js';
|
|
6
6
|
|
|
7
7
|
// Temporal types
|
|
8
|
-
export { DATE_TYPE, TIME_TYPE, DATETIME_TYPE } from './temporal-types.js';
|
|
8
|
+
export { DATE_TYPE, TIME_TYPE, DATETIME_TYPE, TIMESPAN_TYPE } from './temporal-types.js';
|
|
9
9
|
|
|
10
10
|
// JSON type
|
|
11
11
|
export { JSON_TYPE } from './json-type.js';
|
package/src/types/registry.ts
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
NUMERIC_TYPE,
|
|
10
10
|
ANY_TYPE,
|
|
11
11
|
} from './builtin-types.js';
|
|
12
|
-
import { DATE_TYPE, TIME_TYPE, DATETIME_TYPE } from './temporal-types.js';
|
|
12
|
+
import { DATE_TYPE, TIME_TYPE, DATETIME_TYPE, TIMESPAN_TYPE } from './temporal-types.js';
|
|
13
13
|
import { JSON_TYPE } from './json-type.js';
|
|
14
14
|
import { createLogger } from '../common/logger.js';
|
|
15
15
|
|
|
@@ -36,9 +36,13 @@ class TypeRegistry {
|
|
|
36
36
|
this.registerType(DATE_TYPE);
|
|
37
37
|
this.registerType(TIME_TYPE);
|
|
38
38
|
this.registerType(DATETIME_TYPE);
|
|
39
|
+
this.registerType(TIMESPAN_TYPE);
|
|
39
40
|
this.registerType(JSON_TYPE);
|
|
40
41
|
|
|
41
42
|
// Register common aliases
|
|
43
|
+
// Temporal type aliases
|
|
44
|
+
this.types.set('INTERVAL', TIMESPAN_TYPE); // SQL standard alias
|
|
45
|
+
this.types.set('DURATION', TIMESPAN_TYPE); // Alternative name
|
|
42
46
|
this.types.set('INT', INTEGER_TYPE);
|
|
43
47
|
this.types.set('BIGINT', INTEGER_TYPE);
|
|
44
48
|
this.types.set('SMALLINT', INTEGER_TYPE);
|
|
@@ -165,3 +165,126 @@ export const DATETIME_TYPE: LogicalType = {
|
|
|
165
165
|
supportedCollations: [],
|
|
166
166
|
};
|
|
167
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Parse human-readable duration strings into Temporal.Duration
|
|
170
|
+
* Supports formats like "1 hour", "30 minutes", "2 days 3 hours"
|
|
171
|
+
*/
|
|
172
|
+
function parseHumanReadableDuration(input: string): Temporal.Duration | null {
|
|
173
|
+
const normalized = input.trim().toLowerCase();
|
|
174
|
+
|
|
175
|
+
// Handle negative durations
|
|
176
|
+
const isNegative = normalized.startsWith('-');
|
|
177
|
+
const workingInput = isNegative ? normalized.substring(1).trim() : normalized;
|
|
178
|
+
|
|
179
|
+
// Pattern: [number] [unit]
|
|
180
|
+
// Units: year(s), month(s), week(s), day(s), hour(s), minute(s), second(s), min(s), sec(s)
|
|
181
|
+
const pattern = /(\d+(?:\.\d+)?)\s*(years?|months?|weeks?|days?|hours?|minutes?|seconds?|mins?|secs?)/g;
|
|
182
|
+
|
|
183
|
+
const components: Record<string, number> = {};
|
|
184
|
+
let match;
|
|
185
|
+
let hasMatch = false;
|
|
186
|
+
|
|
187
|
+
while ((match = pattern.exec(workingInput)) !== null) {
|
|
188
|
+
hasMatch = true;
|
|
189
|
+
const value = parseFloat(match[1]);
|
|
190
|
+
const unit = match[2];
|
|
191
|
+
|
|
192
|
+
// Map unit to Temporal.Duration field
|
|
193
|
+
if (unit.startsWith('year')) {
|
|
194
|
+
components.years = (components.years || 0) + value;
|
|
195
|
+
} else if (unit.startsWith('month')) {
|
|
196
|
+
components.months = (components.months || 0) + value;
|
|
197
|
+
} else if (unit.startsWith('week')) {
|
|
198
|
+
components.weeks = (components.weeks || 0) + value;
|
|
199
|
+
} else if (unit.startsWith('day')) {
|
|
200
|
+
components.days = (components.days || 0) + value;
|
|
201
|
+
} else if (unit.startsWith('hour')) {
|
|
202
|
+
components.hours = (components.hours || 0) + value;
|
|
203
|
+
} else if (unit.startsWith('min')) {
|
|
204
|
+
components.minutes = (components.minutes || 0) + value;
|
|
205
|
+
} else if (unit.startsWith('sec')) {
|
|
206
|
+
components.seconds = (components.seconds || 0) + value;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (!hasMatch) return null;
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
const duration = Temporal.Duration.from(components);
|
|
214
|
+
return isNegative ? duration.negated() : duration;
|
|
215
|
+
} catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* TIMESPAN type - stores ISO 8601 duration strings
|
|
222
|
+
* Uses Temporal.Duration for validation and parsing
|
|
223
|
+
*/
|
|
224
|
+
export const TIMESPAN_TYPE: LogicalType = {
|
|
225
|
+
name: 'TIMESPAN',
|
|
226
|
+
physicalType: PhysicalType.TEXT,
|
|
227
|
+
isTemporal: true,
|
|
228
|
+
|
|
229
|
+
validate: (v) => {
|
|
230
|
+
if (v === null) return true;
|
|
231
|
+
if (typeof v !== 'string') return false;
|
|
232
|
+
try {
|
|
233
|
+
Temporal.Duration.from(v);
|
|
234
|
+
return true;
|
|
235
|
+
} catch {
|
|
236
|
+
// Try parsing human-readable format
|
|
237
|
+
return parseHumanReadableDuration(v) !== null;
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
parse: (v) => {
|
|
242
|
+
if (v === null) return null;
|
|
243
|
+
|
|
244
|
+
if (typeof v === 'number') {
|
|
245
|
+
// Interpret as seconds
|
|
246
|
+
const duration = Temporal.Duration.from({ seconds: v });
|
|
247
|
+
return duration.toString();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (typeof v === 'string') {
|
|
251
|
+
try {
|
|
252
|
+
// Try ISO 8601 first
|
|
253
|
+
const duration = Temporal.Duration.from(v);
|
|
254
|
+
return duration.toString();
|
|
255
|
+
} catch {
|
|
256
|
+
// Try human-readable format
|
|
257
|
+
const duration = parseHumanReadableDuration(v);
|
|
258
|
+
if (duration) return duration.toString();
|
|
259
|
+
throw new TypeError(`Cannot convert '${v}' to TIMESPAN`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
throw new TypeError(`Cannot convert ${typeof v} to TIMESPAN`);
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
compare: (a, b) => {
|
|
267
|
+
if (a === null && b === null) return 0;
|
|
268
|
+
if (a === null) return -1;
|
|
269
|
+
if (b === null) return 1;
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
const durationA = Temporal.Duration.from(a as string);
|
|
273
|
+
const durationB = Temporal.Duration.from(b as string);
|
|
274
|
+
|
|
275
|
+
// Use a reference date to resolve calendar units
|
|
276
|
+
// This ensures consistent comparison of durations with months/years
|
|
277
|
+
const referenceDate = Temporal.PlainDate.from('2024-01-01');
|
|
278
|
+
const totalA = durationA.total({ unit: 'seconds', relativeTo: referenceDate });
|
|
279
|
+
const totalB = durationB.total({ unit: 'seconds', relativeTo: referenceDate });
|
|
280
|
+
|
|
281
|
+
return totalA < totalB ? -1 : totalA > totalB ? 1 : 0;
|
|
282
|
+
} catch {
|
|
283
|
+
// If parsing fails, fall back to string comparison
|
|
284
|
+
return (a as string).localeCompare(b as string);
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
supportedCollations: [],
|
|
289
|
+
};
|
|
290
|
+
|
|
@@ -21,10 +21,7 @@ export function formatExpressionList(nodes: readonly ScalarPlanNode[]): string {
|
|
|
21
21
|
* Format a scalar type to a simple string representation.
|
|
22
22
|
*/
|
|
23
23
|
export function formatScalarType(type: ScalarType): string {
|
|
24
|
-
|
|
25
|
-
return SqlDataType[type.datatype];
|
|
26
|
-
}
|
|
27
|
-
return SqlDataType[type.affinity];
|
|
24
|
+
return type.logicalType.name;
|
|
28
25
|
}
|
|
29
26
|
|
|
30
27
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RowDescriptor, Attribute } from '../planner/nodes/plan-node.js';
|
|
2
2
|
import type { Row } from '../common/types.js';
|
|
3
|
-
import {
|
|
3
|
+
import { TEXT_TYPE } from '../types/builtin-types.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Utility to build a RowDescriptor (attributeId → columnIndex mapping)
|
|
@@ -94,7 +94,7 @@ export function buildAttributesFromFlatDescriptor(flatRowDescriptor: RowDescript
|
|
|
94
94
|
name: `attr_${attrId}`,
|
|
95
95
|
type: {
|
|
96
96
|
typeClass: 'scalar' as const,
|
|
97
|
-
|
|
97
|
+
logicalType: TEXT_TYPE,
|
|
98
98
|
nullable: true,
|
|
99
99
|
isReadOnly: false
|
|
100
100
|
},
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
7
7
|
import { quereusError } from '../common/errors.js';
|
|
8
|
-
import { StatusCode, type
|
|
8
|
+
import { StatusCode, type SqlValue } from '../common/types.js';
|
|
9
|
+
import type { LogicalType } from '../types/logical-type.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Constraint operators that can be pushed down to virtual tables
|
|
@@ -20,8 +21,8 @@ export interface ColumnMeta {
|
|
|
20
21
|
index: number;
|
|
21
22
|
/** Column name */
|
|
22
23
|
name: string;
|
|
23
|
-
/**
|
|
24
|
-
type:
|
|
24
|
+
/** Logical type information */
|
|
25
|
+
type: LogicalType;
|
|
25
26
|
/** Whether this column is part of the primary key */
|
|
26
27
|
isPrimaryKey: boolean;
|
|
27
28
|
/** Whether this column has a unique constraint */
|
|
@@ -103,7 +103,7 @@ export class MemoryTableModule implements VirtualTableModule<MemoryTable, Memory
|
|
|
103
103
|
return tableInfo.columns.map((col, index) => ({
|
|
104
104
|
index,
|
|
105
105
|
name: col.name,
|
|
106
|
-
type: col.
|
|
106
|
+
type: col.logicalType,
|
|
107
107
|
isPrimaryKey: tableInfo.primaryKeyDefinition.some(pk => pk.index === index),
|
|
108
108
|
isUnique: col.primaryKey // Primary key columns are unique, others would be determined by constraints/indexes
|
|
109
109
|
}));
|