@bjornpagen/bumbledb 0.3.0 → 0.5.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 +246 -92
- package/README.md +31 -16
- package/dist/closed.d.ts +80 -75
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +102 -127
- package/dist/closed.js.map +1 -1
- package/dist/db.d.ts +37 -7
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +95 -55
- package/dist/db.js.map +1 -1
- package/dist/exhume.d.ts.map +1 -1
- package/dist/exhume.js +1 -14
- package/dist/exhume.js.map +1 -1
- package/dist/face.d.ts +40 -40
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +9 -17
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +46 -15
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +58 -29
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +13 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/law.d.ts +2 -1
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +15 -14
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +1 -7
- package/dist/lower.js.map +1 -1
- package/dist/marshal.d.ts +33 -6
- package/dist/marshal.d.ts.map +1 -1
- package/dist/marshal.js +75 -26
- package/dist/marshal.js.map +1 -1
- package/dist/native.d.ts +21 -2
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +20 -3
- package/dist/native.js.map +1 -1
- package/dist/order.d.ts +36 -0
- package/dist/order.d.ts.map +1 -0
- package/dist/order.js +135 -0
- package/dist/order.js.map +1 -0
- package/dist/query/atom.d.ts +76 -28
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +12 -16
- package/dist/query/atom.js.map +1 -1
- package/dist/query/lower.d.ts +5 -8
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +308 -72
- package/dist/query/lower.js.map +1 -1
- package/dist/query/predicate.d.ts.map +1 -1
- package/dist/query/predicate.js +34 -2
- package/dist/query/predicate.js.map +1 -1
- package/dist/query/run.d.ts +15 -5
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +27 -8
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +37 -29
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +19 -47
- package/dist/query/scope.js.map +1 -1
- package/dist/relation.d.ts +17 -29
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +41 -38
- package/dist/relation.js.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +7 -31
- package/dist/schema.js.map +1 -1
- package/dist/spec.d.ts +3 -2
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +13 -4
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +75 -8
- package/dist/statements.js.map +1 -1
- package/package.json +2 -5
- package/src/closed.ts +144 -206
- package/src/db.ts +143 -68
- package/src/exhume.ts +1 -15
- package/src/face.ts +38 -48
- package/src/fields.ts +103 -49
- package/src/index.ts +11 -10
- package/src/law.ts +15 -14
- package/src/lower.ts +2 -9
- package/src/marshal.ts +82 -31
- package/src/native.ts +22 -4
- package/src/order.ts +156 -0
- package/src/query/atom.ts +70 -35
- package/src/query/lower.ts +354 -82
- package/src/query/predicate.ts +39 -4
- package/src/query/run.ts +27 -9
- package/src/query/scope.ts +52 -70
- package/src/relation.ts +54 -68
- package/src/schema.ts +7 -33
- package/src/spec.ts +3 -2
- package/src/statements.ts +82 -8
package/src/order.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-side answer ordering — the census-fired convenience
|
|
3
|
+
* (`docs/architecture/70-api.md` § the freeze ledger). Answers are SETS and
|
|
4
|
+
* the ENGINE NEVER ORDERS; the language owns the sort (`rows.sort(...)`)
|
|
5
|
+
* and the limit (`.slice(0, n)`) — the drizzle law. What JS lacks is a
|
|
6
|
+
* number-returning comparator over the SDK's bigint-bearing cells, so the
|
|
7
|
+
* SDK ships exactly that: sort keys are DATA — a bare column name is
|
|
8
|
+
* ascending (the punning spelling; no `asc` wrapper exists — one spelling
|
|
9
|
+
* per meaning) and `desc(name)` is the one descending spelling — folded by
|
|
10
|
+
* `by(...)` into one row-typed comparator. Cross-type cells cannot arise
|
|
11
|
+
* within one column (one column, one domain), and the cell order is TOTAL
|
|
12
|
+
* anyway (the type-rank wall), so the comparator never throws.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { FactValue } from "#native.ts"
|
|
16
|
+
|
|
17
|
+
/** One DESCENDING sort key, plain data — built by {@link desc}. */
|
|
18
|
+
interface Desc<K extends string> {
|
|
19
|
+
readonly key: K
|
|
20
|
+
readonly desc: true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** One sort key: a bare column name (ascending — the punning spelling) or `desc(name)`. */
|
|
24
|
+
type SortKey<K extends string> = K | Desc<K>
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The type-rank wall: boolean 0, bigint 1, string 2, bytes 3, interval 4.
|
|
28
|
+
* One column carries one domain, so a mixed pair never arises from decoded
|
|
29
|
+
* answer rows — the wall exists to keep the cell order TOTAL (never a
|
|
30
|
+
* throw), not to be reached.
|
|
31
|
+
*/
|
|
32
|
+
function cellRank(value: FactValue): number {
|
|
33
|
+
if (typeof value === "boolean") {
|
|
34
|
+
return 0
|
|
35
|
+
}
|
|
36
|
+
if (typeof value === "bigint") {
|
|
37
|
+
return 1
|
|
38
|
+
}
|
|
39
|
+
if (typeof value === "string") {
|
|
40
|
+
return 2
|
|
41
|
+
}
|
|
42
|
+
if (value instanceof Uint8Array) {
|
|
43
|
+
return 3
|
|
44
|
+
}
|
|
45
|
+
return 4
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* One cell against one cell. Same-type arms: boolean orders false < true;
|
|
50
|
+
* bigint by `<`/`>`; string by the host language's own `<`/`>` (flavor,
|
|
51
|
+
* recorded); bytes bytewise over the shared prefix, then by length;
|
|
52
|
+
* intervals by start, then end. A mixed pair falls through to the
|
|
53
|
+
* type-rank wall.
|
|
54
|
+
*/
|
|
55
|
+
function cellCmp(left: FactValue, right: FactValue): number {
|
|
56
|
+
if (typeof left === "boolean" && typeof right === "boolean") {
|
|
57
|
+
if (left === right) {
|
|
58
|
+
return 0
|
|
59
|
+
}
|
|
60
|
+
if (left) {
|
|
61
|
+
return 1
|
|
62
|
+
}
|
|
63
|
+
return -1
|
|
64
|
+
}
|
|
65
|
+
if (typeof left === "bigint" && typeof right === "bigint") {
|
|
66
|
+
if (left < right) {
|
|
67
|
+
return -1
|
|
68
|
+
}
|
|
69
|
+
if (left > right) {
|
|
70
|
+
return 1
|
|
71
|
+
}
|
|
72
|
+
return 0
|
|
73
|
+
}
|
|
74
|
+
if (typeof left === "string" && typeof right === "string") {
|
|
75
|
+
if (left < right) {
|
|
76
|
+
return -1
|
|
77
|
+
}
|
|
78
|
+
if (left > right) {
|
|
79
|
+
return 1
|
|
80
|
+
}
|
|
81
|
+
return 0
|
|
82
|
+
}
|
|
83
|
+
if (left instanceof Uint8Array && right instanceof Uint8Array) {
|
|
84
|
+
const shared = Math.min(left.length, right.length)
|
|
85
|
+
for (let index = 0; index < shared; index += 1) {
|
|
86
|
+
const leftByte = left[index]
|
|
87
|
+
const rightByte = right[index]
|
|
88
|
+
// `index < shared` keeps both reads in bounds; the `undefined`
|
|
89
|
+
// arms are the checker's indexed-access tax, never taken.
|
|
90
|
+
if (leftByte !== undefined && rightByte !== undefined && leftByte !== rightByte) {
|
|
91
|
+
return leftByte - rightByte
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return left.length - right.length
|
|
95
|
+
}
|
|
96
|
+
if (
|
|
97
|
+
typeof left === "object" &&
|
|
98
|
+
!(left instanceof Uint8Array) &&
|
|
99
|
+
typeof right === "object" &&
|
|
100
|
+
!(right instanceof Uint8Array)
|
|
101
|
+
) {
|
|
102
|
+
if (left.start < right.start) {
|
|
103
|
+
return -1
|
|
104
|
+
}
|
|
105
|
+
if (left.start > right.start) {
|
|
106
|
+
return 1
|
|
107
|
+
}
|
|
108
|
+
if (left.end < right.end) {
|
|
109
|
+
return -1
|
|
110
|
+
}
|
|
111
|
+
if (left.end > right.end) {
|
|
112
|
+
return 1
|
|
113
|
+
}
|
|
114
|
+
return 0
|
|
115
|
+
}
|
|
116
|
+
return cellRank(left) - cellRank(right)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Marks one sort key DESCENDING — the single descending spelling (a bare name is already ascending). */
|
|
120
|
+
function desc<const K extends string>(key: K): Desc<K> {
|
|
121
|
+
const marker: Desc<K> = { key, desc: true }
|
|
122
|
+
return Object.freeze(marker)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Folds sort keys into ONE comparator typed against the row —
|
|
127
|
+
* `Row extends Readonly<Record<K, FactValue>>` — so a key the row lacks, or
|
|
128
|
+
* a column typed `number` (outside the cell domain), is a COMPILE error at
|
|
129
|
+
* the `.sort` call site: the laws typed the columns, and the row type
|
|
130
|
+
* carries that proof here (parse-don't-validate). The generic RETURN is the
|
|
131
|
+
* load-bearing trick: `rows.sort(by("rank"))` instantiates `Row` from the
|
|
132
|
+
* array's own element type and checks the key set right there.
|
|
133
|
+
*/
|
|
134
|
+
function by<const K extends string>(
|
|
135
|
+
first: SortKey<K>,
|
|
136
|
+
...rest: ReadonlyArray<SortKey<K>>
|
|
137
|
+
): <Row extends Readonly<Record<K, FactValue>>>(left: Row, right: Row) => number {
|
|
138
|
+
const entries = [first, ...rest].map(function normalizeKey(sortKey): { readonly key: K; readonly factor: 1 | -1 } {
|
|
139
|
+
if (typeof sortKey === "string") {
|
|
140
|
+
return { key: sortKey, factor: 1 }
|
|
141
|
+
}
|
|
142
|
+
return { key: sortKey.key, factor: -1 }
|
|
143
|
+
})
|
|
144
|
+
return function compare<Row extends Readonly<Record<K, FactValue>>>(left: Row, right: Row): number {
|
|
145
|
+
for (const entry of entries) {
|
|
146
|
+
const order = cellCmp(left[entry.key], right[entry.key]) * entry.factor
|
|
147
|
+
if (order !== 0) {
|
|
148
|
+
return order
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return 0
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export type { Desc, SortKey }
|
|
156
|
+
export { by, desc }
|
package/src/query/atom.ts
CHANGED
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
* (`bumbledb/crates/bumbledb/src/ir.rs`, the bijection target;
|
|
5
5
|
* `docs/architecture/20-query-ir.md` normative). A `match` binding record
|
|
6
6
|
* binds fields to vars, params, ∈-set params, or bare structural literals
|
|
7
|
+
* — a closed-reference field's literal is its handle NAME, and a plain
|
|
8
|
+
* ARRAY of names there is membership, folded into the program (closed-only
|
|
9
|
+
* by owner ruling; see {@link BindingInput})
|
|
7
10
|
* (unmentioned fields ARE the wildcard — no wildcard value exists);
|
|
8
11
|
* `not(Rel, {...})` is negation-as-position (anti-join); `eq`/`ne` and the
|
|
9
|
-
* order roster, `pointIn
|
|
12
|
+
* order roster, `pointIn` (the one spelling of `ir::CmpOp::PointIn`,
|
|
10
13
|
* always lowered interval-left), `allen` (the 13-bit mask pair
|
|
11
14
|
* comparison), and `and`/`or` (the input condition-tree grammar) complete
|
|
12
15
|
* the roster. Nothing beyond the IR exists here — and the walls the engine
|
|
@@ -26,7 +29,7 @@
|
|
|
26
29
|
|
|
27
30
|
import * as errors from "@superbuilders/errors"
|
|
28
31
|
import type { AnyClosed } from "#closed.ts"
|
|
29
|
-
import type { AnyField, ClosedIdField, Infer, IntervalValue } from "#fields.ts"
|
|
32
|
+
import type { AnyField, ClosedIdField, ClosedRoster, Infer, IntervalValue } from "#fields.ts"
|
|
30
33
|
import type { ClassLookup, ClassRecordOf, SchemaClasses } from "#law.ts"
|
|
31
34
|
import type {
|
|
32
35
|
ClassedField,
|
|
@@ -55,23 +58,32 @@ type MatchOwner = AnyRelation | AnyClosed
|
|
|
55
58
|
/**
|
|
56
59
|
* The matchable field block of an atom owner: a relation's declared
|
|
57
60
|
* fields; a closed relation's SEALED shape — the synthetic `id` (the
|
|
58
|
-
* roster-carrying descriptor
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* `
|
|
62
|
-
*
|
|
61
|
+
* value's OWN roster-carrying descriptor, at its precise type: the handle
|
|
62
|
+
* union rides into ψ id bindings and joins exactly as it does on a
|
|
63
|
+
* referencing column) first, then the declared payload columns read
|
|
64
|
+
* through the typed `columns` carrier (the one source of payload typing —
|
|
65
|
+
* no parallel column table exists). The runtime twin is `sealedFieldsOf` in
|
|
66
|
+
* `#query/lower.ts`; the id-first ordinal shift the two tiers share is
|
|
67
|
+
* pinned by the lowering golden.
|
|
63
68
|
*/
|
|
64
69
|
type MatchFields<R extends MatchOwner> = R extends AnyClosed
|
|
65
|
-
? { readonly id:
|
|
70
|
+
? { readonly id: R["id"] } & R["columns"]
|
|
66
71
|
: R extends AnyRelation
|
|
67
72
|
? RelationFields<R>
|
|
68
73
|
: never
|
|
69
74
|
|
|
70
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* One atom-binding position as runtime data. `literalSet` is a membership
|
|
77
|
+
* ARRAY at a closed-reference field, folded into the program: `name` is
|
|
78
|
+
* the content-addressed registry key its dense `ParamId` is minted under
|
|
79
|
+
* (the lowering rides the existing param-set term; the SDK itself supplies
|
|
80
|
+
* the translated member set at every execute — never the host).
|
|
81
|
+
*/
|
|
71
82
|
type BindingTermData =
|
|
72
83
|
| { readonly kind: "var"; readonly name: string }
|
|
73
84
|
| { readonly kind: "param"; readonly name: string }
|
|
74
85
|
| { readonly kind: "setParam"; readonly name: string }
|
|
86
|
+
| { readonly kind: "literalSet"; readonly name: string; readonly members: readonly string[] }
|
|
75
87
|
| { readonly kind: "literal"; readonly value: unknown }
|
|
76
88
|
|
|
77
89
|
/** One resolved binding: the field's name, its descriptor, its law-computed class, and the term. */
|
|
@@ -135,10 +147,18 @@ type SelectEntryData =
|
|
|
135
147
|
| { readonly kind: "measure"; readonly over: string }
|
|
136
148
|
| { readonly kind: "aggregate"; readonly agg: AggData }
|
|
137
149
|
|
|
138
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* One answer column: its name (the row object key), its entry, and — when
|
|
152
|
+
* the column's value is a closed reference (a projected var or an
|
|
153
|
+
* Arg-carried payload bound at a closed-referencing field) — the roster the
|
|
154
|
+
* decode lifts row ids back to handle NAMES through (the read half of the
|
|
155
|
+
* marshal bijection; `undefined` on every bare column). The slice is
|
|
156
|
+
* SDK-side marshaling data only: the wire `ProgramIr` never carries it.
|
|
157
|
+
*/
|
|
139
158
|
interface SelectColumn {
|
|
140
159
|
readonly name: string
|
|
141
160
|
readonly entry: SelectEntryData
|
|
161
|
+
readonly closed: ClosedRoster | undefined
|
|
142
162
|
}
|
|
143
163
|
|
|
144
164
|
/** One body item of a rule, in written order. */
|
|
@@ -151,13 +171,17 @@ type RuleItem =
|
|
|
151
171
|
/**
|
|
152
172
|
* One use of a parameter inside a rule, in written order: the census the
|
|
153
173
|
* query-level registry folds (first use mints the dense `ParamId`, first
|
|
154
|
-
* FIELD-ANCHORED use types the wire).
|
|
174
|
+
* FIELD-ANCHORED use types the wire). `members` is present exactly on a
|
|
175
|
+
* membership-array use (a literal set folded into the program): the handle
|
|
176
|
+
* names the SDK itself translates and supplies at execute — the entry
|
|
177
|
+
* never appears in the host's params object.
|
|
155
178
|
*/
|
|
156
179
|
interface ParamUse {
|
|
157
180
|
readonly name: string
|
|
158
181
|
readonly shape: "value" | "set" | "mask"
|
|
159
182
|
readonly anchor: AnyField | "measure" | undefined
|
|
160
183
|
readonly op: "binding" | CmpKind
|
|
184
|
+
readonly members: readonly string[] | undefined
|
|
161
185
|
}
|
|
162
186
|
|
|
163
187
|
/** One complete rule as runtime data. */
|
|
@@ -184,10 +208,18 @@ interface RecData {
|
|
|
184
208
|
* of the field's value type, a var/param/∈-set-param term — and, when the
|
|
185
209
|
* field is interval-typed, a bare point literal (the IR's membership
|
|
186
210
|
* typing rule: an element-typed term at an interval field is point
|
|
187
|
-
* membership; an interval-typed term is value equality).
|
|
211
|
+
* membership; an interval-typed term is value equality). A
|
|
212
|
+
* CLOSED-reference field additionally takes a plain ARRAY of handle names
|
|
213
|
+
* read as membership — `kind: ["Practice", "Review"]` (the drizzle law:
|
|
214
|
+
* set membership is an array, never an operator). Arrays are CLOSED-ONLY
|
|
215
|
+
* in this packet by owner ruling: ordinary u64/str membership already has
|
|
216
|
+
* its spelling through `r.inSet` params; widening literal arrays to every
|
|
217
|
+
* literal-capable kind is a separate future taste call — deliberately not
|
|
218
|
+
* done here.
|
|
188
219
|
*/
|
|
189
220
|
type BindingInput<F extends AnyField> =
|
|
190
221
|
| Infer<F>
|
|
222
|
+
| (F extends ClosedIdField ? readonly Infer<F>[] : never)
|
|
191
223
|
| (F extends { readonly kind: "interval" } ? bigint : never)
|
|
192
224
|
| Var<string>
|
|
193
225
|
| Param<string>
|
|
@@ -323,10 +355,10 @@ type NeRight = Var<string> | Param<string> | bigint | string | boolean | Uint8Ar
|
|
|
323
355
|
/** One side of an order comparison: orderable terms only (the IR's comparison rules). */
|
|
324
356
|
type OrderSide = Var<string> | Param<string> | Duration<string> | bigint
|
|
325
357
|
|
|
326
|
-
/** The point side of `pointIn
|
|
358
|
+
/** The point side of `pointIn`. */
|
|
327
359
|
type PointSide = Var<string> | Param<string> | bigint
|
|
328
360
|
|
|
329
|
-
/** The interval side of `pointIn`/`
|
|
361
|
+
/** The interval side of `pointIn`/`allen`. */
|
|
330
362
|
type IntervalSide = Var<string> | Param<string> | IntervalValue
|
|
331
363
|
|
|
332
364
|
/** Builds one comparison value. */
|
|
@@ -394,29 +426,21 @@ function ge<const L extends OrderSide, const R extends OrderSide>(left: L, right
|
|
|
394
426
|
}
|
|
395
427
|
|
|
396
428
|
/**
|
|
397
|
-
* Point membership as a predicate (`ir::CmpOp::PointIn`)
|
|
429
|
+
* Point membership as a predicate (`ir::CmpOp::PointIn`) — THE one
|
|
398
430
|
* spelling: `pointIn(t, w)` holds iff `w.start ≤ t < w.end`. The IR
|
|
399
431
|
* orders the operands interval-left, point-right; the value stores them
|
|
400
|
-
* that way whatever the surface
|
|
432
|
+
* that way whatever the surface argument order (a literal `span(...)`
|
|
433
|
+
* interval operand is legal and tags by the point sibling's element
|
|
434
|
+
* domain — the bug-hunt fix, now also a type-level guarantee).
|
|
435
|
+
* Interval ⊇ interval is NOT this operator; that predicate is
|
|
436
|
+
* `allen(a, ALLEN.covers, b)` — the name `covers` belongs to the Allen
|
|
437
|
+
* roster alone (the canonical-utterance law: one meaning, one spelling).
|
|
401
438
|
*/
|
|
402
439
|
function pointIn<const P extends PointSide, const I extends IntervalSide>(point: P, interval: I): Cmp<"pointIn", I, P> {
|
|
403
440
|
assertTermSide("pointIn", point, interval)
|
|
404
441
|
return comparison("pointIn", interval, point, undefined)
|
|
405
442
|
}
|
|
406
443
|
|
|
407
|
-
/**
|
|
408
|
-
* Point membership, coverage spelling — `covers(w, t)` is `pointIn(t, w)`
|
|
409
|
-
* with the interval written first (the IR's own operand order; a literal
|
|
410
|
-
* `span(...)` left operand is legal and tags by the point sibling's
|
|
411
|
-
* element domain — the bug-hunt fix, now also a type-level guarantee).
|
|
412
|
-
* Interval ⊇ interval is NOT this operator; that predicate is
|
|
413
|
-
* `allen(a, ALLEN.covers, b)`.
|
|
414
|
-
*/
|
|
415
|
-
function covers<const I extends IntervalSide, const P extends PointSide>(interval: I, point: P): Cmp<"pointIn", I, P> {
|
|
416
|
-
assertTermSide("covers", interval, point)
|
|
417
|
-
return comparison("pointIn", interval, point, undefined)
|
|
418
|
-
}
|
|
419
|
-
|
|
420
444
|
/**
|
|
421
445
|
* The 13-bit mask range: bits above the low 13 are unrepresentable in the
|
|
422
446
|
* engine's `AllenMask` (`bumbledb/crates/bumbledb/src/allen.rs`:
|
|
@@ -516,11 +540,22 @@ function not<R extends MatchOwner, const B extends MatchShape<MatchFields<R>>>(
|
|
|
516
540
|
return Object.freeze(value)
|
|
517
541
|
}
|
|
518
542
|
|
|
519
|
-
/**
|
|
543
|
+
/**
|
|
544
|
+
* Whether a var name is bound in the environment at an orderable (u64/i64)
|
|
545
|
+
* field. A CLOSED reference is excluded even though its kind is `u64`: a
|
|
546
|
+
* vocabulary's declaration-id order is an accident, not semantics
|
|
547
|
+
* (`docs/architecture/10-data-model.md` § orderability — order on it is
|
|
548
|
+
* refused exactly as the enum's ordinal order was), so every
|
|
549
|
+
* order-comparison and fold position refuses closed-bound terms — this
|
|
550
|
+
* judgment is the one gate they all read, and the construction-time
|
|
551
|
+
* validations in `#query/lower.ts` are its runtime twin.
|
|
552
|
+
*/
|
|
520
553
|
type OrderVarOk<Env extends EnvShape, N extends string> = N extends keyof Env
|
|
521
|
-
? Env[N]["field"]
|
|
522
|
-
?
|
|
523
|
-
:
|
|
554
|
+
? Env[N]["field"] extends { readonly closed: ClosedRoster }
|
|
555
|
+
? false
|
|
556
|
+
: Env[N]["field"]["kind"] extends "u64" | "i64"
|
|
557
|
+
? true
|
|
558
|
+
: false
|
|
524
559
|
: false
|
|
525
560
|
|
|
526
561
|
/** Whether a var name is bound at an interval field. */
|
|
@@ -576,7 +611,7 @@ type NotOk<Env extends EnvShape, F extends FieldsShape, CR, B> = false extends {
|
|
|
576
611
|
* twin of the engine's comparison roster: class-equal joins (off the
|
|
577
612
|
* schema type's class map), orderable order sides (an interval var under a
|
|
578
613
|
* non-`pointIn` op is exactly here refused), kind-correct
|
|
579
|
-
* `pointIn`/`
|
|
614
|
+
* `pointIn`/`allen` sides, and negated-atom safety (the negated
|
|
580
615
|
* relation's class record is resolved through `Classes` by its name). The
|
|
581
616
|
* leading `[AnyTreeChild] extends [C]` arm is the recursion's base case:
|
|
582
617
|
* at an UNRESOLVED constraint (the whole condition union — or a tree's
|
|
@@ -704,4 +739,4 @@ export type {
|
|
|
704
739
|
Tree,
|
|
705
740
|
TreeData
|
|
706
741
|
}
|
|
707
|
-
export { ALLEN, allen, and, comparison,
|
|
742
|
+
export { ALLEN, ALLEN_ALL_BITS, allen, and, comparison, eq, ge, gt, le, lt, ne, not, or, pointIn }
|