@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.
Files changed (103) hide show
  1. package/COOKBOOK.md +33 -49
  2. package/README.md +3 -3
  3. package/dist/capacity.d.ts +24 -136
  4. package/dist/capacity.d.ts.map +1 -1
  5. package/dist/capacity.js +18 -40
  6. package/dist/capacity.js.map +1 -1
  7. package/dist/closed.d.ts +0 -156
  8. package/dist/closed.d.ts.map +1 -1
  9. package/dist/closed.js +0 -104
  10. package/dist/closed.js.map +1 -1
  11. package/dist/db.d.ts +7 -223
  12. package/dist/db.d.ts.map +1 -1
  13. package/dist/db.js +147 -396
  14. package/dist/db.js.map +1 -1
  15. package/dist/face.d.ts +0 -133
  16. package/dist/face.d.ts.map +1 -1
  17. package/dist/face.js +0 -33
  18. package/dist/face.js.map +1 -1
  19. package/dist/fields.d.ts +1 -145
  20. package/dist/fields.d.ts.map +1 -1
  21. package/dist/fields.js +2 -91
  22. package/dist/fields.js.map +1 -1
  23. package/dist/index.d.ts +11 -15
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +9 -13
  26. package/dist/index.js.map +1 -1
  27. package/dist/law.d.ts +111 -93
  28. package/dist/law.d.ts.map +1 -1
  29. package/dist/law.js +23 -27
  30. package/dist/law.js.map +1 -1
  31. package/dist/lower.d.ts +9 -35
  32. package/dist/lower.d.ts.map +1 -1
  33. package/dist/lower.js +8 -53
  34. package/dist/lower.js.map +1 -1
  35. package/dist/marshal.d.ts +0 -65
  36. package/dist/marshal.d.ts.map +1 -1
  37. package/dist/marshal.js +0 -72
  38. package/dist/marshal.js.map +1 -1
  39. package/dist/native.d.ts +25 -290
  40. package/dist/native.d.ts.map +1 -1
  41. package/dist/native.js +6 -66
  42. package/dist/native.js.map +1 -1
  43. package/dist/query/atom.d.ts +10 -276
  44. package/dist/query/atom.d.ts.map +1 -1
  45. package/dist/query/atom.js +1 -96
  46. package/dist/query/atom.js.map +1 -1
  47. package/dist/query/find.d.ts +10 -76
  48. package/dist/query/find.d.ts.map +1 -1
  49. package/dist/query/find.js +0 -30
  50. package/dist/query/find.js.map +1 -1
  51. package/dist/query/lower.d.ts +64 -146
  52. package/dist/query/lower.d.ts.map +1 -1
  53. package/dist/query/lower.js +19 -256
  54. package/dist/query/lower.js.map +1 -1
  55. package/dist/query/parse-ir.d.ts +0 -7
  56. package/dist/query/parse-ir.d.ts.map +1 -1
  57. package/dist/query/parse-ir.js +1 -13
  58. package/dist/query/parse-ir.js.map +1 -1
  59. package/dist/query/run.d.ts +0 -36
  60. package/dist/query/run.d.ts.map +1 -1
  61. package/dist/query/run.js +0 -44
  62. package/dist/query/run.js.map +1 -1
  63. package/dist/query/scope.d.ts +24 -180
  64. package/dist/query/scope.d.ts.map +1 -1
  65. package/dist/query/scope.js +2 -66
  66. package/dist/query/scope.js.map +1 -1
  67. package/dist/relation.d.ts +2 -50
  68. package/dist/relation.d.ts.map +1 -1
  69. package/dist/relation.js +2 -37
  70. package/dist/relation.js.map +1 -1
  71. package/dist/schema.d.ts +13 -63
  72. package/dist/schema.d.ts.map +1 -1
  73. package/dist/schema.js +118 -92
  74. package/dist/schema.js.map +1 -1
  75. package/dist/spec.d.ts +1 -140
  76. package/dist/spec.d.ts.map +1 -1
  77. package/dist/spec.js +1 -68
  78. package/dist/spec.js.map +1 -1
  79. package/dist/statements.d.ts +6 -137
  80. package/dist/statements.d.ts.map +1 -1
  81. package/dist/statements.js +16 -119
  82. package/dist/statements.js.map +1 -1
  83. package/package.json +2 -2
  84. package/src/capacity.ts +26 -140
  85. package/src/closed.ts +5 -206
  86. package/src/db.ts +203 -692
  87. package/src/face.ts +0 -142
  88. package/src/fields.ts +4 -172
  89. package/src/index.ts +9 -15
  90. package/src/law.ts +201 -129
  91. package/src/lower.ts +8 -53
  92. package/src/marshal.ts +1 -85
  93. package/src/native.ts +47 -323
  94. package/src/query/atom.ts +26 -313
  95. package/src/query/find.ts +24 -110
  96. package/src/query/lower.ts +132 -377
  97. package/src/query/parse-ir.ts +1 -14
  98. package/src/query/run.ts +0 -45
  99. package/src/query/scope.ts +25 -186
  100. package/src/relation.ts +2 -66
  101. package/src/schema.ts +143 -122
  102. package/src/spec.ts +1 -160
  103. 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
- /** Payload readback: handle to its declared column values, bare and structural. */
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) {