@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.
Files changed (94) hide show
  1. package/COOKBOOK.md +503 -427
  2. package/README.md +84 -36
  3. package/dist/closed.d.ts +111 -38
  4. package/dist/closed.d.ts.map +1 -1
  5. package/dist/closed.js +94 -99
  6. package/dist/closed.js.map +1 -1
  7. package/dist/db.d.ts +16 -2
  8. package/dist/db.d.ts.map +1 -1
  9. package/dist/db.js +46 -8
  10. package/dist/db.js.map +1 -1
  11. package/dist/face.d.ts +114 -69
  12. package/dist/face.d.ts.map +1 -1
  13. package/dist/face.js +38 -21
  14. package/dist/face.js.map +1 -1
  15. package/dist/fields.d.ts +72 -87
  16. package/dist/fields.d.ts.map +1 -1
  17. package/dist/fields.js +35 -67
  18. package/dist/fields.js.map +1 -1
  19. package/dist/index.d.ts +18 -13
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +11 -7
  22. package/dist/index.js.map +1 -1
  23. package/dist/law.d.ts +224 -0
  24. package/dist/law.d.ts.map +1 -0
  25. package/dist/law.js +224 -0
  26. package/dist/law.js.map +1 -0
  27. package/dist/lower.d.ts +17 -10
  28. package/dist/lower.d.ts.map +1 -1
  29. package/dist/lower.js +34 -23
  30. package/dist/lower.js.map +1 -1
  31. package/dist/marshal.d.ts +33 -6
  32. package/dist/marshal.d.ts.map +1 -1
  33. package/dist/marshal.js +67 -6
  34. package/dist/marshal.js.map +1 -1
  35. package/dist/native.d.ts +6 -2
  36. package/dist/native.d.ts.map +1 -1
  37. package/dist/native.js.map +1 -1
  38. package/dist/query/atom.d.ts +139 -56
  39. package/dist/query/atom.d.ts.map +1 -1
  40. package/dist/query/atom.js +7 -1
  41. package/dist/query/atom.js.map +1 -1
  42. package/dist/query/lower.d.ts +71 -56
  43. package/dist/query/lower.d.ts.map +1 -1
  44. package/dist/query/lower.js +341 -69
  45. package/dist/query/lower.js.map +1 -1
  46. package/dist/query/predicate.d.ts +10 -9
  47. package/dist/query/predicate.d.ts.map +1 -1
  48. package/dist/query/predicate.js +2 -2
  49. package/dist/query/predicate.js.map +1 -1
  50. package/dist/query/run.d.ts +15 -5
  51. package/dist/query/run.d.ts.map +1 -1
  52. package/dist/query/run.js +26 -6
  53. package/dist/query/run.js.map +1 -1
  54. package/dist/query/scope.d.ts +100 -43
  55. package/dist/query/scope.d.ts.map +1 -1
  56. package/dist/query/scope.js +89 -30
  57. package/dist/query/scope.js.map +1 -1
  58. package/dist/query/select.d.ts +5 -5
  59. package/dist/query/select.d.ts.map +1 -1
  60. package/dist/relation.d.ts +29 -15
  61. package/dist/relation.d.ts.map +1 -1
  62. package/dist/relation.js +45 -17
  63. package/dist/relation.js.map +1 -1
  64. package/dist/schema.d.ts +41 -3
  65. package/dist/schema.d.ts.map +1 -1
  66. package/dist/schema.js +16 -2
  67. package/dist/schema.js.map +1 -1
  68. package/dist/spec.d.ts +10 -8
  69. package/dist/spec.d.ts.map +1 -1
  70. package/dist/spec.js.map +1 -1
  71. package/dist/statements.d.ts +67 -31
  72. package/dist/statements.d.ts.map +1 -1
  73. package/dist/statements.js +97 -20
  74. package/dist/statements.js.map +1 -1
  75. package/package.json +2 -2
  76. package/src/closed.ts +214 -146
  77. package/src/db.ts +65 -10
  78. package/src/face.ts +169 -102
  79. package/src/fields.ts +97 -164
  80. package/src/index.ts +43 -18
  81. package/src/law.ts +519 -0
  82. package/src/lower.ts +36 -23
  83. package/src/marshal.ts +74 -7
  84. package/src/native.ts +6 -2
  85. package/src/query/atom.ts +155 -65
  86. package/src/query/lower.ts +572 -167
  87. package/src/query/predicate.ts +43 -33
  88. package/src/query/run.ts +26 -6
  89. package/src/query/scope.ts +161 -51
  90. package/src/query/select.ts +5 -5
  91. package/src/relation.ts +60 -26
  92. package/src/schema.ts +48 -7
  93. package/src/spec.ts +10 -8
  94. package/src/statements.ts +165 -46
package/README.md CHANGED
@@ -4,6 +4,8 @@ Type-theoretic TypeScript SDK for the [bumbledb](https://github.com/bjornpagen/b
4
4
 
5
5
  bumbledb models data as relations judged by statements (functionality, containment, cardinality) and queried with Datalog expressed as plain values — no SQL, no query-string parser. The SDK is a thin, fully typed surface over an in-process native engine (LMDB storage, MVCC snapshots, a single-writer witnessed write loop).
6
6
 
7
+ The surface is structural to the bone. Relation declarations are pure structure — kind, width, element, fresh, nothing else — and domains are never declared anywhere: **the laws type the columns**. `schema()` computes every field's equivalence class from the statement list itself, so the containments and mirrors you already write ARE the typing, at compile time and again at construction. Values stay bare (`bigint`, `string`, …); identity lives in the class the laws compute, not in a wrapper.
8
+
7
9
  > **Research-grade, one platform.** This is a `0.x` release of an embedded engine under active development. It targets a single platform today (below), the API is not yet frozen across `0.x`, and the FFI ABI is pinned exactly per version. Treat it as an early adopter's tool, not a production datastore.
8
10
 
9
11
  ## Platform support
@@ -18,32 +20,51 @@ pnpm add @bjornpagen/bumbledb
18
20
 
19
21
  ## Quick start
20
22
 
21
- Declare a schema, write facts through a transaction, and query with Datalog as
22
- values. Everything is typed end to end branded ids, inferred query rows, and
23
- rejections that arrive as data rather than exceptions.
23
+ Declare relations as pure structure, let the statement list type every column,
24
+ write facts through a transaction, and query with Datalog as values.
25
+ Everything is typed end to end bare structural values in law-computed
26
+ classes, inferred query rows, and rejections that arrive as data rather than
27
+ exceptions.
24
28
 
25
29
  ```ts
26
- import { Db, relation, schema, contained, on, query, match, u64, str, type Brand, type Scope } from "@bjornpagen/bumbledb"
27
-
28
- // Branded, fresh-minted id types.
29
- const HolderId = u64.newtype("HolderId")
30
- const AccountId = u64.newtype("AccountId")
31
-
32
- // Relations. `.fresh` marks an engine-minted primary key.
33
- const Holder = relation("Holder", { id: HolderId.fresh, name: str })
34
- const Account = relation("Account", { id: AccountId.fresh, holder: HolderId })
35
-
36
- // A theory: every Account.holder must reference an existing Holder.id.
37
- const Ledger = schema("Ledger", { Holder, Account }, [contained(on(Account, "holder"), on(Holder, "id"))])
38
-
39
- const db = await Db.create("./ledger.db", Ledger)
40
-
41
- // Write. The delta is judged against every statement at commit.
42
- let adaId: Brand<bigint, "HolderId"> | undefined
30
+ import { bool, closed, contained, Db, gt, type Infer, key, on, query, relation, schema, u64 } from "@bjornpagen/bumbledb"
31
+
32
+ // A closed relation: a sealed roster of axioms with typed payload columns.
33
+ // At the host surface a handle is its NAME — the string literal "DirectPass"
34
+ // is the one spelling, and closed columns type as the handle union.
35
+ const Kind = closed(
36
+ "Kind",
37
+ { mastered: bool, rank: u64 },
38
+ {
39
+ DirectPass: { mastered: true, rank: 30n },
40
+ JudgedPass: { mastered: true, rank: 20n },
41
+ Failed: { mastered: false, rank: 10n }
42
+ }
43
+ )
44
+
45
+ // Relations are pure structure no domain is declared anywhere.
46
+ // `u64.fresh` marks an engine-minted primary key.
47
+ const Attempt = relation("Attempt", { id: u64.fresh, kind: Kind.id })
48
+ const Certificate = relation("Certificate", { attempt: u64, kind: Kind.id })
49
+
50
+ // THE LAWS TYPE THE COLUMNS: schema() computes every field's class FROM this
51
+ // statement list — the containments are the typing. The last statement uses
52
+ // ψ-selection: a certificate may only ever cite a mastered kind.
53
+ const Review = schema("Review", { Kind, Attempt, Certificate }, [
54
+ contained(on(Attempt, "kind"), on(Kind, "id")),
55
+ key(Certificate, ["attempt"]),
56
+ contained(on(Certificate, "attempt"), on(Attempt, "id")),
57
+ contained(on(Certificate, "kind"), on(Kind.where({ mastered: true }), "id"))
58
+ ])
59
+
60
+ const db = await Db.create("./review.db", Review)
61
+
62
+ // Write. The delta is judged against every statement at commit. A closed
63
+ // column takes the handle name — a wrong string is a compile error AND a
64
+ // marshal refusal.
43
65
  const result = db.write((tx) => {
44
- const ada = tx.insert(Holder, { name: "ada" }) // ada.id is a branded HolderId
45
- adaId = ada.id
46
- tx.insert(Account, { holder: ada.id })
66
+ const attempt = tx.insert(Attempt, { kind: "DirectPass" }) // attempt.id minted, a bare bigint
67
+ tx.insert(Certificate, { attempt: attempt.id, kind: "DirectPass" })
47
68
  })
48
69
 
49
70
  // Rejection-as-data: no throw — a rejected commit is a typed value carrying
@@ -54,28 +75,55 @@ if (!result.ok) {
54
75
  }
55
76
  }
56
77
 
57
- // Query: Datalog as values. Rows are typed from the `select` shape.
58
- const accountsOf = query(Ledger, ($: Scope<(typeof Ledger)["relations"]>) => {
59
- const acct = $.var(Account.fields.id)
60
- const holder = $.param("holder", Holder.fields.id)
61
- return { rules: [[match(Account, { id: acct, holder })]], select: { acct } }
78
+ // Query: Datalog as values. Vars are named and typed by the class of their
79
+ // first binding; params are typed by use; rows are typed from the select.
80
+ // `gt` is one of the free comparison exports.
81
+ const certifiedAbove = query(Review).rule((r) => {
82
+ const { a, k, rank } = r.vars("a", "k", "rank")
83
+ return r
84
+ .match(Certificate, { attempt: a, kind: k })
85
+ .match(Kind, { id: k, mastered: true, rank }) // ψ on the read side too
86
+ .where(gt(rank, r.param("floor")))
87
+ .select("a", "rank")
62
88
  })
63
89
 
64
- const prepared = db.prepare(accountsOf)
65
- const rows = db.execute(prepared, { holder: adaId }) // rows: { acct: AccountId }[]
90
+ const prepared = db.prepare(certifiedAbove)
91
+ const rows = db.execute(prepared, { floor: 15n }) // rows: { a: bigint; rank: bigint }[]
92
+ console.log(rows)
93
+
94
+ // Host dispatch over the sealed roster is native `switch` narrowing over
95
+ // the handle union ("DirectPass" | "JudgedPass" | "Failed") — exhaustive
96
+ // via `satisfies never`; the sealed axioms read back typed.
97
+ function describe(kind: Infer<typeof Kind.id>): string {
98
+ switch (kind) {
99
+ case "DirectPass":
100
+ case "JudgedPass":
101
+ return `mastered, rank ${Kind.axioms[kind].rank}`
102
+ case "Failed":
103
+ return "not mastered"
104
+ default:
105
+ return kind satisfies never
106
+ }
107
+ }
108
+ console.log(describe("JudgedPass")) // "mastered, rank 20"
66
109
  ```
67
110
 
111
+ Every `ts` fence in this README is extracted and type-checked against the
112
+ real surface by `test/readme.test.ts` — the examples cannot drift.
113
+
68
114
  ## Surface
69
115
 
70
- - The type kernel brands, fields, `relation()`, `closed()`.
71
- - The statement algebra — `schema()`, `key`, `contained`, `mirrors`, `window`.
72
- - The `Db` runtime path-cached stores, transactions, typed violations, scoped snapshot reads, the witnessed write loop.
73
- - The query surfaceDatalog as values: scoped vars/params, atoms, negation, conditions, aggregates, engine recursion via predicates, `db.prepare`.
74
- - The exhume surface — `Db.exhume`, the schema-independent read path: a store's self-described shapes and raw facts by name.
116
+ The drizzle law governs this surface: the SDK's job at the host boundary is translation, not abstraction — every database idiom arrives as the modern TypeScript idiom for that concept, and the SDK never invents an operator where the language already has one.
117
+
118
+ - The structural type kernel — fields as pure structure (`bool`, `bytes`, `i64`, `u64`, `str`, `interval`, `span`), `relation()`, and `closed()` sealed rosters with typed axiom payloads. A closed reference's value type IS the handle union (`Infer` speaks it); dispatch is native `switch` narrowing with `satisfies never` exhaustiveness. Domains are never declared: `schema()` computes every field's class from the statement list.
119
+ - The statement algebra`schema()`, `key`, `contained`, `mirrors`, `window`; faces via `on` (set membership is a plain array in `.where`); counts via `exactly`, `atLeast`, `atMost`, `between`, `none`; ψ-selection via `.where` on relations and closed rosters.
120
+ - The `Db` runtime — `Db.create`/`Db.open`, path-cached stores, transactions, typed violations, scoped snapshot reads, the witnessed write loop with `abandon`.
121
+ - The query surface — Datalog as values, `query(S).rule(r => ...)`: named vars, params typed by use, negation, aggregates, and the free comparison/connective exports (`eq`, `ne`, `lt`, `le`, `gt`, `ge`, `and`, `or`, `not`, `allen`/`ALLEN`, `pointIn`, `covers`); set membership at a closed field is a plain array in the match record (`r.match(Ticket, { priority: ["Normal", "Urgent"] })` — closed-only there: an ordinary field's membership is a bound `r.inSet` param); stratified recursion via `program()`; `db.prepare` as a plain value.
122
+ - The exhume surface — `Db.exhume`, the schema-independent read path: a store's self-described shapes and raw facts by name, with typed refusals (`ErrExhumeNoDescriptor`, `ErrExhumeFormatMismatch`, `ErrExhumeCorruption`).
75
123
 
76
124
  ## Cookbook
77
125
 
78
- The engine cookbook's 29 modeling recipes, translated to this SDK's structural API: [COOKBOOK.md](./COOKBOOK.md). Every recipe is compile-pinned by `test/cookbook.test.ts` — each schema is admitted by the real engine and every query snippet lowers through `db.prepare` so the cookbook can never drift from the surface.
126
+ The engine cookbook's 29 modeling recipes, translated to this SDK's structural API: [COOKBOOK.md](./COOKBOOK.md). Two referees hold it: `test/cookbook-doc.test.ts` extracts the document's own `ts` fences and type-checks them against the real surface (the doc itself cannot drift), and `test/cookbook.test.ts` runs compiled copies of the recipes — each schema admitted by the real engine, its fingerprint asserted against the cross-host goldens the Rust cookbook suite also pins, every query snippet lowered through `db.prepare`.
79
127
 
80
128
  ## Architecture
81
129
 
package/dist/closed.d.ts CHANGED
@@ -1,22 +1,36 @@
1
1
  /**
2
2
  * Closed relations (`docs/architecture/10-data-model.md` § closed
3
3
  * relations): a vocabulary whose extension is declared in the schema — two
4
- * tiers, one function. The emission per closed relation mirrors the
5
- * macro's (host-enum analog): handle CONSTANTS on the value
6
- * (`Kind.Checking`, ids = declaration order, each a BARE `bigint` — no
7
- * brand), the `fromId` weld, an `id` field descriptor carrying the handle
8
- * DOMAIN (`"KindId"`, mirroring Rust's `closed relation Kind as KindId`)
9
- * for other relations' field blocks (`kind: Kind.id`), payload readback
10
- * (`Kind.axioms`), and the declared payload column descriptors
11
- * (`Kind.columns` the runtime twin of the `Cols` type parameter, which
12
- * the face layer's domain wall reads). Bare tier: `closed("Kind", ["Checking",
13
- * "Savings"])`. Payload tier: `closed("Sev", { pages: bool })({ Critical:
14
- * { pages: true }, ... })` the axioms record IS the handle declaration,
15
- * every handle carrying every column exactly once (type-enforced). No fact
16
- * type and no insert surface exist closed relations are unwritable by
17
- * construction: the value simply lacks the writable relation shape.
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.
18
31
  */
19
32
  import { type AnyField, type ClosedIdField, type Infer } from "#fields.ts";
33
+ import { type SelectionBinding, type SelectionInput } from "#relation.ts";
20
34
  import type { LiteralSpec } from "#spec.ts";
21
35
  /**
22
36
  * A payload column of a closed relation: any field descriptor except a
@@ -25,6 +39,19 @@ import type { LiteralSpec } from "#spec.ts";
25
39
  type PayloadField = Exclude<AnyField, {
26
40
  readonly fresh: true;
27
41
  }>;
42
+ /**
43
+ * A declared payload column BLOCK: name → descriptor, with `id`
44
+ * unspellable — the sealed shape mints the synthetic `id` itself (ordinal
45
+ * 0 of the matchable fields), so a declared column named `id` would be
46
+ * shadowed by the synthetic slot everywhere the shape resolves by name
47
+ * (`matchFieldsOf`, the projected face, `spec.rs`'s resolver). The wall is
48
+ * typed here and judged again at construction in {@link mintClosed} — the
49
+ * runtime twin for untyped callers, warmer and earlier than the engine's
50
+ * `DuplicateFieldName` at `Db.create`.
51
+ */
52
+ type PayloadColumns = Record<string, PayloadField> & {
53
+ readonly id?: never;
54
+ };
28
55
  /** One declared payload column: name plus its field descriptor. */
29
56
  interface ClosedColumn {
30
57
  readonly name: string;
@@ -67,36 +94,77 @@ type Axioms<Handles extends string, Cols extends Record<string, PayloadField>> =
67
94
  interface ClosedCore<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>> {
68
95
  readonly name: Name;
69
96
  /**
70
- * The handle-domain reference descriptor: `kind: Kind.id` in another
71
- * relation's field block is the reference through which bare handle ids
72
- * become legal in that relation's selections. Its domain is the closed
73
- * relation's handle domain (`"KindId"`Rust's `as KindId`).
97
+ * The closed reference descriptor: `kind: Kind.id` in another relation's
98
+ * field block is the reference through which handle literals become
99
+ * legal in that relation's selections. Pure structure plus the PRECISE
100
+ * roster (`ClosedIdField<Handles>`the handle union is the field's
101
+ * value type under `Infer`); the referencing field's domain is law-born:
102
+ * `schema()` computes it from the declared containment (`"Kind.id"`, the
103
+ * generator class).
74
104
  */
75
- readonly id: ClosedIdField<`${Name}Id`>;
105
+ readonly id: ClosedIdField<Handles>;
76
106
  readonly data: ClosedData;
77
107
  /** Payload readback: handle to its declared column values, bare and structural. */
78
108
  readonly axioms: Axioms<Handles, Cols>;
79
109
  /**
80
- * The declared payload columns, name → S1 field descriptor — an HONEST
110
+ * The declared payload columns, name → field descriptor — an HONEST
81
111
  * frozen runtime record (the descriptors themselves, by identity), and
82
- * the typed carrier a projected payload column's domain label is
112
+ * the typed carrier a projected payload column's structural shape is
83
113
  * recovered through off the schema type (the face layer's
84
- * `ProjectedDomain` reads it; `data.columns` carries the same
114
+ * `ProjectedShape` reads it; `data.columns` carries the same
85
115
  * descriptors in declaration order for the lowering).
86
116
  */
87
117
  readonly columns: Cols;
88
- /** The weld: declaration-order id back to its handle, or undefined beyond the roster. */
89
- fromId(id: bigint): Handles | undefined;
90
118
  }
91
119
  /**
92
- * A closed relation value: the core surface plus one BARE constant per
93
- * handle (`Kind.Checking: bigint`, ids = declaration order — the value is
94
- * structural; the roster judges out-of-vocabulary ids at construction and
95
- * the engine at commit).
120
+ * The `where()` argument of a closed relation: EXACTLY the relation
121
+ * surface's {@link SelectionInput}, over the declared payload columns — the
122
+ * ONE selection vocabulary, so a spelling change there (H3's membership
123
+ * arrays) flows through with no local change here. The synthetic `id` is
124
+ * deliberately unspellable ({@link PayloadColumns} refuses an `id` column):
125
+ * an id selection is spelled only as handle literals on the REFERENCING
126
+ * side (the canonical-utterance law).
96
127
  */
97
- type Closed<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>> = ClosedCore<Name, Handles, Cols> & {
98
- readonly [H in Handles]: bigint;
99
- };
128
+ type ClosedSelectionInput<Cols extends Record<string, PayloadField>> = SelectionInput<Cols>;
129
+ /**
130
+ * A closed relation with a ψ selection applied — what `on()` consumes as a
131
+ * σ-carrying closed source (`on(Kind.where({ mastered: true }), "id")`).
132
+ * Deliberately the SAME discriminant shape as the ordinary `Selected`
133
+ * (`relation`/`selection` — `face.ts::faceParts` splits both by `"relation"
134
+ * in source`), and structurally UNMISTAKABLE for one: an `AnyClosed` lacks
135
+ * the relation shape (no `fields` record, no `RelationData`).
136
+ */
137
+ interface SelectedClosed<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>> {
138
+ readonly relation: Closed<Name, Handles, Cols>;
139
+ readonly selection: readonly SelectionBinding[];
140
+ }
141
+ /** Any ψ-selected closed relation value. */
142
+ interface AnySelectedClosed {
143
+ readonly relation: AnyClosed;
144
+ readonly selection: readonly SelectionBinding[];
145
+ }
146
+ /**
147
+ * The ψ-selection surface of a payload-tier closed value. The selection is
148
+ * resolved EAGERLY against the declared columns and lowered as-is — the SDK
149
+ * never pre-folds ψ into an id set: pass-through lowering is what the macro
150
+ * does, and the ENGINE folds against the sealed extension at validate
151
+ * (`compile_member_set`).
152
+ */
153
+ interface ClosedSelectable<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>> {
154
+ where(selection: ClosedSelectionInput<Cols>): SelectedClosed<Name, Handles, Cols>;
155
+ }
156
+ /**
157
+ * A closed relation value: the core surface plus — exactly when payload
158
+ * columns exist — `where()` (the bare tier has nothing to select on, so
159
+ * the method is ABSENT there, not merely uncallable). NOTHING else:
160
+ * handles are data on the roster, never properties of the value (the
161
+ * handle constants, the match operator, and the id-to-handle weld died
162
+ * with the bigint era — dispatch is native `switch` narrowing over the
163
+ * handle union).
164
+ */
165
+ type Closed<Name extends string, Handles extends string, Cols extends Record<string, PayloadField>> = [
166
+ keyof Cols
167
+ ] extends [never] ? ClosedCore<Name, Handles, Cols> : ClosedCore<Name, Handles, Cols> & ClosedSelectable<Name, Handles, Cols>;
100
168
  /** Any closed relation value, whatever its roster and columns. */
101
169
  interface AnyClosed {
102
170
  readonly name: string;
@@ -108,13 +176,18 @@ interface AnyClosed {
108
176
  /** Bare tier: `closed("Kind", ["Checking", "Savings"])` — handles only. */
109
177
  declare function closed<const Name extends string, const Handles extends readonly [string, ...string[]]>(name: Name, handles: Handles): Closed<Name, Handles[number], Record<never, never>>;
110
178
  /**
111
- * Payload tier: declared columns, then ground axioms — `closed("Grade",
112
- * { mastered: bool })({ DirectPass: { mastered: true }, Failed: { mastered:
113
- * false } })`. The axioms record's keys ARE the handles (declaration order
114
- * = key order, integer-index names rejected); every row carries every
115
- * column exactly once (type-enforced by {@link Axioms}).
179
+ * Payload tier: declared columns AND ground axioms, one call — `closed(
180
+ * "Grade", { mastered: bool }, { DirectPass: { mastered: true }, Failed:
181
+ * { mastered: false } })`. The curried tier-2 spelling is DELETED
182
+ * (canonical utterance): `Cols` infers from the column block, the handle
183
+ * set from the axioms record's keys (reverse mapped-type inference), and
184
+ * every row is contextually checked against the declared columns — a
185
+ * wrong-typed value errors ON its property. The axioms record's keys ARE
186
+ * the handles (declaration order = key order, integer-index names
187
+ * rejected); every row carries every column exactly once (type-enforced by
188
+ * {@link Axioms}).
116
189
  */
117
- declare function closed<const Name extends string, const Cols extends Record<string, PayloadField>>(name: Name, columns: Cols): <Handles extends string>(axioms: Axioms<Handles, Cols>) => Closed<Name, Handles, Cols>;
118
- export type { AnyClosed, AxiomRow, Axioms, Closed, ClosedColumn, ClosedCore, ClosedData, ClosedRow, PayloadField };
190
+ declare function closed<const Name extends string, const Cols extends PayloadColumns, Handles extends string>(name: Name, columns: Cols, axioms: Axioms<Handles, Cols>): Closed<Name, Handles, Cols>;
191
+ export type { AnyClosed, AnySelectedClosed, AxiomRow, Axioms, Closed, ClosedColumn, ClosedCore, ClosedData, ClosedRow, ClosedSelectable, ClosedSelectionInput, PayloadField, SelectedClosed };
119
192
  export { closed };
120
193
  //# sourceMappingURL=closed.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"closed.d.ts","sourceRoot":"","sources":["../src/closed.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"closed.d.ts","sourceRoot":"","sources":["../src/closed.ts"],"names":[],"mappings":"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"}