@bjornpagen/bumbledb 0.10.0 → 0.11.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 +155 -136
- package/README.md +3 -7
- package/dist/db.d.ts +77 -109
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +121 -339
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +11 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -10
- package/dist/index.js.map +1 -1
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +8 -1
- package/dist/lower.js.map +1 -1
- package/dist/native.d.ts +69 -50
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +94 -112
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +8 -17
- package/dist/query/atom.js.map +1 -1
- package/dist/query/find.d.ts +18 -35
- package/dist/query/find.d.ts.map +1 -1
- package/dist/query/find.js +13 -32
- package/dist/query/find.js.map +1 -1
- package/dist/query/lower.d.ts +113 -122
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +335 -256
- package/dist/query/lower.js.map +1 -1
- package/dist/query/parse-ir.d.ts +12 -0
- package/dist/query/parse-ir.d.ts.map +1 -0
- package/dist/query/parse-ir.js +71 -0
- package/dist/query/parse-ir.js.map +1 -0
- package/dist/query/run.d.ts +2 -2
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +2 -13
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +4 -16
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +1 -6
- package/dist/query/scope.js.map +1 -1
- package/dist/schema.js +2 -2
- package/dist/schema.js.map +1 -1
- package/dist/statements.d.ts +8 -4
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +7 -9
- package/dist/statements.js.map +1 -1
- package/package.json +2 -2
- package/src/db.ts +182 -443
- package/src/index.ts +9 -23
- package/src/lower.ts +8 -1
- package/src/native.ts +69 -42
- package/src/query/atom.ts +105 -138
- package/src/query/find.ts +39 -80
- package/src/query/lower.ts +577 -427
- package/src/query/parse-ir.ts +82 -0
- package/src/query/run.ts +2 -14
- package/src/query/scope.ts +3 -21
- package/src/schema.ts +2 -2
- package/src/statements.ts +17 -13
- package/dist/order.d.ts +0 -87
- package/dist/order.d.ts.map +0 -1
- package/dist/order.js +0 -153
- package/dist/order.js.map +0 -1
- package/dist/query/predicate.d.ts +0 -91
- package/dist/query/predicate.d.ts.map +0 -1
- package/dist/query/predicate.js +0 -156
- package/dist/query/predicate.js.map +0 -1
- package/src/order.ts +0 -234
- package/src/query/predicate.ts +0 -269
package/src/query/atom.ts
CHANGED
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
* wall only.
|
|
24
24
|
*
|
|
25
25
|
* This module also owns the plain runtime DATA a built rule is made of
|
|
26
|
-
* (`RuleData`/`RecData` and friends): frozen values the
|
|
27
|
-
* pure data (variable references included), so lowering
|
|
28
|
-
* stable function of the query value.
|
|
26
|
+
* (`RuleData`/`InteriorData`/`RecData` and friends): frozen values the
|
|
27
|
+
* lowering walks — pure data (variable references included), so lowering
|
|
28
|
+
* stays a pure, stable function of the query value.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
import * as errors from "@superbuilders/errors"
|
|
@@ -36,23 +36,21 @@ import type {
|
|
|
36
36
|
ClassedField,
|
|
37
37
|
Duration,
|
|
38
38
|
JoinOk,
|
|
39
|
-
MaskParam,
|
|
40
39
|
MatchFields,
|
|
41
40
|
MatchOwner,
|
|
42
41
|
MintSlotOf,
|
|
43
42
|
Param,
|
|
44
|
-
ParamsRecord,
|
|
45
43
|
ParamValueAt,
|
|
46
44
|
SetParam,
|
|
47
45
|
ShapeOf
|
|
48
46
|
} from "#query/scope.ts"
|
|
49
|
-
import {
|
|
47
|
+
import { isTerm, term } from "#query/scope.ts"
|
|
50
48
|
import type { FieldsShape } from "#relation.ts"
|
|
51
49
|
|
|
52
50
|
/**
|
|
53
51
|
* One atom-binding position as runtime data. A variable rides BY REFERENCE
|
|
54
52
|
* (`ref`) — object identity is the join. `literalSet` is a membership
|
|
55
|
-
* ARRAY at a closed-reference field, folded into the
|
|
53
|
+
* ARRAY at a closed-reference field, folded into the query.
|
|
56
54
|
*/
|
|
57
55
|
type BindingTermData =
|
|
58
56
|
| { readonly kind: "var"; readonly ref: AnyVar }
|
|
@@ -86,17 +84,15 @@ type CmpTermData =
|
|
|
86
84
|
| { readonly kind: "measure"; readonly ref: AnyVar }
|
|
87
85
|
| { readonly kind: "literal"; readonly value: unknown }
|
|
88
86
|
|
|
89
|
-
/**
|
|
90
|
-
type
|
|
91
|
-
|
|
92
|
-
/** One comparison condition as runtime data (`mask` present exactly for `allen`). */
|
|
93
|
-
interface CmpData {
|
|
87
|
+
/** One comparison condition as runtime data; the mask lives inside `allen`. */
|
|
88
|
+
type CmpData = {
|
|
94
89
|
readonly kind: "cmp"
|
|
95
|
-
readonly op: CmpKind
|
|
96
|
-
readonly mask: MaskData | undefined
|
|
97
90
|
readonly lhs: CmpTermData
|
|
98
91
|
readonly rhs: CmpTermData
|
|
99
|
-
}
|
|
92
|
+
} & (
|
|
93
|
+
| { readonly op: { readonly kind: "allen"; readonly mask: number } }
|
|
94
|
+
| { readonly op: { readonly kind: Exclude<CmpKind, "allen"> } }
|
|
95
|
+
)
|
|
100
96
|
|
|
101
97
|
/** One condition-tree node as runtime data (`ir::ConditionTree`). */
|
|
102
98
|
interface TreeData {
|
|
@@ -111,13 +107,11 @@ type CondData = CmpData | TreeData
|
|
|
111
107
|
/** One aggregate's runtime description (find vocabulary, over variable REFERENCES). */
|
|
112
108
|
type AggData =
|
|
113
109
|
| { readonly op: "count" }
|
|
114
|
-
| { readonly op: "countDistinct"; readonly over: AnyVar }
|
|
115
110
|
| {
|
|
116
111
|
readonly op: "fold"
|
|
117
112
|
readonly fold: "sum" | "min" | "max"
|
|
118
113
|
readonly over: AnyVar | { readonly duration: AnyVar }
|
|
119
114
|
}
|
|
120
|
-
| { readonly op: "arg"; readonly direction: "argMax" | "argMin"; readonly over: AnyVar; readonly key: AnyVar }
|
|
121
115
|
| { readonly op: "pack"; readonly over: AnyVar }
|
|
122
116
|
|
|
123
117
|
/** One classified find entry as runtime data (variables and the measure ride BY REFERENCE). */
|
|
@@ -129,12 +123,12 @@ type FindEntryData =
|
|
|
129
123
|
/**
|
|
130
124
|
* One answer column: its name (the row object key — the find record's key,
|
|
131
125
|
* so renames are real and a duplicate column is unrepresentable), its entry,
|
|
132
|
-
* the classed mint SLOT its values flow from (a projected var
|
|
133
|
-
*
|
|
134
|
-
*
|
|
126
|
+
* the classed mint SLOT its values flow from (a projected var;
|
|
127
|
+
* `undefined` for counts/folds/measures/pack, which derive numbers or
|
|
128
|
+
* intervals), and — when that slot is a closed reference —
|
|
135
129
|
* the roster the decode lifts row ids back to handle NAMES through
|
|
136
130
|
* (`undefined` on every bare column). The slice is SDK-side marshaling data
|
|
137
|
-
* only: the wire `
|
|
131
|
+
* only: the wire `QueryIr` never carries it.
|
|
138
132
|
*/
|
|
139
133
|
interface FindColumn {
|
|
140
134
|
readonly name: string
|
|
@@ -144,19 +138,23 @@ interface FindColumn {
|
|
|
144
138
|
}
|
|
145
139
|
|
|
146
140
|
/**
|
|
147
|
-
* One body item of a rule, in written order.
|
|
148
|
-
* over the
|
|
149
|
-
* typed wall a record's unordered keys would
|
|
141
|
+
* One body item of a rule, in written order. An interior join is a NAMED
|
|
142
|
+
* record over the derived table's head keys (`key`) bound to local
|
|
143
|
+
* variables (`ref`) — the typed wall a record's unordered keys would
|
|
144
|
+
* otherwise lose.
|
|
150
145
|
*/
|
|
151
146
|
type RuleItem =
|
|
152
147
|
| { readonly kind: "atom"; readonly atom: AtomData }
|
|
153
148
|
| { readonly kind: "negated"; readonly atom: AtomData }
|
|
154
149
|
| {
|
|
155
|
-
readonly kind: "
|
|
156
|
-
readonly
|
|
150
|
+
readonly kind: "interior"
|
|
151
|
+
readonly target: DerivedTable
|
|
152
|
+
readonly bindings: ReadonlyArray<{ readonly key: string; readonly ref: AnyVar }>
|
|
153
|
+
}
|
|
154
|
+
| {
|
|
155
|
+
readonly kind: "negatedInterior"
|
|
156
|
+
readonly target: DerivedTable
|
|
157
157
|
readonly bindings: ReadonlyArray<{ readonly key: string; readonly ref: AnyVar }>
|
|
158
|
-
/** `true` on a negated finished-stratum atom (`r.not(rec, {...})`): probed through its anti-probe, binds nothing. */
|
|
159
|
-
readonly negated: boolean
|
|
160
158
|
}
|
|
161
159
|
| { readonly kind: "cond"; readonly cond: CondData }
|
|
162
160
|
|
|
@@ -168,7 +166,7 @@ type RuleItem =
|
|
|
168
166
|
*/
|
|
169
167
|
interface ParamUse {
|
|
170
168
|
readonly name: string
|
|
171
|
-
readonly shape: "value" | "set"
|
|
169
|
+
readonly shape: "value" | "set"
|
|
172
170
|
readonly anchor: AnyField | "measure" | undefined
|
|
173
171
|
readonly op: "binding" | CmpKind
|
|
174
172
|
readonly members: readonly string[] | undefined
|
|
@@ -181,16 +179,46 @@ interface RuleData {
|
|
|
181
179
|
readonly paramUses: readonly ParamUse[]
|
|
182
180
|
}
|
|
183
181
|
|
|
182
|
+
/** One named interior's runtime description — identity keys the dense `InteriorId` at lowering. */
|
|
183
|
+
interface InteriorData {
|
|
184
|
+
readonly name: string
|
|
185
|
+
readonly finds: readonly FindColumn[]
|
|
186
|
+
readonly rules: readonly RuleData[]
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** A nonempty frozen list — empty base/rec/finds are unrepresentable on RecData. */
|
|
190
|
+
type NonEmpty<T> = readonly [T, ...T[]]
|
|
191
|
+
|
|
184
192
|
/**
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* (frozen) when the program's output is declared.
|
|
193
|
+
* Name-only rec identity used while base arms are in flight. Rec-base
|
|
194
|
+
* arms cannot read the rec; they must not observe a head.
|
|
188
195
|
*/
|
|
189
|
-
interface
|
|
196
|
+
interface RecHandle {
|
|
190
197
|
readonly name: string
|
|
191
|
-
readonly rules: RuleData[]
|
|
192
198
|
}
|
|
193
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Rec identity plus the sealed head, used while rec arms are in flight
|
|
202
|
+
* and as the target those arms capture.
|
|
203
|
+
*/
|
|
204
|
+
interface RecHead {
|
|
205
|
+
readonly name: string
|
|
206
|
+
readonly finds: NonEmpty<FindColumn>
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* The optional linear rec's runtime description — identity keys the dense
|
|
211
|
+
* `InteriorId` (`interiors.length`) at lowering. Base and rec arms are
|
|
212
|
+
* nonempty by type and sealed in one assignment.
|
|
213
|
+
*/
|
|
214
|
+
interface RecData extends RecHead {
|
|
215
|
+
readonly base: NonEmpty<RuleData>
|
|
216
|
+
readonly rec: NonEmpty<RuleData>
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** A named derived table (an interior or the rec) as `.interior(name)` / `r.not(name)` resolve it. */
|
|
220
|
+
type DerivedTable = InteriorData | RecHead
|
|
221
|
+
|
|
194
222
|
/**
|
|
195
223
|
* What a binding position of field `F` accepts: a bare structural literal
|
|
196
224
|
* of the field's value type, a variable/param/∈-set-param term — and, when
|
|
@@ -286,31 +314,15 @@ interface NotAtom<R extends MatchOwner, B> {
|
|
|
286
314
|
}
|
|
287
315
|
|
|
288
316
|
/**
|
|
289
|
-
*
|
|
290
|
-
* rec
|
|
291
|
-
*
|
|
317
|
+
* One negated finished-table atom — negation OF an interior or of the
|
|
318
|
+
* finished rec is engine-legal in main (a finished set is a set), and
|
|
319
|
+
* this value is its one spelling: `r.not("reach", { c })`. Binds nothing,
|
|
320
|
+
* only rejects — every variable it names must be positively bound in the
|
|
321
|
+
* rule (the same safety rule as EDB negation).
|
|
292
322
|
*/
|
|
293
|
-
interface
|
|
323
|
+
interface NotInteriorAtom<B> {
|
|
324
|
+
readonly cond: "notInterior"
|
|
294
325
|
readonly name: string
|
|
295
|
-
readonly data: RecData
|
|
296
|
-
readonly [inferred]?: { readonly params: ParamsRecord; readonly head: HeadShapeOf }
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/** The head signature a threaded rec target carries (`undefined` before its first rule seals one). */
|
|
300
|
-
type HeadShapeOf = Readonly<Record<string, ClassedField>> | undefined
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* One negated FINISHED-STRATUM atom — negation OF a lower stratum is
|
|
304
|
-
* engine-legal (the strata judge refuses only negation *through* a cycle:
|
|
305
|
-
* a finished set is what keeps the operator monotone), and this value is
|
|
306
|
-
* its one spelling: `r.not(reach, { c })` in an output rule rejects every
|
|
307
|
-
* binding the finished stratum extends, through the engine's anti-probe.
|
|
308
|
-
* Binds nothing, only rejects — every variable it names must be positively
|
|
309
|
-
* bound in the rule (the same safety rule as EDB negation).
|
|
310
|
-
*/
|
|
311
|
-
interface NotIdbAtom<Target extends RecTarget, B> {
|
|
312
|
-
readonly cond: "notIdb"
|
|
313
|
-
readonly target: Target
|
|
314
326
|
readonly bindings: B
|
|
315
327
|
}
|
|
316
328
|
|
|
@@ -323,11 +335,11 @@ type AnyTreeChild = AnyCmp | Tree<readonly AnyTreeChild[]>
|
|
|
323
335
|
/** Any negated-atom value. */
|
|
324
336
|
type AnyNotAtom = NotAtom<MatchOwner, unknown>
|
|
325
337
|
|
|
326
|
-
/** Any negated finished-
|
|
327
|
-
type
|
|
338
|
+
/** Any negated finished-table value. */
|
|
339
|
+
type AnyNotInteriorAtom = NotInteriorAtom<unknown>
|
|
328
340
|
|
|
329
|
-
/** Any `.where` input: a comparison, a condition tree, or a negated atom (EDB, closed, or finished
|
|
330
|
-
type AnyCond = AnyCmp | Tree<readonly AnyTreeChild[]> | AnyNotAtom |
|
|
341
|
+
/** Any `.where` input: a comparison, a condition tree, or a negated atom (EDB, closed, or finished table). */
|
|
342
|
+
type AnyCond = AnyCmp | Tree<readonly AnyTreeChild[]> | AnyNotAtom | AnyNotInteriorAtom
|
|
331
343
|
|
|
332
344
|
/** What `eq`'s right side accepts (`ParamSet` is `Eq`-only — the IR's rule). */
|
|
333
345
|
type EqRight = AnyVar | Param<string> | SetParam<string> | bigint | string | boolean | Uint8Array | IntervalValue
|
|
@@ -473,16 +485,15 @@ const ALLEN = Object.freeze({
|
|
|
473
485
|
/**
|
|
474
486
|
* THE interval-pair comparison (`ir::CmpOp::Allen`): two interval terms of
|
|
475
487
|
* one element type, satisfied iff the pair's classification is in the
|
|
476
|
-
* 13-bit mask — a literal built from the `ALLEN` constants
|
|
477
|
-
* parameter (`r.maskParam`).
|
|
488
|
+
* 13-bit mask — a literal built from the `ALLEN` constants.
|
|
478
489
|
*/
|
|
479
|
-
function allen<const A extends IntervalSide, const
|
|
490
|
+
function allen<const A extends IntervalSide, const B extends IntervalSide>(
|
|
480
491
|
left: A,
|
|
481
|
-
mask:
|
|
492
|
+
mask: number,
|
|
482
493
|
right: B
|
|
483
|
-
): Cmp<"allen", A, B,
|
|
494
|
+
): Cmp<"allen", A, B, number> {
|
|
484
495
|
assertTermSide("allen", left, right)
|
|
485
|
-
if (
|
|
496
|
+
if (!Number.isInteger(mask) || mask < 0 || mask > ALLEN_ALL_BITS) {
|
|
486
497
|
throw errors.new(
|
|
487
498
|
`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)`
|
|
488
499
|
)
|
|
@@ -515,35 +526,25 @@ function or<const C extends readonly AnyTreeChild[]>(...children: C): Tree<C> {
|
|
|
515
526
|
* nothing, only rejects: every variable it names must be positively bound
|
|
516
527
|
* in the rule, a construction-time wall (the engine's safety refusal stands
|
|
517
528
|
* behind it). A CLOSED owner is legal here too — and so is a FINISHED
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
* complement query (`(n) | Node(id: n), !reach(n);` on the Rust surface).
|
|
529
|
+
* TABLE: `not("reach", { c })` in a main rule negates the rec's finished
|
|
530
|
+
* set (a named record over its head keys, variables only), the one
|
|
531
|
+
* spelling of the engine-legal complement query.
|
|
522
532
|
*/
|
|
523
533
|
function not<R extends MatchOwner, const B extends MatchShape<MatchFields<R>>>(relation: R, bindings: B): NotAtom<R, B>
|
|
524
|
-
function not<
|
|
525
|
-
|
|
534
|
+
function not<const Name extends string, const B extends Readonly<Record<string, AnyVar>>>(
|
|
535
|
+
name: Name,
|
|
526
536
|
bindings: B
|
|
527
|
-
):
|
|
537
|
+
): NotInteriorAtom<B>
|
|
528
538
|
function not(
|
|
529
|
-
relation: MatchOwner |
|
|
539
|
+
relation: MatchOwner | string,
|
|
530
540
|
bindings: Readonly<Record<string, unknown>>
|
|
531
|
-
): NotAtom<MatchOwner, unknown> |
|
|
532
|
-
if (
|
|
533
|
-
return Object.freeze({ cond: "
|
|
541
|
+
): NotAtom<MatchOwner, unknown> | NotInteriorAtom<unknown> {
|
|
542
|
+
if (typeof relation === "string") {
|
|
543
|
+
return Object.freeze({ cond: "notInterior" as const, name: relation, bindings })
|
|
534
544
|
}
|
|
535
545
|
return Object.freeze({ cond: "not" as const, relation, bindings })
|
|
536
546
|
}
|
|
537
547
|
|
|
538
|
-
/**
|
|
539
|
-
* THE negation-target discriminant: a rec's runtime data carries its rules,
|
|
540
|
-
* a relation's its fields (and a closed relation's its handle roster) — the
|
|
541
|
-
* shapes are disjoint by construction, so the dispatch is total.
|
|
542
|
-
*/
|
|
543
|
-
function isRecTarget(value: MatchOwner | RecTarget): value is RecTarget {
|
|
544
|
-
return "rules" in value.data
|
|
545
|
-
}
|
|
546
|
-
|
|
547
548
|
/**
|
|
548
549
|
* Whether a variable's OWN field is NUMERIC (u64/i64) — the judgment the
|
|
549
550
|
* point side of `pointIn` and the `sum` input read: a point lives in the
|
|
@@ -726,48 +727,15 @@ type NotOk<Classes extends SchemaClasses, F extends FieldsShape, CR, B> = false
|
|
|
726
727
|
? false
|
|
727
728
|
: true
|
|
728
729
|
|
|
729
|
-
/**
|
|
730
|
-
type
|
|
731
|
-
? Exclude<S, undefined> extends { readonly head: infer H }
|
|
732
|
-
? H
|
|
733
|
-
: undefined
|
|
734
|
-
: undefined
|
|
735
|
-
|
|
736
|
-
/** Reads a rec target's params record off its inference slot. */
|
|
737
|
-
type RecParamsOf<T> = T extends { readonly [inferred]?: infer S }
|
|
738
|
-
? Exclude<S, undefined> extends { readonly params: infer P }
|
|
739
|
-
? P
|
|
740
|
-
: never
|
|
741
|
-
: never
|
|
742
|
-
|
|
743
|
-
/** One negated finished-stratum position's judgment: a variable, class-equal to its head slot when the head is carried. */
|
|
744
|
-
type NotIdbBindingOk<Classes extends SchemaClasses, HeadSlot, V> = V extends AnyVar
|
|
745
|
-
? HeadSlot extends ClassedField
|
|
746
|
-
? JoinOk<HeadSlot, MintSlotOf<Classes, V>> extends true
|
|
747
|
-
? true
|
|
748
|
-
: false
|
|
749
|
-
: true
|
|
750
|
-
: false
|
|
730
|
+
/** One negated finished-table position's judgment: a variable. */
|
|
731
|
+
type NotInteriorBindingOk<V> = V extends AnyVar ? true : false
|
|
751
732
|
|
|
752
733
|
/**
|
|
753
|
-
* The whole negated finished-
|
|
754
|
-
*
|
|
755
|
-
* (
|
|
756
|
-
* the head's and each variable must be class-equal to its head slot; an
|
|
757
|
-
* unthreaded handle still takes variables only.
|
|
734
|
+
* The whole negated finished-table atom's judgment — variables only;
|
|
735
|
+
* arity and class against the named table's head are construction-time
|
|
736
|
+
* (the name is a string, so the head is not a type-level fact).
|
|
758
737
|
*/
|
|
759
|
-
type
|
|
760
|
-
Head extends Readonly<Record<string, ClassedField>>
|
|
761
|
-
? [keyof B] extends [keyof Head]
|
|
762
|
-
? [keyof Head] extends [keyof B]
|
|
763
|
-
? false extends { [K in keyof B]: NotIdbBindingOk<Classes, Head[K & keyof Head], B[K]> }[keyof B]
|
|
764
|
-
? false
|
|
765
|
-
: true
|
|
766
|
-
: false
|
|
767
|
-
: false
|
|
768
|
-
: false extends { [K in keyof B]: B[K] extends AnyVar ? true : false }[keyof B]
|
|
769
|
-
? false
|
|
770
|
-
: true
|
|
738
|
+
type NotInteriorOk<B> = false extends { [K in keyof B]: NotInteriorBindingOk<B[K]> }[keyof B] ? false : true
|
|
771
739
|
|
|
772
740
|
/**
|
|
773
741
|
* One condition's judgment — the type-level twin of the engine's comparison
|
|
@@ -795,8 +763,8 @@ type CondOkBool<Classes extends SchemaClasses, C> = [AnyTreeChild] extends [C]
|
|
|
795
763
|
? false extends CondOkBool<Classes, Ch[number]>
|
|
796
764
|
? false
|
|
797
765
|
: true
|
|
798
|
-
: C extends
|
|
799
|
-
?
|
|
766
|
+
: C extends NotInteriorAtom<infer B>
|
|
767
|
+
? NotInteriorOk<B>
|
|
800
768
|
: C extends NotAtom<infer R extends MatchOwner, infer B>
|
|
801
769
|
? NotOk<Classes, MatchFields<R>, ClassRecordOf<Classes, R["name"]>, B>
|
|
802
770
|
: false
|
|
@@ -829,9 +797,6 @@ type PointParams<T> = T extends Param<infer P extends string> ? { readonly [Q in
|
|
|
829
797
|
/** An interval side's params contribution. */
|
|
830
798
|
type IntervalSideParams<T> = T extends Param<infer P extends string> ? { readonly [Q in P]: IntervalValue } : never
|
|
831
799
|
|
|
832
|
-
/** The mask position's params contribution. */
|
|
833
|
-
type MaskParams<M> = M extends MaskParam<infer P extends string> ? { readonly [Q in P]: number } : never
|
|
834
|
-
|
|
835
800
|
/**
|
|
836
801
|
* One condition's params-object fragments (a union; the rule builder folds
|
|
837
802
|
* them into the inferred `Params` record) — every param typed by its use.
|
|
@@ -839,7 +804,7 @@ type MaskParams<M> = M extends MaskParam<infer P extends string> ? { readonly [Q
|
|
|
839
804
|
*/
|
|
840
805
|
type CondParams<C> = [AnyTreeChild] extends [C]
|
|
841
806
|
? never
|
|
842
|
-
: C extends Cmp<infer Op, infer L, infer R, infer
|
|
807
|
+
: C extends Cmp<infer Op, infer L, infer R, infer _M>
|
|
843
808
|
? Op extends "eq" | "ne"
|
|
844
809
|
? EqParams<L, R>
|
|
845
810
|
: Op extends "lt" | "le" | "gt" | "ge"
|
|
@@ -847,12 +812,12 @@ type CondParams<C> = [AnyTreeChild] extends [C]
|
|
|
847
812
|
: Op extends "pointIn"
|
|
848
813
|
? IntervalSideParams<L> | PointParams<R>
|
|
849
814
|
: Op extends "allen"
|
|
850
|
-
? IntervalSideParams<L> | IntervalSideParams<R>
|
|
815
|
+
? IntervalSideParams<L> | IntervalSideParams<R>
|
|
851
816
|
: never
|
|
852
817
|
: C extends Tree<infer Ch extends readonly AnyTreeChild[]>
|
|
853
818
|
? CondParams<Ch[number]>
|
|
854
|
-
: C extends
|
|
855
|
-
?
|
|
819
|
+
: C extends NotInteriorAtom<unknown>
|
|
820
|
+
? never
|
|
856
821
|
: C extends NotAtom<infer R extends MatchOwner, infer B>
|
|
857
822
|
? BindParams<MatchFields<R>, B>
|
|
858
823
|
: never
|
|
@@ -885,23 +850,25 @@ export type {
|
|
|
885
850
|
CondOkBool,
|
|
886
851
|
CondParams,
|
|
887
852
|
CondParamsShape,
|
|
853
|
+
DerivedTable,
|
|
888
854
|
FindColumn,
|
|
889
855
|
FindEntryData,
|
|
856
|
+
InteriorData,
|
|
890
857
|
IntervalSide,
|
|
891
858
|
IntervalVarOk,
|
|
892
|
-
MaskData,
|
|
893
859
|
MatchFields,
|
|
894
860
|
MatchOwner,
|
|
895
861
|
MatchShape,
|
|
896
862
|
NotAtom,
|
|
897
|
-
|
|
863
|
+
NotInteriorAtom,
|
|
898
864
|
NumericVarOk,
|
|
899
865
|
OrderSide,
|
|
900
866
|
OrderVarOk,
|
|
901
867
|
ParamUse,
|
|
902
868
|
PointSide,
|
|
903
869
|
RecData,
|
|
904
|
-
|
|
870
|
+
RecHandle,
|
|
871
|
+
RecHead,
|
|
905
872
|
RuleData,
|
|
906
873
|
RuleItem,
|
|
907
874
|
SlotAt,
|
package/src/query/find.ts
CHANGED
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
* vocabulary, mirroring the IR's aggregate roster exactly
|
|
4
4
|
* (`bumbledb/crates/bumbledb/src/ir.rs` `AggOp`/`FindTerm`;
|
|
5
5
|
* `docs/architecture/20-query-ir.md` § aggregation): `count` (nullary),
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `r.sum(w)` — and are typed by the variable's own descriptor.
|
|
6
|
+
* `sum`/`min`/`max` (over an orderable variable or the measure), and
|
|
7
|
+
* `pack` (the coalescing fold — RELATION-SHAPED, the result position
|
|
8
|
+
* interval-typed). Aggregates fold VARIABLES by reference — `r.sum(w)` —
|
|
9
|
+
* and are typed by the variable's own descriptor.
|
|
11
10
|
*
|
|
12
11
|
* `select(strings)` is DEAD: the head is a `find` RECORD, whose KEYS name
|
|
13
12
|
* the answer columns (`find({ total: r.count(), owner: h })`). The keys are
|
|
@@ -25,25 +24,19 @@ import type { IntervalVarOk, NumericVarOk, OrderVarOk } from "#query/atom.ts"
|
|
|
25
24
|
import type { AnyVar, Duration, MintSlotOf } from "#query/scope.ts"
|
|
26
25
|
|
|
27
26
|
/** One aggregate operator name of the find vocabulary. */
|
|
28
|
-
type AggOpName = "count" | "
|
|
27
|
+
type AggOpName = "count" | "sum" | "min" | "max" | "pack"
|
|
29
28
|
|
|
30
29
|
/**
|
|
31
|
-
* One aggregate find VALUE: the op
|
|
32
|
-
* REFERENCE
|
|
33
|
-
* variable's own descriptor types the result.
|
|
30
|
+
* One aggregate find VALUE: the op and the variable (or measure) it folds
|
|
31
|
+
* BY REFERENCE. The variable's own descriptor types the result.
|
|
34
32
|
*/
|
|
35
|
-
interface Agg<
|
|
36
|
-
Op extends AggOpName,
|
|
37
|
-
Over extends AnyVar | Duration | undefined,
|
|
38
|
-
Key extends AnyVar | undefined = undefined
|
|
39
|
-
> {
|
|
33
|
+
interface Agg<Op extends AggOpName, Over extends AnyVar | Duration | undefined> {
|
|
40
34
|
readonly agg: Op
|
|
41
35
|
readonly over: Over
|
|
42
|
-
readonly key: Key
|
|
43
36
|
}
|
|
44
37
|
|
|
45
38
|
/** Any aggregate find value. */
|
|
46
|
-
type AnyAgg = Agg<AggOpName, AnyVar | Duration | undefined
|
|
39
|
+
type AnyAgg = Agg<AggOpName, AnyVar | Duration | undefined>
|
|
47
40
|
|
|
48
41
|
/** One find entry: a projected variable, the measure, or an aggregate. */
|
|
49
42
|
type FindEntry = AnyVar | Duration | AnyAgg
|
|
@@ -52,22 +45,16 @@ type FindEntry = AnyVar | Duration | AnyAgg
|
|
|
52
45
|
type FindShape = Readonly<Record<string, FindEntry>>
|
|
53
46
|
|
|
54
47
|
/** Builds one aggregate value. */
|
|
55
|
-
function aggregate<Op extends AggOpName, Over extends AnyVar | Duration | undefined
|
|
48
|
+
function aggregate<Op extends AggOpName, Over extends AnyVar | Duration | undefined>(
|
|
56
49
|
op: Op,
|
|
57
|
-
over: Over
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return Object.freeze({ agg: op, over, key })
|
|
50
|
+
over: Over
|
|
51
|
+
): Agg<Op, Over> {
|
|
52
|
+
return Object.freeze({ agg: op, over })
|
|
61
53
|
}
|
|
62
54
|
|
|
63
55
|
/** Nullary count: |the group's set of distinct full bindings|, `bigint`. */
|
|
64
56
|
function count(): Agg<"count", undefined> {
|
|
65
|
-
return aggregate("count", undefined
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** |the distinct values of the variable across the group|, `bigint`; legal over every type. */
|
|
69
|
-
function countDistinct<const V extends AnyVar>(over: V): Agg<"countDistinct", V> {
|
|
70
|
-
return aggregate("countDistinct", over, undefined)
|
|
57
|
+
return aggregate("count", undefined)
|
|
71
58
|
}
|
|
72
59
|
|
|
73
60
|
/**
|
|
@@ -77,33 +64,17 @@ function countDistinct<const V extends AnyVar>(over: V): Agg<"countDistinct", V>
|
|
|
77
64
|
* quantifier is not an addition (R3).
|
|
78
65
|
*/
|
|
79
66
|
function sum<const O extends AnyVar | Duration>(over: O): Agg<"sum", O> {
|
|
80
|
-
return aggregate("sum", over
|
|
67
|
+
return aggregate("sum", over)
|
|
81
68
|
}
|
|
82
69
|
|
|
83
70
|
/** Minimum over an orderable variable (u64/i64/bool — over bool, `Min` is the ALL quantifier; R3) or the measure. */
|
|
84
71
|
function min<const O extends AnyVar | Duration>(over: O): Agg<"min", O> {
|
|
85
|
-
return aggregate("min", over
|
|
72
|
+
return aggregate("min", over)
|
|
86
73
|
}
|
|
87
74
|
|
|
88
75
|
/** Maximum over an orderable variable (u64/i64/bool — over bool, `Max` is the ANY quantifier; R3) or the measure. */
|
|
89
76
|
function max<const O extends AnyVar | Duration>(over: O): Agg<"max", O> {
|
|
90
|
-
return aggregate("max", over
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Arg-restriction toward the maximum of `key` (`ir::AggOp::ArgMax`): the
|
|
95
|
-
* group's binding set is restricted to the bindings attaining the extreme
|
|
96
|
-
* of the orderable key, and `value` is the carried payload — a tie yields
|
|
97
|
-
* every attaining row. All Arg entries of one query share one key and one
|
|
98
|
-
* direction; Arg and fold aggregates never mix (both the engine's rules).
|
|
99
|
-
*/
|
|
100
|
-
function argMax<const V extends AnyVar, const K extends AnyVar>(value: V, key: K): Agg<"argMax", V, K> {
|
|
101
|
-
return aggregate("argMax", value, key)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** Arg-restriction toward the minimum of `key`; rules as {@link argMax}. */
|
|
105
|
-
function argMin<const V extends AnyVar, const K extends AnyVar>(value: V, key: K): Agg<"argMin", V, K> {
|
|
106
|
-
return aggregate("argMin", value, key)
|
|
77
|
+
return aggregate("max", over)
|
|
107
78
|
}
|
|
108
79
|
|
|
109
80
|
/**
|
|
@@ -111,10 +82,10 @@ function argMin<const V extends AnyVar, const K extends AnyVar>(value: V, key: K
|
|
|
111
82
|
* the maximal disjoint half-open segments of the union of the group's
|
|
112
83
|
* interval point sets — RELATION-SHAPED, one answer row per (group, maximal
|
|
113
84
|
* segment), the result position carrying one interval of the input's element
|
|
114
|
-
* type. At most one `pack` per find, never beside a fold
|
|
85
|
+
* type. At most one `pack` per find, never beside a fold entry.
|
|
115
86
|
*/
|
|
116
87
|
function pack<const V extends AnyVar>(over: V): Agg<"pack", V> {
|
|
117
|
-
return aggregate("pack", over
|
|
88
|
+
return aggregate("pack", over)
|
|
118
89
|
}
|
|
119
90
|
|
|
120
91
|
/**
|
|
@@ -142,7 +113,7 @@ type FoldOverOk<O> = O extends AnyVar
|
|
|
142
113
|
/**
|
|
143
114
|
* One find entry's judgment (off the entry's own descriptor — no env, no
|
|
144
115
|
* class map needed): a projected variable is ok, the measure and `pack`
|
|
145
|
-
* demand interval-typed variables, folds
|
|
116
|
+
* demand interval-typed variables, folds demand orderable ones.
|
|
146
117
|
*/
|
|
147
118
|
type FindEntryOk<E> = E extends AnyVar
|
|
148
119
|
? true
|
|
@@ -150,19 +121,13 @@ type FindEntryOk<E> = E extends AnyVar
|
|
|
150
121
|
? IntervalVarOk<V>
|
|
151
122
|
: E extends Agg<"count", undefined>
|
|
152
123
|
? true
|
|
153
|
-
: E extends Agg<"
|
|
154
|
-
?
|
|
155
|
-
: E extends Agg<"
|
|
156
|
-
?
|
|
157
|
-
: E extends Agg<"
|
|
158
|
-
?
|
|
159
|
-
:
|
|
160
|
-
? OrderVarOk<K> extends true
|
|
161
|
-
? true
|
|
162
|
-
: false
|
|
163
|
-
: E extends Agg<"pack", infer V extends AnyVar>
|
|
164
|
-
? IntervalVarOk<V>
|
|
165
|
-
: false
|
|
124
|
+
: E extends Agg<"sum", infer O>
|
|
125
|
+
? SumOverOk<O>
|
|
126
|
+
: E extends Agg<"min" | "max", infer O>
|
|
127
|
+
? FoldOverOk<O>
|
|
128
|
+
: E extends Agg<"pack", infer V extends AnyVar>
|
|
129
|
+
? IntervalVarOk<V>
|
|
130
|
+
: false
|
|
166
131
|
|
|
167
132
|
/** The validated find record (intersect with the inferred entries — errors land on the offending key). */
|
|
168
133
|
type CheckFind<F extends FindShape> = {
|
|
@@ -171,8 +136,7 @@ type CheckFind<F extends FindShape> = {
|
|
|
171
136
|
|
|
172
137
|
/**
|
|
173
138
|
* The validated find record of a RECURSIVE rule: every entry must be a plain
|
|
174
|
-
* variable (aggregates and the measure are unwritable in a
|
|
175
|
-
* the strata quarantine).
|
|
139
|
+
* variable (aggregates and the measure are unwritable in a rec head).
|
|
176
140
|
*/
|
|
177
141
|
type CheckRecFind<F extends FindShape> = {
|
|
178
142
|
readonly [K in keyof F]: F[K] extends AnyVar ? F[K] : never
|
|
@@ -180,9 +144,8 @@ type CheckRecFind<F extends FindShape> = {
|
|
|
180
144
|
|
|
181
145
|
/**
|
|
182
146
|
* One find entry's answer-column value type: a variable carries its field's
|
|
183
|
-
* type, the measure/count
|
|
184
|
-
*
|
|
185
|
-
* payload's type, `pack` its interval type.
|
|
147
|
+
* type, the measure/count are `bigint`, folds carry their input's type
|
|
148
|
+
* (a measure fold is `bigint`), `pack` its interval type.
|
|
186
149
|
*/
|
|
187
150
|
type FindValue<E> = E extends AnyVar
|
|
188
151
|
? Infer<E["field"]>
|
|
@@ -190,17 +153,13 @@ type FindValue<E> = E extends AnyVar
|
|
|
190
153
|
? bigint
|
|
191
154
|
: E extends Agg<"count", undefined>
|
|
192
155
|
? bigint
|
|
193
|
-
: E extends Agg<"
|
|
194
|
-
?
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
:
|
|
200
|
-
? Infer<V["field"]>
|
|
201
|
-
: E extends Agg<"pack", infer V extends AnyVar>
|
|
202
|
-
? Infer<V["field"]>
|
|
203
|
-
: never
|
|
156
|
+
: E extends Agg<"sum" | "min" | "max", infer O>
|
|
157
|
+
? O extends AnyVar
|
|
158
|
+
? Infer<O["field"]>
|
|
159
|
+
: bigint
|
|
160
|
+
: E extends Agg<"pack", infer V extends AnyVar>
|
|
161
|
+
? Infer<V["field"]>
|
|
162
|
+
: never
|
|
204
163
|
|
|
205
164
|
/** The inferred answer-row object type of a find record — the keys ARE the columns. */
|
|
206
165
|
type RowOfFind<F extends FindShape> = { readonly [K in keyof F]: FindValue<F[K]> }
|
|
@@ -208,7 +167,7 @@ type RowOfFind<F extends FindShape> = { readonly [K in keyof F]: FindValue<F[K]>
|
|
|
208
167
|
/**
|
|
209
168
|
* The head signature of a recursive rule's find record as classed mint
|
|
210
169
|
* slots (descriptor + law-computed class), keyed by column name — the
|
|
211
|
-
* signature an
|
|
170
|
+
* signature an interior join pairs against (`F` is variable-only there).
|
|
212
171
|
*/
|
|
213
172
|
type HeadRecordOf<Classes extends SchemaClasses, F extends FindShape> = {
|
|
214
173
|
readonly [K in keyof F]: F[K] extends AnyVar ? MintSlotOf<Classes, F[K]> : never
|
|
@@ -227,4 +186,4 @@ export type {
|
|
|
227
186
|
HeadRecordOf,
|
|
228
187
|
RowOfFind
|
|
229
188
|
}
|
|
230
|
-
export {
|
|
189
|
+
export { count, max, min, pack, sum }
|