@bjornpagen/bumbledb 1.3.0 → 2.0.0-rc.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 (290) hide show
  1. package/COOKBOOK.md +224 -95
  2. package/README.md +114 -45
  3. package/dist/alternatives.d.ts +5 -6
  4. package/dist/alternatives.d.ts.map +1 -1
  5. package/dist/alternatives.js +5 -6
  6. package/dist/alternatives.js.map +1 -1
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +85 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/capacity.d.ts +14 -17
  12. package/dist/capacity.d.ts.map +1 -1
  13. package/dist/capacity.js +7 -7
  14. package/dist/capacity.js.map +1 -1
  15. package/dist/changes.d.ts +32 -41
  16. package/dist/changes.d.ts.map +1 -1
  17. package/dist/changes.js +86 -110
  18. package/dist/changes.js.map +1 -1
  19. package/dist/closed.d.ts +2 -2
  20. package/dist/closed.d.ts.map +1 -1
  21. package/dist/closed.js +5 -5
  22. package/dist/closed.js.map +1 -1
  23. package/dist/codec.d.ts +20 -27
  24. package/dist/codec.d.ts.map +1 -1
  25. package/dist/codec.js +48 -22
  26. package/dist/codec.js.map +1 -1
  27. package/dist/compile.d.ts +26 -50
  28. package/dist/compile.d.ts.map +1 -1
  29. package/dist/compile.js +75 -64
  30. package/dist/compile.js.map +1 -1
  31. package/dist/database/database.d.ts +98 -0
  32. package/dist/database/database.d.ts.map +1 -0
  33. package/dist/database/database.js +249 -0
  34. package/dist/database/database.js.map +1 -0
  35. package/dist/database/driver.d.ts +40 -0
  36. package/dist/database/driver.d.ts.map +1 -0
  37. package/dist/database/driver.js +68 -0
  38. package/dist/database/driver.js.map +1 -0
  39. package/dist/database/fs.d.ts +12 -0
  40. package/dist/database/fs.d.ts.map +1 -0
  41. package/dist/database/fs.js +120 -0
  42. package/dist/database/fs.js.map +1 -0
  43. package/dist/database/generate.d.ts +26 -0
  44. package/dist/database/generate.d.ts.map +1 -0
  45. package/dist/database/generate.js +102 -0
  46. package/dist/database/generate.js.map +1 -0
  47. package/dist/database/hosted.d.ts +32 -0
  48. package/dist/database/hosted.d.ts.map +1 -0
  49. package/dist/database/hosted.js +44 -0
  50. package/dist/database/hosted.js.map +1 -0
  51. package/dist/database/io.d.ts +94 -0
  52. package/dist/database/io.d.ts.map +1 -0
  53. package/dist/database/io.js +35 -0
  54. package/dist/database/io.js.map +1 -0
  55. package/dist/database/mem.d.ts +26 -0
  56. package/dist/database/mem.d.ts.map +1 -0
  57. package/dist/database/mem.js +67 -0
  58. package/dist/database/mem.js.map +1 -0
  59. package/dist/database/migration.d.ts +55 -0
  60. package/dist/database/migration.d.ts.map +1 -0
  61. package/dist/database/migration.js +46 -0
  62. package/dist/database/migration.js.map +1 -0
  63. package/dist/database/s3.d.ts +36 -0
  64. package/dist/database/s3.d.ts.map +1 -0
  65. package/dist/database/s3.js +141 -0
  66. package/dist/database/s3.js.map +1 -0
  67. package/dist/db.d.ts +44 -128
  68. package/dist/db.d.ts.map +1 -1
  69. package/dist/db.js +163 -287
  70. package/dist/db.js.map +1 -1
  71. package/dist/engine.d.ts +7 -0
  72. package/dist/engine.d.ts.map +1 -0
  73. package/dist/engine.js +2 -0
  74. package/dist/engine.js.map +1 -0
  75. package/dist/errors.d.ts +152 -46
  76. package/dist/errors.d.ts.map +1 -1
  77. package/dist/errors.js +107 -19
  78. package/dist/errors.js.map +1 -1
  79. package/dist/face.d.ts +5 -5
  80. package/dist/face.d.ts.map +1 -1
  81. package/dist/face.js +6 -6
  82. package/dist/face.js.map +1 -1
  83. package/dist/fields.d.ts +4 -5
  84. package/dist/fields.d.ts.map +1 -1
  85. package/dist/fields.js +3 -3
  86. package/dist/fields.js.map +1 -1
  87. package/dist/index.d.ts +60 -58
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +27 -29
  90. package/dist/index.js.map +1 -1
  91. package/dist/judgment.d.ts +1 -1
  92. package/dist/judgment.js +1 -1
  93. package/dist/law.d.ts +16 -68
  94. package/dist/law.d.ts.map +1 -1
  95. package/dist/law.js +3 -3
  96. package/dist/law.js.map +1 -1
  97. package/dist/lower.d.ts +3 -3
  98. package/dist/lower.d.ts.map +1 -1
  99. package/dist/lower.js +35 -39
  100. package/dist/lower.js.map +1 -1
  101. package/dist/native/addon.d.ts +23 -0
  102. package/dist/native/addon.d.ts.map +1 -0
  103. package/dist/native/addon.js +15 -0
  104. package/dist/native/addon.js.map +1 -0
  105. package/dist/native/binding.d.ts +996 -0
  106. package/dist/native/json.d.ts +14 -0
  107. package/dist/native/json.d.ts.map +1 -0
  108. package/dist/native/json.js +73 -0
  109. package/dist/native/json.js.map +1 -0
  110. package/dist/native/load.d.ts +9 -0
  111. package/dist/native/load.d.ts.map +1 -0
  112. package/dist/native/load.js +30 -0
  113. package/dist/native/load.js.map +1 -0
  114. package/dist/native/op.d.ts +29 -0
  115. package/dist/native/op.d.ts.map +1 -0
  116. package/dist/native/op.js +50 -0
  117. package/dist/native/op.js.map +1 -0
  118. package/dist/query/atom.d.ts +13 -14
  119. package/dist/query/atom.d.ts.map +1 -1
  120. package/dist/query/atom.js +2 -2
  121. package/dist/query/atom.js.map +1 -1
  122. package/dist/query/compute.d.ts +7 -7
  123. package/dist/query/compute.d.ts.map +1 -1
  124. package/dist/query/compute.js +7 -16
  125. package/dist/query/compute.js.map +1 -1
  126. package/dist/query/find.d.ts +8 -8
  127. package/dist/query/find.d.ts.map +1 -1
  128. package/dist/query/find.js +1 -1
  129. package/dist/query/lower.d.ts +31 -17
  130. package/dist/query/lower.d.ts.map +1 -1
  131. package/dist/query/lower.js +260 -368
  132. package/dist/query/lower.js.map +1 -1
  133. package/dist/query/run.d.ts +5 -5
  134. package/dist/query/run.d.ts.map +1 -1
  135. package/dist/query/run.js +32 -15
  136. package/dist/query/run.js.map +1 -1
  137. package/dist/query/scope.d.ts +20 -28
  138. package/dist/query/scope.d.ts.map +1 -1
  139. package/dist/query/scope.js +13 -8
  140. package/dist/query/scope.js.map +1 -1
  141. package/dist/query/segments.d.ts +2 -2
  142. package/dist/query/segments.d.ts.map +1 -1
  143. package/dist/query/segments.js +3 -3
  144. package/dist/query/segments.js.map +1 -1
  145. package/dist/relation.d.ts +1 -1
  146. package/dist/relation.d.ts.map +1 -1
  147. package/dist/relation.js +4 -4
  148. package/dist/relation.js.map +1 -1
  149. package/dist/result.d.ts +15 -22
  150. package/dist/result.d.ts.map +1 -1
  151. package/dist/result.js +30 -39
  152. package/dist/result.js.map +1 -1
  153. package/dist/rows.d.ts +9 -33
  154. package/dist/rows.d.ts.map +1 -1
  155. package/dist/rows.js +8 -12
  156. package/dist/rows.js.map +1 -1
  157. package/dist/runtime.d.ts +17 -43
  158. package/dist/runtime.d.ts.map +1 -1
  159. package/dist/runtime.js +41 -241
  160. package/dist/runtime.js.map +1 -1
  161. package/dist/scalar.d.ts +36 -106
  162. package/dist/scalar.d.ts.map +1 -1
  163. package/dist/scalar.js +36 -185
  164. package/dist/scalar.js.map +1 -1
  165. package/dist/schema.d.ts +7 -18
  166. package/dist/schema.d.ts.map +1 -1
  167. package/dist/schema.js +18 -228
  168. package/dist/schema.js.map +1 -1
  169. package/dist/selection.d.ts +4 -4
  170. package/dist/selection.d.ts.map +1 -1
  171. package/dist/selection.js +5 -5
  172. package/dist/selection.js.map +1 -1
  173. package/dist/shape.d.ts +5 -5
  174. package/dist/shape.d.ts.map +1 -1
  175. package/dist/spec.d.ts +7 -79
  176. package/dist/spec.d.ts.map +1 -1
  177. package/dist/spec.js.map +1 -1
  178. package/dist/statements.d.ts +3 -3
  179. package/dist/statements.d.ts.map +1 -1
  180. package/dist/statements.js +10 -10
  181. package/dist/statements.js.map +1 -1
  182. package/dist/uuid.d.ts +1 -1
  183. package/dist/uuid.d.ts.map +1 -1
  184. package/dist/uuid.js +1 -1
  185. package/dist/uuid.js.map +1 -1
  186. package/dist/values.d.ts +2 -2
  187. package/dist/values.d.ts.map +1 -1
  188. package/dist/values.js +2 -2
  189. package/dist/values.js.map +1 -1
  190. package/package.json +18 -18
  191. package/src/alternatives.ts +7 -8
  192. package/src/bin.ts +82 -0
  193. package/src/capacity.ts +20 -23
  194. package/src/changes.ts +134 -197
  195. package/src/closed.ts +5 -5
  196. package/src/codec.ts +77 -51
  197. package/src/compile.ts +91 -113
  198. package/src/database/database.ts +413 -0
  199. package/src/database/driver.ts +134 -0
  200. package/src/database/fs.ts +119 -0
  201. package/src/database/generate.ts +116 -0
  202. package/src/database/hosted.ts +102 -0
  203. package/src/database/io.ts +134 -0
  204. package/src/database/mem.ts +113 -0
  205. package/src/database/migration.ts +107 -0
  206. package/src/database/s3.ts +231 -0
  207. package/src/db.ts +290 -547
  208. package/src/engine.ts +14 -0
  209. package/src/errors.ts +118 -39
  210. package/src/face.ts +9 -9
  211. package/src/fields.ts +6 -7
  212. package/src/index.ts +102 -109
  213. package/src/judgment.ts +1 -1
  214. package/src/law.ts +18 -70
  215. package/src/lower.ts +61 -72
  216. package/src/native/addon.ts +54 -0
  217. package/src/native/binding.d.ts +996 -0
  218. package/src/native/json.ts +100 -0
  219. package/src/native/load.ts +31 -0
  220. package/src/native/op.ts +73 -0
  221. package/src/query/atom.ts +15 -16
  222. package/src/query/compute.ts +13 -22
  223. package/src/query/find.ts +8 -8
  224. package/src/query/lower.ts +323 -414
  225. package/src/query/run.ts +42 -21
  226. package/src/query/scope.ts +37 -38
  227. package/src/query/segments.ts +4 -4
  228. package/src/relation.ts +4 -4
  229. package/src/result.ts +53 -80
  230. package/src/rows.ts +18 -46
  231. package/src/runtime.ts +50 -346
  232. package/src/scalar.ts +76 -336
  233. package/src/schema.ts +23 -284
  234. package/src/selection.ts +6 -6
  235. package/src/shape.ts +5 -5
  236. package/src/spec.ts +7 -85
  237. package/src/statements.ts +11 -11
  238. package/src/uuid.ts +1 -1
  239. package/src/values.ts +4 -4
  240. package/dist/close.d.ts +0 -24
  241. package/dist/close.d.ts.map +0 -1
  242. package/dist/close.js +0 -34
  243. package/dist/close.js.map +0 -1
  244. package/dist/db-native.d.ts +0 -196
  245. package/dist/db-native.d.ts.map +0 -1
  246. package/dist/db-native.js +0 -13
  247. package/dist/db-native.js.map +0 -1
  248. package/dist/internal/log.d.ts +0 -26
  249. package/dist/internal/log.d.ts.map +0 -1
  250. package/dist/internal/log.js +0 -12
  251. package/dist/internal/log.js.map +0 -1
  252. package/dist/migration.d.ts +0 -31
  253. package/dist/migration.d.ts.map +0 -1
  254. package/dist/migration.js +0 -47
  255. package/dist/migration.js.map +0 -1
  256. package/dist/native.d.ts +0 -562
  257. package/dist/native.d.ts.map +0 -1
  258. package/dist/native.js +0 -123
  259. package/dist/native.js.map +0 -1
  260. package/dist/query/description.d.ts +0 -41
  261. package/dist/query/description.d.ts.map +0 -1
  262. package/dist/query/description.js +0 -311
  263. package/dist/query/description.js.map +0 -1
  264. package/dist/query/parse-ir.d.ts +0 -10
  265. package/dist/query/parse-ir.d.ts.map +0 -1
  266. package/dist/query/parse-ir.js +0 -280
  267. package/dist/query/parse-ir.js.map +0 -1
  268. package/dist/runtime-codes.d.ts +0 -2
  269. package/dist/runtime-codes.d.ts.map +0 -1
  270. package/dist/runtime-codes.js +0 -18
  271. package/dist/runtime-codes.js.map +0 -1
  272. package/dist/runtime-errors.d.ts +0 -118
  273. package/dist/runtime-errors.d.ts.map +0 -1
  274. package/dist/runtime-errors.js +0 -98
  275. package/dist/runtime-errors.js.map +0 -1
  276. package/dist/runtime-native.d.ts +0 -141
  277. package/dist/runtime-native.d.ts.map +0 -1
  278. package/dist/runtime-native.js +0 -5
  279. package/dist/runtime-native.js.map +0 -1
  280. package/pack-provenance.json +0 -7
  281. package/src/close.ts +0 -53
  282. package/src/db-native.ts +0 -243
  283. package/src/internal/log.ts +0 -48
  284. package/src/migration.ts +0 -61
  285. package/src/native.ts +0 -736
  286. package/src/query/description.ts +0 -424
  287. package/src/query/parse-ir.ts +0 -291
  288. package/src/runtime-codes.ts +0 -17
  289. package/src/runtime-errors.ts +0 -109
  290. package/src/runtime-native.ts +0 -189
package/src/scalar.ts CHANGED
@@ -1,26 +1,9 @@
1
- /**
2
- * The ONE leaf-scoped scalar AST (C1/C8): one tagged literal grammar and
3
- * operator roster, parameterized by {@link ScalarLeafScope}. TypeScript never
4
- * evaluates — the native compiler binds source fields and the engine
5
- * `ScalarEvaluator` executes. Construction is constant work against cached
6
- * depth/kind summaries; it does not re-walk the tree.
7
- *
8
- * Query-var leaves carry a known schema kind. Source-field leaves stay
9
- * `unresolved` until native snapshot binding. A result kind is recorded only
10
- * when it is derivable from known operands; otherwise it stays unresolved.
11
- * Known incompatible kinds refuse here. Unresolved trees are inert metadata,
12
- * not typechecked programs.
13
- *
14
- * Wire spellings (the grammar arms, not a second flattened interpretation):
15
- * migration plan JSON — field/literal/operator nodes; one-arm literals (`{ u64: n }`)
16
- * query IR — `{ kind: "literal", value: ValueSpec }` via `literalWireOf`
17
- */
18
- import { AuthoringError } from "#errors.ts"
19
- import type { ScalarExprIr } from "#native.ts"
20
- import type { ValueSpec } from "#spec.ts"
21
-
22
- /** F0: leaf scope for the shared AST (C1). Query vars are typed; source fields stay unresolved. */
23
- export type ScalarLeafScope = "query-var" | "source-field"
1
+ /** Query scalar nodes, with cached kind and depth. Construction is constant
2
+ * work; native preparation binds variables and evaluates the expressions. */
3
+ import { AuthoringError } from "./errors.ts"
4
+ import type { ScalarExprIn } from "./native/binding.d.ts"
5
+ import { valueIn } from "./native/json.ts"
6
+ import type { ValueSpec } from "./spec.ts"
24
7
 
25
8
  /** The engine's scalar result vocabulary — distinct at the type level. */
26
9
  type ScalarKind = "u64" | "i64" | "f64" | "bool"
@@ -28,7 +11,7 @@ type ScalarKind = "u64" | "i64" | "f64" | "bool"
28
11
  /** Cached result kind: known only when derivable; otherwise honestly unresolved. */
29
12
  type IntervalKind = "intervalU64" | "intervalI64" | "intervalF64"
30
13
  type ScalarInputKind = ScalarKind | IntervalKind
31
- type ScalarResultKind = ScalarInputKind | "unresolved"
14
+ type ScalarResultKind = ScalarInputKind
32
15
  type Rounding = "towardZero" | "nearestTiesAwayFromZero" | "nearestTiesToEven"
33
16
 
34
17
  /** Host value for a derived scalar kind. */
@@ -38,26 +21,6 @@ type NumericCast = "toF64" | "toF64Exact" | "toI64Exact" | "toU64Exact"
38
21
 
39
22
  type NumericKind = "u64" | "i64" | "f64"
40
23
 
41
- type NumericOrUnresolved = NumericKind | "unresolved"
42
-
43
- /**
44
- * Combine known numeric kinds, or stay unresolved when a source-field leaf
45
- * still needs native binding. Distinct known kinds collapse to `never`
46
- * (static refusal) and throw at the constructor.
47
- */
48
- type CombineNumeric<L, R> = L extends "unresolved"
49
- ? R extends "bool"
50
- ? never
51
- : "unresolved"
52
- : R extends "unresolved"
53
- ? L extends "bool"
54
- ? never
55
- : "unresolved"
56
- : L extends R
57
- ? L
58
- : never
59
-
60
- /** The tagged literal subset shared by every leaf scope. */
61
24
  type ScalarLiteral =
62
25
  | { readonly bool: boolean }
63
26
  | { readonly u64: bigint }
@@ -89,69 +52,48 @@ interface ScalarQueryVar {
89
52
 
90
53
  type QueryVarLeaf = { readonly kind: "var"; readonly ref: ScalarQueryVar }
91
54
 
92
- type SourceFieldLeaf = { readonly kind: "field"; readonly name: string }
93
-
94
- type ScalarLeaf<S extends ScalarLeafScope> = S extends "query-var" ? QueryVarLeaf : SourceFieldLeaf
95
-
96
- type ScalarNodeBody<S extends ScalarLeafScope> =
97
- | { readonly kind: "measure"; readonly expr: ScalarNode<S> }
55
+ type ScalarNodeBody =
56
+ | { readonly kind: "measure"; readonly expr: ScalarNode }
98
57
  | {
99
58
  readonly kind: "mulDiv"
100
- readonly a: ScalarNode<S>
101
- readonly b: ScalarNode<S>
102
- readonly divisor: ScalarNode<S>
59
+ readonly a: ScalarNode
60
+ readonly b: ScalarNode
61
+ readonly divisor: ScalarNode
103
62
  readonly rounding: Rounding
104
63
  }
105
- | ScalarLeaf<S>
64
+ | QueryVarLeaf
106
65
  | { readonly kind: "literal"; readonly value: ScalarLiteral }
107
- | { readonly kind: "negate"; readonly expr: ScalarNode<S> }
108
- | { readonly kind: "isNaN"; readonly expr: ScalarNode<S> }
109
- | { readonly kind: "isFinite"; readonly expr: ScalarNode<S> }
110
- | { readonly kind: "add"; readonly left: ScalarNode<S>; readonly right: ScalarNode<S> }
111
- | { readonly kind: "subtract"; readonly left: ScalarNode<S>; readonly right: ScalarNode<S> }
112
- | { readonly kind: "multiply"; readonly left: ScalarNode<S>; readonly right: ScalarNode<S> }
113
- | { readonly kind: "divide"; readonly left: ScalarNode<S>; readonly right: ScalarNode<S> }
114
- | { readonly kind: "cast"; readonly cast: NumericCast; readonly expr: ScalarNode<S> }
115
-
116
- /**
117
- * One authored node: roster arms plus cached `scope` / `result` / `depth`.
118
- * Summaries are construction metadata; lowering and L17 serialization read
119
- * the grammar arms and ignore the summaries.
120
- */
121
- type ScalarNode<
122
- S extends ScalarLeafScope = ScalarLeafScope,
123
- K extends ScalarResultKind = ScalarResultKind
124
- > = ScalarNodeBody<S> & {
125
- readonly scope: S
66
+ | { readonly kind: "negate"; readonly expr: ScalarNode }
67
+ | { readonly kind: "isNaN"; readonly expr: ScalarNode }
68
+ | { readonly kind: "isFinite"; readonly expr: ScalarNode }
69
+ | { readonly kind: "add"; readonly left: ScalarNode; readonly right: ScalarNode }
70
+ | { readonly kind: "subtract"; readonly left: ScalarNode; readonly right: ScalarNode }
71
+ | { readonly kind: "multiply"; readonly left: ScalarNode; readonly right: ScalarNode }
72
+ | { readonly kind: "divide"; readonly left: ScalarNode; readonly right: ScalarNode }
73
+ | { readonly kind: "cast"; readonly cast: NumericCast; readonly expr: ScalarNode }
74
+
75
+ /** Cached summaries never replace the expression grammar. */
76
+ type ScalarNode<K extends ScalarResultKind = ScalarResultKind> = ScalarNodeBody & {
126
77
  readonly result: K
127
78
  readonly depth: number
128
79
  }
129
80
 
130
- /**
131
- * Migration authoring expression (source-field scope). `K` is the cached
132
- * result kind, not a host value type: I64 and U64 remain distinct even
133
- * though both use bigint in JavaScript.
134
- */
135
- type ScalarExpr<K extends ScalarResultKind = ScalarResultKind> = ScalarNode<"source-field", K>
136
-
137
- /** A migration field read: unresolved until native snapshot binding. */
138
- type ScalarFieldRef = ScalarNode<"source-field", "unresolved"> & SourceFieldLeaf
139
-
140
81
  const MAX_SCALAR_DEPTH = 128
141
82
  const U64_MAX = (1n << 64n) - 1n
142
83
  const I64_MIN = -(1n << 63n)
143
84
  const I64_MAX = (1n << 63n) - 1n
144
85
 
145
- /** Constructor admissions only — not descendant visits. D27 construction-work pin. */
86
+ /** Constructor admissions only, not descendant visits. */
146
87
  let authoringWork = 0
147
88
 
148
89
  function scalarAuthoringWork(): number {
149
90
  return authoringWork
150
91
  }
151
92
 
152
- function admit<
153
- const Node extends { readonly scope: ScalarLeafScope; readonly result: ScalarResultKind; readonly depth: number }
154
- >(where: string, node: Node): Readonly<Node> {
93
+ function admit<const Node extends { readonly result: ScalarResultKind; readonly depth: number }>(
94
+ where: string,
95
+ node: Node
96
+ ): Readonly<Node> {
155
97
  authoringWork += 1
156
98
  assertDepth(where, node.depth)
157
99
  return Object.freeze(node)
@@ -229,40 +171,19 @@ function assertNumeric(where: string, kind: ScalarInputKind): asserts kind is Nu
229
171
  function assertSameKind(where: string, left: ScalarInputKind, right: ScalarInputKind): ScalarInputKind {
230
172
  if (left !== right) {
231
173
  throw new AuthoringError({
232
- message: `${where}: operand kinds differ (${left} vs ${right}) — the engine has no mixed promotion; cast explicitly (Scalar.toF64/ toF64Exact/ toI64Exact/ toU64Exact)`
174
+ message: `${where}: operand kinds differ (${left} vs ${right}) — the engine has no mixed promotion; cast explicitly (Compute.toF64/ toF64Exact/ toI64Exact/ toU64Exact)`
233
175
  })
234
176
  }
235
177
  return left
236
178
  }
237
179
 
238
- function assertScope<S extends ScalarLeafScope>(where: string, left: ScalarNode<S>, right: ScalarNode<S>): S {
239
- if (left.scope !== right.scope) {
240
- throw new AuthoringError({
241
- message: `${where}: leaf scopes differ (${left.scope} vs ${right.scope}) — query-var and source-field trees do not mix`
242
- })
243
- }
244
- return left.scope
245
- }
246
-
247
180
  function combineNumeric(where: string, left: ScalarResultKind, right: ScalarResultKind): ScalarResultKind {
248
- if (left === "unresolved" || right === "unresolved") {
249
- if (left !== "unresolved") {
250
- assertNumeric(where, left)
251
- }
252
- if (right !== "unresolved") {
253
- assertNumeric(where, right)
254
- }
255
- return "unresolved"
256
- }
257
181
  assertNumeric(where, left)
258
182
  assertNumeric(where, right)
259
183
  return assertSameKind(where, left, right)
260
184
  }
261
185
 
262
186
  function negateKind(where: string, inner: ScalarResultKind): ScalarResultKind {
263
- if (inner === "unresolved") {
264
- return "unresolved"
265
- }
266
187
  if (inner !== "i64" && inner !== "f64") {
267
188
  throw new AuthoringError({
268
189
  message: `${where}: the operand is ${inner} — negation is defined over i64 and f64 only`
@@ -272,86 +193,46 @@ function negateKind(where: string, inner: ScalarResultKind): ScalarResultKind {
272
193
  }
273
194
 
274
195
  function assertCastOperand(where: string, inner: ScalarResultKind): void {
275
- if (inner === "unresolved") {
276
- return
277
- }
278
196
  assertNumeric(where, inner)
279
197
  }
280
198
 
281
199
  function assertFloatOperand(where: string, inner: ScalarResultKind): void {
282
- if (inner === "unresolved") {
283
- return
284
- }
285
200
  if (inner !== "f64") {
286
201
  throw new AuthoringError({ message: `${where}: the operand is ${inner} — the float predicates read f64` })
287
202
  }
288
203
  }
289
204
 
290
205
  function isScalarNode(value: unknown): value is ScalarNode {
291
- return (
292
- typeof value === "object" &&
293
- value !== null &&
294
- "kind" in value &&
295
- "scope" in value &&
296
- "result" in value &&
297
- "depth" in value
298
- )
299
- }
300
-
301
- function isUnresolvedScalar(node: ScalarNode): boolean {
302
- return node.result === "unresolved"
303
- }
304
-
305
- /** Source-field leaf — unresolved until L14 binds it against the verified snapshot. */
306
- function sourceField(name: string): ScalarFieldRef {
307
- if (typeof name !== "string" || name.length === 0) {
308
- throw new AuthoringError({ message: "scalar field(...) names a nonempty source field" })
309
- }
310
- return admit("Scalar.field", {
311
- kind: "field",
312
- name,
313
- scope: "source-field",
314
- result: "unresolved",
315
- depth: 1
316
- })
206
+ return typeof value === "object" && value !== null && "kind" in value && "result" in value && "depth" in value
317
207
  }
318
208
 
319
209
  /** Query-var leaf — kind is the variable's schema kind, already known. */
320
- function queryVarLeaf<K extends ScalarInputKind>(ref: ScalarQueryVar, kind: K): ScalarNode<"query-var", K> {
321
- return admit("Scalar.queryVar", {
210
+ function queryVarLeaf<K extends ScalarInputKind>(ref: ScalarQueryVar, kind: K): ScalarNode<K> {
211
+ return admit("Compute.variable", {
322
212
  kind: "var",
323
213
  ref,
324
- scope: "query-var",
325
214
  result: kind,
326
215
  depth: 1
327
216
  })
328
217
  }
329
218
 
330
- function scalarLiteral<S extends ScalarLeafScope>(scope: S, value: ScalarLiteral): ScalarNode<S, ScalarKind> {
219
+ function scalarLiteral(value: ScalarLiteral): ScalarNode<ScalarKind> {
331
220
  const kind = literalKindOf(value)
332
- return admit("Scalar.literal", {
221
+ return admit("Compute.literal", {
333
222
  kind: "literal",
334
223
  value: literalValue(value),
335
- scope,
336
224
  result: kind,
337
225
  depth: 1
338
- }) as ScalarNode<S, ScalarKind>
226
+ }) as ScalarNode<ScalarKind>
339
227
  }
340
228
 
341
229
  type BinaryOp = "add" | "subtract" | "multiply" | "divide"
342
230
 
343
- function scalarBinary<S extends ScalarLeafScope>(
344
- where: string,
345
- op: BinaryOp,
346
- left: ScalarNode<S>,
347
- right: ScalarNode<S>
348
- ): ScalarNode<S, ScalarResultKind> {
349
- const scope = assertScope(where, left, right)
231
+ function scalarBinary(where: string, op: BinaryOp, left: ScalarNode, right: ScalarNode): ScalarNode {
350
232
  return admit(where, {
351
233
  kind: op,
352
234
  left,
353
235
  right,
354
- scope,
355
236
  result: combineNumeric(where, left.result, right.result),
356
237
  depth: Math.max(left.depth, right.depth) + 1
357
238
  })
@@ -363,18 +244,15 @@ function roundingMode(value: unknown): Rounding {
363
244
  return value
364
245
  }
365
246
 
366
- function scalarMulDiv<S extends ScalarLeafScope>(
247
+ function scalarMulDiv(
367
248
  where: string,
368
- a: ScalarNode<S>,
369
- b: ScalarNode<S>,
370
- divisor: ScalarNode<S>,
249
+ a: ScalarNode,
250
+ b: ScalarNode,
251
+ divisor: ScalarNode,
371
252
  rounding: Rounding
372
- ): ScalarNode<S> {
373
- const scope = assertScope(where, a, b)
374
- assertScope(where, a, divisor)
253
+ ): ScalarNode {
375
254
  let known: "i64" | "u64" | undefined
376
255
  for (const operand of [a, b, divisor]) {
377
- if (operand.result === "unresolved") continue
378
256
  if ((operand.result !== "i64" && operand.result !== "u64") || (known !== undefined && known !== operand.result))
379
257
  throw new AuthoringError({ message: `${where}: operands must have one matching integer kind` })
380
258
  known = operand.result
@@ -385,74 +263,57 @@ function scalarMulDiv<S extends ScalarLeafScope>(
385
263
  b,
386
264
  divisor,
387
265
  rounding: roundingMode(rounding),
388
- scope,
389
- result:
390
- a.result === "unresolved" || b.result === "unresolved" || divisor.result === "unresolved"
391
- ? "unresolved"
392
- : a.result,
266
+ result: a.result,
393
267
  depth: Math.max(a.depth, b.depth, divisor.depth) + 1
394
268
  })
395
269
  }
396
270
 
397
- function scalarMeasure<S extends ScalarLeafScope>(where: string, expr: ScalarNode<S>): ScalarNode<S> {
271
+ function scalarMeasure(where: string, expr: ScalarNode): ScalarNode {
398
272
  const kind = expr.result
399
- if (kind !== "unresolved" && kind !== "intervalU64" && kind !== "intervalI64" && kind !== "intervalF64")
273
+ if (kind !== "intervalU64" && kind !== "intervalI64" && kind !== "intervalF64")
400
274
  throw new AuthoringError({ message: `${where}: measure requires an interval` })
401
275
  return admit(where, {
402
276
  kind: "measure",
403
277
  expr,
404
- scope: expr.scope,
405
- result: ({ unresolved: "unresolved", intervalF64: "f64", intervalI64: "u64", intervalU64: "u64" } as const)[kind],
278
+ result: ({ intervalF64: "f64", intervalI64: "u64", intervalU64: "u64" } as const)[kind],
406
279
  depth: expr.depth + 1
407
280
  })
408
281
  }
409
282
 
410
- function scalarNegate<S extends ScalarLeafScope>(where: string, expr: ScalarNode<S>): ScalarNode<S, ScalarResultKind> {
283
+ function scalarNegate(where: string, expr: ScalarNode): ScalarNode {
411
284
  return admit(where, {
412
285
  kind: "negate",
413
286
  expr,
414
- scope: expr.scope,
415
287
  result: negateKind(where, expr.result),
416
288
  depth: expr.depth + 1
417
289
  })
418
290
  }
419
291
 
420
- function scalarCast<S extends ScalarLeafScope>(
421
- where: string,
422
- cast: NumericCast,
423
- result: ScalarKind,
424
- expr: ScalarNode<S>
425
- ): ScalarNode<S, ScalarKind> {
292
+ function scalarCast(where: string, cast: NumericCast, result: ScalarKind, expr: ScalarNode): ScalarNode<ScalarKind> {
426
293
  assertCastOperand(where, expr.result)
427
294
  return admit(where, {
428
295
  kind: "cast",
429
296
  cast,
430
297
  expr,
431
- scope: expr.scope,
432
298
  result,
433
299
  depth: expr.depth + 1
434
300
  })
435
301
  }
436
302
 
437
- function scalarFloatPredicate<S extends ScalarLeafScope>(
438
- where: string,
439
- op: "isNaN" | "isFinite",
440
- expr: ScalarNode<S>
441
- ): ScalarNode<S, "bool"> {
303
+ function scalarFloatPredicate(where: string, op: "isNaN" | "isFinite", expr: ScalarNode): ScalarNode<"bool"> {
442
304
  assertFloatOperand(where, expr.result)
443
305
  return admit(where, {
444
306
  kind: op,
445
307
  expr,
446
- scope: expr.scope,
447
308
  result: "bool",
448
309
  depth: expr.depth + 1
449
310
  })
450
311
  }
451
312
 
452
313
  /** Query-var leaves collected once at find-binding time — not during construction. */
453
- function queryVarsOf(node: ScalarNode<"query-var">): readonly ScalarQueryVar[] {
314
+ function queryVarsOf(node: ScalarNode): readonly ScalarQueryVar[] {
454
315
  const vars: ScalarQueryVar[] = []
455
- const pending: ScalarNode<"query-var">[] = [node]
316
+ const pending: ScalarNode[] = [node]
456
317
  while (pending.length > 0) {
457
318
  const next = pending.pop()
458
319
  if (next === undefined) {
@@ -480,179 +341,61 @@ function queryVarsOf(node: ScalarNode<"query-var">): readonly ScalarQueryVar[] {
480
341
  case "divide":
481
342
  pending.push(next.left, next.right)
482
343
  break
483
- default:
484
- throw new AuthoringError({
485
- message: "queryVarsOf: a query-var tree cannot carry a source-field leaf"
486
- })
487
344
  }
488
345
  }
489
346
  return vars
490
347
  }
491
348
 
492
- function field(name: string): ScalarFieldRef {
493
- return sourceField(name)
494
- }
495
-
496
- function literal(value: ScalarLiteral): ScalarExpr<ScalarKind> {
497
- return scalarLiteral("source-field", value)
498
- }
499
-
500
- function u64(value: bigint): ScalarExpr<"u64"> {
501
- checkU64(value, "Scalar.u64")
502
- return scalarLiteral("source-field", { u64: value }) as ScalarExpr<"u64">
503
- }
504
-
505
- function i64(value: bigint): ScalarExpr<"i64"> {
506
- checkI64(value, "Scalar.i64")
507
- return scalarLiteral("source-field", { i64: value }) as ScalarExpr<"i64">
508
- }
509
-
510
- function f64(value: number): ScalarExpr<"f64"> {
511
- checkF64(value, "Scalar.f64")
512
- return scalarLiteral("source-field", { f64: value }) as ScalarExpr<"f64">
513
- }
514
-
515
- function bool(value: boolean): ScalarExpr<"bool"> {
516
- checkBool(value, "Scalar.bool")
517
- return scalarLiteral("source-field", { bool: value }) as ScalarExpr<"bool">
518
- }
519
-
520
- function negate<K extends "i64" | "f64" | "unresolved">(expr: ScalarExpr<K>): ScalarExpr<K> {
521
- return scalarNegate("Scalar.negate", expr) as ScalarExpr<K>
522
- }
523
-
524
- function add<L extends NumericOrUnresolved, R extends CombineNumeric<L, R> extends never ? never : NumericOrUnresolved>(
525
- left: ScalarExpr<L>,
526
- right: ScalarExpr<R>
527
- ): ScalarExpr<CombineNumeric<L, R>> {
528
- return scalarBinary("Scalar.add", "add", left, right) as ScalarExpr<CombineNumeric<L, R>>
529
- }
530
-
531
- function subtract<
532
- L extends NumericOrUnresolved,
533
- R extends CombineNumeric<L, R> extends never ? never : NumericOrUnresolved
534
- >(left: ScalarExpr<L>, right: ScalarExpr<R>): ScalarExpr<CombineNumeric<L, R>> {
535
- return scalarBinary("Scalar.subtract", "subtract", left, right) as ScalarExpr<CombineNumeric<L, R>>
536
- }
537
-
538
- function multiply<
539
- L extends NumericOrUnresolved,
540
- R extends CombineNumeric<L, R> extends never ? never : NumericOrUnresolved
541
- >(left: ScalarExpr<L>, right: ScalarExpr<R>): ScalarExpr<CombineNumeric<L, R>> {
542
- return scalarBinary("Scalar.multiply", "multiply", left, right) as ScalarExpr<CombineNumeric<L, R>>
543
- }
544
-
545
- function divide<
546
- L extends NumericOrUnresolved,
547
- R extends CombineNumeric<L, R> extends never ? never : NumericOrUnresolved
548
- >(left: ScalarExpr<L>, right: ScalarExpr<R>): ScalarExpr<CombineNumeric<L, R>> {
549
- return scalarBinary("Scalar.divide", "divide", left, right) as ScalarExpr<CombineNumeric<L, R>>
550
- }
551
-
552
- function mulDiv<
553
- L extends "i64" | "u64" | "unresolved",
554
- R extends CombineNumeric<L, R> extends never ? never : "i64" | "u64" | "unresolved",
555
- D extends CombineNumeric<L, D> extends never
556
- ? never
557
- : CombineNumeric<R, D> extends never
558
- ? never
559
- : "i64" | "u64" | "unresolved"
560
- >(
561
- a: ScalarExpr<L>,
562
- b: ScalarExpr<R>,
563
- divisor: ScalarExpr<D>,
564
- rounding: Rounding
565
- ): ScalarExpr<CombineNumeric<CombineNumeric<L, R>, D>> {
566
- return scalarMulDiv("Scalar.mulDiv", a, b, divisor, rounding) as ScalarExpr<CombineNumeric<CombineNumeric<L, R>, D>>
567
- }
568
-
569
- function measure(expr: ScalarFieldRef): ScalarExpr<"unresolved"> {
570
- return scalarMeasure("Scalar.measure", expr) as ScalarExpr<"unresolved">
571
- }
572
-
573
- function toF64(expr: ScalarExpr<NumericOrUnresolved>): ScalarExpr<"f64"> {
574
- return scalarCast("Scalar.toF64", "toF64", "f64", expr) as ScalarExpr<"f64">
575
- }
349
+ /** Lower each query variable through its existing binding. */
350
+ const ROUNDING = {
351
+ towardZero: "TowardZero",
352
+ nearestTiesAwayFromZero: "NearestTiesAwayFromZero",
353
+ nearestTiesToEven: "NearestTiesToEven"
354
+ } as const
576
355
 
577
- function toF64Exact(expr: ScalarExpr<NumericOrUnresolved>): ScalarExpr<"f64"> {
578
- return scalarCast("Scalar.toF64Exact", "toF64Exact", "f64", expr) as ScalarExpr<"f64">
579
- }
356
+ const CAST = { toF64: "ToF64", toF64Exact: "ToF64Exact", toI64Exact: "ToI64Exact", toU64Exact: "ToU64Exact" } as const
580
357
 
581
- function toI64Exact(expr: ScalarExpr<NumericOrUnresolved>): ScalarExpr<"i64"> {
582
- return scalarCast("Scalar.toI64Exact", "toI64Exact", "i64", expr) as ScalarExpr<"i64">
583
- }
358
+ const UNARY = { measure: "Measure", negate: "Negate", isNaN: "IsNaN", isFinite: "IsFinite" } as const
584
359
 
585
- function toU64Exact(expr: ScalarExpr<NumericOrUnresolved>): ScalarExpr<"u64"> {
586
- return scalarCast("Scalar.toU64Exact", "toU64Exact", "u64", expr) as ScalarExpr<"u64">
587
- }
360
+ const BINARY = { add: "Add", subtract: "Subtract", multiply: "Multiply", divide: "Divide" } as const
588
361
 
589
- function isNaNExpr(expr: ScalarExpr<"f64" | "unresolved">): ScalarExpr<"bool"> {
590
- return scalarFloatPredicate("Scalar.isNaN", "isNaN", expr)
591
- }
592
-
593
- function isFiniteExpr(expr: ScalarExpr<"f64" | "unresolved">): ScalarExpr<"bool"> {
594
- return scalarFloatPredicate("Scalar.isFinite", "isFinite", expr)
595
- }
596
-
597
- /** One lowering walk for query variables and row-field bindings. */
598
- function scalarWire(node: ScalarNode, leaf: (node: QueryVarLeaf | SourceFieldLeaf) => number): ScalarExprIr {
599
- const walk = (expr: ScalarNode): ScalarExprIr => scalarWire(expr, leaf)
362
+ /** Lowers a scalar expression to the addon's `ScalarExprIn`; `leaf` numbers the rule variables. */
363
+ function scalarWire(node: ScalarNode, leaf: (node: QueryVarLeaf) => number): ScalarExprIn {
364
+ const walk = (expr: ScalarNode): ScalarExprIn => scalarWire(expr, leaf)
600
365
  switch (node.kind) {
601
366
  case "var":
602
- case "field":
603
- return { kind: "var", var: leaf(node) }
367
+ return { kind: "Var", var: leaf(node) }
604
368
  case "literal":
605
- return { kind: "literal", value: literalWireOf(node.value) }
369
+ return { kind: "Literal", value: valueIn(literalWireOf(node.value)) }
606
370
  case "measure":
607
371
  case "negate":
608
372
  case "isNaN":
609
373
  case "isFinite":
610
- return { kind: node.kind, expr: walk(node.expr) }
374
+ return { kind: UNARY[node.kind], expr: walk(node.expr) }
611
375
  case "cast":
612
- return { kind: node.kind, cast: node.cast, expr: walk(node.expr) }
376
+ return { kind: "Cast", cast: CAST[node.cast], expr: walk(node.expr) }
613
377
  case "mulDiv":
614
- return { kind: node.kind, a: walk(node.a), b: walk(node.b), divisor: walk(node.divisor), rounding: node.rounding }
378
+ return {
379
+ kind: "MulDiv",
380
+ a: walk(node.a),
381
+ b: walk(node.b),
382
+ divisor: walk(node.divisor),
383
+ rounding: ROUNDING[node.rounding]
384
+ }
615
385
  case "add":
616
386
  case "subtract":
617
387
  case "multiply":
618
388
  case "divide":
619
- return { kind: node.kind, left: walk(node.left), right: walk(node.right) }
389
+ return { kind: BINARY[node.kind], left: walk(node.left), right: walk(node.right) }
620
390
  }
621
391
  }
622
392
 
623
- /** The authoring namespace: `Scalar.field("units")`, `Scalar.add(...)`. */
624
- const Scalar = Object.freeze({
625
- field,
626
- literal,
627
- u64,
628
- i64,
629
- f64,
630
- bool,
631
- negate,
632
- add,
633
- subtract,
634
- multiply,
635
- divide,
636
- mulDiv,
637
- measure,
638
- toF64,
639
- toF64Exact,
640
- toI64Exact,
641
- toU64Exact,
642
- isNaN: isNaNExpr,
643
- isFinite: isFiniteExpr
644
- })
645
-
646
393
  export type {
647
- CombineNumeric,
648
394
  IntervalKind,
649
395
  NumericCast,
650
396
  NumericKind,
651
- NumericOrUnresolved,
652
397
  QueryVarLeaf,
653
398
  Rounding,
654
- ScalarExpr,
655
- ScalarFieldRef,
656
399
  ScalarInputKind,
657
400
  ScalarKind,
658
401
  ScalarLiteral,
@@ -660,8 +403,7 @@ export type {
660
403
  ScalarOpKind,
661
404
  ScalarQueryVar,
662
405
  ScalarResultKind,
663
- ScalarValue,
664
- SourceFieldLeaf
406
+ ScalarValue
665
407
  }
666
408
  export {
667
409
  assertDepth,
@@ -672,7 +414,6 @@ export {
672
414
  checkI64,
673
415
  checkU64,
674
416
  isScalarNode,
675
- isUnresolvedScalar,
676
417
  literalKindOf,
677
418
  literalValue,
678
419
  literalWireOf,
@@ -680,7 +421,6 @@ export {
680
421
  queryVarLeaf,
681
422
  queryVarsOf,
682
423
  roundingMode,
683
- Scalar,
684
424
  scalarAuthoringWork,
685
425
  scalarBinary,
686
426
  scalarCast,