@bjornpagen/bumbledb 1.2.1 → 1.3.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.
- package/COOKBOOK.md +240 -9
- package/README.md +9 -6
- package/dist/alternatives.d.ts +25 -0
- package/dist/alternatives.d.ts.map +1 -0
- package/dist/alternatives.js +59 -0
- package/dist/alternatives.js.map +1 -0
- package/dist/changes.d.ts +0 -1
- package/dist/changes.d.ts.map +1 -1
- package/dist/changes.js +2 -8
- package/dist/changes.js.map +1 -1
- package/dist/codec.d.ts +8 -1
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +29 -2
- package/dist/codec.js.map +1 -1
- package/dist/db-native.d.ts +2 -9
- package/dist/db-native.d.ts.map +1 -1
- package/dist/db-native.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/log.d.ts +4 -4
- package/dist/internal/log.d.ts.map +1 -1
- package/dist/internal/log.js +2 -2
- package/dist/internal/log.js.map +1 -1
- package/dist/native.d.ts +23 -9
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +2 -1
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js.map +1 -1
- package/dist/query/compute.d.ts +19 -4
- package/dist/query/compute.d.ts.map +1 -1
- package/dist/query/compute.js +17 -13
- package/dist/query/compute.js.map +1 -1
- package/dist/query/description.d.ts +10 -2
- package/dist/query/description.d.ts.map +1 -1
- package/dist/query/description.js +14 -5
- package/dist/query/description.js.map +1 -1
- package/dist/query/find.d.ts +13 -6
- package/dist/query/find.d.ts.map +1 -1
- package/dist/query/find.js +1 -1
- package/dist/query/find.js.map +1 -1
- package/dist/query/lower.d.ts +14 -2
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +64 -50
- package/dist/query/lower.js.map +1 -1
- package/dist/query/parse-ir.d.ts.map +1 -1
- package/dist/query/parse-ir.js +26 -3
- package/dist/query/parse-ir.js.map +1 -1
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +6 -1
- package/dist/query/scope.js.map +1 -1
- package/dist/query/segments.d.ts +20 -0
- package/dist/query/segments.d.ts.map +1 -0
- package/dist/query/segments.js +35 -0
- package/dist/query/segments.js.map +1 -0
- package/dist/runtime-codes.d.ts +1 -1
- package/dist/runtime-codes.d.ts.map +1 -1
- package/dist/runtime-codes.js +1 -0
- package/dist/runtime-codes.js.map +1 -1
- package/dist/runtime-errors.d.ts +23 -3
- package/dist/runtime-errors.d.ts.map +1 -1
- package/dist/runtime-errors.js +16 -3
- package/dist/runtime-errors.js.map +1 -1
- package/dist/runtime-native.d.ts +3 -8
- package/dist/runtime-native.d.ts.map +1 -1
- package/dist/runtime-native.js.map +1 -1
- package/dist/runtime.d.ts +0 -23
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +0 -36
- package/dist/runtime.js.map +1 -1
- package/dist/scalar.d.ts +46 -94
- package/dist/scalar.d.ts.map +1 -1
- package/dist/scalar.js +69 -156
- package/dist/scalar.js.map +1 -1
- package/dist/schema-file.d.ts +7 -0
- package/dist/schema-file.d.ts.map +1 -0
- package/dist/schema-file.js +24 -0
- package/dist/schema-file.js.map +1 -0
- package/pack-provenance.json +4 -4
- package/package.json +4 -4
- package/src/alternatives.ts +95 -0
- package/src/changes.ts +2 -8
- package/src/codec.ts +43 -3
- package/src/db-native.ts +2 -10
- package/src/index.ts +23 -6
- package/src/internal/log.ts +2 -4
- package/src/native.ts +21 -7
- package/src/query/atom.ts +2 -0
- package/src/query/compute.ts +46 -16
- package/src/query/description.ts +38 -8
- package/src/query/find.ts +37 -26
- package/src/query/lower.ts +89 -52
- package/src/query/parse-ir.ts +27 -3
- package/src/query/scope.ts +8 -1
- package/src/query/segments.ts +61 -0
- package/src/runtime-codes.ts +1 -0
- package/src/runtime-errors.ts +16 -3
- package/src/runtime-native.ts +1 -9
- package/src/runtime.ts +1 -70
- package/src/scalar.ts +138 -285
- package/src/schema-file.ts +38 -0
- package/dist/migration.d.ts +0 -31
- package/dist/migration.d.ts.map +0 -1
- package/dist/migration.js +0 -47
- package/dist/migration.js.map +0 -1
- package/src/migration.ts +0 -61
package/src/scalar.ts
CHANGED
|
@@ -1,31 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
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
|
-
*/
|
|
1
|
+
/** Query scalar nodes, with cached kind and depth. Construction is constant
|
|
2
|
+
* work; native preparation binds variables and evaluates the expressions. */
|
|
18
3
|
import { AuthoringError } from "#errors.ts"
|
|
4
|
+
import type { ScalarExprIr } from "#native.ts"
|
|
19
5
|
import type { ValueSpec } from "#spec.ts"
|
|
20
6
|
|
|
21
|
-
/** F0: leaf scope for the shared AST (C1). Query vars are typed; source fields stay unresolved. */
|
|
22
|
-
export type ScalarLeafScope = "query-var" | "source-field"
|
|
23
|
-
|
|
24
7
|
/** The engine's scalar result vocabulary — distinct at the type level. */
|
|
25
8
|
type ScalarKind = "u64" | "i64" | "f64" | "bool"
|
|
26
9
|
|
|
27
10
|
/** Cached result kind: known only when derivable; otherwise honestly unresolved. */
|
|
28
|
-
type
|
|
11
|
+
type IntervalKind = "intervalU64" | "intervalI64" | "intervalF64"
|
|
12
|
+
type ScalarInputKind = ScalarKind | IntervalKind
|
|
13
|
+
type ScalarResultKind = ScalarInputKind
|
|
14
|
+
type Rounding = "towardZero" | "nearestTiesAwayFromZero" | "nearestTiesToEven"
|
|
29
15
|
|
|
30
16
|
/** Host value for a derived scalar kind. */
|
|
31
17
|
type ScalarValue<K extends ScalarKind> = K extends "f64" ? number : K extends "bool" ? boolean : bigint
|
|
@@ -34,33 +20,24 @@ type NumericCast = "toF64" | "toF64Exact" | "toI64Exact" | "toU64Exact"
|
|
|
34
20
|
|
|
35
21
|
type NumericKind = "u64" | "i64" | "f64"
|
|
36
22
|
|
|
37
|
-
type NumericOrUnresolved = NumericKind | "unresolved"
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Combine known numeric kinds, or stay unresolved when a source-field leaf
|
|
41
|
-
* still needs native binding. Distinct known kinds collapse to `never`
|
|
42
|
-
* (static refusal) and throw at the constructor.
|
|
43
|
-
*/
|
|
44
|
-
type CombineNumeric<L, R> = L extends "unresolved"
|
|
45
|
-
? R extends "bool"
|
|
46
|
-
? never
|
|
47
|
-
: "unresolved"
|
|
48
|
-
: R extends "unresolved"
|
|
49
|
-
? L extends "bool"
|
|
50
|
-
? never
|
|
51
|
-
: "unresolved"
|
|
52
|
-
: L extends R
|
|
53
|
-
? L
|
|
54
|
-
: never
|
|
55
|
-
|
|
56
|
-
/** The tagged literal subset shared by every leaf scope. */
|
|
57
23
|
type ScalarLiteral =
|
|
58
24
|
| { readonly bool: boolean }
|
|
59
25
|
| { readonly u64: bigint }
|
|
60
26
|
| { readonly i64: bigint }
|
|
61
27
|
| { readonly f64: number }
|
|
62
28
|
|
|
63
|
-
type ScalarOpKind =
|
|
29
|
+
type ScalarOpKind =
|
|
30
|
+
| "literal"
|
|
31
|
+
| "negate"
|
|
32
|
+
| "isNaN"
|
|
33
|
+
| "isFinite"
|
|
34
|
+
| "add"
|
|
35
|
+
| "subtract"
|
|
36
|
+
| "multiply"
|
|
37
|
+
| "divide"
|
|
38
|
+
| "cast"
|
|
39
|
+
| "mulDiv"
|
|
40
|
+
| "measure"
|
|
64
41
|
|
|
65
42
|
/**
|
|
66
43
|
* Structural query-variable leaf. The query layer supplies a bound variable
|
|
@@ -74,46 +51,32 @@ interface ScalarQueryVar {
|
|
|
74
51
|
|
|
75
52
|
type QueryVarLeaf = { readonly kind: "var"; readonly ref: ScalarQueryVar }
|
|
76
53
|
|
|
77
|
-
type
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
54
|
+
type ScalarNodeBody =
|
|
55
|
+
| { readonly kind: "measure"; readonly expr: ScalarNode }
|
|
56
|
+
| {
|
|
57
|
+
readonly kind: "mulDiv"
|
|
58
|
+
readonly a: ScalarNode
|
|
59
|
+
readonly b: ScalarNode
|
|
60
|
+
readonly divisor: ScalarNode
|
|
61
|
+
readonly rounding: Rounding
|
|
62
|
+
}
|
|
63
|
+
| QueryVarLeaf
|
|
83
64
|
| { readonly kind: "literal"; readonly value: ScalarLiteral }
|
|
84
|
-
| { readonly kind: "negate"; readonly expr: ScalarNode
|
|
85
|
-
| { readonly kind: "isNaN"; readonly expr: ScalarNode
|
|
86
|
-
| { readonly kind: "isFinite"; readonly expr: ScalarNode
|
|
87
|
-
| { readonly kind: "add"; readonly left: ScalarNode
|
|
88
|
-
| { readonly kind: "subtract"; readonly left: ScalarNode
|
|
89
|
-
| { readonly kind: "multiply"; readonly left: ScalarNode
|
|
90
|
-
| { readonly kind: "divide"; readonly left: ScalarNode
|
|
91
|
-
| { readonly kind: "cast"; readonly cast: NumericCast; readonly expr: ScalarNode
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
|
|
95
|
-
* Summaries are construction metadata; lowering and L17 serialization read
|
|
96
|
-
* the grammar arms and ignore the summaries.
|
|
97
|
-
*/
|
|
98
|
-
type ScalarNode<
|
|
99
|
-
S extends ScalarLeafScope = ScalarLeafScope,
|
|
100
|
-
K extends ScalarResultKind = ScalarResultKind
|
|
101
|
-
> = ScalarNodeBody<S> & {
|
|
102
|
-
readonly scope: S
|
|
65
|
+
| { readonly kind: "negate"; readonly expr: ScalarNode }
|
|
66
|
+
| { readonly kind: "isNaN"; readonly expr: ScalarNode }
|
|
67
|
+
| { readonly kind: "isFinite"; readonly expr: ScalarNode }
|
|
68
|
+
| { readonly kind: "add"; readonly left: ScalarNode; readonly right: ScalarNode }
|
|
69
|
+
| { readonly kind: "subtract"; readonly left: ScalarNode; readonly right: ScalarNode }
|
|
70
|
+
| { readonly kind: "multiply"; readonly left: ScalarNode; readonly right: ScalarNode }
|
|
71
|
+
| { readonly kind: "divide"; readonly left: ScalarNode; readonly right: ScalarNode }
|
|
72
|
+
| { readonly kind: "cast"; readonly cast: NumericCast; readonly expr: ScalarNode }
|
|
73
|
+
|
|
74
|
+
/** Cached summaries never replace the expression grammar. */
|
|
75
|
+
type ScalarNode<K extends ScalarResultKind = ScalarResultKind> = ScalarNodeBody & {
|
|
103
76
|
readonly result: K
|
|
104
77
|
readonly depth: number
|
|
105
78
|
}
|
|
106
79
|
|
|
107
|
-
/**
|
|
108
|
-
* Migration authoring expression (source-field scope). `K` is the cached
|
|
109
|
-
* result kind, not a host value type: I64 and U64 remain distinct even
|
|
110
|
-
* though both use bigint in JavaScript.
|
|
111
|
-
*/
|
|
112
|
-
type ScalarExpr<K extends ScalarResultKind = ScalarResultKind> = ScalarNode<"source-field", K>
|
|
113
|
-
|
|
114
|
-
/** A migration field read: unresolved until native snapshot binding. */
|
|
115
|
-
type ScalarFieldRef = ScalarNode<"source-field", "unresolved"> & SourceFieldLeaf
|
|
116
|
-
|
|
117
80
|
const MAX_SCALAR_DEPTH = 128
|
|
118
81
|
const U64_MAX = (1n << 64n) - 1n
|
|
119
82
|
const I64_MIN = -(1n << 63n)
|
|
@@ -126,9 +89,10 @@ function scalarAuthoringWork(): number {
|
|
|
126
89
|
return authoringWork
|
|
127
90
|
}
|
|
128
91
|
|
|
129
|
-
function admit<
|
|
130
|
-
|
|
131
|
-
|
|
92
|
+
function admit<const Node extends { readonly result: ScalarResultKind; readonly depth: number }>(
|
|
93
|
+
where: string,
|
|
94
|
+
node: Node
|
|
95
|
+
): Readonly<Node> {
|
|
132
96
|
authoringWork += 1
|
|
133
97
|
assertDepth(where, node.depth)
|
|
134
98
|
return Object.freeze(node)
|
|
@@ -197,49 +161,28 @@ function assertDepth(where: string, depth: number): void {
|
|
|
197
161
|
}
|
|
198
162
|
}
|
|
199
163
|
|
|
200
|
-
function assertNumeric(where: string, kind:
|
|
201
|
-
if (kind
|
|
164
|
+
function assertNumeric(where: string, kind: ScalarInputKind): asserts kind is NumericKind {
|
|
165
|
+
if (kind !== "u64" && kind !== "i64" && kind !== "f64") {
|
|
202
166
|
throw new AuthoringError({ message: `${where}: the operand is bool, not numeric (u64/i64/f64)` })
|
|
203
167
|
}
|
|
204
168
|
}
|
|
205
169
|
|
|
206
|
-
function assertSameKind(where: string, left:
|
|
170
|
+
function assertSameKind(where: string, left: ScalarInputKind, right: ScalarInputKind): ScalarInputKind {
|
|
207
171
|
if (left !== right) {
|
|
208
172
|
throw new AuthoringError({
|
|
209
|
-
message: `${where}: operand kinds differ (${left} vs ${right}) — the engine has no mixed promotion; cast explicitly (
|
|
173
|
+
message: `${where}: operand kinds differ (${left} vs ${right}) — the engine has no mixed promotion; cast explicitly (Compute.toF64/ toF64Exact/ toI64Exact/ toU64Exact)`
|
|
210
174
|
})
|
|
211
175
|
}
|
|
212
176
|
return left
|
|
213
177
|
}
|
|
214
178
|
|
|
215
|
-
function assertScope<S extends ScalarLeafScope>(where: string, left: ScalarNode<S>, right: ScalarNode<S>): S {
|
|
216
|
-
if (left.scope !== right.scope) {
|
|
217
|
-
throw new AuthoringError({
|
|
218
|
-
message: `${where}: leaf scopes differ (${left.scope} vs ${right.scope}) — query-var and source-field trees do not mix`
|
|
219
|
-
})
|
|
220
|
-
}
|
|
221
|
-
return left.scope
|
|
222
|
-
}
|
|
223
|
-
|
|
224
179
|
function combineNumeric(where: string, left: ScalarResultKind, right: ScalarResultKind): ScalarResultKind {
|
|
225
|
-
if (left === "unresolved" || right === "unresolved") {
|
|
226
|
-
if (left !== "unresolved") {
|
|
227
|
-
assertNumeric(where, left)
|
|
228
|
-
}
|
|
229
|
-
if (right !== "unresolved") {
|
|
230
|
-
assertNumeric(where, right)
|
|
231
|
-
}
|
|
232
|
-
return "unresolved"
|
|
233
|
-
}
|
|
234
180
|
assertNumeric(where, left)
|
|
235
181
|
assertNumeric(where, right)
|
|
236
182
|
return assertSameKind(where, left, right)
|
|
237
183
|
}
|
|
238
184
|
|
|
239
185
|
function negateKind(where: string, inner: ScalarResultKind): ScalarResultKind {
|
|
240
|
-
if (inner === "unresolved") {
|
|
241
|
-
return "unresolved"
|
|
242
|
-
}
|
|
243
186
|
if (inner !== "i64" && inner !== "f64") {
|
|
244
187
|
throw new AuthoringError({
|
|
245
188
|
message: `${where}: the operand is ${inner} — negation is defined over i64 and f64 only`
|
|
@@ -249,137 +192,127 @@ function negateKind(where: string, inner: ScalarResultKind): ScalarResultKind {
|
|
|
249
192
|
}
|
|
250
193
|
|
|
251
194
|
function assertCastOperand(where: string, inner: ScalarResultKind): void {
|
|
252
|
-
if (inner === "unresolved") {
|
|
253
|
-
return
|
|
254
|
-
}
|
|
255
195
|
assertNumeric(where, inner)
|
|
256
196
|
}
|
|
257
197
|
|
|
258
198
|
function assertFloatOperand(where: string, inner: ScalarResultKind): void {
|
|
259
|
-
if (inner === "unresolved") {
|
|
260
|
-
return
|
|
261
|
-
}
|
|
262
199
|
if (inner !== "f64") {
|
|
263
200
|
throw new AuthoringError({ message: `${where}: the operand is ${inner} — the float predicates read f64` })
|
|
264
201
|
}
|
|
265
202
|
}
|
|
266
203
|
|
|
267
204
|
function isScalarNode(value: unknown): value is ScalarNode {
|
|
268
|
-
return
|
|
269
|
-
typeof value === "object" &&
|
|
270
|
-
value !== null &&
|
|
271
|
-
"kind" in value &&
|
|
272
|
-
"scope" in value &&
|
|
273
|
-
"result" in value &&
|
|
274
|
-
"depth" in value
|
|
275
|
-
)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
function isUnresolvedScalar(node: ScalarNode): boolean {
|
|
279
|
-
return node.result === "unresolved"
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/** Source-field leaf — unresolved until L14 binds it against the verified snapshot. */
|
|
283
|
-
function sourceField(name: string): ScalarFieldRef {
|
|
284
|
-
if (typeof name !== "string" || name.length === 0) {
|
|
285
|
-
throw new AuthoringError({ message: "scalar field(...) names a nonempty source field" })
|
|
286
|
-
}
|
|
287
|
-
return admit("Scalar.field", {
|
|
288
|
-
kind: "field",
|
|
289
|
-
name,
|
|
290
|
-
scope: "source-field",
|
|
291
|
-
result: "unresolved",
|
|
292
|
-
depth: 1
|
|
293
|
-
})
|
|
205
|
+
return typeof value === "object" && value !== null && "kind" in value && "result" in value && "depth" in value
|
|
294
206
|
}
|
|
295
207
|
|
|
296
208
|
/** Query-var leaf — kind is the variable's schema kind, already known. */
|
|
297
|
-
function queryVarLeaf<K extends
|
|
298
|
-
return admit("
|
|
209
|
+
function queryVarLeaf<K extends ScalarInputKind>(ref: ScalarQueryVar, kind: K): ScalarNode<K> {
|
|
210
|
+
return admit("Compute.variable", {
|
|
299
211
|
kind: "var",
|
|
300
212
|
ref,
|
|
301
|
-
scope: "query-var",
|
|
302
213
|
result: kind,
|
|
303
214
|
depth: 1
|
|
304
215
|
})
|
|
305
216
|
}
|
|
306
217
|
|
|
307
|
-
function scalarLiteral
|
|
218
|
+
function scalarLiteral(value: ScalarLiteral): ScalarNode<ScalarKind> {
|
|
308
219
|
const kind = literalKindOf(value)
|
|
309
|
-
return admit("
|
|
220
|
+
return admit("Compute.literal", {
|
|
310
221
|
kind: "literal",
|
|
311
222
|
value: literalValue(value),
|
|
312
|
-
scope,
|
|
313
223
|
result: kind,
|
|
314
224
|
depth: 1
|
|
315
|
-
}) as ScalarNode<
|
|
225
|
+
}) as ScalarNode<ScalarKind>
|
|
316
226
|
}
|
|
317
227
|
|
|
318
228
|
type BinaryOp = "add" | "subtract" | "multiply" | "divide"
|
|
319
229
|
|
|
320
|
-
function scalarBinary
|
|
321
|
-
where: string,
|
|
322
|
-
op: BinaryOp,
|
|
323
|
-
left: ScalarNode<S>,
|
|
324
|
-
right: ScalarNode<S>
|
|
325
|
-
): ScalarNode<S, ScalarResultKind> {
|
|
326
|
-
const scope = assertScope(where, left, right)
|
|
230
|
+
function scalarBinary(where: string, op: BinaryOp, left: ScalarNode, right: ScalarNode): ScalarNode {
|
|
327
231
|
return admit(where, {
|
|
328
232
|
kind: op,
|
|
329
233
|
left,
|
|
330
234
|
right,
|
|
331
|
-
scope,
|
|
332
235
|
result: combineNumeric(where, left.result, right.result),
|
|
333
236
|
depth: Math.max(left.depth, right.depth) + 1
|
|
334
237
|
})
|
|
335
238
|
}
|
|
336
239
|
|
|
337
|
-
function
|
|
240
|
+
function roundingMode(value: unknown): Rounding {
|
|
241
|
+
if (value !== "towardZero" && value !== "nearestTiesAwayFromZero" && value !== "nearestTiesToEven")
|
|
242
|
+
throw new AuthoringError({ message: "unknown integer rounding mode" })
|
|
243
|
+
return value
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function scalarMulDiv(
|
|
247
|
+
where: string,
|
|
248
|
+
a: ScalarNode,
|
|
249
|
+
b: ScalarNode,
|
|
250
|
+
divisor: ScalarNode,
|
|
251
|
+
rounding: Rounding
|
|
252
|
+
): ScalarNode {
|
|
253
|
+
let known: "i64" | "u64" | undefined
|
|
254
|
+
for (const operand of [a, b, divisor]) {
|
|
255
|
+
if ((operand.result !== "i64" && operand.result !== "u64") || (known !== undefined && known !== operand.result))
|
|
256
|
+
throw new AuthoringError({ message: `${where}: operands must have one matching integer kind` })
|
|
257
|
+
known = operand.result
|
|
258
|
+
}
|
|
259
|
+
return admit(where, {
|
|
260
|
+
kind: "mulDiv",
|
|
261
|
+
a,
|
|
262
|
+
b,
|
|
263
|
+
divisor,
|
|
264
|
+
rounding: roundingMode(rounding),
|
|
265
|
+
result: a.result,
|
|
266
|
+
depth: Math.max(a.depth, b.depth, divisor.depth) + 1
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function scalarMeasure(where: string, expr: ScalarNode): ScalarNode {
|
|
271
|
+
const kind = expr.result
|
|
272
|
+
if (kind !== "intervalU64" && kind !== "intervalI64" && kind !== "intervalF64")
|
|
273
|
+
throw new AuthoringError({ message: `${where}: measure requires an interval` })
|
|
274
|
+
return admit(where, {
|
|
275
|
+
kind: "measure",
|
|
276
|
+
expr,
|
|
277
|
+
result: ({ intervalF64: "f64", intervalI64: "u64", intervalU64: "u64" } as const)[kind],
|
|
278
|
+
depth: expr.depth + 1
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function scalarNegate(where: string, expr: ScalarNode): ScalarNode {
|
|
338
283
|
return admit(where, {
|
|
339
284
|
kind: "negate",
|
|
340
285
|
expr,
|
|
341
|
-
scope: expr.scope,
|
|
342
286
|
result: negateKind(where, expr.result),
|
|
343
287
|
depth: expr.depth + 1
|
|
344
288
|
})
|
|
345
289
|
}
|
|
346
290
|
|
|
347
|
-
function scalarCast
|
|
348
|
-
where: string,
|
|
349
|
-
cast: NumericCast,
|
|
350
|
-
result: ScalarKind,
|
|
351
|
-
expr: ScalarNode<S>
|
|
352
|
-
): ScalarNode<S, ScalarKind> {
|
|
291
|
+
function scalarCast(where: string, cast: NumericCast, result: ScalarKind, expr: ScalarNode): ScalarNode<ScalarKind> {
|
|
353
292
|
assertCastOperand(where, expr.result)
|
|
354
293
|
return admit(where, {
|
|
355
294
|
kind: "cast",
|
|
356
295
|
cast,
|
|
357
296
|
expr,
|
|
358
|
-
scope: expr.scope,
|
|
359
297
|
result,
|
|
360
298
|
depth: expr.depth + 1
|
|
361
299
|
})
|
|
362
300
|
}
|
|
363
301
|
|
|
364
|
-
function scalarFloatPredicate
|
|
365
|
-
where: string,
|
|
366
|
-
op: "isNaN" | "isFinite",
|
|
367
|
-
expr: ScalarNode<S>
|
|
368
|
-
): ScalarNode<S, "bool"> {
|
|
302
|
+
function scalarFloatPredicate(where: string, op: "isNaN" | "isFinite", expr: ScalarNode): ScalarNode<"bool"> {
|
|
369
303
|
assertFloatOperand(where, expr.result)
|
|
370
304
|
return admit(where, {
|
|
371
305
|
kind: op,
|
|
372
306
|
expr,
|
|
373
|
-
scope: expr.scope,
|
|
374
307
|
result: "bool",
|
|
375
308
|
depth: expr.depth + 1
|
|
376
309
|
})
|
|
377
310
|
}
|
|
378
311
|
|
|
379
312
|
/** Query-var leaves collected once at find-binding time — not during construction. */
|
|
380
|
-
function queryVarsOf(node: ScalarNode
|
|
313
|
+
function queryVarsOf(node: ScalarNode): readonly ScalarQueryVar[] {
|
|
381
314
|
const vars: ScalarQueryVar[] = []
|
|
382
|
-
const pending: ScalarNode
|
|
315
|
+
const pending: ScalarNode[] = [node]
|
|
383
316
|
while (pending.length > 0) {
|
|
384
317
|
const next = pending.pop()
|
|
385
318
|
if (next === undefined) {
|
|
@@ -391,148 +324,66 @@ function queryVarsOf(node: ScalarNode<"query-var">): readonly ScalarQueryVar[] {
|
|
|
391
324
|
break
|
|
392
325
|
case "literal":
|
|
393
326
|
break
|
|
327
|
+
case "measure":
|
|
394
328
|
case "negate":
|
|
395
329
|
case "isNaN":
|
|
396
330
|
case "isFinite":
|
|
397
331
|
case "cast":
|
|
398
332
|
pending.push(next.expr)
|
|
399
333
|
break
|
|
334
|
+
case "mulDiv":
|
|
335
|
+
pending.push(next.a, next.b, next.divisor)
|
|
336
|
+
break
|
|
400
337
|
case "add":
|
|
401
338
|
case "subtract":
|
|
402
339
|
case "multiply":
|
|
403
340
|
case "divide":
|
|
404
341
|
pending.push(next.left, next.right)
|
|
405
342
|
break
|
|
406
|
-
default:
|
|
407
|
-
throw new AuthoringError({
|
|
408
|
-
message: "queryVarsOf: a query-var tree cannot carry a source-field leaf"
|
|
409
|
-
})
|
|
410
343
|
}
|
|
411
344
|
}
|
|
412
345
|
return vars
|
|
413
346
|
}
|
|
414
347
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
function bool(value: boolean): ScalarExpr<"bool"> {
|
|
439
|
-
checkBool(value, "Scalar.bool")
|
|
440
|
-
return scalarLiteral("source-field", { bool: value }) as ScalarExpr<"bool">
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
function negate<K extends "i64" | "f64" | "unresolved">(expr: ScalarExpr<K>): ScalarExpr<K> {
|
|
444
|
-
return scalarNegate("Scalar.negate", expr) as ScalarExpr<K>
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
function add<L extends NumericOrUnresolved, R extends CombineNumeric<L, R> extends never ? never : NumericOrUnresolved>(
|
|
448
|
-
left: ScalarExpr<L>,
|
|
449
|
-
right: ScalarExpr<R>
|
|
450
|
-
): ScalarExpr<CombineNumeric<L, R>> {
|
|
451
|
-
return scalarBinary("Scalar.add", "add", left, right) as ScalarExpr<CombineNumeric<L, R>>
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
function subtract<
|
|
455
|
-
L extends NumericOrUnresolved,
|
|
456
|
-
R extends CombineNumeric<L, R> extends never ? never : NumericOrUnresolved
|
|
457
|
-
>(left: ScalarExpr<L>, right: ScalarExpr<R>): ScalarExpr<CombineNumeric<L, R>> {
|
|
458
|
-
return scalarBinary("Scalar.subtract", "subtract", left, right) as ScalarExpr<CombineNumeric<L, R>>
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
function multiply<
|
|
462
|
-
L extends NumericOrUnresolved,
|
|
463
|
-
R extends CombineNumeric<L, R> extends never ? never : NumericOrUnresolved
|
|
464
|
-
>(left: ScalarExpr<L>, right: ScalarExpr<R>): ScalarExpr<CombineNumeric<L, R>> {
|
|
465
|
-
return scalarBinary("Scalar.multiply", "multiply", left, right) as ScalarExpr<CombineNumeric<L, R>>
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
function divide<
|
|
469
|
-
L extends NumericOrUnresolved,
|
|
470
|
-
R extends CombineNumeric<L, R> extends never ? never : NumericOrUnresolved
|
|
471
|
-
>(left: ScalarExpr<L>, right: ScalarExpr<R>): ScalarExpr<CombineNumeric<L, R>> {
|
|
472
|
-
return scalarBinary("Scalar.divide", "divide", left, right) as ScalarExpr<CombineNumeric<L, R>>
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
function toF64(expr: ScalarExpr<NumericOrUnresolved>): ScalarExpr<"f64"> {
|
|
476
|
-
return scalarCast("Scalar.toF64", "toF64", "f64", expr) as ScalarExpr<"f64">
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
function toF64Exact(expr: ScalarExpr<NumericOrUnresolved>): ScalarExpr<"f64"> {
|
|
480
|
-
return scalarCast("Scalar.toF64Exact", "toF64Exact", "f64", expr) as ScalarExpr<"f64">
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
function toI64Exact(expr: ScalarExpr<NumericOrUnresolved>): ScalarExpr<"i64"> {
|
|
484
|
-
return scalarCast("Scalar.toI64Exact", "toI64Exact", "i64", expr) as ScalarExpr<"i64">
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
function toU64Exact(expr: ScalarExpr<NumericOrUnresolved>): ScalarExpr<"u64"> {
|
|
488
|
-
return scalarCast("Scalar.toU64Exact", "toU64Exact", "u64", expr) as ScalarExpr<"u64">
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
function isNaNExpr(expr: ScalarExpr<"f64" | "unresolved">): ScalarExpr<"bool"> {
|
|
492
|
-
return scalarFloatPredicate("Scalar.isNaN", "isNaN", expr)
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
function isFiniteExpr(expr: ScalarExpr<"f64" | "unresolved">): ScalarExpr<"bool"> {
|
|
496
|
-
return scalarFloatPredicate("Scalar.isFinite", "isFinite", expr)
|
|
348
|
+
/** Lower each query variable through its existing binding. */
|
|
349
|
+
function scalarWire(node: ScalarNode, leaf: (node: QueryVarLeaf) => number): ScalarExprIr {
|
|
350
|
+
const walk = (expr: ScalarNode): ScalarExprIr => scalarWire(expr, leaf)
|
|
351
|
+
switch (node.kind) {
|
|
352
|
+
case "var":
|
|
353
|
+
return { kind: "var", var: leaf(node) }
|
|
354
|
+
case "literal":
|
|
355
|
+
return { kind: "literal", value: literalWireOf(node.value) }
|
|
356
|
+
case "measure":
|
|
357
|
+
case "negate":
|
|
358
|
+
case "isNaN":
|
|
359
|
+
case "isFinite":
|
|
360
|
+
return { kind: node.kind, expr: walk(node.expr) }
|
|
361
|
+
case "cast":
|
|
362
|
+
return { kind: node.kind, cast: node.cast, expr: walk(node.expr) }
|
|
363
|
+
case "mulDiv":
|
|
364
|
+
return { kind: node.kind, a: walk(node.a), b: walk(node.b), divisor: walk(node.divisor), rounding: node.rounding }
|
|
365
|
+
case "add":
|
|
366
|
+
case "subtract":
|
|
367
|
+
case "multiply":
|
|
368
|
+
case "divide":
|
|
369
|
+
return { kind: node.kind, left: walk(node.left), right: walk(node.right) }
|
|
370
|
+
}
|
|
497
371
|
}
|
|
498
372
|
|
|
499
|
-
/** The authoring namespace: `Scalar.field("units")`, `Scalar.add(...)`. */
|
|
500
|
-
const Scalar = Object.freeze({
|
|
501
|
-
field,
|
|
502
|
-
literal,
|
|
503
|
-
u64,
|
|
504
|
-
i64,
|
|
505
|
-
f64,
|
|
506
|
-
bool,
|
|
507
|
-
negate,
|
|
508
|
-
add,
|
|
509
|
-
subtract,
|
|
510
|
-
multiply,
|
|
511
|
-
divide,
|
|
512
|
-
toF64,
|
|
513
|
-
toF64Exact,
|
|
514
|
-
toI64Exact,
|
|
515
|
-
toU64Exact,
|
|
516
|
-
isNaN: isNaNExpr,
|
|
517
|
-
isFinite: isFiniteExpr
|
|
518
|
-
})
|
|
519
|
-
|
|
520
373
|
export type {
|
|
521
|
-
|
|
374
|
+
IntervalKind,
|
|
522
375
|
NumericCast,
|
|
523
376
|
NumericKind,
|
|
524
|
-
NumericOrUnresolved,
|
|
525
377
|
QueryVarLeaf,
|
|
526
|
-
|
|
527
|
-
|
|
378
|
+
Rounding,
|
|
379
|
+
ScalarInputKind,
|
|
528
380
|
ScalarKind,
|
|
529
381
|
ScalarLiteral,
|
|
530
382
|
ScalarNode,
|
|
531
383
|
ScalarOpKind,
|
|
532
384
|
ScalarQueryVar,
|
|
533
385
|
ScalarResultKind,
|
|
534
|
-
ScalarValue
|
|
535
|
-
SourceFieldLeaf
|
|
386
|
+
ScalarValue
|
|
536
387
|
}
|
|
537
388
|
export {
|
|
538
389
|
assertDepth,
|
|
@@ -543,18 +394,20 @@ export {
|
|
|
543
394
|
checkI64,
|
|
544
395
|
checkU64,
|
|
545
396
|
isScalarNode,
|
|
546
|
-
isUnresolvedScalar,
|
|
547
397
|
literalKindOf,
|
|
548
398
|
literalValue,
|
|
549
399
|
literalWireOf,
|
|
550
400
|
MAX_SCALAR_DEPTH,
|
|
551
401
|
queryVarLeaf,
|
|
552
402
|
queryVarsOf,
|
|
553
|
-
|
|
403
|
+
roundingMode,
|
|
554
404
|
scalarAuthoringWork,
|
|
555
405
|
scalarBinary,
|
|
556
406
|
scalarCast,
|
|
557
407
|
scalarFloatPredicate,
|
|
558
408
|
scalarLiteral,
|
|
559
|
-
|
|
409
|
+
scalarMeasure,
|
|
410
|
+
scalarMulDiv,
|
|
411
|
+
scalarNegate,
|
|
412
|
+
scalarWire
|
|
560
413
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Effect } from "effect"
|
|
2
|
+
import { dbNative } from "#db-native.ts"
|
|
3
|
+
import { nativeOperationWith, runtimeHandle } from "#runtime.ts"
|
|
4
|
+
import { DbError, dbError } from "#runtime-errors.ts"
|
|
5
|
+
import type { SchemaSpec } from "#spec.ts"
|
|
6
|
+
|
|
7
|
+
const decoder = new TextDecoder("utf-8", { fatal: true })
|
|
8
|
+
|
|
9
|
+
function text(operation: string, bytes: Uint8Array | null): string {
|
|
10
|
+
if (bytes === null) throw dbError(operation, { _tag: "Internal" })
|
|
11
|
+
return decoder.decode(bytes)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const internalSchemaSnapshot = Effect.fn("internalSchemaSnapshot")(function* (spec: SchemaSpec) {
|
|
15
|
+
const runtime = yield* runtimeHandle()
|
|
16
|
+
return yield* nativeOperationWith(
|
|
17
|
+
"internalSchemaSnapshot",
|
|
18
|
+
(callback) => dbNative.runtimeSchemaSnapshot(runtime, spec, callback),
|
|
19
|
+
dbNative.runtimeBytesTake,
|
|
20
|
+
(bytes) => text("internalSchemaSnapshot", bytes)
|
|
21
|
+
)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const internalSchemaBindings = Effect.fn("internalSchemaBindings")(function* (snapshot: string) {
|
|
25
|
+
if (typeof snapshot !== "string" || !snapshot.isWellFormed()) {
|
|
26
|
+
return yield* Effect.fail(new DbError({ operation: "internalSchemaBindings", reason: { _tag: "InvalidArgument" } }))
|
|
27
|
+
}
|
|
28
|
+
const runtime = yield* runtimeHandle()
|
|
29
|
+
const bytes = new TextEncoder().encode(snapshot)
|
|
30
|
+
return yield* nativeOperationWith(
|
|
31
|
+
"internalSchemaBindings",
|
|
32
|
+
(callback) => dbNative.runtimeSchemaBindings(runtime, bytes, callback),
|
|
33
|
+
dbNative.runtimeBytesTake,
|
|
34
|
+
(bytes) => text("internalSchemaBindings", bytes)
|
|
35
|
+
)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
export { internalSchemaBindings, internalSchemaSnapshot }
|
package/dist/migration.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Private log-migration integration entrypoints: the two read-only
|
|
3
|
-
* native migration-codec verbs the `@bjornpagen/bumbledb-log/migrations`
|
|
4
|
-
* generator imports, wired over the shared executor onto the native
|
|
5
|
-
* `schema_file`, `migration::plan` and `migration::manifest` modules.
|
|
6
|
-
*
|
|
7
|
-
* Both follow `hashChunk`'s shape: bounded owned input, bounded owned JSON
|
|
8
|
-
* response bytes, ONE registered cancellable operation under the acquired
|
|
9
|
-
* `NativeRuntime`. The schema verb takes the SDK `SchemaSpec` object — the
|
|
10
|
-
* same wire that already crosses the bridge for open/create — never a
|
|
11
|
-
* respelled text form. Neither verb opens, initializes, freezes or migrates
|
|
12
|
-
* a database; the durable migrate/activate/abort workflow is the log's
|
|
13
|
-
* admin surface, not this seam.
|
|
14
|
-
*/
|
|
15
|
-
import { Effect } from "effect";
|
|
16
|
-
import { DbError } from "./runtime-errors.js";
|
|
17
|
-
import type { SchemaSpec } from "./spec.js";
|
|
18
|
-
/**
|
|
19
|
-
* Canonical schema admission for the migration generator: validates the
|
|
20
|
-
* spec natively and yields bounded JSON bytes carrying the canonical
|
|
21
|
-
* `schemaId` and the rendered schema snapshot.
|
|
22
|
-
*/
|
|
23
|
-
declare const internalMigrationSchema: (spec: SchemaSpec) => Effect.Effect<Uint8Array<ArrayBufferLike>, DbError, import("./runtime.js").NativeRuntime>;
|
|
24
|
-
/**
|
|
25
|
-
* One bounded read-only migration-codec request (plan parse/validate/
|
|
26
|
-
* render/digest, manifest verify/append preview, plan-set digests): owned
|
|
27
|
-
* JSON request bytes in, owned JSON response bytes out.
|
|
28
|
-
*/
|
|
29
|
-
declare const internalMigrationRead: (request: Uint8Array<ArrayBufferLike>) => Effect.Effect<Uint8Array<ArrayBufferLike>, DbError, import("./runtime.js").NativeRuntime>;
|
|
30
|
-
export { internalMigrationRead, internalMigrationSchema };
|
|
31
|
-
//# sourceMappingURL=migration.d.ts.map
|