@bjornpagen/bumbledb 0.2.0 → 0.4.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 +503 -427
- package/README.md +84 -36
- package/dist/closed.d.ts +111 -38
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +94 -99
- package/dist/closed.js.map +1 -1
- package/dist/db.d.ts +16 -2
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +46 -8
- package/dist/db.js.map +1 -1
- package/dist/face.d.ts +114 -69
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +38 -21
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +72 -87
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +35 -67
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +18 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -7
- package/dist/index.js.map +1 -1
- package/dist/law.d.ts +224 -0
- package/dist/law.d.ts.map +1 -0
- package/dist/law.js +224 -0
- package/dist/law.js.map +1 -0
- package/dist/lower.d.ts +17 -10
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +34 -23
- 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 +67 -6
- package/dist/marshal.js.map +1 -1
- package/dist/native.d.ts +6 -2
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +139 -56
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +7 -1
- package/dist/query/atom.js.map +1 -1
- package/dist/query/lower.d.ts +71 -56
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +341 -69
- package/dist/query/lower.js.map +1 -1
- package/dist/query/predicate.d.ts +10 -9
- package/dist/query/predicate.d.ts.map +1 -1
- package/dist/query/predicate.js +2 -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 +26 -6
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +100 -43
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +89 -30
- package/dist/query/scope.js.map +1 -1
- package/dist/query/select.d.ts +5 -5
- package/dist/query/select.d.ts.map +1 -1
- package/dist/relation.d.ts +29 -15
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +45 -17
- package/dist/relation.js.map +1 -1
- package/dist/schema.d.ts +41 -3
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +16 -2
- package/dist/schema.js.map +1 -1
- package/dist/spec.d.ts +10 -8
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +67 -31
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +97 -20
- package/dist/statements.js.map +1 -1
- package/package.json +2 -2
- package/src/closed.ts +214 -146
- package/src/db.ts +65 -10
- package/src/face.ts +169 -102
- package/src/fields.ts +97 -164
- package/src/index.ts +43 -18
- package/src/law.ts +519 -0
- package/src/lower.ts +36 -23
- package/src/marshal.ts +74 -7
- package/src/native.ts +6 -2
- package/src/query/atom.ts +155 -65
- package/src/query/lower.ts +572 -167
- package/src/query/predicate.ts +43 -33
- package/src/query/run.ts +26 -6
- package/src/query/scope.ts +161 -51
- package/src/query/select.ts +5 -5
- package/src/relation.ts +60 -26
- package/src/schema.ts +48 -7
- package/src/spec.ts +10 -8
- package/src/statements.ts +165 -46
package/src/marshal.ts
CHANGED
|
@@ -13,10 +13,22 @@
|
|
|
13
13
|
* the engine admitted IS a legal fact of its relation (the same trust
|
|
14
14
|
* direction as Rust's typed readback). Shape mismatches here are genuine
|
|
15
15
|
* failures and THROW typed; they are never domain data.
|
|
16
|
+
*
|
|
17
|
+
* THE CLOSED BIJECTION (0.4.0): a closed-referencing cell crosses this
|
|
18
|
+
* boundary as its handle NAME — the write side lowers name → u64 row id
|
|
19
|
+
* (declaration order = row ids, the sealed roster's own law, ≤ 256 rows),
|
|
20
|
+
* the read side lifts id → name, and both directions are total and static
|
|
21
|
+
* over the roster. An unknown name is a pointed THROW at the write seam —
|
|
22
|
+
* a deliberate UPGRADE over 0.3.0, where any bigint sailed through the
|
|
23
|
+
* marshal to a commit-time containment violation; the wrong spelling now
|
|
24
|
+
* dies here, before the engine ever sees the row. An out-of-roster id on
|
|
25
|
+
* the read side (reachable only in a store whose closed-typed column was
|
|
26
|
+
* never pinned by its containment law) is equally pointed — never a
|
|
27
|
+
* silent fallback, never `undefined`.
|
|
16
28
|
*/
|
|
17
29
|
|
|
18
30
|
import * as errors from "@superbuilders/errors"
|
|
19
|
-
import type { AnyField } from "#fields.ts"
|
|
31
|
+
import type { AnyField, ClosedRoster } from "#fields.ts"
|
|
20
32
|
import type { FactValue } from "#native.ts"
|
|
21
33
|
import type { AnyRelation, Fact, FreshKeys, RelationData } from "#relation.ts"
|
|
22
34
|
|
|
@@ -80,14 +92,64 @@ function recordOf(fact: object): Record<string, unknown> {
|
|
|
80
92
|
return Object.fromEntries(Object.entries(fact))
|
|
81
93
|
}
|
|
82
94
|
|
|
95
|
+
/**
|
|
96
|
+
* The write half of the closed bijection: one handle NAME to its u64 row
|
|
97
|
+
* id (declaration order = row ids — the engine's own minting of the
|
|
98
|
+
* sealed extension). An unknown name is a pointed refusal naming the
|
|
99
|
+
* vocabulary and its roster — the 0.4.0 upgrade over any-bigint-compiles:
|
|
100
|
+
* the wrong spelling dies at the marshal, never as a commit-time
|
|
101
|
+
* violation. `indexOf` is the whole machine (the roster is ≤ 256 rows,
|
|
102
|
+
* engine law — no map is warranted).
|
|
103
|
+
*/
|
|
104
|
+
function closedCellOf(context: string, closed: ClosedRoster, name: string): FactValue {
|
|
105
|
+
const id = closed.handles.indexOf(name)
|
|
106
|
+
if (id === -1) {
|
|
107
|
+
throw errors.new(
|
|
108
|
+
`${context}: "${name}" is not a handle of ${closed.name} — the roster is ${closed.handles.join(", ")}`
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
return BigInt(id)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The read half of the closed bijection: one u64 row id back to its handle
|
|
116
|
+
* NAME (`Number(cell)` is safe — the sealed extension holds at most 256
|
|
117
|
+
* rows, engine law). An id outside the roster THROWS pointed, never a
|
|
118
|
+
* silent fallback and never `undefined`: the state is reachable only in a
|
|
119
|
+
* store whose closed-typed column was never pinned by its containment law,
|
|
120
|
+
* and the error names that missing piece.
|
|
121
|
+
*/
|
|
122
|
+
function handleOf(context: string, closed: ClosedRoster, cell: FactValue): string {
|
|
123
|
+
if (typeof cell !== "bigint") {
|
|
124
|
+
throw cellShapeError(context, `a ${closed.name} handle id (bigint)`, cell)
|
|
125
|
+
}
|
|
126
|
+
const handle = closed.handles[Number(cell)]
|
|
127
|
+
if (handle === undefined) {
|
|
128
|
+
throw errors.new(
|
|
129
|
+
`${context}: id ${cell} is outside the ${closed.name} roster (${closed.handles.join(", ")}) — the column types ${closed.name} but no law pins it — a containment statement is the missing piece`
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
return handle
|
|
133
|
+
}
|
|
134
|
+
|
|
83
135
|
/**
|
|
84
136
|
* Marshals one host cell at its field position to the natural wire value,
|
|
85
137
|
* schema-directed by the field descriptor's structural kind (never
|
|
86
|
-
* guessed).
|
|
87
|
-
*
|
|
88
|
-
*
|
|
138
|
+
* guessed). A closed-referencing cell arrives as its handle NAME and
|
|
139
|
+
* lowers through {@link closedCellOf} — the arm precedes the switch
|
|
140
|
+
* because a closed reference is structurally a u64 descriptor plus the
|
|
141
|
+
* roster (the same precedence `Infer` pins at the type level). Everything
|
|
142
|
+
* else is bare, so the runtime values ARE the wire's natural JS values;
|
|
143
|
+
* widths and domain labels are the engine's own judgment at the write
|
|
144
|
+
* boundary.
|
|
89
145
|
*/
|
|
90
146
|
function cellOf(context: string, field: AnyField, value: unknown): FactValue {
|
|
147
|
+
if ("closed" in field) {
|
|
148
|
+
if (typeof value !== "string") {
|
|
149
|
+
throw cellShapeError(context, `a ${field.closed.name} handle name (string)`, value)
|
|
150
|
+
}
|
|
151
|
+
return closedCellOf(context, field.closed, value)
|
|
152
|
+
}
|
|
91
153
|
switch (field.kind) {
|
|
92
154
|
case "bool": {
|
|
93
155
|
if (typeof value !== "boolean") {
|
|
@@ -210,7 +272,9 @@ function isMintedFresh<R extends AnyRelation>(
|
|
|
210
272
|
/**
|
|
211
273
|
* Unmarshals one positional row to the relation's named, frozen fact object
|
|
212
274
|
* of bare structural values — the inverse of {@link rowOf},
|
|
213
|
-
* ordinal-directed by the same declaration order.
|
|
275
|
+
* ordinal-directed by the same declaration order. Closed-referencing cells
|
|
276
|
+
* lift id → handle NAME through {@link handleOf} (the read half of the
|
|
277
|
+
* bijection), so every fact a user sees speaks the roster's vocabulary.
|
|
214
278
|
*/
|
|
215
279
|
function factOf<R extends AnyRelation>(relation: R, row: readonly FactValue[]): Fact<R> {
|
|
216
280
|
const data = relation.data
|
|
@@ -225,7 +289,10 @@ function factOf<R extends AnyRelation>(relation: R, row: readonly FactValue[]):
|
|
|
225
289
|
if (cell === undefined) {
|
|
226
290
|
throw errors.new(`relation ${data.name}: row cell ${ordinal} (${declared.name}) is absent`)
|
|
227
291
|
}
|
|
228
|
-
decoded[declared.name] =
|
|
292
|
+
decoded[declared.name] =
|
|
293
|
+
"closed" in declared.field
|
|
294
|
+
? handleOf(`relation ${data.name} field ${declared.name}`, declared.field.closed, cell)
|
|
295
|
+
: cell
|
|
229
296
|
})
|
|
230
297
|
Object.freeze(decoded)
|
|
231
298
|
if (!isCompleteFact(relation, decoded)) {
|
|
@@ -235,4 +302,4 @@ function factOf<R extends AnyRelation>(relation: R, row: readonly FactValue[]):
|
|
|
235
302
|
}
|
|
236
303
|
|
|
237
304
|
export type { KeyFact, Minted }
|
|
238
|
-
export { cellOf, factOf, isFreshField, isMintedFresh, keyRowOf, recordOf, rowOf }
|
|
305
|
+
export { cellOf, factOf, handleOf, isFreshField, isMintedFresh, keyRowOf, recordOf, rowOf }
|
package/src/native.ts
CHANGED
|
@@ -244,13 +244,17 @@ interface Violation {
|
|
|
244
244
|
* `dbCreate`/`dbOpen`'s domain outcome. `schemaError` covers both spec
|
|
245
245
|
* resolution (unresolvable names, banned spellings — every issue in one
|
|
246
246
|
* message) and schema validation at the declaration boundary;
|
|
247
|
-
* `
|
|
247
|
+
* `newtypeMismatch` is the coherence wall's own kind — a spec whose
|
|
248
|
+
* statement pairs faces with disagreeing newtype labels (the engine twin
|
|
249
|
+
* of the schema-level class wall; unreachable through the typed builder,
|
|
250
|
+
* which computes every label from the laws, so only a raw spec can reach
|
|
251
|
+
* it); `fingerprintMismatch` is `dbOpen`'s stored-theory refusal.
|
|
248
252
|
*/
|
|
249
253
|
type DbOpenResult =
|
|
250
254
|
| { readonly ok: true; readonly db: DbHandle }
|
|
251
255
|
| {
|
|
252
256
|
readonly ok: false
|
|
253
|
-
readonly kind: "schemaError" | "fingerprintMismatch"
|
|
257
|
+
readonly kind: "schemaError" | "newtypeMismatch" | "fingerprintMismatch"
|
|
254
258
|
readonly message: string
|
|
255
259
|
}
|
|
256
260
|
|
package/src/query/atom.ts
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
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
12
|
* order roster, `pointIn`/`covers` (both spellings of `ir::CmpOp::PointIn`,
|
|
@@ -25,8 +28,11 @@
|
|
|
25
28
|
*/
|
|
26
29
|
|
|
27
30
|
import * as errors from "@superbuilders/errors"
|
|
28
|
-
import type {
|
|
31
|
+
import type { AnyClosed } from "#closed.ts"
|
|
32
|
+
import type { AnyField, ClosedIdField, ClosedRoster, Infer, IntervalValue } from "#fields.ts"
|
|
33
|
+
import type { ClassLookup, ClassRecordOf, SchemaClasses } from "#law.ts"
|
|
29
34
|
import type {
|
|
35
|
+
ClassedField,
|
|
30
36
|
Duration,
|
|
31
37
|
EnvShape,
|
|
32
38
|
JoinOk,
|
|
@@ -38,25 +44,59 @@ import type {
|
|
|
38
44
|
Var
|
|
39
45
|
} from "#query/scope.ts"
|
|
40
46
|
import { isTerm } from "#query/scope.ts"
|
|
41
|
-
import type { AnyRelation, FieldsShape,
|
|
47
|
+
import type { AnyRelation, FieldsShape, RelationFields } from "#relation.ts"
|
|
42
48
|
|
|
43
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* What a query atom matches over: an ordinary relation or a CLOSED
|
|
51
|
+
* vocabulary (ψ query atoms — the engine folds a resolvable closed atom
|
|
52
|
+
* into a plan-constant member set at prepare, or joins the L1-resident
|
|
53
|
+
* virtual image when the shape does not fold; the SDK never pre-folds and
|
|
54
|
+
* never knows which — transparency is the contract).
|
|
55
|
+
*/
|
|
56
|
+
type MatchOwner = AnyRelation | AnyClosed
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The matchable field block of an atom owner: a relation's declared
|
|
60
|
+
* fields; a closed relation's SEALED shape — the synthetic `id` (the
|
|
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 `matchFieldsOf` in
|
|
66
|
+
* `#query/lower.ts`; the id-first ordinal shift the two tiers share is
|
|
67
|
+
* pinned by the lowering golden.
|
|
68
|
+
*/
|
|
69
|
+
type MatchFields<R extends MatchOwner> = R extends AnyClosed
|
|
70
|
+
? { readonly id: R["id"] } & R["columns"]
|
|
71
|
+
: R extends AnyRelation
|
|
72
|
+
? RelationFields<R>
|
|
73
|
+
: never
|
|
74
|
+
|
|
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
|
+
*/
|
|
44
82
|
type BindingTermData =
|
|
45
83
|
| { readonly kind: "var"; readonly name: string }
|
|
46
84
|
| { readonly kind: "param"; readonly name: string }
|
|
47
85
|
| { readonly kind: "setParam"; readonly name: string }
|
|
86
|
+
| { readonly kind: "literalSet"; readonly name: string; readonly members: readonly string[] }
|
|
48
87
|
| { readonly kind: "literal"; readonly value: unknown }
|
|
49
88
|
|
|
50
|
-
/** One resolved binding: the field's name, its descriptor, and the term. */
|
|
89
|
+
/** One resolved binding: the field's name, its descriptor, its law-computed class, and the term. */
|
|
51
90
|
interface BindingEntry {
|
|
52
91
|
readonly field: string
|
|
53
92
|
readonly data: AnyField
|
|
93
|
+
readonly class: string | undefined
|
|
54
94
|
readonly term: BindingTermData
|
|
55
95
|
}
|
|
56
96
|
|
|
57
|
-
/** One EDB atom as runtime data (either polarity — polarity is the rule item's). */
|
|
97
|
+
/** One EDB atom as runtime data (either polarity — polarity is the rule item's; a closed owner is a ψ atom). */
|
|
58
98
|
interface AtomData {
|
|
59
|
-
readonly relation:
|
|
99
|
+
readonly relation: MatchOwner
|
|
60
100
|
readonly bindings: readonly BindingEntry[]
|
|
61
101
|
}
|
|
62
102
|
|
|
@@ -107,10 +147,18 @@ type SelectEntryData =
|
|
|
107
147
|
| { readonly kind: "measure"; readonly over: string }
|
|
108
148
|
| { readonly kind: "aggregate"; readonly agg: AggData }
|
|
109
149
|
|
|
110
|
-
/**
|
|
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
|
+
*/
|
|
111
158
|
interface SelectColumn {
|
|
112
159
|
readonly name: string
|
|
113
160
|
readonly entry: SelectEntryData
|
|
161
|
+
readonly closed: ClosedRoster | undefined
|
|
114
162
|
}
|
|
115
163
|
|
|
116
164
|
/** One body item of a rule, in written order. */
|
|
@@ -123,21 +171,25 @@ type RuleItem =
|
|
|
123
171
|
/**
|
|
124
172
|
* One use of a parameter inside a rule, in written order: the census the
|
|
125
173
|
* query-level registry folds (first use mints the dense `ParamId`, first
|
|
126
|
-
* 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.
|
|
127
178
|
*/
|
|
128
179
|
interface ParamUse {
|
|
129
180
|
readonly name: string
|
|
130
181
|
readonly shape: "value" | "set" | "mask"
|
|
131
182
|
readonly anchor: AnyField | "measure" | undefined
|
|
132
183
|
readonly op: "binding" | CmpKind
|
|
184
|
+
readonly members: readonly string[] | undefined
|
|
133
185
|
}
|
|
134
186
|
|
|
135
187
|
/** One complete rule as runtime data. */
|
|
136
188
|
interface RuleData {
|
|
137
189
|
readonly items: readonly RuleItem[]
|
|
138
190
|
readonly select: readonly SelectColumn[]
|
|
139
|
-
/** Variable name → the
|
|
140
|
-
readonly varFields: Readonly<Record<string,
|
|
191
|
+
/** Variable name → the classed slot its FIRST positive binding carries (the runtime env — descriptor + class). */
|
|
192
|
+
readonly varFields: Readonly<Record<string, ClassedField>>
|
|
141
193
|
readonly paramUses: readonly ParamUse[]
|
|
142
194
|
}
|
|
143
195
|
|
|
@@ -156,10 +208,18 @@ interface RecData {
|
|
|
156
208
|
* of the field's value type, a var/param/∈-set-param term — and, when the
|
|
157
209
|
* field is interval-typed, a bare point literal (the IR's membership
|
|
158
210
|
* typing rule: an element-typed term at an interval field is point
|
|
159
|
-
* 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.
|
|
160
219
|
*/
|
|
161
220
|
type BindingInput<F extends AnyField> =
|
|
162
221
|
| Infer<F>
|
|
222
|
+
| (F extends ClosedIdField ? readonly Infer<F>[] : never)
|
|
163
223
|
| (F extends { readonly kind: "interval" } ? bigint : never)
|
|
164
224
|
| Var<string>
|
|
165
225
|
| Param<string>
|
|
@@ -174,50 +234,61 @@ type MatchShape<F extends FieldsShape> = {
|
|
|
174
234
|
readonly [K in keyof F]?: BindingInput<F[K]>
|
|
175
235
|
}
|
|
176
236
|
|
|
237
|
+
/**
|
|
238
|
+
* One field position of a bindings record as a classed slot: the declared
|
|
239
|
+
* descriptor plus the slot's law-computed class, read off the relation's
|
|
240
|
+
* class record (`CR` — the schema class map's entry for the atom's
|
|
241
|
+
* relation). The one shape every join judgment compares.
|
|
242
|
+
*/
|
|
243
|
+
type SlotAt<F extends FieldsShape, CR, K> = {
|
|
244
|
+
readonly field: F[K & keyof F]
|
|
245
|
+
readonly class: ClassLookup<CR, K>
|
|
246
|
+
}
|
|
247
|
+
|
|
177
248
|
/**
|
|
178
249
|
* The var binding's judgment against the incoming rule environment: a name
|
|
179
|
-
* already bound must land on a
|
|
250
|
+
* already bound must land on a class-equal slot (bare pairs only with bare).
|
|
180
251
|
*/
|
|
181
|
-
type EnvJoinOk<Env extends EnvShape, F extends FieldsShape, K, N extends string> = N extends keyof Env
|
|
182
|
-
? JoinOk<Env[N], F
|
|
252
|
+
type EnvJoinOk<Env extends EnvShape, F extends FieldsShape, CR, K, N extends string> = N extends keyof Env
|
|
253
|
+
? JoinOk<Env[N], SlotAt<F, CR, K>>
|
|
183
254
|
: true
|
|
184
255
|
|
|
185
256
|
/**
|
|
186
257
|
* The var binding's judgment against its OWN record's siblings: two
|
|
187
258
|
* bindings of one var name inside a single bindings record are the same
|
|
188
259
|
* join the environment check judges across atoms, so every same-named
|
|
189
|
-
* sibling must be
|
|
260
|
+
* sibling must be class-equal too. Without this arm two FIRST occurrences
|
|
190
261
|
* of one name (a record the environment has not seen yet) would meet no
|
|
191
|
-
* check at all — the intra-atom join would silently cross
|
|
262
|
+
* check at all — the intra-atom join would silently cross classes.
|
|
192
263
|
*/
|
|
193
|
-
type SiblingJoinOk<F extends FieldsShape, B, K extends keyof B, N extends string> = false extends {
|
|
194
|
-
[K2 in Exclude<keyof B & keyof F, K>]: B[K2] extends Var<N> ? JoinOk<F
|
|
264
|
+
type SiblingJoinOk<F extends FieldsShape, CR, B, K extends keyof B, N extends string> = false extends {
|
|
265
|
+
[K2 in Exclude<keyof B & keyof F, K>]: B[K2] extends Var<N> ? JoinOk<SlotAt<F, CR, K2>, SlotAt<F, CR, K>> : true
|
|
195
266
|
}[Exclude<keyof B & keyof F, K>]
|
|
196
267
|
? false
|
|
197
268
|
: true
|
|
198
269
|
|
|
199
270
|
/**
|
|
200
271
|
* The per-property join judgment of a bindings record: a var binding must
|
|
201
|
-
* be
|
|
202
|
-
* every same-named sibling of its own record (a cross-
|
|
272
|
+
* be class-equal to the rule environment's binding of the name AND to
|
|
273
|
+
* every same-named sibling of its own record (a cross-class reuse maps
|
|
203
274
|
* the property to `never` — the compile error the old value brand carried,
|
|
204
|
-
* now
|
|
275
|
+
* now law-born off the schema type's class map).
|
|
205
276
|
*/
|
|
206
|
-
type BindingOk<Env extends EnvShape, F extends FieldsShape, B, K extends keyof B> =
|
|
277
|
+
type BindingOk<Env extends EnvShape, F extends FieldsShape, CR, B, K extends keyof B> =
|
|
207
278
|
B[K] extends Var<infer N extends string>
|
|
208
|
-
? [EnvJoinOk<Env, F, K, N>, SiblingJoinOk<F, B, K, N>] extends [true, true]
|
|
279
|
+
? [EnvJoinOk<Env, F, CR, K, N>, SiblingJoinOk<F, CR, B, K, N>] extends [true, true]
|
|
209
280
|
? true
|
|
210
281
|
: false
|
|
211
282
|
: true
|
|
212
283
|
|
|
213
284
|
/** The validated bindings record (intersect with the inferred `B` — errors land on the offending property). */
|
|
214
|
-
type CheckBindings<Env extends EnvShape, F extends FieldsShape, B> = {
|
|
215
|
-
readonly [K in keyof B]: K extends keyof F ? (BindingOk<Env, F, B, K> extends true ? B[K] : never) : never
|
|
285
|
+
type CheckBindings<Env extends EnvShape, F extends FieldsShape, CR, B> = {
|
|
286
|
+
readonly [K in keyof B]: K extends keyof F ? (BindingOk<Env, F, CR, B, K> extends true ? B[K] : never) : never
|
|
216
287
|
}
|
|
217
288
|
|
|
218
|
-
/** The environment a bindings record contributes: var name → the bound
|
|
219
|
-
type BindEnv<F extends FieldsShape, B> = {
|
|
220
|
-
readonly [K in keyof B & keyof F as B[K] extends Var<infer N extends string> ? N : never]: F
|
|
289
|
+
/** The environment a bindings record contributes: var name → the bound slot (descriptor + class). */
|
|
290
|
+
type BindEnv<F extends FieldsShape, CR, B> = {
|
|
291
|
+
readonly [K in keyof B & keyof F as B[K] extends Var<infer N extends string> ? N : never]: SlotAt<F, CR, K>
|
|
221
292
|
}
|
|
222
293
|
|
|
223
294
|
/** The params-object fragments a bindings record contributes (one union member per param use). */
|
|
@@ -257,9 +328,9 @@ interface Tree<Ch extends readonly AnyTreeChild[]> {
|
|
|
257
328
|
* membership at `.where` IS the safety rule, a compile error before it is
|
|
258
329
|
* the engine's refusal.
|
|
259
330
|
*/
|
|
260
|
-
interface NotAtom<
|
|
331
|
+
interface NotAtom<R extends MatchOwner, B> {
|
|
261
332
|
readonly cond: "not"
|
|
262
|
-
readonly relation:
|
|
333
|
+
readonly relation: R
|
|
263
334
|
readonly bindings: B
|
|
264
335
|
}
|
|
265
336
|
|
|
@@ -270,7 +341,7 @@ type AnyCmp = Cmp<CmpKind, unknown, unknown, unknown>
|
|
|
270
341
|
type AnyTreeChild = AnyCmp | Tree<readonly AnyTreeChild[]>
|
|
271
342
|
|
|
272
343
|
/** Any negated-atom value. */
|
|
273
|
-
type AnyNotAtom = NotAtom<
|
|
344
|
+
type AnyNotAtom = NotAtom<MatchOwner, unknown>
|
|
274
345
|
|
|
275
346
|
/** Any `.where` input: a comparison, a condition tree, or a negated atom. */
|
|
276
347
|
type AnyCond = AnyCmp | Tree<readonly AnyTreeChild[]> | AnyNotAtom
|
|
@@ -464,26 +535,40 @@ function or<const C extends readonly AnyTreeChild[]>(...children: C): Tree<C> {
|
|
|
464
535
|
* rejects every binding some matching fact extends. A negated atom binds
|
|
465
536
|
* nothing, only rejects: every variable it names must be positively bound
|
|
466
537
|
* in the rule, which `.where`'s environment check makes a COMPILE error
|
|
467
|
-
* (the engine's safety refusal stands behind it).
|
|
538
|
+
* (the engine's safety refusal stands behind it). A CLOSED owner is legal
|
|
539
|
+
* here too — the engine folds a resolvable negated closed atom to the
|
|
540
|
+
* COMPLEMENT of its member set (domain-witness guarded), and the SDK's
|
|
541
|
+
* negation rules apply to it unchanged.
|
|
468
542
|
*/
|
|
469
|
-
function not<
|
|
470
|
-
relation:
|
|
543
|
+
function not<R extends MatchOwner, const B extends MatchShape<MatchFields<R>>>(
|
|
544
|
+
relation: R,
|
|
471
545
|
bindings: B
|
|
472
|
-
): NotAtom<
|
|
473
|
-
const value: NotAtom<
|
|
546
|
+
): NotAtom<R, B> {
|
|
547
|
+
const value: NotAtom<R, B> = { cond: "not", relation, bindings }
|
|
474
548
|
return Object.freeze(value)
|
|
475
549
|
}
|
|
476
550
|
|
|
477
|
-
/**
|
|
551
|
+
/**
|
|
552
|
+
* Whether a var name is bound in the environment at an orderable (u64/i64)
|
|
553
|
+
* field. A CLOSED reference is excluded even though its kind is `u64`: a
|
|
554
|
+
* vocabulary's declaration-id order is an accident, not semantics
|
|
555
|
+
* (`docs/architecture/10-data-model.md` § orderability — order on it is
|
|
556
|
+
* refused exactly as the enum's ordinal order was), so every
|
|
557
|
+
* order-comparison and fold position refuses closed-bound terms — this
|
|
558
|
+
* judgment is the one gate they all read, and the construction-time
|
|
559
|
+
* validations in `#query/lower.ts` are its runtime twin.
|
|
560
|
+
*/
|
|
478
561
|
type OrderVarOk<Env extends EnvShape, N extends string> = N extends keyof Env
|
|
479
|
-
? Env[N]["
|
|
480
|
-
?
|
|
481
|
-
:
|
|
562
|
+
? Env[N]["field"] extends { readonly closed: ClosedRoster }
|
|
563
|
+
? false
|
|
564
|
+
: Env[N]["field"]["kind"] extends "u64" | "i64"
|
|
565
|
+
? true
|
|
566
|
+
: false
|
|
482
567
|
: false
|
|
483
568
|
|
|
484
569
|
/** Whether a var name is bound at an interval field. */
|
|
485
570
|
type IntervalVarOk<Env extends EnvShape, N extends string> = N extends keyof Env
|
|
486
|
-
? Env[N]["kind"] extends "interval"
|
|
571
|
+
? Env[N]["field"]["kind"] extends "interval"
|
|
487
572
|
? true
|
|
488
573
|
: false
|
|
489
574
|
: false
|
|
@@ -502,7 +587,7 @@ type PointSideOk<Env extends EnvShape, T> = T extends Var<infer N extends string
|
|
|
502
587
|
/** One interval side's judgment. */
|
|
503
588
|
type IntervalSideOk<Env extends EnvShape, T> = T extends Var<infer N extends string> ? IntervalVarOk<Env, N> : true
|
|
504
589
|
|
|
505
|
-
/** The `eq`/`ne` judgment: left var bound; right joins it (
|
|
590
|
+
/** The `eq`/`ne` judgment: left var bound; right joins it (class-equal var, param, or an exact-type literal). */
|
|
506
591
|
type EqOk<Env extends EnvShape, L, R> =
|
|
507
592
|
L extends Var<infer N extends string>
|
|
508
593
|
? N extends keyof Env
|
|
@@ -512,34 +597,36 @@ type EqOk<Env extends EnvShape, L, R> =
|
|
|
512
597
|
: false
|
|
513
598
|
: R extends Param<string> | SetParam<string>
|
|
514
599
|
? true
|
|
515
|
-
: [R] extends [Infer<Env[N]>]
|
|
600
|
+
: [R] extends [Infer<Env[N]["field"]>]
|
|
516
601
|
? true
|
|
517
602
|
: false
|
|
518
603
|
: false
|
|
519
604
|
: false
|
|
520
605
|
|
|
521
|
-
/** One negated-atom binding's judgment: a var must be positively bound (safety) AND
|
|
522
|
-
type NotBindingOk<Env extends EnvShape,
|
|
523
|
-
T extends Var<infer N extends string> ? (N extends keyof Env ? JoinOk<Env[N],
|
|
606
|
+
/** One negated-atom binding's judgment: a var must be positively bound (safety) AND class-equal. */
|
|
607
|
+
type NotBindingOk<Env extends EnvShape, S extends ClassedField, T> =
|
|
608
|
+
T extends Var<infer N extends string> ? (N extends keyof Env ? JoinOk<Env[N], S> : false) : true
|
|
524
609
|
|
|
525
|
-
/** The whole negated atom's judgment. */
|
|
526
|
-
type NotOk<Env extends EnvShape, F extends FieldsShape, B> = false extends {
|
|
527
|
-
[K in keyof B]: NotBindingOk<Env,
|
|
610
|
+
/** The whole negated atom's judgment (`CR` — the negated relation's class record off the schema class map). */
|
|
611
|
+
type NotOk<Env extends EnvShape, F extends FieldsShape, CR, B> = false extends {
|
|
612
|
+
[K in keyof B]: NotBindingOk<Env, SlotAt<F, CR, K>, B[K]>
|
|
528
613
|
}[keyof B]
|
|
529
614
|
? false
|
|
530
615
|
: true
|
|
531
616
|
|
|
532
617
|
/**
|
|
533
618
|
* One condition's judgment against the rule environment — the type-level
|
|
534
|
-
* twin of the engine's comparison roster:
|
|
535
|
-
* order sides (an interval var under a
|
|
536
|
-
* refused), kind-correct
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
619
|
+
* twin of the engine's comparison roster: class-equal joins (off the
|
|
620
|
+
* schema type's class map), orderable order sides (an interval var under a
|
|
621
|
+
* non-`pointIn` op is exactly here refused), kind-correct
|
|
622
|
+
* `pointIn`/`covers`/`allen` sides, and negated-atom safety (the negated
|
|
623
|
+
* relation's class record is resolved through `Classes` by its name). The
|
|
624
|
+
* leading `[AnyTreeChild] extends [C]` arm is the recursion's base case:
|
|
625
|
+
* at an UNRESOLVED constraint (the whole condition union — or a tree's
|
|
626
|
+
* child union, which is the union itself) the judgment is vacuously true —
|
|
627
|
+
* without it the constraint instantiation recurses into itself.
|
|
541
628
|
*/
|
|
542
|
-
type CondOkBool<Env extends EnvShape, C> = [AnyTreeChild] extends [C]
|
|
629
|
+
type CondOkBool<Env extends EnvShape, Classes extends SchemaClasses, C> = [AnyTreeChild] extends [C]
|
|
543
630
|
? true
|
|
544
631
|
: C extends Cmp<infer Op, infer L, infer R, unknown>
|
|
545
632
|
? Op extends "eq" | "ne"
|
|
@@ -558,23 +645,24 @@ type CondOkBool<Env extends EnvShape, C> = [AnyTreeChild] extends [C]
|
|
|
558
645
|
: false
|
|
559
646
|
: false
|
|
560
647
|
: C extends Tree<infer Ch extends readonly AnyTreeChild[]>
|
|
561
|
-
? false extends CondOkBool<Env, Ch[number]>
|
|
648
|
+
? false extends CondOkBool<Env, Classes, Ch[number]>
|
|
562
649
|
? false
|
|
563
650
|
: true
|
|
564
|
-
: C extends NotAtom<infer
|
|
565
|
-
? NotOk<Env,
|
|
651
|
+
: C extends NotAtom<infer R extends MatchOwner, infer B>
|
|
652
|
+
? NotOk<Env, MatchFields<R>, ClassRecordOf<Classes, R["name"]>, B>
|
|
566
653
|
: false
|
|
567
654
|
|
|
568
655
|
/** The validated `.where` argument (intersect with the inferred condition type). */
|
|
569
|
-
type CheckCond<Env extends EnvShape,
|
|
656
|
+
type CheckCond<Env extends EnvShape, Classes extends SchemaClasses, C> =
|
|
657
|
+
CondOkBool<Env, Classes, C> extends true ? C : never
|
|
570
658
|
|
|
571
659
|
/** The `eq`/`ne` params contribution: the param typed by the left variable's field. */
|
|
572
660
|
type EqParams<Env extends EnvShape, L, R> =
|
|
573
661
|
L extends Var<infer N extends string>
|
|
574
662
|
? R extends Param<infer P extends string>
|
|
575
|
-
? { readonly [Q in P]: Infer<Env[N & keyof Env]> }
|
|
663
|
+
? { readonly [Q in P]: Infer<Env[N & keyof Env]["field"]> }
|
|
576
664
|
: R extends SetParam<infer P extends string>
|
|
577
|
-
? { readonly [Q in P]: readonly Infer<Env[N & keyof Env]>[] }
|
|
665
|
+
? { readonly [Q in P]: readonly Infer<Env[N & keyof Env]["field"]>[] }
|
|
578
666
|
: never
|
|
579
667
|
: never
|
|
580
668
|
|
|
@@ -607,8 +695,8 @@ type CondParams<Env extends EnvShape, C> = [AnyTreeChild] extends [C]
|
|
|
607
695
|
: never
|
|
608
696
|
: C extends Tree<infer Ch extends readonly AnyTreeChild[]>
|
|
609
697
|
? CondParams<Env, Ch[number]>
|
|
610
|
-
: C extends NotAtom<infer
|
|
611
|
-
? BindParams<
|
|
698
|
+
: C extends NotAtom<infer R extends MatchOwner, infer B>
|
|
699
|
+
? BindParams<MatchFields<R>, B>
|
|
612
700
|
: never
|
|
613
701
|
|
|
614
702
|
/** The flattened params record one bindings record contributes. */
|
|
@@ -643,6 +731,8 @@ export type {
|
|
|
643
731
|
IntervalSide,
|
|
644
732
|
IntervalVarOk,
|
|
645
733
|
MaskData,
|
|
734
|
+
MatchFields,
|
|
735
|
+
MatchOwner,
|
|
646
736
|
MatchShape,
|
|
647
737
|
NotAtom,
|
|
648
738
|
OrderSide,
|