@quereus/quereus 0.5.2 → 0.6.1

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 (226) hide show
  1. package/README.md +5 -1
  2. package/dist/src/common/datatype.d.ts +4 -5
  3. package/dist/src/common/datatype.d.ts.map +1 -1
  4. package/dist/src/common/datatype.js.map +1 -1
  5. package/dist/src/common/type-inference.d.ts +3 -6
  6. package/dist/src/common/type-inference.d.ts.map +1 -1
  7. package/dist/src/common/type-inference.js +17 -22
  8. package/dist/src/common/type-inference.js.map +1 -1
  9. package/dist/src/core/param.d.ts.map +1 -1
  10. package/dist/src/core/param.js +3 -18
  11. package/dist/src/core/param.js.map +1 -1
  12. package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
  13. package/dist/src/func/builtins/aggregate.js +24 -2
  14. package/dist/src/func/builtins/aggregate.js.map +1 -1
  15. package/dist/src/func/builtins/builtin-window-functions.js +10 -10
  16. package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
  17. package/dist/src/func/builtins/conversion.d.ts +10 -0
  18. package/dist/src/func/builtins/conversion.d.ts.map +1 -1
  19. package/dist/src/func/builtins/conversion.js +20 -1
  20. package/dist/src/func/builtins/conversion.js.map +1 -1
  21. package/dist/src/func/builtins/datetime.js +9 -9
  22. package/dist/src/func/builtins/datetime.js.map +1 -1
  23. package/dist/src/func/builtins/explain.js +53 -53
  24. package/dist/src/func/builtins/explain.js.map +1 -1
  25. package/dist/src/func/builtins/generation.js +2 -2
  26. package/dist/src/func/builtins/generation.js.map +1 -1
  27. package/dist/src/func/builtins/index.d.ts.map +1 -1
  28. package/dist/src/func/builtins/index.js +16 -1
  29. package/dist/src/func/builtins/index.js.map +1 -1
  30. package/dist/src/func/builtins/json-tvf.js +17 -17
  31. package/dist/src/func/builtins/json-tvf.js.map +1 -1
  32. package/dist/src/func/builtins/json.js +11 -11
  33. package/dist/src/func/builtins/json.js.map +1 -1
  34. package/dist/src/func/builtins/scalar.d.ts.map +1 -1
  35. package/dist/src/func/builtins/scalar.js +202 -13
  36. package/dist/src/func/builtins/scalar.js.map +1 -1
  37. package/dist/src/func/builtins/schema.js +18 -18
  38. package/dist/src/func/builtins/schema.js.map +1 -1
  39. package/dist/src/func/builtins/string.d.ts.map +1 -1
  40. package/dist/src/func/builtins/string.js +59 -50
  41. package/dist/src/func/builtins/string.js.map +1 -1
  42. package/dist/src/func/builtins/timespan.d.ts +45 -0
  43. package/dist/src/func/builtins/timespan.d.ts.map +1 -0
  44. package/dist/src/func/builtins/timespan.js +147 -0
  45. package/dist/src/func/builtins/timespan.js.map +1 -0
  46. package/dist/src/func/registration.d.ts +26 -0
  47. package/dist/src/func/registration.d.ts.map +1 -1
  48. package/dist/src/func/registration.js +9 -5
  49. package/dist/src/func/registration.js.map +1 -1
  50. package/dist/src/index.d.ts +1 -1
  51. package/dist/src/index.d.ts.map +1 -1
  52. package/dist/src/index.js +1 -1
  53. package/dist/src/index.js.map +1 -1
  54. package/dist/src/parser/parser.js +2 -2
  55. package/dist/src/parser/parser.js.map +1 -1
  56. package/dist/src/planner/building/constraint-builder.js +2 -2
  57. package/dist/src/planner/building/constraint-builder.js.map +1 -1
  58. package/dist/src/planner/building/delete.js +3 -3
  59. package/dist/src/planner/building/delete.js.map +1 -1
  60. package/dist/src/planner/building/function-call.d.ts.map +1 -1
  61. package/dist/src/planner/building/function-call.js +24 -4
  62. package/dist/src/planner/building/function-call.js.map +1 -1
  63. package/dist/src/planner/building/insert.js +3 -3
  64. package/dist/src/planner/building/insert.js.map +1 -1
  65. package/dist/src/planner/building/select.d.ts.map +1 -1
  66. package/dist/src/planner/building/select.js +3 -2
  67. package/dist/src/planner/building/select.js.map +1 -1
  68. package/dist/src/planner/building/update.js +7 -7
  69. package/dist/src/planner/building/update.js.map +1 -1
  70. package/dist/src/planner/nodes/aggregate-function.d.ts +2 -1
  71. package/dist/src/planner/nodes/aggregate-function.d.ts.map +1 -1
  72. package/dist/src/planner/nodes/aggregate-function.js +10 -3
  73. package/dist/src/planner/nodes/aggregate-function.js.map +1 -1
  74. package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
  75. package/dist/src/planner/nodes/cte-node.js +2 -2
  76. package/dist/src/planner/nodes/cte-node.js.map +1 -1
  77. package/dist/src/planner/nodes/declarative-schema.js +3 -3
  78. package/dist/src/planner/nodes/declarative-schema.js.map +1 -1
  79. package/dist/src/planner/nodes/function.d.ts +2 -1
  80. package/dist/src/planner/nodes/function.d.ts.map +1 -1
  81. package/dist/src/planner/nodes/function.js +6 -3
  82. package/dist/src/planner/nodes/function.js.map +1 -1
  83. package/dist/src/planner/nodes/insert-node.js +1 -1
  84. package/dist/src/planner/nodes/insert-node.js.map +1 -1
  85. package/dist/src/planner/nodes/pragma.d.ts +1 -1
  86. package/dist/src/planner/nodes/pragma.d.ts.map +1 -1
  87. package/dist/src/planner/nodes/pragma.js +3 -3
  88. package/dist/src/planner/nodes/pragma.js.map +1 -1
  89. package/dist/src/planner/nodes/reference.js +1 -1
  90. package/dist/src/planner/nodes/reference.js.map +1 -1
  91. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  92. package/dist/src/planner/nodes/scalar.js +55 -101
  93. package/dist/src/planner/nodes/scalar.js.map +1 -1
  94. package/dist/src/planner/nodes/sequencing-node.js +2 -2
  95. package/dist/src/planner/nodes/sequencing-node.js.map +1 -1
  96. package/dist/src/planner/nodes/sink-node.js +2 -2
  97. package/dist/src/planner/nodes/sink-node.js.map +1 -1
  98. package/dist/src/planner/nodes/subquery.d.ts.map +1 -1
  99. package/dist/src/planner/nodes/subquery.js +4 -7
  100. package/dist/src/planner/nodes/subquery.js.map +1 -1
  101. package/dist/src/planner/nodes/view-reference-node.d.ts.map +1 -1
  102. package/dist/src/planner/nodes/view-reference-node.js +2 -2
  103. package/dist/src/planner/nodes/view-reference-node.js.map +1 -1
  104. package/dist/src/planner/nodes/window-function.js +3 -3
  105. package/dist/src/planner/nodes/window-function.js.map +1 -1
  106. package/dist/src/planner/rules/access/rule-select-access-path.js +1 -1
  107. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  108. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +1 -1
  109. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
  110. package/dist/src/planner/scopes/global.js +3 -3
  111. package/dist/src/planner/scopes/global.js.map +1 -1
  112. package/dist/src/planner/scopes/param.d.ts.map +1 -1
  113. package/dist/src/planner/scopes/param.js +2 -2
  114. package/dist/src/planner/scopes/param.js.map +1 -1
  115. package/dist/src/planner/type-utils.d.ts +2 -12
  116. package/dist/src/planner/type-utils.d.ts.map +1 -1
  117. package/dist/src/planner/type-utils.js +6 -21
  118. package/dist/src/planner/type-utils.js.map +1 -1
  119. package/dist/src/runtime/emit/between.js +2 -2
  120. package/dist/src/runtime/emit/between.js.map +1 -1
  121. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  122. package/dist/src/runtime/emit/binary.js +66 -30
  123. package/dist/src/runtime/emit/binary.js.map +1 -1
  124. package/dist/src/runtime/emit/subquery.js +8 -8
  125. package/dist/src/runtime/emit/subquery.js.map +1 -1
  126. package/dist/src/runtime/emit/temporal-arithmetic.d.ts +33 -0
  127. package/dist/src/runtime/emit/temporal-arithmetic.d.ts.map +1 -0
  128. package/dist/src/runtime/emit/temporal-arithmetic.js +269 -0
  129. package/dist/src/runtime/emit/temporal-arithmetic.js.map +1 -0
  130. package/dist/src/runtime/emit/unary.d.ts.map +1 -1
  131. package/dist/src/runtime/emit/unary.js +16 -4
  132. package/dist/src/runtime/emit/unary.js.map +1 -1
  133. package/dist/src/schema/catalog.js +3 -3
  134. package/dist/src/schema/catalog.js.map +1 -1
  135. package/dist/src/schema/column.d.ts +0 -3
  136. package/dist/src/schema/column.d.ts.map +1 -1
  137. package/dist/src/schema/column.js +0 -2
  138. package/dist/src/schema/column.js.map +1 -1
  139. package/dist/src/schema/function.d.ts +29 -1
  140. package/dist/src/schema/function.d.ts.map +1 -1
  141. package/dist/src/schema/function.js.map +1 -1
  142. package/dist/src/schema/table.d.ts +3 -3
  143. package/dist/src/schema/table.d.ts.map +1 -1
  144. package/dist/src/schema/table.js +4 -6
  145. package/dist/src/schema/table.js.map +1 -1
  146. package/dist/src/types/index.d.ts +1 -1
  147. package/dist/src/types/index.d.ts.map +1 -1
  148. package/dist/src/types/index.js +1 -1
  149. package/dist/src/types/index.js.map +1 -1
  150. package/dist/src/types/registry.d.ts.map +1 -1
  151. package/dist/src/types/registry.js +5 -1
  152. package/dist/src/types/registry.js.map +1 -1
  153. package/dist/src/types/temporal-types.d.ts +5 -0
  154. package/dist/src/types/temporal-types.d.ts.map +1 -1
  155. package/dist/src/types/temporal-types.js +122 -0
  156. package/dist/src/types/temporal-types.js.map +1 -1
  157. package/dist/src/util/plan-formatter.d.ts.map +1 -1
  158. package/dist/src/util/plan-formatter.js +1 -5
  159. package/dist/src/util/plan-formatter.js.map +1 -1
  160. package/dist/src/util/row-descriptor.js +2 -2
  161. package/dist/src/util/row-descriptor.js.map +1 -1
  162. package/dist/src/vtab/best-access-plan.d.ts +4 -3
  163. package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
  164. package/dist/src/vtab/best-access-plan.js.map +1 -1
  165. package/dist/src/vtab/memory/module.js +1 -1
  166. package/dist/src/vtab/memory/module.js.map +1 -1
  167. package/package.json +1 -1
  168. package/src/common/datatype.ts +4 -5
  169. package/src/common/type-inference.ts +13 -22
  170. package/src/core/param.ts +4 -11
  171. package/src/func/builtins/aggregate.ts +24 -2
  172. package/src/func/builtins/builtin-window-functions.ts +10 -10
  173. package/src/func/builtins/conversion.ts +26 -1
  174. package/src/func/builtins/datetime.ts +9 -9
  175. package/src/func/builtins/explain.ts +53 -53
  176. package/src/func/builtins/generation.ts +2 -2
  177. package/src/func/builtins/index.ts +20 -1
  178. package/src/func/builtins/json-tvf.ts +17 -17
  179. package/src/func/builtins/json.ts +11 -11
  180. package/src/func/builtins/scalar.ts +205 -14
  181. package/src/func/builtins/schema.ts +18 -18
  182. package/src/func/builtins/string.ts +93 -80
  183. package/src/func/builtins/timespan.ts +179 -0
  184. package/src/func/registration.ts +35 -5
  185. package/src/index.ts +2 -1
  186. package/src/parser/parser.ts +2 -2
  187. package/src/planner/building/constraint-builder.ts +2 -2
  188. package/src/planner/building/delete.ts +3 -3
  189. package/src/planner/building/function-call.ts +44 -3
  190. package/src/planner/building/insert.ts +3 -3
  191. package/src/planner/building/select.ts +3 -2
  192. package/src/planner/building/update.ts +7 -7
  193. package/src/planner/nodes/aggregate-function.ts +13 -3
  194. package/src/planner/nodes/cte-node.ts +2 -2
  195. package/src/planner/nodes/declarative-schema.ts +3 -3
  196. package/src/planner/nodes/function.ts +8 -3
  197. package/src/planner/nodes/insert-node.ts +1 -1
  198. package/src/planner/nodes/pragma.ts +4 -3
  199. package/src/planner/nodes/reference.ts +1 -1
  200. package/src/planner/nodes/scalar.ts +54 -102
  201. package/src/planner/nodes/sequencing-node.ts +2 -2
  202. package/src/planner/nodes/sink-node.ts +2 -2
  203. package/src/planner/nodes/subquery.ts +5 -7
  204. package/src/planner/nodes/view-reference-node.ts +2 -2
  205. package/src/planner/nodes/window-function.ts +3 -3
  206. package/src/planner/rules/access/rule-select-access-path.ts +1 -1
  207. package/src/planner/rules/retrieve/rule-grow-retrieve.ts +1 -1
  208. package/src/planner/scopes/global.ts +3 -3
  209. package/src/planner/scopes/param.ts +2 -2
  210. package/src/planner/type-utils.ts +6 -14
  211. package/src/runtime/emit/between.ts +2 -2
  212. package/src/runtime/emit/binary.ts +74 -30
  213. package/src/runtime/emit/subquery.ts +8 -8
  214. package/src/runtime/emit/temporal-arithmetic.ts +302 -0
  215. package/src/runtime/emit/unary.ts +17 -4
  216. package/src/schema/catalog.ts +3 -3
  217. package/src/schema/column.ts +0 -3
  218. package/src/schema/function.ts +29 -1
  219. package/src/schema/table.ts +5 -7
  220. package/src/types/index.ts +1 -1
  221. package/src/types/registry.ts +5 -1
  222. package/src/types/temporal-types.ts +123 -0
  223. package/src/util/plan-formatter.ts +1 -4
  224. package/src/util/row-descriptor.ts +2 -2
  225. package/src/vtab/best-access-plan.ts +4 -3
  226. package/src/vtab/memory/module.ts +1 -1
@@ -1,4 +1,4 @@
1
- import { SqlDataType, type SqlValue } from '../../common/types.js';
1
+ import type { SqlValue } from '../../common/types.js';
2
2
  import * as AST from '../../parser/ast.js';
3
3
  import { Attribute, type RelationalPlanNode } from './plan-node.js';
4
4
  import { PlanNodeType } from './plan-node-type.js';
@@ -6,6 +6,7 @@ import { expressionToString } from '../../util/ast-stringify.js';
6
6
  import { PlanNode } from './plan-node.js';
7
7
  import { RelationType } from '../../common/datatype.js';
8
8
  import { Scope } from '../scopes/scope.js';
9
+ import { TEXT_TYPE } from '../../types/builtin-types.js';
9
10
 
10
11
  export class PragmaPlanNode extends PlanNode implements RelationalPlanNode {
11
12
  override readonly nodeType = PlanNodeType.Pragma;
@@ -29,7 +30,7 @@ export class PragmaPlanNode extends PlanNode implements RelationalPlanNode {
29
30
  name: "name",
30
31
  type: {
31
32
  typeClass: 'scalar',
32
- affinity: SqlDataType.TEXT,
33
+ logicalType: TEXT_TYPE,
33
34
  nullable: false,
34
35
  isReadOnly: true,
35
36
  },
@@ -39,7 +40,7 @@ export class PragmaPlanNode extends PlanNode implements RelationalPlanNode {
39
40
  name: "value",
40
41
  type: {
41
42
  typeClass: 'scalar',
42
- affinity: SqlDataType.TEXT,
43
+ logicalType: TEXT_TYPE,
43
44
  nullable: false,
44
45
  },
45
46
  generated: true,
@@ -38,7 +38,7 @@ export class TableReferenceNode extends PlanNode implements ZeroAryRelationalNod
38
38
  name: column.name,
39
39
  type: {
40
40
  typeClass: 'scalar' as const,
41
- affinity: column.affinity,
41
+ logicalType: column.logicalType,
42
42
  nullable: !column.notNull,
43
43
  isReadOnly: false,
44
44
  collationName: column.collation
@@ -8,6 +8,8 @@ import { Cached } from "../../util/cached.js";
8
8
  import { formatExpression, formatScalarType } from "../../util/plan-formatter.js";
9
9
  import { quereusError } from '../../common/errors.js';
10
10
  import { StatusCode } from '../../common/types.js';
11
+ import { NULL_TYPE, INTEGER_TYPE, REAL_TYPE, TEXT_TYPE, BLOB_TYPE, BOOLEAN_TYPE } from "../../types/builtin-types.js";
12
+ import { typeRegistry } from "../../types/registry.js";
11
13
 
12
14
  export class UnaryOpNode extends PlanNode implements UnaryScalarNode {
13
15
  readonly nodeType = PlanNodeType.UnaryOp;
@@ -25,36 +27,31 @@ export class UnaryOpNode extends PlanNode implements UnaryScalarNode {
25
27
  generateType = (): ScalarType => {
26
28
  const operandType = this.operand.getType();
27
29
 
28
- let datatype: SqlDataType | undefined;
29
- let affinity: SqlDataType = operandType.affinity;
30
+ let logicalType = operandType.logicalType;
30
31
  let nullable = operandType.nullable;
31
32
 
32
33
  switch (this.expression.operator) {
33
34
  case 'NOT':
34
35
  case 'IS NULL':
35
36
  case 'IS NOT NULL':
36
- datatype = SqlDataType.INTEGER;
37
- affinity = SqlDataType.INTEGER;
37
+ logicalType = BOOLEAN_TYPE;
38
38
  nullable = false; // Boolean results are never null
39
39
  break;
40
40
  case '-':
41
41
  case '+':
42
- // Numeric unary operators preserve type but may change nullability
43
- datatype = operandType.datatype;
42
+ // Numeric unary operators preserve type
44
43
  break;
45
44
  case '~':
46
45
  // Bitwise NOT - results in integer
47
- datatype = SqlDataType.INTEGER;
48
- affinity = SqlDataType.INTEGER;
46
+ logicalType = INTEGER_TYPE;
49
47
  break;
50
48
  }
51
49
 
52
50
  return {
53
51
  typeClass: 'scalar',
54
- affinity,
52
+ logicalType,
55
53
  nullable,
56
54
  isReadOnly: operandType.isReadOnly,
57
- datatype,
58
55
  collationName: operandType.collationName,
59
56
  };
60
57
  }
@@ -130,17 +127,11 @@ export class BinaryOpNode extends PlanNode implements BinaryScalarNode {
130
127
  const leftType = this.left.getType();
131
128
  const rightType = this.right.getType();
132
129
 
133
- const affinity = leftType.affinity;
130
+ let logicalType = leftType.logicalType;
134
131
 
135
- let datatype: SqlDataType | undefined;
136
132
  switch (this.expression.operator) {
137
133
  case 'OR':
138
134
  case 'AND':
139
- case '+':
140
- case '-':
141
- case '*':
142
- case '/':
143
- case '%':
144
135
  case '=':
145
136
  case '!=':
146
137
  case '<':
@@ -150,10 +141,33 @@ export class BinaryOpNode extends PlanNode implements BinaryScalarNode {
150
141
  case 'IS':
151
142
  case 'IS NOT':
152
143
  case 'IN':
153
- datatype = SqlDataType.INTEGER;
144
+ // Comparison and logical operators return boolean
145
+ logicalType = BOOLEAN_TYPE;
146
+ break;
147
+ case '+':
148
+ case '-':
149
+ case '*':
150
+ case '/':
151
+ case '%':
152
+ // Arithmetic operators - implement numeric type promotion
153
+ // Rules: INTEGER + INTEGER -> INTEGER, INTEGER + REAL -> REAL, REAL + REAL -> REAL
154
+ if (leftType.logicalType.isNumeric && rightType.logicalType.isNumeric) {
155
+ // Both operands are numeric
156
+ if (leftType.logicalType.name === 'REAL' || rightType.logicalType.name === 'REAL') {
157
+ // If either is REAL, result is REAL
158
+ logicalType = REAL_TYPE;
159
+ } else {
160
+ // Both are INTEGER, result is INTEGER
161
+ logicalType = INTEGER_TYPE;
162
+ }
163
+ } else {
164
+ // Non-numeric operands - use left operand type (fallback)
165
+ logicalType = leftType.logicalType;
166
+ }
154
167
  break;
155
168
  case '||':
156
- datatype = SqlDataType.TEXT;
169
+ // String concatenation
170
+ logicalType = TEXT_TYPE;
157
171
  break;
158
172
  };
159
173
 
@@ -162,10 +176,9 @@ export class BinaryOpNode extends PlanNode implements BinaryScalarNode {
162
176
 
163
177
  return {
164
178
  typeClass: 'scalar',
165
- affinity,
179
+ logicalType,
166
180
  nullable: leftType.nullable || rightType.nullable,
167
181
  isReadOnly: leftType.isReadOnly || rightType.isReadOnly,
168
- datatype,
169
182
  collationName,
170
183
  };
171
184
  }
@@ -252,55 +265,49 @@ export class LiteralNode extends PlanNode implements ZeroAryScalarNode, Constant
252
265
  if (value === null) {
253
266
  return {
254
267
  typeClass: 'scalar',
255
- affinity: SqlDataType.NULL,
268
+ logicalType: NULL_TYPE,
256
269
  nullable: true,
257
270
  isReadOnly: true,
258
- datatype: SqlDataType.NULL,
259
271
  };
260
272
  }
261
273
  if (typeof value === 'number') {
262
274
  return {
263
275
  typeClass: 'scalar',
264
- affinity: SqlDataType.REAL,
276
+ logicalType: REAL_TYPE,
265
277
  nullable: false,
266
278
  isReadOnly: true,
267
- datatype: SqlDataType.REAL,
268
279
  };
269
280
  }
270
281
  if (typeof value === 'bigint') {
271
282
  return {
272
283
  typeClass: 'scalar',
273
- affinity: SqlDataType.INTEGER,
284
+ logicalType: INTEGER_TYPE,
274
285
  nullable: false,
275
286
  isReadOnly: true,
276
- datatype: SqlDataType.INTEGER,
277
287
  };
278
288
  }
279
289
  if (typeof value === 'string') {
280
290
  return {
281
291
  typeClass: 'scalar',
282
- affinity: SqlDataType.TEXT,
292
+ logicalType: TEXT_TYPE,
283
293
  nullable: false,
284
294
  isReadOnly: true,
285
- datatype: SqlDataType.TEXT,
286
295
  };
287
296
  }
288
297
  if (typeof value === 'boolean') {
289
298
  return {
290
299
  typeClass: 'scalar',
291
- affinity: SqlDataType.INTEGER,
300
+ logicalType: BOOLEAN_TYPE,
292
301
  nullable: false,
293
302
  isReadOnly: true,
294
- datatype: SqlDataType.INTEGER,
295
303
  };
296
304
  }
297
305
  if (value instanceof Uint8Array) {
298
306
  return {
299
307
  typeClass: 'scalar',
300
- affinity: SqlDataType.BLOB,
308
+ logicalType: BLOB_TYPE,
301
309
  nullable: false,
302
310
  isReadOnly: true,
303
- datatype: SqlDataType.BLOB,
304
311
  };
305
312
  }
306
313
  quereusError(`Unknown literal type ${typeof value}`, StatusCode.INTERNAL);
@@ -377,16 +384,15 @@ export class CaseExprNode extends PlanNode implements NaryScalarNode {
377
384
  // No THEN clauses and no ELSE - should not happen in valid SQL
378
385
  return {
379
386
  typeClass: 'scalar',
380
- affinity: SqlDataType.NULL,
387
+ logicalType: NULL_TYPE,
381
388
  nullable: true,
382
389
  isReadOnly: true,
383
- datatype: SqlDataType.NULL,
384
390
  };
385
391
  }
386
392
 
387
393
  // Use the first result expression as the base type
388
394
  const firstType = resultExpressions[0].getType();
389
- let affinity = firstType.affinity;
395
+ let logicalType = firstType.logicalType;
390
396
  let nullable = firstType.nullable;
391
397
  let isReadOnly = firstType.isReadOnly;
392
398
  let collationName = firstType.collationName;
@@ -411,9 +417,9 @@ export class CaseExprNode extends PlanNode implements NaryScalarNode {
411
417
  }
412
418
 
413
419
  // TODO: Implement proper type coercion rules for SQL
414
- // For now, if types differ, default to TEXT affinity
415
- if (exprType.affinity !== affinity) {
416
- affinity = SqlDataType.TEXT;
420
+ // For now, if types differ, default to TEXT
421
+ if (exprType.logicalType !== logicalType) {
422
+ logicalType = TEXT_TYPE;
417
423
  }
418
424
  }
419
425
 
@@ -424,11 +430,10 @@ export class CaseExprNode extends PlanNode implements NaryScalarNode {
424
430
 
425
431
  return {
426
432
  typeClass: 'scalar',
427
- affinity,
433
+ logicalType,
428
434
  nullable,
429
435
  isReadOnly,
430
436
  collationName,
431
- // Don't set datatype since it can vary based on runtime conditions
432
437
  };
433
438
  }
434
439
 
@@ -558,69 +563,17 @@ export class CastNode extends PlanNode implements UnaryScalarNode {
558
563
 
559
564
  generateType = (): ScalarType => {
560
565
  const operandType = this.operand.getType();
561
- const targetType = this.expression.targetType.toUpperCase();
562
-
563
- // Determine the SQL data type and affinity based on the target type
564
- let datatype: SqlDataType;
565
- let affinity: SqlDataType;
566
-
567
- switch (targetType) {
568
- case 'INTEGER':
569
- case 'INT':
570
- case 'TINYINT':
571
- case 'SMALLINT':
572
- case 'MEDIUMINT':
573
- case 'BIGINT':
574
- case 'UNSIGNED BIG INT':
575
- case 'INT2':
576
- case 'INT8':
577
- datatype = SqlDataType.INTEGER;
578
- affinity = SqlDataType.INTEGER;
579
- break;
580
- case 'REAL':
581
- case 'DOUBLE':
582
- case 'DOUBLE PRECISION':
583
- case 'FLOAT':
584
- datatype = SqlDataType.REAL;
585
- affinity = SqlDataType.REAL;
586
- break;
587
- case 'TEXT':
588
- case 'CHARACTER':
589
- case 'VARCHAR':
590
- case 'VARYING CHARACTER':
591
- case 'NCHAR':
592
- case 'NATIVE CHARACTER':
593
- case 'NVARCHAR':
594
- case 'CLOB':
595
- datatype = SqlDataType.TEXT;
596
- affinity = SqlDataType.TEXT;
597
- break;
598
- case 'BLOB':
599
- datatype = SqlDataType.BLOB;
600
- affinity = SqlDataType.BLOB;
601
- break;
602
- case 'NUMERIC':
603
- case 'DECIMAL':
604
- case 'BOOLEAN':
605
- case 'DATE':
606
- case 'DATETIME':
607
- datatype = SqlDataType.NUMERIC;
608
- affinity = SqlDataType.NUMERIC;
609
- break;
610
- default:
611
- // For unknown types, default to BLOB affinity
612
- datatype = SqlDataType.BLOB;
613
- affinity = SqlDataType.BLOB;
614
- break;
615
- }
566
+ const targetType = this.expression.targetType;
567
+
568
+ // Look up the logical type from the type registry
569
+ const logicalType = typeRegistry.getTypeOrDefault(targetType);
616
570
 
617
571
  return {
618
572
  typeClass: 'scalar',
619
- affinity,
573
+ logicalType,
620
574
  nullable: operandType.nullable, // CAST preserves nullability
621
575
  isReadOnly: operandType.isReadOnly,
622
- datatype,
623
- collationName: affinity === SqlDataType.TEXT ? operandType.collationName : undefined,
576
+ collationName: logicalType.isTextual ? operandType.collationName : undefined,
624
577
  };
625
578
  }
626
579
 
@@ -756,13 +709,12 @@ export class BetweenNode extends PlanNode implements TernaryScalarNode {
756
709
  }
757
710
 
758
711
  getType(): ScalarType {
759
- // BETWEEN always returns INTEGER (0 or 1)
712
+ // BETWEEN always returns BOOLEAN
760
713
  return {
761
714
  typeClass: 'scalar',
762
- affinity: SqlDataType.INTEGER,
715
+ logicalType: BOOLEAN_TYPE,
763
716
  nullable: false,
764
717
  isReadOnly: true,
765
- datatype: SqlDataType.INTEGER,
766
718
  };
767
719
  }
768
720
 
@@ -3,7 +3,7 @@ import { isRelationalNode, PlanNode, type Attribute, type RelationalPlanNode, ty
3
3
  import type { RelationType } from '../../common/datatype.js';
4
4
  import type { Scope } from '../scopes/scope.js';
5
5
  import { Cached } from '../../util/cached.js';
6
- import { SqlDataType } from '../../common/types.js';
6
+ import { INTEGER_TYPE } from '../../types/builtin-types.js';
7
7
 
8
8
  /**
9
9
  * Represents a sequencing operation that adds a row number column to convert bags to sets.
@@ -31,7 +31,7 @@ export class SequencingNode extends PlanNode implements UnaryRelationalNode {
31
31
  name: this.sequenceColumnName,
32
32
  type: {
33
33
  typeClass: 'scalar' as const,
34
- affinity: SqlDataType.INTEGER,
34
+ logicalType: INTEGER_TYPE,
35
35
  nullable: false,
36
36
  isReadOnly: true
37
37
  },
@@ -2,7 +2,7 @@ import { PlanNodeType } from './plan-node-type.js';
2
2
  import { PlanNode, type RelationalPlanNode } from './plan-node.js';
3
3
  import type { ScalarType } from '../../common/datatype.js';
4
4
  import type { Scope } from '../scopes/scope.js';
5
- import { SqlDataType } from '../../common/types.js';
5
+ import { INTEGER_TYPE } from '../../types/builtin-types.js';
6
6
 
7
7
  /**
8
8
  * A sink node that consumes an async iterable for side effects.
@@ -25,7 +25,7 @@ export class SinkNode extends PlanNode {
25
25
  return {
26
26
  typeClass: 'scalar',
27
27
  isReadOnly: true,
28
- affinity: SqlDataType.INTEGER,
28
+ logicalType: INTEGER_TYPE,
29
29
  nullable: false
30
30
  };
31
31
  }
@@ -1,13 +1,14 @@
1
1
  import { PlanNode, type ScalarPlanNode } from "./plan-node.js";
2
2
  import type { ScalarType } from "../../common/datatype.js";
3
3
  import type { RelationalPlanNode } from "./plan-node.js";
4
- import { type CompareFn, SqlDataType } from "../../common/types.js";
4
+ import { type CompareFn } from "../../common/types.js";
5
5
  import { PlanNodeType } from "./plan-node-type.js";
6
6
  import type { Scope } from "../scopes/scope.js";
7
7
  import { compareSqlValues } from "../../util/comparison.js";
8
8
  import type { Expression } from "../../parser/ast.js";
9
9
  import { formatExpression, formatScalarType } from "../../util/plan-formatter.js";
10
10
  import { quereusError } from "../../common/errors.js";
11
+ import { BLOB_TYPE, BOOLEAN_TYPE, INTEGER_TYPE } from "../../types/builtin-types.js";
11
12
  import { StatusCode } from "../../common/types.js";
12
13
 
13
14
  export class ScalarSubqueryNode extends PlanNode implements ScalarPlanNode {
@@ -31,10 +32,9 @@ export class ScalarSubqueryNode extends PlanNode implements ScalarPlanNode {
31
32
  // Fallback to nullable BLOB if we can't determine type
32
33
  return {
33
34
  typeClass: 'scalar',
34
- affinity: SqlDataType.BLOB,
35
+ logicalType: BLOB_TYPE,
35
36
  nullable: true,
36
37
  isReadOnly: true,
37
- datatype: SqlDataType.BLOB,
38
38
  };
39
39
  }
40
40
 
@@ -103,10 +103,9 @@ export class InNode extends PlanNode implements ScalarPlanNode {
103
103
  getType(): ScalarType {
104
104
  return {
105
105
  typeClass: 'scalar',
106
- affinity: SqlDataType.INTEGER,
106
+ logicalType: BOOLEAN_TYPE,
107
107
  nullable: false,
108
108
  isReadOnly: true,
109
- datatype: SqlDataType.INTEGER,
110
109
  }
111
110
  }
112
111
 
@@ -216,10 +215,9 @@ export class ExistsNode extends PlanNode implements ScalarPlanNode {
216
215
  getType(): ScalarType {
217
216
  return {
218
217
  typeClass: 'scalar',
219
- affinity: SqlDataType.INTEGER,
218
+ logicalType: BOOLEAN_TYPE,
220
219
  nullable: false,
221
220
  isReadOnly: true,
222
- datatype: SqlDataType.INTEGER,
223
221
  };
224
222
  }
225
223
 
@@ -1,10 +1,10 @@
1
1
  import { PlanNode, type ZeroAryRelationalNode, type Attribute } from './plan-node.js';
2
2
  import type { RelationType } from '../../common/datatype.js';
3
- import { SqlDataType } from '../../common/types.js';
4
3
  import { PlanNodeType } from './plan-node-type.js';
5
4
  import type { Scope } from '../scopes/scope.js';
6
5
  import type { ViewSchema } from '../../schema/view.js';
7
6
  import { Cached } from '../../util/cached.js';
7
+ import { TEXT_TYPE } from '../../types/builtin-types.js';
8
8
 
9
9
  /**
10
10
  * Plan node for referencing a view in a FROM clause.
@@ -36,7 +36,7 @@ export class ViewReferenceNode extends PlanNode implements ZeroAryRelationalNode
36
36
  name: columnName,
37
37
  type: {
38
38
  typeClass: 'scalar' as const,
39
- affinity: SqlDataType.TEXT,
39
+ logicalType: TEXT_TYPE,
40
40
  nullable: true,
41
41
  isReadOnly: false
42
42
  }, // Default type, should be inferred
@@ -4,8 +4,8 @@ import type { ScalarType } from '../../common/datatype.js';
4
4
  import type { Scope } from '../scopes/scope.js';
5
5
  import type { WindowFunctionExpr } from '../../parser/ast.js';
6
6
  import { Cached } from '../../util/cached.js';
7
- import { SqlDataType } from '../../common/types.js';
8
7
  import { formatScalarType } from '../../util/plan-formatter.js';
8
+ import { INTEGER_TYPE, REAL_TYPE } from '../../types/builtin-types.js';
9
9
 
10
10
  /**
11
11
  * Represents a window function call in the query plan.
@@ -30,10 +30,10 @@ export class WindowFunctionCallNode extends PlanNode implements ZeroAryScalarNod
30
30
  // Most window functions return numeric types
31
31
  // row_number() specifically returns an integer
32
32
  if (this.functionName === 'row_number') {
33
- return { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: false } satisfies ScalarType;
33
+ return { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false } satisfies ScalarType;
34
34
  }
35
35
  // Other window functions would have their own type inference
36
- return { typeClass: 'scalar', affinity: SqlDataType.NUMERIC, nullable: false } satisfies ScalarType;
36
+ return { typeClass: 'scalar', logicalType: REAL_TYPE, nullable: false } satisfies ScalarType;
37
37
  });
38
38
  }
39
39
 
@@ -120,7 +120,7 @@ function createIndexBasedAccess(retrieveNode: RetrieveNode, context: OptContext)
120
120
  columns: tableSchema.columns.map((col, index) => ({
121
121
  index,
122
122
  name: col.name,
123
- type: col.affinity,
123
+ type: col.logicalType,
124
124
  isPrimaryKey: col.primaryKey || false,
125
125
  isUnique: col.primaryKey || false // For now, assume only PK columns are unique
126
126
  } as ColumnMeta)),
@@ -231,7 +231,7 @@ function fallbackIndexSupports(
231
231
  columns: tableSchema.columns.map((col, index) => ({
232
232
  index,
233
233
  name: col.name,
234
- type: col.affinity,
234
+ type: col.logicalType,
235
235
  isPrimaryKey: col.primaryKey || false,
236
236
  isUnique: col.primaryKey || false
237
237
  })),
@@ -5,8 +5,8 @@ import * as AST from "../../parser/ast.js";
5
5
  import { FunctionReferenceNode, TableReferenceNode } from "../nodes/reference.js";
6
6
  import { Ambiguous } from "./scope.js";
7
7
  import type { ScalarType } from "../../common/datatype.js";
8
- import { SqlDataType } from "../../common/types.js";
9
8
  import { isScalarFunctionSchema } from "../../schema/function.js";
9
+ import { REAL_TYPE } from "../../types/builtin-types.js";
10
10
 
11
11
  export class GlobalScope extends BaseScope {
12
12
  constructor(public readonly manager: SchemaManager) {
@@ -25,7 +25,7 @@ export class GlobalScope extends BaseScope {
25
25
  // Get the proper scalar type from the function schema
26
26
  const scalarType: ScalarType = isScalarFunctionSchema(func)
27
27
  ? func.returnType
28
- : { typeClass: 'scalar', affinity: SqlDataType.NUMERIC, nullable: true, isReadOnly: true };
28
+ : { typeClass: 'scalar', logicalType: REAL_TYPE, nullable: true, isReadOnly: true };
29
29
 
30
30
  return new FunctionReferenceNode(this, func, scalarType);
31
31
  }
@@ -54,7 +54,7 @@ export class GlobalScope extends BaseScope {
54
54
  // Get the proper scalar type from the function schema
55
55
  const scalarType: ScalarType = isScalarFunctionSchema(func)
56
56
  ? func.returnType
57
- : { typeClass: 'scalar', affinity: SqlDataType.NUMERIC, nullable: true, isReadOnly: true };
57
+ : { typeClass: 'scalar', logicalType: REAL_TYPE, nullable: true, isReadOnly: true };
58
58
 
59
59
  return new FunctionReferenceNode(this, func, scalarType);
60
60
  }
@@ -3,13 +3,13 @@ import { ParameterReferenceNode } from '../nodes/reference.js'; // Corrected imp
3
3
  import { BaseScope } from './base.js';
4
4
  import { Ambiguous, type Scope } from './scope.js';
5
5
  import type { ScalarType } from '../../common/datatype.js';
6
- import { SqlDataType } from '../../common/types.js';
7
6
  import type { PlanNode } from '../nodes/plan-node.js';
7
+ import { TEXT_TYPE } from '../../types/builtin-types.js';
8
8
 
9
9
  // Default type for parameters when not otherwise specified.
10
10
  const DEFAULT_PARAMETER_TYPE: ScalarType = {
11
11
  typeClass: 'scalar',
12
- affinity: SqlDataType.TEXT,
12
+ logicalType: TEXT_TYPE,
13
13
  nullable: true,
14
14
  };
15
15
 
@@ -4,8 +4,7 @@ import type { RelationType, ColumnDef, ScalarType, ColRef } from '../common/data
4
4
  import { SqlDataType, StatusCode, type DeepReadonly, type SqlValue } from '../common/types.js'; // Import SqlValue and ensure SqlDataType is not type-only
5
5
  import type { AstNode } from '../parser/ast.js';
6
6
  import { QuereusError } from '../common/errors.js';
7
- // Note: getAffinity from '../schema/column.js' is used by the ColumnSchema type from table.js itself if that's what we use.
8
- // If tableSchema.columns are of type from '../schema/column.js', then their affinity is already SqlDataType.
7
+ import { inferLogicalTypeFromValue } from '../common/type-inference.js';
9
8
 
10
9
  /**
11
10
  * Converts a TableSchema (from src/schema/table.ts) to a RelationType (from src/common/datatype.ts).
@@ -17,7 +16,7 @@ export function relationTypeFromTableSchema(tableSchema: TableSchema): RelationT
17
16
  name: col.name,
18
17
  type: {
19
18
  typeClass: 'scalar',
20
- affinity: col.affinity,
19
+ logicalType: col.logicalType,
21
20
  collationName: col.collation,
22
21
  nullable: !col.notNull,
23
22
  isReadOnly: false,
@@ -53,18 +52,11 @@ export function relationTypeFromTableSchema(tableSchema: TableSchema): RelationT
53
52
  * @returns A ScalarType representing the inferred type of the value.
54
53
  */
55
54
  export function getParameterScalarType(value: SqlValue): ScalarType {
56
- let affinity: SqlDataType;
57
- if (value === null) affinity = SqlDataType.NULL;
58
- else if (typeof value === 'number') affinity = SqlDataType.REAL;
59
- else if (typeof value === 'bigint') affinity = SqlDataType.INTEGER;
60
- else if (typeof value === 'string') affinity = SqlDataType.TEXT;
61
- else if (value instanceof Uint8Array) affinity = SqlDataType.BLOB;
62
- else if (typeof value === 'boolean') affinity = SqlDataType.INTEGER; // Store booleans as INTEGER
63
- else affinity = SqlDataType.BLOB; // Default for unknown types that might pass as SqlValue
55
+ const logicalType = inferLogicalTypeFromValue(value);
64
56
 
65
57
  return {
66
58
  typeClass: 'scalar',
67
- affinity: affinity,
59
+ logicalType,
68
60
  nullable: true, // No guarantees about the value, so it's nullable
69
61
  isReadOnly: true, // Parameters are read-only within the query execution context
70
62
  };
@@ -80,12 +72,12 @@ export function checkRelationsAssignable(source: RelationType, target: RelationT
80
72
  return checkColumnsAssignable(source.columns, target.columns, astNode);
81
73
  }
82
74
 
83
- export function columnSchemaToDef(colName: string, colDef: ColumnSchema): { name: string; type: { typeClass: "scalar"; affinity: SqlDataType; collationName: string; nullable: boolean; isReadOnly: false; }; generated: boolean; } {
75
+ export function columnSchemaToDef(colName: string, colDef: ColumnSchema): ColumnDef {
84
76
  return {
85
77
  name: colName,
86
78
  type: {
87
79
  typeClass: 'scalar',
88
- affinity: colDef.affinity,
80
+ logicalType: colDef.logicalType,
89
81
  collationName: colDef.collation,
90
82
  nullable: !colDef.notNull,
91
83
  isReadOnly: false,
@@ -27,11 +27,11 @@ export function emitBetween(plan: BetweenNode, ctx: EmissionContext): Instructio
27
27
  const upperResult = compareSqlValuesFast(coercedValue2, coercedUpper, collationFunc);
28
28
 
29
29
  // value >= lowerBound AND value <= upperBound
30
- const betweenResult = (lowerResult >= 0 && upperResult <= 0) ? 1 : 0;
30
+ const betweenResult = (lowerResult >= 0 && upperResult <= 0);
31
31
 
32
32
  // Handle NOT BETWEEN
33
33
  if (plan.expression.not) {
34
- return betweenResult ? 0 : 1;
34
+ return !betweenResult;
35
35
  }
36
36
 
37
37
  return betweenResult;