@bjornpagen/bumbledb 0.20.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COOKBOOK.md +283 -1611
- package/README.md +156 -118
- package/dist/capacity.d.ts +16 -12
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js +16 -48
- package/dist/capacity.js.map +1 -1
- package/dist/changes.d.ts +54 -0
- package/dist/changes.d.ts.map +1 -0
- package/dist/changes.js +245 -0
- package/dist/changes.js.map +1 -0
- package/dist/close.d.ts +24 -0
- package/dist/close.d.ts.map +1 -0
- package/dist/close.js +34 -0
- package/dist/close.js.map +1 -0
- package/dist/closed.d.ts +1 -3
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +24 -12
- package/dist/closed.js.map +1 -1
- package/dist/codec.d.ts +56 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +289 -0
- package/dist/codec.js.map +1 -0
- package/dist/compile.d.ts +68 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +75 -0
- package/dist/compile.js.map +1 -0
- package/dist/db-native.d.ts +170 -0
- package/dist/db-native.d.ts.map +1 -0
- package/dist/db-native.js +5 -0
- package/dist/db-native.js.map +1 -0
- package/dist/db.d.ts +101 -233
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +232 -1084
- package/dist/db.js.map +1 -1
- package/dist/errors.d.ts +57 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +2 -2
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +65 -24
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +94 -24
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +37 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -21
- package/dist/index.js.map +1 -1
- package/dist/internal/log.d.ts +24 -0
- package/dist/internal/log.d.ts.map +1 -0
- package/dist/internal/log.js +10 -0
- package/dist/internal/log.js.map +1 -0
- package/dist/law.d.ts +8 -13
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +6 -59
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts +0 -13
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +9 -17
- package/dist/lower.js.map +1 -1
- package/dist/migration.d.ts +33 -0
- package/dist/migration.d.ts.map +1 -0
- package/dist/migration.js +48 -0
- package/dist/migration.js.map +1 -0
- package/dist/native.d.ts +256 -301
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +65 -108
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +24 -13
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +7 -3
- package/dist/query/atom.js.map +1 -1
- package/dist/query/compute.d.ts +68 -0
- package/dist/query/compute.d.ts.map +1 -0
- package/dist/query/compute.js +141 -0
- package/dist/query/compute.js.map +1 -0
- package/dist/query/find.d.ts +15 -8
- package/dist/query/find.d.ts.map +1 -1
- package/dist/query/find.js +6 -2
- package/dist/query/find.js.map +1 -1
- package/dist/query/lower.d.ts +23 -2
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +433 -80
- package/dist/query/lower.js.map +1 -1
- package/dist/query/parse-ir.d.ts.map +1 -1
- package/dist/query/parse-ir.js +17 -8
- package/dist/query/parse-ir.js.map +1 -1
- package/dist/query/run.d.ts +12 -2
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +26 -9
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +47 -3
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +83 -19
- package/dist/query/scope.js.map +1 -1
- package/dist/relation.d.ts +3 -8
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +16 -10
- package/dist/relation.js.map +1 -1
- package/dist/result.d.ts +47 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +50 -0
- package/dist/result.js.map +1 -0
- package/dist/rows.d.ts +69 -0
- package/dist/rows.d.ts.map +1 -0
- package/dist/rows.js +328 -0
- package/dist/rows.js.map +1 -0
- package/dist/runtime-codes.d.ts +2 -0
- package/dist/runtime-codes.d.ts.map +1 -0
- package/dist/runtime-codes.js +19 -0
- package/dist/runtime-codes.js.map +1 -0
- package/dist/runtime-errors.d.ts +106 -0
- package/dist/runtime-errors.d.ts.map +1 -0
- package/dist/runtime-errors.js +62 -0
- package/dist/runtime-errors.js.map +1 -0
- package/dist/runtime-native.d.ts +171 -0
- package/dist/runtime-native.d.ts.map +1 -0
- package/dist/runtime-native.js +5 -0
- package/dist/runtime-native.js.map +1 -0
- package/dist/runtime.d.ts +73 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +293 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scalar.d.ts +165 -0
- package/dist/scalar.d.ts.map +1 -0
- package/dist/scalar.js +344 -0
- package/dist/scalar.js.map +1 -0
- package/dist/schema.d.ts +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +34 -37
- package/dist/schema.js.map +1 -1
- package/dist/shape.d.ts +28 -0
- package/dist/shape.d.ts.map +1 -0
- package/dist/shape.js +2 -0
- package/dist/shape.js.map +1 -0
- package/dist/spec.d.ts +27 -3
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js +22 -1
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +16 -3
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +54 -28
- package/dist/statements.js.map +1 -1
- package/dist/uuid.d.ts +23 -0
- package/dist/uuid.d.ts.map +1 -0
- package/dist/uuid.js +54 -0
- package/dist/uuid.js.map +1 -0
- package/pack-provenance.json +7 -0
- package/package.json +12 -16
- package/src/capacity.ts +34 -54
- package/src/changes.ts +361 -0
- package/src/close.ts +53 -0
- package/src/closed.ts +25 -19
- package/src/codec.ts +379 -0
- package/src/compile.ts +149 -0
- package/src/db-native.ts +247 -0
- package/src/db.ts +461 -1632
- package/src/errors.ts +50 -0
- package/src/face.ts +2 -2
- package/src/fields.ts +182 -55
- package/src/index.ts +62 -126
- package/src/internal/log.ts +51 -0
- package/src/law.ts +13 -28
- package/src/lower.ts +9 -4
- package/src/migration.ts +69 -0
- package/src/native.ts +326 -487
- package/src/query/atom.ts +61 -25
- package/src/query/compute.ts +237 -0
- package/src/query/find.ts +31 -12
- package/src/query/lower.ts +531 -143
- package/src/query/parse-ir.ts +18 -13
- package/src/query/run.ts +32 -16
- package/src/query/scope.ts +140 -8
- package/src/relation.ts +17 -21
- package/src/result.ts +130 -0
- package/src/rows.ts +404 -0
- package/src/runtime-codes.ts +18 -0
- package/src/runtime-errors.ts +69 -0
- package/src/runtime-native.ts +242 -0
- package/src/runtime.ts +440 -0
- package/src/scalar.ts +560 -0
- package/src/schema.ts +35 -37
- package/src/shape.ts +31 -0
- package/src/spec.ts +33 -3
- package/src/statements.ts +75 -68
- package/src/uuid.ts +69 -0
- package/dist/marshal.d.ts +0 -44
- package/dist/marshal.d.ts.map +0 -1
- package/dist/marshal.js +0 -165
- package/dist/marshal.js.map +0 -1
- package/src/marshal.ts +0 -200
package/src/query/atom.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { AnyClosedRoster, AnyField, Infer, IntervalValue } from "#fields.ts"
|
|
1
|
+
import { AuthoringError } from "#errors.ts"
|
|
2
|
+
import type { AnyClosedRoster, AnyField, FloatIntervalValue, Infer, IntervalValue } from "#fields.ts"
|
|
3
3
|
import type { ClassLookup, ClassRecordOf, SchemaClasses } from "#law.ts"
|
|
4
|
+
import type { QueryNode } from "#query/compute.ts"
|
|
4
5
|
import type {
|
|
5
6
|
AntiJoinOk,
|
|
6
7
|
AnyVar,
|
|
@@ -16,6 +17,8 @@ import type {
|
|
|
16
17
|
} from "#query/scope.ts"
|
|
17
18
|
import { isTerm, term } from "#query/scope.ts"
|
|
18
19
|
import type { FieldsShape } from "#relation.ts"
|
|
20
|
+
import type { ScalarKind } from "#scalar.ts"
|
|
21
|
+
import type { Uuid } from "#uuid.ts"
|
|
19
22
|
|
|
20
23
|
type BindingTermData =
|
|
21
24
|
| { readonly kind: "var"; readonly ref: AnyVar }
|
|
@@ -65,14 +68,16 @@ type AggData =
|
|
|
65
68
|
| { readonly op: "count" }
|
|
66
69
|
| {
|
|
67
70
|
readonly op: "fold"
|
|
68
|
-
readonly fold: "sum" | "min" | "max"
|
|
71
|
+
readonly fold: "sum" | "mean" | "min" | "max"
|
|
69
72
|
readonly over: AnyVar
|
|
70
73
|
}
|
|
71
74
|
| { readonly op: "pack"; readonly over: AnyVar }
|
|
72
75
|
|
|
76
|
+
/** Compute `expr` is the shared `#scalar.ts` query-var node (one grammar). */
|
|
73
77
|
type FindEntryData =
|
|
74
78
|
| { readonly kind: "var"; readonly over: AnyVar }
|
|
75
79
|
| { readonly kind: "aggregate"; readonly agg: AggData }
|
|
80
|
+
| { readonly kind: "compute"; readonly expr: QueryNode; readonly result: ScalarKind }
|
|
76
81
|
|
|
77
82
|
interface FindColumn {
|
|
78
83
|
readonly name: string
|
|
@@ -141,7 +146,11 @@ type DerivedTable = InteriorData | RecHead
|
|
|
141
146
|
type BindingInput<F extends AnyField> =
|
|
142
147
|
| Infer<F>
|
|
143
148
|
| (F extends { readonly closed: { readonly handles: readonly string[] } } ? readonly Infer<F>[] : never)
|
|
144
|
-
| (F extends { readonly kind: "interval"
|
|
149
|
+
| (F extends { readonly kind: "interval"; readonly element: "f64" }
|
|
150
|
+
? number
|
|
151
|
+
: F extends { readonly kind: "interval" }
|
|
152
|
+
? bigint
|
|
153
|
+
: never)
|
|
145
154
|
| AnyVar
|
|
146
155
|
| Param<string>
|
|
147
156
|
| SetParam<string>
|
|
@@ -216,15 +225,34 @@ type AnyNotInteriorAtom = NotInteriorAtom<unknown>
|
|
|
216
225
|
|
|
217
226
|
type AnyCond = AnyCmp | Tree<readonly AnyTreeChild[]> | AnyNotAtom | AnyNotInteriorAtom
|
|
218
227
|
|
|
219
|
-
type EqRight =
|
|
220
|
-
|
|
221
|
-
|
|
228
|
+
type EqRight =
|
|
229
|
+
| AnyVar
|
|
230
|
+
| Param<string>
|
|
231
|
+
| SetParam<string>
|
|
232
|
+
| bigint
|
|
233
|
+
| number
|
|
234
|
+
| string
|
|
235
|
+
| boolean
|
|
236
|
+
| Uint8Array
|
|
237
|
+
| IntervalValue
|
|
238
|
+
| FloatIntervalValue
|
|
239
|
+
|
|
240
|
+
type NeRight =
|
|
241
|
+
| AnyVar
|
|
242
|
+
| Param<string>
|
|
243
|
+
| bigint
|
|
244
|
+
| number
|
|
245
|
+
| string
|
|
246
|
+
| boolean
|
|
247
|
+
| Uint8Array
|
|
248
|
+
| IntervalValue
|
|
249
|
+
| FloatIntervalValue
|
|
222
250
|
|
|
223
|
-
type OrderSide = AnyVar | Param<string> | bigint | boolean
|
|
251
|
+
type OrderSide = AnyVar | Param<string> | bigint | number | boolean | Uuid
|
|
224
252
|
|
|
225
|
-
type PointSide = AnyVar | Param<string> | bigint
|
|
253
|
+
type PointSide = AnyVar | Param<string> | bigint | number
|
|
226
254
|
|
|
227
|
-
type IntervalSide = AnyVar | Param<string> | IntervalValue
|
|
255
|
+
type IntervalSide = AnyVar | Param<string> | IntervalValue | FloatIntervalValue
|
|
228
256
|
|
|
229
257
|
function comparison<Op extends CmpKind, L, R, M>(op: Op, lhs: L, rhs: R, mask: M): Cmp<Op, L, R, M> {
|
|
230
258
|
return Object.freeze({ cond: "cmp", op, lhs, rhs, mask })
|
|
@@ -236,9 +264,9 @@ function isVariableSide(value: unknown): boolean {
|
|
|
236
264
|
|
|
237
265
|
function assertTermSide(op: string, lhs: unknown, rhs: unknown): void {
|
|
238
266
|
if (!isVariableSide(lhs) && !isVariableSide(rhs)) {
|
|
239
|
-
throw
|
|
240
|
-
`${op}: a comparison without a variable side is constant-valued (a parameter is a constant at execution) — write the query you mean`
|
|
241
|
-
)
|
|
267
|
+
throw new AuthoringError({
|
|
268
|
+
message: `${op}: a comparison without a variable side is constant-valued (a parameter is a constant at execution) — write the query you mean`
|
|
269
|
+
})
|
|
242
270
|
}
|
|
243
271
|
}
|
|
244
272
|
|
|
@@ -313,9 +341,9 @@ function allen<const A extends IntervalSide, const B extends IntervalSide>(
|
|
|
313
341
|
): Cmp<"allen", A, B, number> {
|
|
314
342
|
assertTermSide("allen", left, right)
|
|
315
343
|
if (!Number.isInteger(mask) || mask < 0 || mask > ALLEN_ALL_BITS) {
|
|
316
|
-
throw
|
|
317
|
-
`allen mask ${mask} is not a 13-bit mask — build masks from the ALLEN constants (bumbledb allen.rs: bits above the low 13 are unrepresentable)`
|
|
318
|
-
)
|
|
344
|
+
throw new AuthoringError({
|
|
345
|
+
message: `allen mask ${mask} is not a 13-bit mask — build masks from the ALLEN constants (bumbledb allen.rs: bits above the low 13 are unrepresentable)`
|
|
346
|
+
})
|
|
319
347
|
}
|
|
320
348
|
return comparison("allen", left, right, mask)
|
|
321
349
|
}
|
|
@@ -354,7 +382,7 @@ function not(
|
|
|
354
382
|
}
|
|
355
383
|
|
|
356
384
|
/**
|
|
357
|
-
* Whether a variable's OWN field is NUMERIC (u64/i64) — the judgment the
|
|
385
|
+
* Whether a variable's OWN field is NUMERIC (u64/i64/f64) — the judgment the
|
|
358
386
|
* point side of `pointIn` and the `sum` input read: a point lives in the
|
|
359
387
|
* interval's element domain, and a quantifier is not an addition, so bool
|
|
360
388
|
* (orderable, never numeric) is exactly here refused. A CLOSED reference
|
|
@@ -366,11 +394,11 @@ function not(
|
|
|
366
394
|
*/
|
|
367
395
|
type NumericVarOk<V extends AnyVar> = V["field"] extends { readonly closed: AnyClosedRoster }
|
|
368
396
|
? false
|
|
369
|
-
: V["field"]["kind"] extends "u64" | "i64"
|
|
397
|
+
: V["field"]["kind"] extends "u64" | "i64" | "f64"
|
|
370
398
|
? true
|
|
371
399
|
: false
|
|
372
400
|
|
|
373
|
-
type OrderVarOk<V extends AnyVar> = V["field"]["kind"] extends "bool" ? true : NumericVarOk<V>
|
|
401
|
+
type OrderVarOk<V extends AnyVar> = V["field"]["kind"] extends "bool" | "uuid" ? true : NumericVarOk<V>
|
|
374
402
|
|
|
375
403
|
type IntervalVarOk<V extends AnyVar> = V["field"]["kind"] extends "interval" ? true : false
|
|
376
404
|
|
|
@@ -384,9 +412,13 @@ type OrderDomain<T> = T extends AnyVar
|
|
|
384
412
|
? "open"
|
|
385
413
|
: T extends bigint
|
|
386
414
|
? "integer"
|
|
387
|
-
: T extends
|
|
388
|
-
? "
|
|
389
|
-
:
|
|
415
|
+
: T extends number
|
|
416
|
+
? "f64"
|
|
417
|
+
: T extends boolean
|
|
418
|
+
? "bool"
|
|
419
|
+
: T extends Uuid
|
|
420
|
+
? "uuid"
|
|
421
|
+
: never
|
|
390
422
|
|
|
391
423
|
type OrderDomainsOk<A, B> = [A] extends [never]
|
|
392
424
|
? false
|
|
@@ -403,9 +435,13 @@ type OrderDomainsOk<A, B> = [A] extends [never]
|
|
|
403
435
|
: B extends "bool"
|
|
404
436
|
? false
|
|
405
437
|
: A extends "integer"
|
|
406
|
-
?
|
|
407
|
-
: B extends "integer"
|
|
438
|
+
? B extends "integer" | "u64" | "i64"
|
|
408
439
|
? true
|
|
440
|
+
: false
|
|
441
|
+
: B extends "integer"
|
|
442
|
+
? A extends "u64" | "i64"
|
|
443
|
+
? true
|
|
444
|
+
: false
|
|
409
445
|
: A extends B
|
|
410
446
|
? true
|
|
411
447
|
: false
|
|
@@ -413,7 +449,7 @@ type OrderDomainsOk<A, B> = [A] extends [never]
|
|
|
413
449
|
type OrderPairOk<L, R> = CmpVarSideOk<L, R> extends true ? OrderDomainsOk<OrderDomain<L>, OrderDomain<R>> : false
|
|
414
450
|
|
|
415
451
|
type IntervalElementDomain<T> = T extends AnyVar
|
|
416
|
-
? T["field"] extends { readonly kind: "interval"; readonly element: infer E extends "u64" | "i64" }
|
|
452
|
+
? T["field"] extends { readonly kind: "interval"; readonly element: infer E extends "u64" | "i64" | "f64" }
|
|
417
453
|
? E
|
|
418
454
|
: never
|
|
419
455
|
: "open"
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query-scoped scalar expressions (C05 `FindTerm::Compute`): the
|
|
3
|
+
* variable-addressed leaf scope over the ONE shared operator roster in
|
|
4
|
+
* `#scalar.ts`. Leaves are bound query variables that lower to `VarId`s.
|
|
5
|
+
* Operators are the shared constructors — this module only admits known
|
|
6
|
+
* schema kinds at query-var leaves.
|
|
7
|
+
*
|
|
8
|
+
* `ComputeExpr<K>` is a `ScalarNode<"query-var", K>`. Distinct I64 and U64
|
|
9
|
+
* survive host inference; they do not collapse to plain `bigint`.
|
|
10
|
+
*/
|
|
11
|
+
import { AuthoringError } from "#errors.ts"
|
|
12
|
+
import type { AnyField } from "#fields.ts"
|
|
13
|
+
import { bool as boolField, f64 as f64Field, i64 as i64Field, rosterOf, u64 as u64Field } from "#fields.ts"
|
|
14
|
+
import type { AnyVar } from "#query/scope.ts"
|
|
15
|
+
import { isTerm, term } from "#query/scope.ts"
|
|
16
|
+
import type { ScalarKind, ScalarLiteral, ScalarNode } from "#scalar.ts"
|
|
17
|
+
import {
|
|
18
|
+
checkBool,
|
|
19
|
+
checkF64,
|
|
20
|
+
checkI64,
|
|
21
|
+
checkU64,
|
|
22
|
+
isScalarNode,
|
|
23
|
+
MAX_SCALAR_DEPTH,
|
|
24
|
+
queryVarLeaf,
|
|
25
|
+
queryVarsOf,
|
|
26
|
+
scalarBinary,
|
|
27
|
+
scalarCast,
|
|
28
|
+
scalarFloatPredicate,
|
|
29
|
+
scalarLiteral,
|
|
30
|
+
scalarNegate
|
|
31
|
+
} from "#scalar.ts"
|
|
32
|
+
|
|
33
|
+
/** Query-var tree: the shared AST restricted to this leaf scope. */
|
|
34
|
+
type QueryNode = ScalarNode<"query-var">
|
|
35
|
+
|
|
36
|
+
/** Host value for a derived query compute kind. */
|
|
37
|
+
type ComputeValue<K extends ScalarKind> = K extends "f64" ? number : K extends "bool" ? boolean : bigint
|
|
38
|
+
|
|
39
|
+
type ComputeExpr<K extends ScalarKind> = ScalarNode<"query-var", K>
|
|
40
|
+
|
|
41
|
+
type AnyComputeExpr = ComputeExpr<"u64"> | ComputeExpr<"i64"> | ComputeExpr<"f64"> | ComputeExpr<"bool">
|
|
42
|
+
|
|
43
|
+
/** One operand as the runtime judgment sees it. */
|
|
44
|
+
type Operand = AnyVar | AnyComputeExpr
|
|
45
|
+
|
|
46
|
+
type NumericVarOperand = AnyVar & { readonly field: { readonly kind: "u64" | "i64" | "f64" } }
|
|
47
|
+
type ArithmeticOperand = ComputeExpr<"u64"> | ComputeExpr<"i64"> | ComputeExpr<"f64"> | NumericVarOperand
|
|
48
|
+
type SignedOperand =
|
|
49
|
+
| ComputeExpr<"i64">
|
|
50
|
+
| ComputeExpr<"f64">
|
|
51
|
+
| (AnyVar & { readonly field: { readonly kind: "i64" | "f64" } })
|
|
52
|
+
type FloatOperand = ComputeExpr<"f64"> | (AnyVar & { readonly field: { readonly kind: "f64" } })
|
|
53
|
+
|
|
54
|
+
type OperandKind<O> =
|
|
55
|
+
O extends ComputeExpr<infer K extends ScalarKind>
|
|
56
|
+
? K
|
|
57
|
+
: O extends AnyVar
|
|
58
|
+
? O["field"]["kind"] extends "u64" | "i64" | "f64" | "bool"
|
|
59
|
+
? O["field"]["kind"]
|
|
60
|
+
: never
|
|
61
|
+
: never
|
|
62
|
+
|
|
63
|
+
function isComputeExpr(value: unknown): value is AnyComputeExpr {
|
|
64
|
+
return isScalarNode(value) && value.scope === "query-var" && value.result !== "unresolved"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function varKindOf(where: string, ref: AnyVar): ScalarKind {
|
|
68
|
+
const roster = rosterOf(ref.field)
|
|
69
|
+
if (roster !== undefined) {
|
|
70
|
+
throw new AuthoringError({
|
|
71
|
+
message: `${where}: ${ref.label} is a ${roster.name} reference — declaration order is an accident, not semantics: a closed reference never enters arithmetic`
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
const kind = ref.field.kind
|
|
75
|
+
if (kind === "u64" || kind === "i64" || kind === "f64" || kind === "bool") {
|
|
76
|
+
return kind
|
|
77
|
+
}
|
|
78
|
+
throw new AuthoringError({
|
|
79
|
+
message: `${where}: ${ref.label} is ${kind} — a scalar expression reads u64/i64/f64/bool variables only`
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function asQueryNode(where: string, operand: Operand): QueryNode {
|
|
84
|
+
if (isComputeExpr(operand)) {
|
|
85
|
+
return operand
|
|
86
|
+
}
|
|
87
|
+
if (isTerm(operand) && operand[term] === "var") {
|
|
88
|
+
return queryVarLeaf(operand, varKindOf(where, operand))
|
|
89
|
+
}
|
|
90
|
+
throw new AuthoringError({
|
|
91
|
+
message: `${where}: expected a query variable or a Compute expression — literals are tagged (Compute.u64/i64/f64/bool)`
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function literal<K extends ScalarKind>(value: ScalarLiteral): ComputeExpr<K> {
|
|
96
|
+
return scalarLiteral("query-var", value) as ComputeExpr<K>
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function u64(value: bigint): ComputeExpr<"u64"> {
|
|
100
|
+
checkU64(value, "Compute.u64")
|
|
101
|
+
return literal({ u64: value })
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function i64(value: bigint): ComputeExpr<"i64"> {
|
|
105
|
+
checkI64(value, "Compute.i64")
|
|
106
|
+
return literal({ i64: value })
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function f64(value: number): ComputeExpr<"f64"> {
|
|
110
|
+
checkF64(value, "Compute.f64")
|
|
111
|
+
return literal({ f64: value })
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function bool(value: boolean): ComputeExpr<"bool"> {
|
|
115
|
+
checkBool(value, "Compute.bool")
|
|
116
|
+
return literal({ bool: value })
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
type BinaryKind = "add" | "subtract" | "multiply" | "divide"
|
|
120
|
+
|
|
121
|
+
/** The right operand must have the left operand's kind, never an inferred union. */
|
|
122
|
+
type SameKind<L, R> = [OperandKind<R>] extends [OperandKind<L>]
|
|
123
|
+
? [OperandKind<L>] extends [OperandKind<R>]
|
|
124
|
+
? R
|
|
125
|
+
: never
|
|
126
|
+
: never
|
|
127
|
+
|
|
128
|
+
function binary<K extends "u64" | "i64" | "f64">(
|
|
129
|
+
op: BinaryKind,
|
|
130
|
+
left: ArithmeticOperand,
|
|
131
|
+
right: ArithmeticOperand
|
|
132
|
+
): ComputeExpr<K> {
|
|
133
|
+
const where = `Compute.${op}`
|
|
134
|
+
return scalarBinary(where, op, asQueryNode(where, left), asQueryNode(where, right)) as ComputeExpr<K>
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function add<L extends ArithmeticOperand, R extends ArithmeticOperand>(
|
|
138
|
+
left: L,
|
|
139
|
+
right: R & SameKind<NoInfer<L>, R>
|
|
140
|
+
): ComputeExpr<OperandKind<L> & OperandKind<R> & ("u64" | "i64" | "f64")> {
|
|
141
|
+
return binary("add", left, right)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function subtract<L extends ArithmeticOperand, R extends ArithmeticOperand>(
|
|
145
|
+
left: L,
|
|
146
|
+
right: R & SameKind<NoInfer<L>, R>
|
|
147
|
+
): ComputeExpr<OperandKind<L> & OperandKind<R> & ("u64" | "i64" | "f64")> {
|
|
148
|
+
return binary("subtract", left, right)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function multiply<L extends ArithmeticOperand, R extends ArithmeticOperand>(
|
|
152
|
+
left: L,
|
|
153
|
+
right: R & SameKind<NoInfer<L>, R>
|
|
154
|
+
): ComputeExpr<OperandKind<L> & OperandKind<R> & ("u64" | "i64" | "f64")> {
|
|
155
|
+
return binary("multiply", left, right)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function divide<L extends ArithmeticOperand, R extends ArithmeticOperand>(
|
|
159
|
+
left: L,
|
|
160
|
+
right: R & SameKind<NoInfer<L>, R>
|
|
161
|
+
): ComputeExpr<OperandKind<L> & OperandKind<R> & ("u64" | "i64" | "f64")> {
|
|
162
|
+
return binary("divide", left, right)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function negate<O extends SignedOperand>(operand: O): ComputeExpr<OperandKind<O> & ("i64" | "f64")> {
|
|
166
|
+
const where = "Compute.negate"
|
|
167
|
+
return scalarNegate(where, asQueryNode(where, operand)) as ComputeExpr<OperandKind<O> & ("i64" | "f64")>
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function toF64(operand: ArithmeticOperand): ComputeExpr<"f64"> {
|
|
171
|
+
const where = "Compute.toF64"
|
|
172
|
+
return scalarCast(where, "toF64", "f64", asQueryNode(where, operand)) as ComputeExpr<"f64">
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function toF64Exact(operand: ArithmeticOperand): ComputeExpr<"f64"> {
|
|
176
|
+
const where = "Compute.toF64Exact"
|
|
177
|
+
return scalarCast(where, "toF64Exact", "f64", asQueryNode(where, operand)) as ComputeExpr<"f64">
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function toI64Exact(operand: ArithmeticOperand): ComputeExpr<"i64"> {
|
|
181
|
+
const where = "Compute.toI64Exact"
|
|
182
|
+
return scalarCast(where, "toI64Exact", "i64", asQueryNode(where, operand)) as ComputeExpr<"i64">
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function toU64Exact(operand: ArithmeticOperand): ComputeExpr<"u64"> {
|
|
186
|
+
const where = "Compute.toU64Exact"
|
|
187
|
+
return scalarCast(where, "toU64Exact", "u64", asQueryNode(where, operand)) as ComputeExpr<"u64">
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function isNaNExpr(operand: FloatOperand): ComputeExpr<"bool"> {
|
|
191
|
+
const where = "Compute.isNaN"
|
|
192
|
+
return scalarFloatPredicate(where, "isNaN", asQueryNode(where, operand))
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function isFiniteExpr(operand: FloatOperand): ComputeExpr<"bool"> {
|
|
196
|
+
const where = "Compute.isFinite"
|
|
197
|
+
return scalarFloatPredicate(where, "isFinite", asQueryNode(where, operand))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Every variable the expression reads (validation binds them like any term). */
|
|
201
|
+
function computeVarsOf(data: QueryNode): readonly AnyVar[] {
|
|
202
|
+
return queryVarsOf(data) as readonly AnyVar[]
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function computeFieldOf(kind: ScalarKind): AnyField {
|
|
206
|
+
switch (kind) {
|
|
207
|
+
case "u64":
|
|
208
|
+
return u64Field
|
|
209
|
+
case "i64":
|
|
210
|
+
return i64Field
|
|
211
|
+
case "f64":
|
|
212
|
+
return f64Field
|
|
213
|
+
case "bool":
|
|
214
|
+
return boolField
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const Compute = Object.freeze({
|
|
219
|
+
u64,
|
|
220
|
+
i64,
|
|
221
|
+
f64,
|
|
222
|
+
bool,
|
|
223
|
+
negate,
|
|
224
|
+
add,
|
|
225
|
+
subtract,
|
|
226
|
+
multiply,
|
|
227
|
+
divide,
|
|
228
|
+
toF64,
|
|
229
|
+
toF64Exact,
|
|
230
|
+
toI64Exact,
|
|
231
|
+
toU64Exact,
|
|
232
|
+
isNaN: isNaNExpr,
|
|
233
|
+
isFinite: isFiniteExpr
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
export type { AnyComputeExpr, ComputeExpr, ComputeValue, QueryNode }
|
|
237
|
+
export { Compute, computeFieldOf, computeVarsOf, isComputeExpr, MAX_SCALAR_DEPTH as MAX_COMPUTE_DEPTH }
|
package/src/query/find.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import type { Infer } from "#fields.ts"
|
|
1
|
+
import type { AnyField, Infer } from "#fields.ts"
|
|
2
2
|
import type { SchemaClasses } from "#law.ts"
|
|
3
3
|
import type { IntervalVarOk, NumericVarOk } from "#query/atom.ts"
|
|
4
|
+
import type { AnyComputeExpr, ComputeExpr, ComputeValue } from "#query/compute.ts"
|
|
4
5
|
import type { AnyVar, MintSlotOf } from "#query/scope.ts"
|
|
6
|
+
import type { ScalarKind } from "#scalar.ts"
|
|
5
7
|
|
|
6
|
-
type FoldOpName = "sum" | "min" | "max" | "pack"
|
|
8
|
+
type FoldOpName = "sum" | "mean" | "min" | "max" | "pack"
|
|
7
9
|
|
|
8
10
|
interface CountAgg {
|
|
9
11
|
readonly agg: "count"
|
|
@@ -16,7 +18,7 @@ interface Agg<Op extends FoldOpName, Over extends AnyVar> {
|
|
|
16
18
|
|
|
17
19
|
type AnyAgg = CountAgg | Agg<FoldOpName, AnyVar>
|
|
18
20
|
|
|
19
|
-
type FindEntry = AnyVar | AnyAgg
|
|
21
|
+
type FindEntry = AnyVar | AnyAgg | AnyComputeExpr
|
|
20
22
|
|
|
21
23
|
type FindShape = Readonly<Record<string, FindEntry>>
|
|
22
24
|
|
|
@@ -29,7 +31,7 @@ function count(): CountAgg {
|
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
|
-
* Exact checked sum over a NUMERIC (u64/i64) variable — wide accumulator,
|
|
34
|
+
* Exact checked sum over a NUMERIC (u64/i64/f64) variable — wide accumulator,
|
|
33
35
|
* one finalize range check; overflow is the engine's typed runtime error —
|
|
34
36
|
* or over the measure (`r.sum(r.duration(w))`). Bool stays refused: a
|
|
35
37
|
* quantifier is not an addition (R3).
|
|
@@ -38,6 +40,11 @@ function sum<const O extends AnyVar>(over: O): Agg<"sum", O> {
|
|
|
38
40
|
return aggregate("sum", over)
|
|
39
41
|
}
|
|
40
42
|
|
|
43
|
+
/** Exact sum divided by the binding count, rounded once. F64 inputs only. */
|
|
44
|
+
function mean<const O extends AnyVar>(over: O): Agg<"mean", O> {
|
|
45
|
+
return aggregate("mean", over)
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
function min<const O extends AnyVar>(over: O): Agg<"min", O> {
|
|
42
49
|
return aggregate("min", over)
|
|
43
50
|
}
|
|
@@ -54,11 +61,17 @@ type FindEntryOk<E> = E extends AnyVar
|
|
|
54
61
|
? true
|
|
55
62
|
: E extends CountAgg
|
|
56
63
|
? true
|
|
57
|
-
: E extends Agg<"
|
|
58
|
-
?
|
|
59
|
-
|
|
60
|
-
? IntervalVarOk<V>
|
|
64
|
+
: E extends Agg<"mean", infer O extends AnyVar>
|
|
65
|
+
? O["field"]["kind"] extends "f64"
|
|
66
|
+
? true
|
|
61
67
|
: false
|
|
68
|
+
: E extends Agg<"sum" | "min" | "max", infer O extends AnyVar>
|
|
69
|
+
? NumericVarOk<O>
|
|
70
|
+
: E extends Agg<"pack", infer V extends AnyVar>
|
|
71
|
+
? IntervalVarOk<V>
|
|
72
|
+
: E extends AnyComputeExpr
|
|
73
|
+
? true
|
|
74
|
+
: false
|
|
62
75
|
|
|
63
76
|
type CheckFind<F extends FindShape> = {
|
|
64
77
|
readonly [K in keyof F]: FindEntryOk<F[K]> extends true ? F[K] : never
|
|
@@ -72,11 +85,13 @@ type FindValue<E> = E extends AnyVar
|
|
|
72
85
|
? Infer<E["field"]>
|
|
73
86
|
: E extends CountAgg
|
|
74
87
|
? bigint
|
|
75
|
-
: E extends Agg<"sum" | "min" | "max", infer O extends AnyVar>
|
|
88
|
+
: E extends Agg<"sum" | "mean" | "min" | "max", infer O extends AnyVar>
|
|
76
89
|
? Infer<O["field"]>
|
|
77
90
|
: E extends Agg<"pack", infer V extends AnyVar>
|
|
78
91
|
? Infer<V["field"]>
|
|
79
|
-
:
|
|
92
|
+
: E extends ComputeExpr<infer K extends ScalarKind>
|
|
93
|
+
? ComputeValue<K>
|
|
94
|
+
: never
|
|
80
95
|
|
|
81
96
|
type RowOfFind<F extends FindShape> = { readonly [K in keyof F]: FindValue<F[K]> }
|
|
82
97
|
|
|
@@ -86,8 +101,12 @@ type RowOfFind<F extends FindShape> = { readonly [K in keyof F]: FindValue<F[K]>
|
|
|
86
101
|
* signature an interior join pairs against (`F` is variable-only there).
|
|
87
102
|
*/
|
|
88
103
|
type HeadRecordOf<Classes extends SchemaClasses, F extends FindShape> = {
|
|
89
|
-
readonly [K in keyof F]: F[K] extends AnyVar
|
|
104
|
+
readonly [K in keyof F]: F[K] extends AnyVar
|
|
105
|
+
? MintSlotOf<Classes, F[K]>
|
|
106
|
+
: F[K] extends AnyComputeExpr
|
|
107
|
+
? { readonly field: AnyField; readonly class: undefined }
|
|
108
|
+
: never
|
|
90
109
|
}
|
|
91
110
|
|
|
92
111
|
export type { Agg, CheckFind, CheckRecFind, FindEntry, FindShape, HeadRecordOf, RowOfFind }
|
|
93
|
-
export { count, max, min, pack, sum }
|
|
112
|
+
export { count, max, mean, min, pack, sum }
|