@bjornpagen/bumbledb 0.15.0 → 0.17.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 +33 -49
- package/README.md +3 -3
- package/dist/capacity.d.ts +24 -136
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js +18 -40
- package/dist/capacity.js.map +1 -1
- package/dist/closed.d.ts +0 -156
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +0 -104
- package/dist/closed.js.map +1 -1
- package/dist/db.d.ts +7 -223
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +147 -396
- package/dist/db.js.map +1 -1
- package/dist/face.d.ts +0 -133
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +0 -33
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +1 -145
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +2 -91
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +11 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -13
- package/dist/index.js.map +1 -1
- package/dist/law.d.ts +111 -93
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +23 -27
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts +9 -35
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +8 -53
- package/dist/lower.js.map +1 -1
- package/dist/marshal.d.ts +0 -65
- package/dist/marshal.d.ts.map +1 -1
- package/dist/marshal.js +0 -72
- package/dist/marshal.js.map +1 -1
- package/dist/native.d.ts +25 -290
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +6 -66
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +10 -276
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +1 -96
- package/dist/query/atom.js.map +1 -1
- package/dist/query/find.d.ts +10 -76
- package/dist/query/find.d.ts.map +1 -1
- package/dist/query/find.js +0 -30
- package/dist/query/find.js.map +1 -1
- package/dist/query/lower.d.ts +64 -146
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +19 -256
- package/dist/query/lower.js.map +1 -1
- package/dist/query/parse-ir.d.ts +0 -7
- package/dist/query/parse-ir.d.ts.map +1 -1
- package/dist/query/parse-ir.js +1 -13
- package/dist/query/parse-ir.js.map +1 -1
- package/dist/query/run.d.ts +0 -36
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +0 -44
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +24 -180
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +2 -66
- package/dist/query/scope.js.map +1 -1
- package/dist/relation.d.ts +2 -50
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +2 -37
- package/dist/relation.js.map +1 -1
- package/dist/schema.d.ts +13 -63
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +118 -92
- package/dist/schema.js.map +1 -1
- package/dist/spec.d.ts +1 -140
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js +1 -68
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +6 -137
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +16 -119
- package/dist/statements.js.map +1 -1
- package/package.json +2 -2
- package/src/capacity.ts +26 -140
- package/src/closed.ts +5 -206
- package/src/db.ts +203 -692
- package/src/face.ts +0 -142
- package/src/fields.ts +4 -172
- package/src/index.ts +9 -15
- package/src/law.ts +201 -129
- package/src/lower.ts +8 -53
- package/src/marshal.ts +1 -85
- package/src/native.ts +47 -323
- package/src/query/atom.ts +26 -313
- package/src/query/find.ts +24 -110
- package/src/query/lower.ts +132 -377
- package/src/query/parse-ir.ts +1 -14
- package/src/query/run.ts +0 -45
- package/src/query/scope.ts +25 -186
- package/src/relation.ts +2 -66
- package/src/schema.ts +143 -122
- package/src/spec.ts +1 -160
- package/src/statements.ts +22 -174
package/src/closed.ts
CHANGED
|
@@ -1,35 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Closed relations (`docs/architecture/10-data-model.md` § closed
|
|
3
|
-
* relations): a vocabulary whose extension is declared in the schema — two
|
|
4
|
-
* tiers, one function. Bare tier: `closed("Kind", ["Checking",
|
|
5
|
-
* "Savings"])`. Payload tier: `closed("Sev", { pages: bool }, { Critical:
|
|
6
|
-
* { pages: true }, ... })` — one call, three arguments (the curried tier-2
|
|
7
|
-
* spelling is DELETED — canonical utterance): the axioms record IS the
|
|
8
|
-
* handle declaration, every handle carrying every column exactly once
|
|
9
|
-
* (type-enforced). At the host surface a handle is its NAME — a string
|
|
10
|
-
* literal of the roster's union (the drizzle law: translation, not
|
|
11
|
-
* abstraction; dispatch over a vocabulary is native `switch` narrowing, so
|
|
12
|
-
* no match operator is minted and no handle constants exist — the literal
|
|
13
|
-
* `"Checking"` is the ONE spelling). Handles are pure DATA, not properties
|
|
14
|
-
* of the value, so NO handle name is reserved: a vocabulary may legally
|
|
15
|
-
* contain handles named `match`, `where`, or `id` — the axioms record and
|
|
16
|
-
* the roster are their own namespaces. The value's whole surface: `name`;
|
|
17
|
-
* `id` — the field descriptor carrying the CLOSED LINKAGE (the roster —
|
|
18
|
-
* pure structure, no declared domain: the laws type the columns, and
|
|
19
|
-
* `schema()` names the id's generator class `"Kind.id"`) for other
|
|
20
|
-
* relations' field blocks (`kind: Kind.id`); `data` (the lowering
|
|
21
|
-
* carrier); `axioms` (payload readback, `Kind.axioms`); `columns` (the
|
|
22
|
-
* runtime twin of the `Cols` type parameter, which the face layer's
|
|
23
|
-
* structural wall reads); and — exactly when payload columns exist —
|
|
24
|
-
* `where()`, the ψ-selection surface (`Kind.where({ mastered: true })` as a
|
|
25
|
-
* face source), resolved through the ONE selection machine
|
|
26
|
-
* (`relation.ts::resolveSelection`); the bare tier has no payload columns
|
|
27
|
-
* to select on, so `.where` is absent there, at the type AND on the value.
|
|
28
|
-
* No fact type and no insert surface exist — closed relations are
|
|
29
|
-
* unwritable by construction: the value simply lacks the writable relation
|
|
30
|
-
* shape.
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
1
|
import * as errors from "@superbuilders/errors"
|
|
34
2
|
import {
|
|
35
3
|
type AnyField,
|
|
@@ -44,42 +12,20 @@ import type { AnyRelation, RelationField } from "#relation.ts"
|
|
|
44
12
|
import { resolveSelection, type SelectionBinding, type SelectionInput } from "#relation.ts"
|
|
45
13
|
import type { LiteralSpec } from "#spec.ts"
|
|
46
14
|
|
|
47
|
-
/**
|
|
48
|
-
* A payload column of a closed relation: any field descriptor except a
|
|
49
|
-
* fresh-marked one (a vocabulary's rows are ground axioms, never minted).
|
|
50
|
-
*/
|
|
51
15
|
type PayloadField = Exclude<AnyField, { readonly fresh: true }>
|
|
52
16
|
|
|
53
|
-
/**
|
|
54
|
-
* A declared payload column BLOCK: name → descriptor, with `id`
|
|
55
|
-
* unspellable — the sealed shape mints the synthetic `id` itself (ordinal
|
|
56
|
-
* 0 of the matchable fields), so a declared column named `id` would be
|
|
57
|
-
* shadowed by the synthetic slot everywhere the shape resolves by name
|
|
58
|
-
* (`sealedFieldsOf`, the projected face, `spec.rs`'s resolver). The wall is
|
|
59
|
-
* typed here and judged again at construction in {@link mintClosed} — the
|
|
60
|
-
* runtime twin for untyped callers, warmer and earlier than the engine's
|
|
61
|
-
* `DuplicateFieldName` at `Db.create`.
|
|
62
|
-
*/
|
|
63
17
|
type PayloadColumns = Record<string, PayloadField> & { readonly id?: never }
|
|
64
18
|
|
|
65
|
-
/** One declared payload column: name plus its field descriptor. */
|
|
66
19
|
interface ClosedColumn {
|
|
67
20
|
readonly name: string
|
|
68
21
|
readonly field: PayloadField
|
|
69
22
|
}
|
|
70
23
|
|
|
71
|
-
/**
|
|
72
|
-
* One ground axiom, already lowered: the handle plus one wire literal per
|
|
73
|
-
* declared column in column-declaration order (row id = index). Lowered
|
|
74
|
-
* EAGERLY at construction so axiom literals ride the same selection-literal
|
|
75
|
-
* machine as `where()` bindings, with the same errors (the macro's rule).
|
|
76
|
-
*/
|
|
77
24
|
interface ClosedRow {
|
|
78
25
|
readonly handle: string
|
|
79
26
|
readonly values: readonly LiteralSpec[]
|
|
80
27
|
}
|
|
81
28
|
|
|
82
|
-
/** A closed relation's runtime description. */
|
|
83
29
|
interface ClosedData {
|
|
84
30
|
readonly name: string
|
|
85
31
|
readonly handles: readonly string[]
|
|
@@ -87,108 +33,45 @@ interface ClosedData {
|
|
|
87
33
|
readonly rows: readonly ClosedRow[]
|
|
88
34
|
}
|
|
89
35
|
|
|
90
|
-
/** One axiom row as the host writes and reads it: column name to bare structural value. */
|
|
91
36
|
type AxiomRow<Cols extends Record<string, PayloadField>> = { readonly [C in keyof Cols]: Infer<Cols[C]> }
|
|
92
37
|
|
|
93
|
-
/**
|
|
94
|
-
* The whole axiom record: every handle exactly once, every column exactly
|
|
95
|
-
* once per row — a missing or extra column is a TYPE error (each row is
|
|
96
|
-
* contextually checked against the declared columns), and the handle set
|
|
97
|
-
* IS the record's key set.
|
|
98
|
-
*/
|
|
99
38
|
type Axioms<Handles extends string, Cols extends Record<string, PayloadField>> = {
|
|
100
39
|
readonly [H in Handles]: AxiomRow<Cols>
|
|
101
40
|
}
|
|
102
41
|
|
|
103
|
-
/**
|
|
104
|
-
* The named surface of a closed relation value, minus the handle constants
|
|
105
|
-
* (which {@link Closed} intersects in).
|
|
106
|
-
*/
|
|
107
42
|
interface ClosedCore<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>> {
|
|
108
43
|
readonly name: Name
|
|
109
|
-
|
|
110
|
-
* The closed reference descriptor: `kind: Kind.id` in another relation's
|
|
111
|
-
* field block is the reference through which handle literals become
|
|
112
|
-
* legal in that relation's selections. Pure structure plus the PRECISE
|
|
113
|
-
* roster (`ClosedIdField<Name, Handles>` — the handle union is the
|
|
114
|
-
* field's value type under `Infer`, and the name literal keeps two
|
|
115
|
-
* same-shaped vocabularies distinct at the type tier, matching the
|
|
116
|
-
* runtime's roster-identity judgment); the referencing field's domain is
|
|
117
|
-
* law-born: `schema()` computes it from the declared containment
|
|
118
|
-
* (`"Kind.id"`, the generator class).
|
|
119
|
-
*/
|
|
44
|
+
|
|
120
45
|
readonly id: ClosedIdField<Name, Handles>
|
|
121
46
|
readonly data: ClosedData
|
|
122
|
-
|
|
47
|
+
|
|
123
48
|
readonly axioms: Axioms<Handles, Cols>
|
|
124
|
-
|
|
125
|
-
* The declared payload columns, name → field descriptor — an HONEST
|
|
126
|
-
* frozen runtime record (the descriptors themselves, by identity), and
|
|
127
|
-
* the typed carrier a projected payload column's structural shape is
|
|
128
|
-
* recovered through off the schema type (the face layer's
|
|
129
|
-
* `ProjectedShape` reads it; `data.columns` carries the same
|
|
130
|
-
* descriptors in declaration order for the lowering).
|
|
131
|
-
*/
|
|
49
|
+
|
|
132
50
|
readonly columns: Cols
|
|
133
51
|
}
|
|
134
52
|
|
|
135
|
-
/**
|
|
136
|
-
* The `where()` argument of a closed relation: EXACTLY the relation
|
|
137
|
-
* surface's {@link SelectionInput}, over the declared payload columns — the
|
|
138
|
-
* ONE selection vocabulary, so a spelling change there (H3's membership
|
|
139
|
-
* arrays) flows through with no local change here. The synthetic `id` is
|
|
140
|
-
* deliberately unspellable ({@link PayloadColumns} refuses an `id` column):
|
|
141
|
-
* an id selection is spelled only as handle literals on the REFERENCING
|
|
142
|
-
* side (the canonical-utterance law).
|
|
143
|
-
*/
|
|
144
53
|
type ClosedSelectionInput<Cols extends Record<string, PayloadField>> = SelectionInput<Cols>
|
|
145
54
|
|
|
146
|
-
/**
|
|
147
|
-
* A closed relation with a ψ selection applied — what `on()` consumes as a
|
|
148
|
-
* σ-carrying closed source (`on(Kind.where({ mastered: true }), "id")`).
|
|
149
|
-
* Deliberately the SAME discriminant shape as the ordinary `Selected`
|
|
150
|
-
* (`relation`/`selection` — `face.ts::faceParts` splits both by `"relation"
|
|
151
|
-
* in source`), and structurally UNMISTAKABLE for one: an `AnyClosed` lacks
|
|
152
|
-
* the relation shape (no `fields` record, no `RelationData`).
|
|
153
|
-
*/
|
|
154
55
|
interface SelectedClosed<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>> {
|
|
155
56
|
readonly relation: Closed<Name, Handles, Cols>
|
|
156
57
|
readonly selection: readonly SelectionBinding[]
|
|
157
58
|
}
|
|
158
59
|
|
|
159
|
-
/** Any ψ-selected closed relation value. */
|
|
160
60
|
interface AnySelectedClosed {
|
|
161
61
|
readonly relation: AnyClosed
|
|
162
62
|
readonly selection: readonly SelectionBinding[]
|
|
163
63
|
}
|
|
164
64
|
|
|
165
|
-
/**
|
|
166
|
-
* The ψ-selection surface of a payload-tier closed value. The selection is
|
|
167
|
-
* resolved EAGERLY against the declared columns and lowered as-is — the SDK
|
|
168
|
-
* never pre-folds ψ into an id set: pass-through lowering is what the macro
|
|
169
|
-
* does, and the ENGINE folds against the sealed extension at validate
|
|
170
|
-
* (`compile_member_set`).
|
|
171
|
-
*/
|
|
172
65
|
interface ClosedSelectable<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>> {
|
|
173
66
|
where(selection: ClosedSelectionInput<Cols>): SelectedClosed<Name, Handles, Cols>
|
|
174
67
|
}
|
|
175
68
|
|
|
176
|
-
/**
|
|
177
|
-
* A closed relation value: the core surface plus — exactly when payload
|
|
178
|
-
* columns exist — `where()` (the bare tier has nothing to select on, so
|
|
179
|
-
* the method is ABSENT there, not merely uncallable). NOTHING else:
|
|
180
|
-
* handles are data on the roster, never properties of the value (the
|
|
181
|
-
* handle constants, the match operator, and the id-to-handle weld died
|
|
182
|
-
* with the bigint era — dispatch is native `switch` narrowing over the
|
|
183
|
-
* handle union).
|
|
184
|
-
*/
|
|
185
69
|
type Closed<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>> = [
|
|
186
70
|
keyof Cols
|
|
187
71
|
] extends [never]
|
|
188
72
|
? ClosedCore<Name, Handles, Cols>
|
|
189
73
|
: ClosedCore<Name, Handles, Cols> & ClosedSelectable<Name, Handles, Cols>
|
|
190
74
|
|
|
191
|
-
/** Any closed relation value, whatever its roster and columns. */
|
|
192
75
|
interface AnyClosed {
|
|
193
76
|
readonly name: string
|
|
194
77
|
readonly id: ClosedIdField
|
|
@@ -197,27 +80,10 @@ interface AnyClosed {
|
|
|
197
80
|
readonly columns: Readonly<Record<string, PayloadField>>
|
|
198
81
|
}
|
|
199
82
|
|
|
200
|
-
/**
|
|
201
|
-
* THE relation-kind discriminant — the ONE spelling of "is this schema
|
|
202
|
-
* member closed?" (the type tier's twin is the `AnyClosed` conditional
|
|
203
|
-
* arms). A closed relation's runtime description carries its handle
|
|
204
|
-
* roster; an ordinary relation's never does. Every runtime closed/ordinary
|
|
205
|
-
* fork in the SDK judges through this predicate — never a re-spelled
|
|
206
|
-
* structural probe.
|
|
207
|
-
*/
|
|
208
83
|
function isClosedMember(member: AnyRelation | AnyClosed): member is AnyClosed {
|
|
209
84
|
return "handles" in member.data
|
|
210
85
|
}
|
|
211
86
|
|
|
212
|
-
/**
|
|
213
|
-
* The SEALED field list of a schema member — THE one reader of "what
|
|
214
|
-
* fields does this owner expose": an ordinary relation's declared fields;
|
|
215
|
-
* a closed relation's sealed shape — the synthetic `id` (the value's own
|
|
216
|
-
* roster-carrying descriptor, by identity) at ordinal 0, then the declared
|
|
217
|
-
* payload columns at declared index + 1 (the sealed shift, mirroring the
|
|
218
|
-
* engine's `SchemaDescriptor::sealed_fields`). A `ClosedColumn` is
|
|
219
|
-
* structurally a `RelationField`, so both kinds read uniformly.
|
|
220
|
-
*/
|
|
221
87
|
function sealedFieldsOf(member: AnyRelation | AnyClosed): readonly RelationField[] {
|
|
222
88
|
if (isClosedMember(member)) {
|
|
223
89
|
return Object.freeze([Object.freeze({ name: "id", field: member.id }), ...member.data.columns])
|
|
@@ -225,13 +91,6 @@ function sealedFieldsOf(member: AnyRelation | AnyClosed): readonly RelationField
|
|
|
225
91
|
return member.data.fields
|
|
226
92
|
}
|
|
227
93
|
|
|
228
|
-
/**
|
|
229
|
-
* One sealed field by name — derived from {@link sealedFieldsOf}, so the
|
|
230
|
-
* closed synthetic `id` resolves everywhere a name is looked up (no reader
|
|
231
|
-
* can silently lack the `id` arm). `undefined` when the name is foreign
|
|
232
|
-
* (the type tiers make that unwritable; the engine re-judges at
|
|
233
|
-
* `Db.create`).
|
|
234
|
-
*/
|
|
235
94
|
function sealedFieldOf(member: AnyRelation | AnyClosed, fieldName: string): AnyField | undefined {
|
|
236
95
|
const declared = sealedFieldsOf(member).find(function byName(candidate) {
|
|
237
96
|
return candidate.name === fieldName
|
|
@@ -239,7 +98,6 @@ function sealedFieldOf(member: AnyRelation | AnyClosed, fieldName: string): AnyF
|
|
|
239
98
|
return declared?.field
|
|
240
99
|
}
|
|
241
100
|
|
|
242
|
-
/** Narrows the two-tier second argument: a handle tuple (bare tier) or a column block (payload tier). */
|
|
243
101
|
function isHandleTuple(
|
|
244
102
|
shape: readonly [string, ...string[]] | Record<string, PayloadField>
|
|
245
103
|
): shape is readonly [string, ...string[]] {
|
|
@@ -284,13 +142,6 @@ function axiomsMinted<Handles extends string, Cols extends Record<string, Payloa
|
|
|
284
142
|
})
|
|
285
143
|
}
|
|
286
144
|
|
|
287
|
-
/**
|
|
288
|
-
* Mints the axiom-readback record: one own frozen row per handle (the bare
|
|
289
|
-
* tier's rows are empty — it declares no columns), each row a fresh copy of
|
|
290
|
-
* its ground axiom. Both tiers supply a REAL axioms record ({@link
|
|
291
|
-
* closedBare} mints its empty rows), so the columns-without-axioms state is
|
|
292
|
-
* unrepresentable here — no undefined arm exists to guard.
|
|
293
|
-
*/
|
|
294
145
|
function mintAxioms<Handles extends string, Cols extends Record<string, PayloadField>>(
|
|
295
146
|
name: string,
|
|
296
147
|
handles: readonly Handles[],
|
|
@@ -309,24 +160,11 @@ function mintAxioms<Handles extends string, Cols extends Record<string, PayloadF
|
|
|
309
160
|
return out
|
|
310
161
|
}
|
|
311
162
|
|
|
312
|
-
/** Bare tier: `closed("Kind", ["Checking", "Savings"])` — handles only. */
|
|
313
163
|
function closed<const Name extends string, const Handles extends readonly [string, ...string[]]>(
|
|
314
164
|
name: Name,
|
|
315
165
|
handles: Handles
|
|
316
166
|
): Closed<Name, Handles[number], Record<never, never>>
|
|
317
167
|
|
|
318
|
-
/**
|
|
319
|
-
* Payload tier: declared columns AND ground axioms, one call — `closed(
|
|
320
|
-
* "Grade", { mastered: bool }, { DirectPass: { mastered: true }, Failed:
|
|
321
|
-
* { mastered: false } })`. The curried tier-2 spelling is DELETED
|
|
322
|
-
* (canonical utterance): `Cols` infers from the column block, the handle
|
|
323
|
-
* set from the axioms record's keys (reverse mapped-type inference), and
|
|
324
|
-
* every row is contextually checked against the declared columns — a
|
|
325
|
-
* wrong-typed value errors ON its property. The axioms record's keys ARE
|
|
326
|
-
* the handles (declaration order = key order, integer-index names
|
|
327
|
-
* rejected); every row carries every column exactly once (type-enforced by
|
|
328
|
-
* {@link Axioms}).
|
|
329
|
-
*/
|
|
330
168
|
function closed<const Name extends string, const Cols extends PayloadColumns, Handles extends string>(
|
|
331
169
|
name: Name,
|
|
332
170
|
columns: Cols,
|
|
@@ -352,13 +190,6 @@ function closed<const Name extends string, const Cols extends PayloadColumns, Ha
|
|
|
352
190
|
return closedPayload(name, shape, axioms)
|
|
353
191
|
}
|
|
354
192
|
|
|
355
|
-
/**
|
|
356
|
-
* The bare tier's precisely-typed builder: no columns, and the axioms
|
|
357
|
-
* record is the EMPTY-ROW record over the handle roster (one own frozen
|
|
358
|
-
* `{}` per handle, `__proto__`-safe own-property definition) — the same
|
|
359
|
-
* representation the payload tier carries, so `mintClosed` never sees a
|
|
360
|
-
* tier fork and the columns-without-axioms state stops being spellable.
|
|
361
|
-
*/
|
|
362
193
|
function closedBare<Name extends string, Handles extends string>(
|
|
363
194
|
name: Name,
|
|
364
195
|
handles: readonly [Handles, ...Handles[]]
|
|
@@ -377,11 +208,6 @@ function closedBare<Name extends string, Handles extends string>(
|
|
|
377
208
|
return mintClosed<Name, Handles, Record<never, never>>(name, handles, {}, empty)
|
|
378
209
|
}
|
|
379
210
|
|
|
380
|
-
/**
|
|
381
|
-
* The payload tier's precisely-typed builder: column names are judged
|
|
382
|
-
* first (the macro-expansion analog), then the handle set is read off the
|
|
383
|
-
* axioms record's own keys.
|
|
384
|
-
*/
|
|
385
211
|
function closedPayload<Name extends string, Handles extends string, Cols extends PayloadColumns>(
|
|
386
212
|
name: Name,
|
|
387
213
|
columns: Cols,
|
|
@@ -402,13 +228,6 @@ function closedPayload<Name extends string, Handles extends string, Cols extends
|
|
|
402
228
|
return mintClosed<Name, Handles, Cols>(name, handles, columns, axioms)
|
|
403
229
|
}
|
|
404
230
|
|
|
405
|
-
/**
|
|
406
|
-
* The trusted seam of the ergonomic-surface mint: `where` reads back as an
|
|
407
|
-
* own function exactly when payload columns exist, and is ABSENT otherwise
|
|
408
|
-
* — the runtime twin of the {@link Closed} type's conditional arm
|
|
409
|
-
* (`ClosedCore` alone vs `ClosedCore & ClosedSelectable`), verified before
|
|
410
|
-
* the minted value is admitted at the conditional type.
|
|
411
|
-
*/
|
|
412
231
|
function surfaceMinted<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>>(
|
|
413
232
|
value: ClosedCore<Name, Handles, Cols>,
|
|
414
233
|
cols: readonly ClosedColumn[]
|
|
@@ -417,14 +236,6 @@ function surfaceMinted<Name extends string, Handles extends string, Cols extends
|
|
|
417
236
|
return cols.length > 0 ? selectable : !selectable
|
|
418
237
|
}
|
|
419
238
|
|
|
420
|
-
/**
|
|
421
|
-
* Mints one closed relation value — the shared seam of both tiers, HONESTLY
|
|
422
|
-
* typed end to end (a wrong-shaped mint is a compile error here, not a
|
|
423
|
-
* laundered `unknown`): roster checks, eager axiom lowering, the
|
|
424
|
-
* roster-carrying `id` descriptor, the frozen `columns` carrier (the runtime
|
|
425
|
-
* twin of the `Cols` type parameter), and — on the payload tier only — the
|
|
426
|
-
* ψ-selection `where()`.
|
|
427
|
-
*/
|
|
428
239
|
function mintClosed<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>>(
|
|
429
240
|
name: Name,
|
|
430
241
|
handles: readonly Handles[],
|
|
@@ -469,24 +280,12 @@ function mintClosed<Name extends string, Handles extends string, Cols extends Re
|
|
|
469
280
|
rows: Object.freeze(rows)
|
|
470
281
|
})
|
|
471
282
|
const id: ClosedIdField<Name, Handles> = Object.freeze({ kind: "u64", closed: roster })
|
|
472
|
-
|
|
473
|
-
* Handle names are arbitrary identifiers, so axiom rows are minted with
|
|
474
|
-
* OWN-property definition (inside {@link mintAxioms}), never assignment:
|
|
475
|
-
* a handle named "__proto__" would otherwise ride the Object.prototype
|
|
476
|
-
* accessor — silently swapping the record's prototype instead of
|
|
477
|
-
* creating the row. (Object SPREAD is CreateDataProperty by spec, so the
|
|
478
|
-
* copies below are own-property safe for column names too.)
|
|
479
|
-
*/
|
|
283
|
+
|
|
480
284
|
const axiomsOut = mintAxioms<Handles, Cols>(name, handleList, cols, axioms)
|
|
481
285
|
const columnsOut: Cols = { ...columns }
|
|
482
286
|
Object.freeze(columnsOut)
|
|
483
287
|
const holder: { value: Closed<Name, Handles, Cols> | undefined } = { value: undefined }
|
|
484
|
-
|
|
485
|
-
* The ψ selection: resolved against the declared payload columns through
|
|
486
|
-
* the ONE selection machine (`relation.ts::resolveSelection` — a
|
|
487
|
-
* `ClosedColumn` is structurally a `RelationField`), never pre-folded
|
|
488
|
-
* into an id set (the engine folds at validate).
|
|
489
|
-
*/
|
|
288
|
+
|
|
490
289
|
function where(selection: ClosedSelectionInput<Cols>): SelectedClosed<Name, Handles, Cols> {
|
|
491
290
|
const owner = holder.value
|
|
492
291
|
if (owner === undefined) {
|