@bjornpagen/bumbledb 0.2.0 → 0.3.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 (84) hide show
  1. package/COOKBOOK.md +462 -406
  2. package/README.md +66 -31
  3. package/dist/closed.d.ts +121 -25
  4. package/dist/closed.d.ts.map +1 -1
  5. package/dist/closed.js +108 -42
  6. package/dist/closed.js.map +1 -1
  7. package/dist/db.d.ts +12 -1
  8. package/dist/db.d.ts.map +1 -1
  9. package/dist/db.js +20 -5
  10. package/dist/db.js.map +1 -1
  11. package/dist/face.d.ts +100 -55
  12. package/dist/face.d.ts.map +1 -1
  13. package/dist/face.js +36 -10
  14. package/dist/face.js.map +1 -1
  15. package/dist/fields.d.ts +50 -79
  16. package/dist/fields.d.ts.map +1 -1
  17. package/dist/fields.js +20 -53
  18. package/dist/fields.js.map +1 -1
  19. package/dist/index.d.ts +17 -12
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +10 -6
  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/native.d.ts +6 -2
  32. package/dist/native.d.ts.map +1 -1
  33. package/dist/native.js.map +1 -1
  34. package/dist/query/atom.d.ts +88 -50
  35. package/dist/query/atom.d.ts.map +1 -1
  36. package/dist/query/atom.js +4 -1
  37. package/dist/query/atom.js.map +1 -1
  38. package/dist/query/lower.d.ts +71 -56
  39. package/dist/query/lower.d.ts.map +1 -1
  40. package/dist/query/lower.js +90 -43
  41. package/dist/query/lower.js.map +1 -1
  42. package/dist/query/predicate.d.ts +10 -9
  43. package/dist/query/predicate.d.ts.map +1 -1
  44. package/dist/query/predicate.js +2 -2
  45. package/dist/query/predicate.js.map +1 -1
  46. package/dist/query/scope.d.ts +76 -41
  47. package/dist/query/scope.d.ts.map +1 -1
  48. package/dist/query/scope.js +77 -30
  49. package/dist/query/scope.js.map +1 -1
  50. package/dist/query/select.d.ts +5 -5
  51. package/dist/query/select.d.ts.map +1 -1
  52. package/dist/relation.d.ts +21 -8
  53. package/dist/relation.d.ts.map +1 -1
  54. package/dist/relation.js +13 -7
  55. package/dist/relation.js.map +1 -1
  56. package/dist/schema.d.ts +41 -3
  57. package/dist/schema.d.ts.map +1 -1
  58. package/dist/schema.js +16 -2
  59. package/dist/schema.js.map +1 -1
  60. package/dist/spec.d.ts +7 -6
  61. package/dist/spec.d.ts.map +1 -1
  62. package/dist/spec.js.map +1 -1
  63. package/dist/statements.d.ts +61 -31
  64. package/dist/statements.d.ts.map +1 -1
  65. package/dist/statements.js +22 -17
  66. package/dist/statements.js.map +1 -1
  67. package/package.json +2 -2
  68. package/src/closed.ts +243 -68
  69. package/src/db.ts +23 -5
  70. package/src/face.ts +162 -84
  71. package/src/fields.ts +57 -136
  72. package/src/index.ts +42 -16
  73. package/src/law.ts +519 -0
  74. package/src/lower.ts +36 -23
  75. package/src/native.ts +6 -2
  76. package/src/query/atom.ts +105 -58
  77. package/src/query/lower.ts +271 -139
  78. package/src/query/predicate.ts +43 -33
  79. package/src/query/scope.ts +125 -49
  80. package/src/query/select.ts +5 -5
  81. package/src/relation.ts +15 -9
  82. package/src/schema.ts +48 -7
  83. package/src/spec.ts +7 -6
  84. package/src/statements.ts +83 -43
package/src/face.ts CHANGED
@@ -4,16 +4,23 @@
4
4
  * position, `on(Booking, ["room", "during"])` the composite/pointwise
5
5
  * position (one spelling, arity-generic), `on(Account.where({ kind:
6
6
  * Kind.Savings }), "id")` the σ-carrying source, `on(Kind, "id")` a closed
7
- * relation's sealed shape opened through its synthetic `id`. Projection is
7
+ * relation's sealed shape opened through its synthetic `id`,
8
+ * `on(Kind.where({ mastered: true }), "id")` the ψ-selected closed source
9
+ * (the selection lowered as-is — the ENGINE folds it against the sealed
10
+ * extension at validate, never the SDK). Projection is
8
11
  * positional: tuple order is preserved in the type, and the statement
9
12
  * constructors pair the two sides' tuples by arity ({@link SameArity}) AND
10
- * by domain ({@link SameDomains}) — the domain wall of the structural
11
- * design: every projected field's domain LABEL is read off the schema type
12
- * (`F["domain"]`, the S1 kernel) and compared positionwise by
13
- * string-literal equality, never by any value brand.
13
+ * by structural shape ({@link SameShapes}) — every projected field's
14
+ * kind/width/element triple is read off the schema type (the minimal
15
+ * kernel: descriptors are pure structure) and compared positionwise. There
16
+ * is no domain to compare at construction — domains are LAW-BORN: the
17
+ * statements themselves define the equivalence classes, and `schema()` is
18
+ * where they aggregate and get judged (the one-generator-per-class wall).
14
19
  */
15
20
 
16
- import type { AnyClosed, PayloadField } from "#closed.ts"
21
+ import * as errors from "@superbuilders/errors"
22
+ import type { AnyClosed, AnySelectedClosed, PayloadField } from "#closed.ts"
23
+ import type { AnyField } from "#fields.ts"
17
24
  import type { AnyRelation, AnySelected, FieldsShape, RelationFields, SelectionBinding } from "#relation.ts"
18
25
  import { renderLiteralSet } from "#spec.ts"
19
26
 
@@ -21,10 +28,21 @@ import { renderLiteralSet } from "#spec.ts"
21
28
  const emptySelection: readonly SelectionBinding[] = Object.freeze([])
22
29
 
23
30
  /**
24
- * Splits a face source into its owner and σ: a selected relation carries
25
- * its own bindings (`relation` is the discriminant the property exists on
26
- * no relation or closed value, and `closed()` reserves the name against
27
- * handle collisions); a bare relation or closed relation carries none.
31
+ * The OWNER a face source resolves to: a selected relation — ordinary σ or
32
+ * closed ψ, one shape projects from its underlying relation; a bare
33
+ * relation or closed relation is its own owner. The type-level twin of
34
+ * {@link faceParts}'s split, and what a statement's face `data` carries at
35
+ * its EXACT type — `schema()`'s law-typing reads the owner's literal name
36
+ * (and the projection tuple) straight off the statement type.
37
+ */
38
+ type OwnerOf<S extends FaceSource> = S extends AnySelected | AnySelectedClosed ? S["relation"] : S
39
+
40
+ /**
41
+ * Splits a face source into its owner and σ: a selected relation — ordinary
42
+ * σ or closed ψ, one shape — carries its own bindings (`relation` is the
43
+ * discriminant — the property exists on no relation or closed value, and
44
+ * `closed()` reserves the name against handle collisions); a bare relation
45
+ * or closed relation carries none.
28
46
  */
29
47
  function faceParts(source: FaceSource): {
30
48
  readonly owner: FaceOwner
@@ -60,10 +78,17 @@ function oneOf<V>(first: V, second: V, ...rest: V[]): OneOf<V> {
60
78
  /** The relation a face projects from — ordinary or closed. */
61
79
  type FaceOwner = AnyRelation | AnyClosed
62
80
 
63
- /** A face's runtime description: owner, π (written order), σ (resolved bindings). */
64
- interface FaceData {
65
- readonly owner: FaceOwner
66
- readonly projection: readonly string[]
81
+ /**
82
+ * A face's runtime description: owner, π (written order), σ (resolved
83
+ * bindings). Generic over the owner and projection so a STATEMENT value
84
+ * carries its paired coordinates at their exact types — the honest runtime
85
+ * properties (`owner.name`, `projection`) ARE the type-level carrier
86
+ * `schema()`'s law-typing reads; the defaults are the wide shape every
87
+ * renderer and lowering walk consumes.
88
+ */
89
+ interface FaceData<O extends FaceOwner = FaceOwner, P extends readonly string[] = readonly string[]> {
90
+ readonly owner: O
91
+ readonly projection: P
67
92
  readonly selection: readonly SelectionBinding[]
68
93
  }
69
94
 
@@ -72,70 +97,92 @@ interface FaceData {
72
97
  * selected relation, or closed relation `on()` was handed — the statement
73
98
  * constructors resolve each projected field's DOMAIN through it), and `P`
74
99
  * is the projection tuple as written (its length is the positional-pairing
75
- * arity). Both are honest runtime properties, not phantoms.
100
+ * arity). Both are honest runtime properties, not phantoms — and `data`
101
+ * carries the resolved owner at its exact type, which is what a statement
102
+ * value hands to `schema()`'s law-typing.
76
103
  */
77
104
  interface Face<S extends FaceSource, P extends readonly string[]> {
78
105
  readonly source: S
79
106
  readonly projection: P
80
- readonly data: FaceData
107
+ readonly data: FaceData<OwnerOf<S>, P>
81
108
  }
82
109
 
83
110
  /** Any face value, whatever its source and projection. */
84
111
  type AnyFace = Face<FaceSource, readonly string[]>
85
112
 
86
- /** What `on()` accepts: a relation, a selected relation, or a closed relation. */
87
- type FaceSource = AnyRelation | AnyClosed | AnySelected
113
+ /** What `on()` accepts: a relation, a closed relation, or either with a selection applied. */
114
+ type FaceSource = AnyRelation | AnyClosed | AnySelected | AnySelectedClosed
88
115
 
89
116
  /**
90
117
  * The field names a face over `S` may project: a relation's declared
91
118
  * fields; a selected relation's underlying fields; a closed relation's
92
- * SEALED shape — the synthetic `id` plus its declared payload columns
93
- * (`docs/architecture/70-api.md`: statement field names address the sealed
94
- * shape).
119
+ * SEALED shape — the synthetic `id` plus its declared payload columns,
120
+ * bare or ψ-selected alike (`docs/architecture/70-api.md`: statement field
121
+ * names address the sealed shape).
95
122
  */
96
123
  type FaceFields<S extends FaceSource> = S extends AnySelected
97
124
  ? keyof S["relation"]["fields"] & string
98
- : S extends AnyRelation
99
- ? keyof S["fields"] & string
100
- : S extends { readonly axioms: Readonly<Record<string, infer Row>> }
101
- ? "id" | (keyof Row & string)
102
- : never
103
-
104
- /** One field's domain label within a declared field block (`undefined` when the name is foreign). */
105
- type DomainIn<Fields extends FieldsShape, K extends string> = K extends keyof Fields ? Fields[K]["domain"] : undefined
106
-
107
- /**
108
- * The domain LABEL of one projected field, read structurally off the
109
- * source's schema type an ordinary or selected relation's field carries
110
- * its S1 descriptor's `domain`; a closed relation's synthetic `id` carries
111
- * the handle domain (`"KindId"`), and its payload columns carry their own
112
- * declared descriptors' labels through the closed value's typed `columns`
113
- * carrier (whose runtime twin is the frozen `columns` record the mint
114
- * carries), so a same-label closed-payload relation-field pairing
115
- * compiles and a mismatched one refuses — the identical wall every other
116
- * face position gets. The lowering carries the same label to the engine,
117
- * which stays the final authority.
118
- */
119
- type ProjectedDomain<S extends FaceSource, K extends string> = S extends AnySelected
120
- ? DomainIn<RelationFields<S["relation"]>, K>
121
- : S extends AnyRelation
122
- ? DomainIn<RelationFields<S>, K>
123
- : S extends {
124
- readonly id: { readonly domain: infer D extends string }
125
- readonly columns: infer Cols extends Record<string, PayloadField>
126
- }
127
- ? K extends "id"
128
- ? D
129
- : DomainIn<Cols, K>
130
- : undefined
131
-
132
- /** The positionwise domain-label tuple of a projection over `S`. */
133
- type DomainsOf<S extends FaceSource, P extends readonly string[]> = {
134
- readonly [I in keyof P]: ProjectedDomain<S, P[I] & string>
125
+ : S extends AnySelectedClosed
126
+ ? "id" | (keyof S["relation"]["columns"] & string)
127
+ : S extends AnyRelation
128
+ ? keyof S["fields"] & string
129
+ : S extends { readonly axioms: Readonly<Record<string, infer Row>> }
130
+ ? "id" | (keyof Row & string)
131
+ : never
132
+
133
+ /**
134
+ * One descriptor's structural comparand: the kind/width/element triple —
135
+ * exactly the structure the minimal kernel carries, compared exactly as the
136
+ * engine's Q1 law pairs positions (`schema/validate.rs`): a `bytes` width is
137
+ * bound (bytes<16> vs bytes<32> mismatch), while an INTERVAL width is FREE —
138
+ * the pointwise judgments quantify over points, which carry an element
139
+ * domain and not a width, so `interval(u64)` pairs with `interval(u64, 1n)`
140
+ * (recipe 9's extent/slot mirrors, recipe 29's mixed-width zones) and the
141
+ * width slot reads `undefined` for every interval. Elements stay bound:
142
+ * u64-vs-i64 interval pairs still mismatch.
143
+ */
144
+ type ShapeOf<F extends AnyField> = readonly [
145
+ F["kind"],
146
+ F extends { readonly element: unknown } ? undefined : F extends { readonly width: infer W } ? W : undefined,
147
+ F extends { readonly element: infer E } ? E : undefined
148
+ ]
149
+
150
+ /** One field's structural shape within a declared field block (`undefined` when the name is foreign). */
151
+ type ShapeIn<Fields extends FieldsShape, K extends string> = K extends keyof Fields ? ShapeOf<Fields[K]> : undefined
152
+
153
+ /**
154
+ * The structural SHAPE of one projected field, read off the source's
155
+ * schema type — an ordinary or selected relation's field contributes its
156
+ * descriptor's triple; a closed relation (bare or ψ-selected) contributes
157
+ * its synthetic `id` as a u64 and its payload columns' declared
158
+ * descriptors' triples through the closed value's typed `columns` carrier
159
+ * (whose runtime twin is the frozen `columns` record the mint carries).
160
+ * The engine stays the final authority at `Db.create`/`Db.open`.
161
+ */
162
+ type ProjectedShape<S extends FaceSource, K extends string> = S extends AnySelected
163
+ ? ShapeIn<RelationFields<S["relation"]>, K>
164
+ : S extends AnySelectedClosed
165
+ ? K extends "id"
166
+ ? ShapeOf<S["relation"]["id"]>
167
+ : ShapeIn<S["relation"]["columns"], K>
168
+ : S extends AnyRelation
169
+ ? ShapeIn<RelationFields<S>, K>
170
+ : S extends {
171
+ readonly id: infer Id extends AnyField
172
+ readonly columns: infer Cols extends Record<string, PayloadField>
173
+ }
174
+ ? K extends "id"
175
+ ? ShapeOf<Id>
176
+ : ShapeIn<Cols, K>
177
+ : undefined
178
+
179
+ /** The positionwise structural-shape tuple of a projection over `S`. */
180
+ type ShapesOf<S extends FaceSource, P extends readonly string[]> = {
181
+ readonly [I in keyof P]: ProjectedShape<S, P[I] & string>
135
182
  }
136
183
 
137
- /** The domain-label tuple a face projects, positionwise — the comparand of {@link SameDomains}. */
138
- type FaceDomains<F extends AnyFace> = F extends Face<infer S, infer P> ? DomainsOf<S, P> : never
184
+ /** The shape tuple a face projects, positionwise — the comparand of {@link SameShapes}. */
185
+ type FaceShapes<F extends AnyFace> = F extends Face<infer S, infer P> ? ShapesOf<S, P> : never
139
186
 
140
187
  /** The projection arity of a face. */
141
188
  type Arity<F extends AnyFace> = F["projection"]["length"]
@@ -165,31 +212,35 @@ type SameArity<A extends AnyFace, B extends AnyFace> =
165
212
  : FaceArityMismatch<Arity<A>, Arity<B>>
166
213
 
167
214
  /**
168
- * The legible domain-mismatch verdict: when the two faces of a containment,
169
- * bijection, or window project different domain labels at any position,
170
- * this type is intersected into the second face's parameter and names both
171
- * label tuples — a cross-domain pair is a COMPILE error, achieved by
172
- * string-literal comparison of descriptor shapes (the structural design's
173
- * ratified check), never by a value brand.
215
+ * The legible shape-mismatch verdict: when the two faces of a containment,
216
+ * bijection, or window project structurally incompatible fields at any
217
+ * position, this type is intersected into the second face's parameter and
218
+ * names both shape tuples — a u64 face against a str face, a bytes width
219
+ * mismatch, or an interval element mismatch is a COMPILE error.
174
220
  */
175
- interface FaceDomainMismatch<Left, Right> {
176
- readonly "face domain mismatch — positionwise domain labels must be equal on both sides": readonly [Left, Right]
221
+ interface FaceShapeMismatch<Left, Right> {
222
+ readonly "face shape mismatch — positionwise kind, width, and element must be equal on both sides": readonly [
223
+ Left,
224
+ Right
225
+ ]
177
226
  }
178
227
 
179
228
  /**
180
229
  * Resolves to `unknown` (a no-op intersection) when the two faces project
181
- * positionwise-equal domain labels, and to {@link FaceDomainMismatch}
182
- * otherwise. Equality is mutual tuple assignability over string-literal
183
- * labels (`undefined` pairs only with `undefined` an unlabeled field
184
- * links only unlabeled fields, mirroring Rust where `u64` and `u64 as
185
- * HolderId` are different host types).
186
- */
187
- type SameDomains<A extends AnyFace, B extends AnyFace> =
188
- FaceDomains<A> extends FaceDomains<B>
189
- ? FaceDomains<B> extends FaceDomains<A>
230
+ * positionwise-equal structural shapes, and to {@link FaceShapeMismatch}
231
+ * otherwise. Equality is mutual tuple assignability over the
232
+ * kind/width/element triples. This is the whole construction-time wall
233
+ * deliberately: there is no domain to compare here. The domain wall lives
234
+ * where domains are BORN: `schema()` computes every field's class from the
235
+ * statement list and holds the one-generator-per-class law, and query
236
+ * joins compare class names off the schema type.
237
+ */
238
+ type SameShapes<A extends AnyFace, B extends AnyFace> =
239
+ FaceShapes<A> extends FaceShapes<B>
240
+ ? FaceShapes<B> extends FaceShapes<A>
190
241
  ? unknown
191
- : FaceDomainMismatch<FaceDomains<A>, FaceDomains<B>>
192
- : FaceDomainMismatch<FaceDomains<A>, FaceDomains<B>>
242
+ : FaceShapeMismatch<FaceShapes<A>, FaceShapes<B>>
243
+ : FaceShapeMismatch<FaceShapes<A>, FaceShapes<B>>
193
244
 
194
245
  /**
195
246
  * Projects a face — one spelling, arity-generic: `on(Account, "holder")`
@@ -206,7 +257,7 @@ function on<S extends FaceSource, const P extends readonly [FaceFields<S>, ...Fa
206
257
  source: S,
207
258
  fields: P
208
259
  ): Face<S, P>
209
- function on(source: FaceSource, fields: string | readonly string[]): Face<FaceSource, readonly string[]> {
260
+ function on<S extends FaceSource>(source: S, fields: string | readonly string[]): Face<S, readonly string[]> {
210
261
  const projection: readonly string[] = Object.freeze(typeof fields === "string" ? [fields] : [...fields])
211
262
  const parts = faceParts(source)
212
263
  const data: FaceData = Object.freeze({
@@ -214,7 +265,33 @@ function on(source: FaceSource, fields: string | readonly string[]): Face<FaceSo
214
265
  projection,
215
266
  selection: parts.selection
216
267
  })
217
- return Object.freeze({ source, projection, data })
268
+ const value = Object.freeze({ source, projection, data })
269
+ if (!faceMinted<S, readonly string[]>(value, source, projection)) {
270
+ throw errors.new(`face over ${parts.owner.name}: face construction incomplete`)
271
+ }
272
+ return value
273
+ }
274
+
275
+ /**
276
+ * The trusted seam of the face mint (the `refsComplete` pattern): the
277
+ * checkable facts — the value carries exactly the source and projection it
278
+ * was built from, and `data.owner` is exactly the owner {@link faceParts}
279
+ * resolves for that source — are verified before the wide construction is
280
+ * admitted at the exact {@link Face} type (whose `data` claims the owner at
281
+ * its precise type, the carrier the schema-level law-typing reads).
282
+ */
283
+ function faceMinted<S extends FaceSource, P extends readonly string[]>(
284
+ value: { readonly source: FaceSource; readonly projection: readonly string[]; readonly data: FaceData },
285
+ source: S,
286
+ projection: P
287
+ ): value is Face<S, P> {
288
+ const owner = "relation" in source ? source.relation : source
289
+ return (
290
+ value.source === source &&
291
+ value.projection === projection &&
292
+ value.data.owner === owner &&
293
+ value.data.projection === projection
294
+ )
218
295
  }
219
296
 
220
297
  /**
@@ -241,13 +318,14 @@ export type {
241
318
  Face,
242
319
  FaceArityMismatch,
243
320
  FaceData,
244
- FaceDomainMismatch,
245
- FaceDomains,
246
321
  FaceFields,
247
322
  FaceOwner,
323
+ FaceShapeMismatch,
324
+ FaceShapes,
248
325
  FaceSource,
249
326
  OneOf,
327
+ OwnerOf,
250
328
  SameArity,
251
- SameDomains
329
+ SameShapes
252
330
  }
253
331
  export { on, oneOf, renderFace }