@bjornpagen/bumbledb 0.9.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/capacity.d.ts +14 -1
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js.map +1 -1
- 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 +162 -122
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +26 -22
- 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 +336 -260
- 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 +15 -9
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +14 -9
- package/dist/statements.js.map +1 -1
- package/package.json +2 -2
- package/src/capacity.ts +24 -1
- 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 +255 -165
- package/src/query/find.ts +39 -80
- package/src/query/lower.ts +578 -432
- 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 +33 -17
- 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
|
|
@@ -350,14 +362,28 @@ function comparison<Op extends CmpKind, L, R, M>(op: Op, lhs: L, rhs: R, mask: M
|
|
|
350
362
|
}
|
|
351
363
|
|
|
352
364
|
/**
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
365
|
+
* Whether a comparison side is a VARIABLE side in the engine's sense — a
|
|
366
|
+
* bound variable or the measure. A param is a constant at execution, so a
|
|
367
|
+
* comparison whose every side is a param or literal is constant-valued:
|
|
368
|
+
* the engine's `ConstantComparison` conviction
|
|
369
|
+
* (`bumbledb/crates/bumbledb/src/ir/validate/context.rs`,
|
|
370
|
+
* `comparison_shape`'s last arm).
|
|
371
|
+
*/
|
|
372
|
+
function isVariableSide(value: unknown): boolean {
|
|
373
|
+
return isTerm(value) && (value[term] === "var" || value[term] === "duration")
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Rejects a comparison with no variable side: it is constant-valued —
|
|
378
|
+
* params included, a param is a constant the moment it binds — the
|
|
379
|
+
* engine's own validation refuses it (`ConstantComparison`), and the
|
|
380
|
+
* lowering has no anchored position to type the literals by — fail here
|
|
381
|
+
* with the same verdict.
|
|
356
382
|
*/
|
|
357
383
|
function assertTermSide(op: string, lhs: unknown, rhs: unknown): void {
|
|
358
|
-
if (!
|
|
384
|
+
if (!isVariableSide(lhs) && !isVariableSide(rhs)) {
|
|
359
385
|
throw errors.new(
|
|
360
|
-
`${op}: a comparison without a variable
|
|
386
|
+
`${op}: a comparison without a variable side is constant-valued (a parameter is a constant at execution) — write the query you mean`
|
|
361
387
|
)
|
|
362
388
|
}
|
|
363
389
|
}
|
|
@@ -459,16 +485,15 @@ const ALLEN = Object.freeze({
|
|
|
459
485
|
/**
|
|
460
486
|
* THE interval-pair comparison (`ir::CmpOp::Allen`): two interval terms of
|
|
461
487
|
* one element type, satisfied iff the pair's classification is in the
|
|
462
|
-
* 13-bit mask — a literal built from the `ALLEN` constants
|
|
463
|
-
* parameter (`r.maskParam`).
|
|
488
|
+
* 13-bit mask — a literal built from the `ALLEN` constants.
|
|
464
489
|
*/
|
|
465
|
-
function allen<const A extends IntervalSide, const
|
|
490
|
+
function allen<const A extends IntervalSide, const B extends IntervalSide>(
|
|
466
491
|
left: A,
|
|
467
|
-
mask:
|
|
492
|
+
mask: number,
|
|
468
493
|
right: B
|
|
469
|
-
): Cmp<"allen", A, B,
|
|
494
|
+
): Cmp<"allen", A, B, number> {
|
|
470
495
|
assertTermSide("allen", left, right)
|
|
471
|
-
if (
|
|
496
|
+
if (!Number.isInteger(mask) || mask < 0 || mask > ALLEN_ALL_BITS) {
|
|
472
497
|
throw errors.new(
|
|
473
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)`
|
|
474
499
|
)
|
|
@@ -501,35 +526,25 @@ function or<const C extends readonly AnyTreeChild[]>(...children: C): Tree<C> {
|
|
|
501
526
|
* nothing, only rejects: every variable it names must be positively bound
|
|
502
527
|
* in the rule, a construction-time wall (the engine's safety refusal stands
|
|
503
528
|
* behind it). A CLOSED owner is legal here too — and so is a FINISHED
|
|
504
|
-
*
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
* 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.
|
|
508
532
|
*/
|
|
509
533
|
function not<R extends MatchOwner, const B extends MatchShape<MatchFields<R>>>(relation: R, bindings: B): NotAtom<R, B>
|
|
510
|
-
function not<
|
|
511
|
-
|
|
534
|
+
function not<const Name extends string, const B extends Readonly<Record<string, AnyVar>>>(
|
|
535
|
+
name: Name,
|
|
512
536
|
bindings: B
|
|
513
|
-
):
|
|
537
|
+
): NotInteriorAtom<B>
|
|
514
538
|
function not(
|
|
515
|
-
relation: MatchOwner |
|
|
539
|
+
relation: MatchOwner | string,
|
|
516
540
|
bindings: Readonly<Record<string, unknown>>
|
|
517
|
-
): NotAtom<MatchOwner, unknown> |
|
|
518
|
-
if (
|
|
519
|
-
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 })
|
|
520
544
|
}
|
|
521
545
|
return Object.freeze({ cond: "not" as const, relation, bindings })
|
|
522
546
|
}
|
|
523
547
|
|
|
524
|
-
/**
|
|
525
|
-
* THE negation-target discriminant: a rec's runtime data carries its rules,
|
|
526
|
-
* a relation's its fields (and a closed relation's its handle roster) — the
|
|
527
|
-
* shapes are disjoint by construction, so the dispatch is total.
|
|
528
|
-
*/
|
|
529
|
-
function isRecTarget(value: MatchOwner | RecTarget): value is RecTarget {
|
|
530
|
-
return "rules" in value.data
|
|
531
|
-
}
|
|
532
|
-
|
|
533
548
|
/**
|
|
534
549
|
* Whether a variable's OWN field is NUMERIC (u64/i64) — the judgment the
|
|
535
550
|
* point side of `pointIn` and the `sum` input read: a point lives in the
|
|
@@ -560,18 +575,130 @@ type OrderVarOk<V extends AnyVar> = V["field"]["kind"] extends "bool" ? true : N
|
|
|
560
575
|
/** Whether a variable's OWN field is interval-typed. */
|
|
561
576
|
type IntervalVarOk<V extends AnyVar> = V["field"]["kind"] extends "interval" ? true : false
|
|
562
577
|
|
|
563
|
-
/**
|
|
564
|
-
|
|
565
|
-
|
|
578
|
+
/**
|
|
579
|
+
* Whether a comparison has a VARIABLE side (a var or the measure) — the
|
|
580
|
+
* type-level twin of the engine's `ConstantComparison` rule: a param is a
|
|
581
|
+
* constant at execution, so param-vs-param and param-vs-literal are
|
|
582
|
+
* constant-valued whatever their domains ({@link assertTermSide} is the
|
|
583
|
+
* runtime wall behind this one).
|
|
584
|
+
*/
|
|
585
|
+
type CmpVarSideOk<L, R> = L extends AnyVar | Duration ? true : R extends AnyVar | Duration ? true : false
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* One order side's DOMAIN — the type-level twin of the engine's resolved
|
|
589
|
+
* operand type (`ir/validate/context.rs`, `classify`'s `Ord*` arms): a
|
|
590
|
+
* variable names its own field kind, the measure is u64 by definition (and
|
|
591
|
+
* never meets another measure — `DurationBothSides`), a bigint literal
|
|
592
|
+
* spans the integer domains, a param is typed by its sibling (`"open"`).
|
|
593
|
+
* `never` marks a side that is itself unorderable: interval/bytes/string
|
|
594
|
+
* vars (the operand screen), closed-bound vars (R4), a measure over a
|
|
595
|
+
* non-interval var.
|
|
596
|
+
*/
|
|
597
|
+
type OrderDomain<T> = T extends AnyVar
|
|
598
|
+
? OrderVarOk<T> extends true
|
|
599
|
+
? T["field"]["kind"]
|
|
600
|
+
: never
|
|
566
601
|
: T extends Duration<infer V extends AnyVar>
|
|
567
|
-
? IntervalVarOk<V>
|
|
568
|
-
|
|
602
|
+
? IntervalVarOk<V> extends true
|
|
603
|
+
? "duration"
|
|
604
|
+
: never
|
|
605
|
+
: T extends Param<string>
|
|
606
|
+
? "open"
|
|
607
|
+
: T extends bigint
|
|
608
|
+
? "integer"
|
|
609
|
+
: T extends boolean
|
|
610
|
+
? "bool"
|
|
611
|
+
: never
|
|
569
612
|
|
|
570
|
-
/**
|
|
571
|
-
|
|
613
|
+
/**
|
|
614
|
+
* Whether two order domains may MEET under one operator — the engine's
|
|
615
|
+
* same-type rule judged pairwise, not per side: bool meets only bool (a
|
|
616
|
+
* bigint literal against a bool var is exactly `check_const`'s
|
|
617
|
+
* conviction; R3 made bool orderable, never cross-orderable), u64 and i64
|
|
618
|
+
* never meet, the measure's sibling must live in u64 (`OrdMeasureVar`:
|
|
619
|
+
* scalar ≠ U64 is `IllegalComparison`), two measures never meet, and an
|
|
620
|
+
* open side (param, integer literal) takes whatever its sibling names.
|
|
621
|
+
*/
|
|
622
|
+
type OrderDomainsOk<A, B> = [A] extends [never]
|
|
623
|
+
? false
|
|
624
|
+
: [B] extends [never]
|
|
625
|
+
? false
|
|
626
|
+
: A extends "open"
|
|
627
|
+
? true
|
|
628
|
+
: B extends "open"
|
|
629
|
+
? true
|
|
630
|
+
: A extends "duration"
|
|
631
|
+
? B extends "u64" | "integer"
|
|
632
|
+
? true
|
|
633
|
+
: false
|
|
634
|
+
: B extends "duration"
|
|
635
|
+
? A extends "u64" | "integer"
|
|
636
|
+
? true
|
|
637
|
+
: false
|
|
638
|
+
: A extends "bool"
|
|
639
|
+
? B extends "bool"
|
|
640
|
+
? true
|
|
641
|
+
: false
|
|
642
|
+
: B extends "bool"
|
|
643
|
+
? false
|
|
644
|
+
: A extends "integer"
|
|
645
|
+
? true
|
|
646
|
+
: B extends "integer"
|
|
647
|
+
? true
|
|
648
|
+
: A extends B
|
|
649
|
+
? true
|
|
650
|
+
: false
|
|
651
|
+
|
|
652
|
+
/** The whole order comparison's judgment: a variable side exists, and the sides' domains meet. */
|
|
653
|
+
type OrderPairOk<L, R> = CmpVarSideOk<L, R> extends true ? OrderDomainsOk<OrderDomain<L>, OrderDomain<R>> : false
|
|
572
654
|
|
|
573
|
-
/**
|
|
574
|
-
|
|
655
|
+
/**
|
|
656
|
+
* An interval side's ELEMENT domain: a variable names its field's element
|
|
657
|
+
* (`never` on a non-interval var), a param or bare interval literal is
|
|
658
|
+
* `"open"` — no type exists to name its element at this tier; the engine
|
|
659
|
+
* anchors it at prepare.
|
|
660
|
+
*/
|
|
661
|
+
type IntervalElementDomain<T> = T extends AnyVar
|
|
662
|
+
? T["field"] extends { readonly kind: "interval"; readonly element: infer E extends "u64" | "i64" }
|
|
663
|
+
? E
|
|
664
|
+
: never
|
|
665
|
+
: "open"
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* The point side's domain — a point lives in the interval's element
|
|
669
|
+
* domain: a numeric var names its kind (never bool, never closed), a
|
|
670
|
+
* param or bigint literal is open.
|
|
671
|
+
*/
|
|
672
|
+
type PointDomain<T> = T extends AnyVar ? (NumericVarOk<T> extends true ? T["field"]["kind"] : never) : "open"
|
|
673
|
+
|
|
674
|
+
/** Whether two element domains meet: both legal, and equal unless one is open. */
|
|
675
|
+
type ElementMeets<A, B> = [A] extends [never]
|
|
676
|
+
? false
|
|
677
|
+
: [B] extends [never]
|
|
678
|
+
? false
|
|
679
|
+
: A extends "open"
|
|
680
|
+
? true
|
|
681
|
+
: B extends "open"
|
|
682
|
+
? true
|
|
683
|
+
: A extends B
|
|
684
|
+
? true
|
|
685
|
+
: false
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* The whole `pointIn` judgment (operands already sealed interval-left):
|
|
689
|
+
* the point's domain must BE the interval's element domain — `pointIn(t,
|
|
690
|
+
* w)` with an i64-typed `t` against `interval(u64)` is the engine's
|
|
691
|
+
* `IllegalComparison`, judged here first.
|
|
692
|
+
*/
|
|
693
|
+
type PointInPairOk<L, R> =
|
|
694
|
+
CmpVarSideOk<L, R> extends true ? ElementMeets<IntervalElementDomain<L>, PointDomain<R>> : false
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* The whole `allen` judgment: two interval sides of ONE element domain
|
|
698
|
+
* (Q1 — widths meet freely, u64-vs-i64 stays illegal), judged pairwise.
|
|
699
|
+
*/
|
|
700
|
+
type AllenPairOk<L, R> =
|
|
701
|
+
CmpVarSideOk<L, R> extends true ? ElementMeets<IntervalElementDomain<L>, IntervalElementDomain<R>> : false
|
|
575
702
|
|
|
576
703
|
/** The `eq`/`ne` judgment: var-var joins by mint slot; var-literal is exact-typed by the var's own field. */
|
|
577
704
|
type EqOk<Classes extends SchemaClasses, L, R> = L extends AnyVar
|
|
@@ -600,55 +727,25 @@ type NotOk<Classes extends SchemaClasses, F extends FieldsShape, CR, B> = false
|
|
|
600
727
|
? false
|
|
601
728
|
: true
|
|
602
729
|
|
|
603
|
-
/**
|
|
604
|
-
type
|
|
605
|
-
? Exclude<S, undefined> extends { readonly head: infer H }
|
|
606
|
-
? H
|
|
607
|
-
: undefined
|
|
608
|
-
: undefined
|
|
609
|
-
|
|
610
|
-
/** Reads a rec target's params record off its inference slot. */
|
|
611
|
-
type RecParamsOf<T> = T extends { readonly [inferred]?: infer S }
|
|
612
|
-
? Exclude<S, undefined> extends { readonly params: infer P }
|
|
613
|
-
? P
|
|
614
|
-
: never
|
|
615
|
-
: never
|
|
616
|
-
|
|
617
|
-
/** One negated finished-stratum position's judgment: a variable, class-equal to its head slot when the head is carried. */
|
|
618
|
-
type NotIdbBindingOk<Classes extends SchemaClasses, HeadSlot, V> = V extends AnyVar
|
|
619
|
-
? HeadSlot extends ClassedField
|
|
620
|
-
? JoinOk<HeadSlot, MintSlotOf<Classes, V>> extends true
|
|
621
|
-
? true
|
|
622
|
-
: false
|
|
623
|
-
: true
|
|
624
|
-
: false
|
|
730
|
+
/** One negated finished-table position's judgment: a variable. */
|
|
731
|
+
type NotInteriorBindingOk<V> = V extends AnyVar ? true : false
|
|
625
732
|
|
|
626
733
|
/**
|
|
627
|
-
* The whole negated finished-
|
|
628
|
-
*
|
|
629
|
-
* (
|
|
630
|
-
* the head's and each variable must be class-equal to its head slot; an
|
|
631
|
-
* 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).
|
|
632
737
|
*/
|
|
633
|
-
type
|
|
634
|
-
Head extends Readonly<Record<string, ClassedField>>
|
|
635
|
-
? [keyof B] extends [keyof Head]
|
|
636
|
-
? [keyof Head] extends [keyof B]
|
|
637
|
-
? false extends { [K in keyof B]: NotIdbBindingOk<Classes, Head[K & keyof Head], B[K]> }[keyof B]
|
|
638
|
-
? false
|
|
639
|
-
: true
|
|
640
|
-
: false
|
|
641
|
-
: false
|
|
642
|
-
: false extends { [K in keyof B]: B[K] extends AnyVar ? true : false }[keyof B]
|
|
643
|
-
? false
|
|
644
|
-
: true
|
|
738
|
+
type NotInteriorOk<B> = false extends { [K in keyof B]: NotInteriorBindingOk<B[K]> }[keyof B] ? false : true
|
|
645
739
|
|
|
646
740
|
/**
|
|
647
741
|
* One condition's judgment — the type-level twin of the engine's comparison
|
|
648
|
-
* roster: class-equal joins (off the mint slots),
|
|
649
|
-
* interval var under a non-`pointIn` op is
|
|
650
|
-
*
|
|
651
|
-
*
|
|
742
|
+
* roster: class-equal joins (off the mint slots), PAIRWISE-judged order
|
|
743
|
+
* domains (an interval var under a non-`pointIn` op is refused per side;
|
|
744
|
+
* bool-vs-numeric, u64-vs-i64, and measure-vs-non-u64 are refused as
|
|
745
|
+
* pairs — the engine's same-type rule), element-matched `pointIn`/`allen`
|
|
746
|
+
* pairs, the no-variable-side (constant comparison) rule, and
|
|
747
|
+
* negated-atom class safety. The leading `[AnyTreeChild] extends [C]` arm
|
|
748
|
+
* is the recursion's base case.
|
|
652
749
|
*/
|
|
653
750
|
type CondOkBool<Classes extends SchemaClasses, C> = [AnyTreeChild] extends [C]
|
|
654
751
|
? true
|
|
@@ -656,24 +753,18 @@ type CondOkBool<Classes extends SchemaClasses, C> = [AnyTreeChild] extends [C]
|
|
|
656
753
|
? Op extends "eq" | "ne"
|
|
657
754
|
? EqOk<Classes, L, R>
|
|
658
755
|
: Op extends "lt" | "le" | "gt" | "ge"
|
|
659
|
-
?
|
|
660
|
-
? true
|
|
661
|
-
: false
|
|
756
|
+
? OrderPairOk<L, R>
|
|
662
757
|
: Op extends "pointIn"
|
|
663
|
-
?
|
|
664
|
-
? true
|
|
665
|
-
: false
|
|
758
|
+
? PointInPairOk<L, R>
|
|
666
759
|
: Op extends "allen"
|
|
667
|
-
?
|
|
668
|
-
? true
|
|
669
|
-
: false
|
|
760
|
+
? AllenPairOk<L, R>
|
|
670
761
|
: false
|
|
671
762
|
: C extends Tree<infer Ch extends readonly AnyTreeChild[]>
|
|
672
763
|
? false extends CondOkBool<Classes, Ch[number]>
|
|
673
764
|
? false
|
|
674
765
|
: true
|
|
675
|
-
: C extends
|
|
676
|
-
?
|
|
766
|
+
: C extends NotInteriorAtom<infer B>
|
|
767
|
+
? NotInteriorOk<B>
|
|
677
768
|
: C extends NotAtom<infer R extends MatchOwner, infer B>
|
|
678
769
|
? NotOk<Classes, MatchFields<R>, ClassRecordOf<Classes, R["name"]>, B>
|
|
679
770
|
: false
|
|
@@ -706,9 +797,6 @@ type PointParams<T> = T extends Param<infer P extends string> ? { readonly [Q in
|
|
|
706
797
|
/** An interval side's params contribution. */
|
|
707
798
|
type IntervalSideParams<T> = T extends Param<infer P extends string> ? { readonly [Q in P]: IntervalValue } : never
|
|
708
799
|
|
|
709
|
-
/** The mask position's params contribution. */
|
|
710
|
-
type MaskParams<M> = M extends MaskParam<infer P extends string> ? { readonly [Q in P]: number } : never
|
|
711
|
-
|
|
712
800
|
/**
|
|
713
801
|
* One condition's params-object fragments (a union; the rule builder folds
|
|
714
802
|
* them into the inferred `Params` record) — every param typed by its use.
|
|
@@ -716,7 +804,7 @@ type MaskParams<M> = M extends MaskParam<infer P extends string> ? { readonly [Q
|
|
|
716
804
|
*/
|
|
717
805
|
type CondParams<C> = [AnyTreeChild] extends [C]
|
|
718
806
|
? never
|
|
719
|
-
: C extends Cmp<infer Op, infer L, infer R, infer
|
|
807
|
+
: C extends Cmp<infer Op, infer L, infer R, infer _M>
|
|
720
808
|
? Op extends "eq" | "ne"
|
|
721
809
|
? EqParams<L, R>
|
|
722
810
|
: Op extends "lt" | "le" | "gt" | "ge"
|
|
@@ -724,12 +812,12 @@ type CondParams<C> = [AnyTreeChild] extends [C]
|
|
|
724
812
|
: Op extends "pointIn"
|
|
725
813
|
? IntervalSideParams<L> | PointParams<R>
|
|
726
814
|
: Op extends "allen"
|
|
727
|
-
? IntervalSideParams<L> | IntervalSideParams<R>
|
|
815
|
+
? IntervalSideParams<L> | IntervalSideParams<R>
|
|
728
816
|
: never
|
|
729
817
|
: C extends Tree<infer Ch extends readonly AnyTreeChild[]>
|
|
730
818
|
? CondParams<Ch[number]>
|
|
731
|
-
: C extends
|
|
732
|
-
?
|
|
819
|
+
: C extends NotInteriorAtom<unknown>
|
|
820
|
+
? never
|
|
733
821
|
: C extends NotAtom<infer R extends MatchOwner, infer B>
|
|
734
822
|
? BindParams<MatchFields<R>, B>
|
|
735
823
|
: never
|
|
@@ -762,23 +850,25 @@ export type {
|
|
|
762
850
|
CondOkBool,
|
|
763
851
|
CondParams,
|
|
764
852
|
CondParamsShape,
|
|
853
|
+
DerivedTable,
|
|
765
854
|
FindColumn,
|
|
766
855
|
FindEntryData,
|
|
856
|
+
InteriorData,
|
|
767
857
|
IntervalSide,
|
|
768
858
|
IntervalVarOk,
|
|
769
|
-
MaskData,
|
|
770
859
|
MatchFields,
|
|
771
860
|
MatchOwner,
|
|
772
861
|
MatchShape,
|
|
773
862
|
NotAtom,
|
|
774
|
-
|
|
863
|
+
NotInteriorAtom,
|
|
775
864
|
NumericVarOk,
|
|
776
865
|
OrderSide,
|
|
777
866
|
OrderVarOk,
|
|
778
867
|
ParamUse,
|
|
779
868
|
PointSide,
|
|
780
869
|
RecData,
|
|
781
|
-
|
|
870
|
+
RecHandle,
|
|
871
|
+
RecHead,
|
|
782
872
|
RuleData,
|
|
783
873
|
RuleItem,
|
|
784
874
|
SlotAt,
|