@bjornpagen/bumbledb 0.4.0 → 0.5.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 (92) hide show
  1. package/COOKBOOK.md +181 -47
  2. package/README.md +4 -2
  3. package/dist/closed.d.ts +30 -2
  4. package/dist/closed.d.ts.map +1 -1
  5. package/dist/closed.js +66 -20
  6. package/dist/closed.js.map +1 -1
  7. package/dist/db.d.ts +33 -6
  8. package/dist/db.d.ts.map +1 -1
  9. package/dist/db.js +87 -70
  10. package/dist/db.js.map +1 -1
  11. package/dist/exhume.d.ts.map +1 -1
  12. package/dist/exhume.js +1 -14
  13. package/dist/exhume.js.map +1 -1
  14. package/dist/face.d.ts +1 -1
  15. package/dist/face.d.ts.map +1 -1
  16. package/dist/face.js +2 -1
  17. package/dist/face.js.map +1 -1
  18. package/dist/fields.d.ts +18 -1
  19. package/dist/fields.d.ts.map +1 -1
  20. package/dist/fields.js +44 -16
  21. package/dist/fields.js.map +1 -1
  22. package/dist/index.d.ts +11 -6
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +8 -4
  25. package/dist/index.js.map +1 -1
  26. package/dist/law.d.ts +2 -1
  27. package/dist/law.d.ts.map +1 -1
  28. package/dist/law.js +15 -14
  29. package/dist/law.js.map +1 -1
  30. package/dist/lower.d.ts.map +1 -1
  31. package/dist/lower.js +1 -7
  32. package/dist/lower.js.map +1 -1
  33. package/dist/marshal.d.ts.map +1 -1
  34. package/dist/marshal.js +15 -27
  35. package/dist/marshal.js.map +1 -1
  36. package/dist/native.d.ts +21 -2
  37. package/dist/native.d.ts.map +1 -1
  38. package/dist/native.js +20 -3
  39. package/dist/native.js.map +1 -1
  40. package/dist/order.d.ts +36 -0
  41. package/dist/order.d.ts.map +1 -0
  42. package/dist/order.js +135 -0
  43. package/dist/order.js.map +1 -0
  44. package/dist/query/atom.d.ts +18 -15
  45. package/dist/query/atom.d.ts.map +1 -1
  46. package/dist/query/atom.js +9 -16
  47. package/dist/query/atom.js.map +1 -1
  48. package/dist/query/lower.d.ts +5 -8
  49. package/dist/query/lower.d.ts.map +1 -1
  50. package/dist/query/lower.js +87 -76
  51. package/dist/query/lower.js.map +1 -1
  52. package/dist/query/predicate.d.ts.map +1 -1
  53. package/dist/query/predicate.js +34 -2
  54. package/dist/query/predicate.js.map +1 -1
  55. package/dist/query/run.d.ts.map +1 -1
  56. package/dist/query/run.js +1 -2
  57. package/dist/query/run.js.map +1 -1
  58. package/dist/query/scope.d.ts +2 -16
  59. package/dist/query/scope.d.ts.map +1 -1
  60. package/dist/query/scope.js +7 -47
  61. package/dist/query/scope.js.map +1 -1
  62. package/dist/relation.d.ts +9 -22
  63. package/dist/relation.d.ts.map +1 -1
  64. package/dist/relation.js +9 -28
  65. package/dist/relation.js.map +1 -1
  66. package/dist/schema.d.ts.map +1 -1
  67. package/dist/schema.js +7 -31
  68. package/dist/schema.js.map +1 -1
  69. package/dist/statements.d.ts +5 -2
  70. package/dist/statements.d.ts.map +1 -1
  71. package/dist/statements.js +30 -35
  72. package/dist/statements.js.map +1 -1
  73. package/package.json +2 -5
  74. package/src/closed.ts +73 -28
  75. package/src/db.ts +122 -84
  76. package/src/exhume.ts +1 -15
  77. package/src/face.ts +4 -3
  78. package/src/fields.ts +58 -16
  79. package/src/index.ts +10 -8
  80. package/src/law.ts +15 -14
  81. package/src/lower.ts +2 -9
  82. package/src/marshal.ts +15 -31
  83. package/src/native.ts +22 -4
  84. package/src/order.ts +156 -0
  85. package/src/query/atom.ts +13 -21
  86. package/src/query/lower.ts +90 -91
  87. package/src/query/predicate.ts +39 -4
  88. package/src/query/run.ts +1 -3
  89. package/src/query/scope.ts +7 -59
  90. package/src/relation.ts +9 -51
  91. package/src/schema.ts +7 -33
  92. package/src/statements.ts +33 -38
@@ -12,8 +12,11 @@
12
12
  * schema type (the minimal kernel — descriptors are pure structure) and
13
13
  * constrained positionwise equal, so a u64 face against a str face, a
14
14
  * bytes width mismatch, an interval element mismatch, or a bare column
15
- * against a closed reference is a compile error. The ROSTER slot carries a
16
- * construction-time runtime twin here ({@link assertRosterAgreement}
15
+ * against a closed reference is a compile error. TWO of those walls carry
16
+ * construction-time runtime twins here for untyped callers: ARITY
17
+ * ({@link assertArityAgreement} — cleanup-0.5.0 ruling 9: an
18
+ * arity-mismatched pairing fails at the statement, never by silent
19
+ * truncation) and the ROSTER slot ({@link assertRosterAgreement} —
17
20
  * roster IDENTITY, positionwise: a closed vocabulary's referencing column
18
21
  * is spelled with the vocabulary's own id descriptor, the ONE spelling, so
19
22
  * a plain u64 column can never alias a vocabulary through a declared law
@@ -31,42 +34,28 @@
31
34
  * authority).
32
35
  */
33
36
  import * as errors from "@superbuilders/errors";
37
+ import { isClosedMember, sealedFieldOf } from "#closed.ts";
34
38
  import { renderFace } from "#face.ts";
39
+ import { rosterOf } from "#fields.ts";
35
40
  import { renderWindow } from "#spec.ts";
36
- /**
37
- * The field descriptor one face position projects: an ordinary relation's
38
- * declared field; a closed relation's SEALED shape — the synthetic `id`
39
- * (the value's own roster-carrying descriptor, by identity) or a declared
40
- * payload column. `undefined` when the name is foreign (the type tier makes
41
- * that unwritable; the engine re-judges projections at `Db.create`).
42
- */
43
- function projectedFieldOf(face, fieldName) {
44
- const owner = face.owner;
45
- if ("axioms" in owner) {
46
- if (fieldName === "id") {
47
- return owner.id;
48
- }
49
- const column = owner.data.columns.find(function byName(candidate) {
50
- return candidate.name === fieldName;
51
- });
52
- return column?.field;
53
- }
54
- const declared = owner.data.fields.find(function byName(candidate) {
55
- return candidate.name === fieldName;
56
- });
57
- return declared?.field;
58
- }
59
- /** The roster a descriptor carries: present exactly on a closed reference, absent on every other kind. */
60
- function rosterOfField(field) {
61
- if (field !== undefined && "closed" in field) {
62
- return field.closed;
63
- }
64
- return undefined;
65
- }
66
41
  /** Renders one face position's closedness for the roster-agreement diagnostics. */
67
42
  function renderRosterSide(roster) {
68
43
  return roster === undefined ? "a bare column" : `a ${roster.name} reference`;
69
44
  }
45
+ /**
46
+ * The runtime twin of {@link SameArity} (cleanup-0.5.0 ruling 9): the two
47
+ * faces must project equally many fields, judged at CONSTRUCTION for
48
+ * untyped callers too — without it an arity-mismatched containment
49
+ * silently truncates to the shorter projection (this module's positionwise
50
+ * walk and `law.ts`'s `unionSlot` both skip unpaired positions) until
51
+ * `Db.create`'s colder engine refusal. The error carries the two faces'
52
+ * own facts: names, arities, and the rendered statement.
53
+ */
54
+ function assertArityAgreement(source, target, statement) {
55
+ if (source.projection.length !== target.projection.length) {
56
+ throw errors.new(`${source.owner.name}(${source.projection.join(", ")}) and ${target.owner.name}(${target.projection.join(", ")}) project ${source.projection.length} vs ${target.projection.length} fields — positional pairing requires both faces to project equally many — ${renderStatement(statement)}`);
57
+ }
58
+ }
70
59
  /**
71
60
  * The runtime twin of {@link SameShapes}'s roster slot: the two faces'
72
61
  * projected descriptors must agree POSITIONWISE on closedness — the same
@@ -79,6 +68,9 @@ function renderRosterSide(roster) {
79
68
  * vocabulary's own descriptor (`Kind.id`) is the ONE spelling of a closed
80
69
  * reference at this surface (the canonical-utterance law); the engine
81
70
  * cannot backstop this one — the wire carries plain u64s, no rosters.
71
+ * Arity agreement ({@link assertArityAgreement}) runs first, so the
72
+ * positionwise walk here never sees an unpaired position from a well-typed
73
+ * OR an untyped caller.
82
74
  */
83
75
  function assertRosterAgreement(source, target, statement) {
84
76
  source.projection.forEach(function agreeAt(fieldName, position) {
@@ -86,8 +78,8 @@ function assertRosterAgreement(source, target, statement) {
86
78
  if (targetField === undefined) {
87
79
  return;
88
80
  }
89
- const sourceRoster = rosterOfField(projectedFieldOf(source, fieldName));
90
- const targetRoster = rosterOfField(projectedFieldOf(target, targetField));
81
+ const sourceRoster = rosterOf(sealedFieldOf(source.owner, fieldName));
82
+ const targetRoster = rosterOf(sealedFieldOf(target.owner, targetField));
91
83
  if (sourceRoster !== targetRoster) {
92
84
  throw errors.new(`${source.owner.name}.${fieldName} is ${renderRosterSide(sourceRoster)} but ${target.owner.name}.${targetField} is ${renderRosterSide(targetRoster)} — closedness rides the descriptor: a closed reference is spelled with the vocabulary's own id descriptor (one meaning, one spelling), so faces pair closed-with-closed through one roster or bare-with-bare, never across — ${renderStatement(statement)}`);
93
85
  }
@@ -105,7 +97,7 @@ function assertRosterAgreement(source, target, statement) {
105
97
  * through the owner's schema type.
106
98
  */
107
99
  function key(relation, fields) {
108
- if (!("fields" in relation.data)) {
100
+ if (isClosedMember(relation)) {
109
101
  throw errors.new(`key(${relation.name}, ...): closedness already materializes ${relation.name}(id) -> ${relation.name} — an explicit key on a closed relation is rejected as a duplicate`);
110
102
  }
111
103
  const data = Object.freeze({
@@ -132,6 +124,7 @@ function contained(source, target) {
132
124
  bidirectional: false
133
125
  });
134
126
  const statement = Object.freeze({ data });
127
+ assertArityAgreement(data.source, data.target, statement);
135
128
  assertRosterAgreement(data.source, data.target, statement);
136
129
  return statement;
137
130
  }
@@ -152,6 +145,7 @@ function mirrors(source, target) {
152
145
  bidirectional: true
153
146
  });
154
147
  const statement = Object.freeze({ data });
148
+ assertArityAgreement(data.source, data.target, statement);
155
149
  assertRosterAgreement(data.source, data.target, statement);
156
150
  return statement;
157
151
  }
@@ -173,6 +167,7 @@ function window(target, count, source) {
173
167
  source: source.data
174
168
  });
175
169
  const statement = Object.freeze({ data });
170
+ assertArityAgreement(data.source, data.target, statement);
176
171
  assertRosterAgreement(data.source, data.target, statement);
177
172
  return statement;
178
173
  }
@@ -1 +1 @@
1
- {"version":3,"file":"statements.js","sourceRoot":"","sources":["../src/statements.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"statements.js","sourceRoot":"","sources":["../src/statements.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,10 +1,7 @@
1
1
  {
2
2
  "name": "@bjornpagen/bumbledb",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Type-theoretic TypeScript SDK for the bumbledb embedded relational engine",
5
- "module": "dist/index.js",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
5
  "type": "module",
9
6
  "exports": {
10
7
  ".": {
@@ -44,7 +41,7 @@
44
41
  "@superbuilders/errors": "^4.0.2"
45
42
  },
46
43
  "optionalDependencies": {
47
- "@bjornpagen/bumbledb-darwin-arm64": "0.4.0"
44
+ "@bjornpagen/bumbledb-darwin-arm64": "0.5.0"
48
45
  },
49
46
  "devDependencies": {
50
47
  "@biomejs/biome": "^2.0.0-beta.5",
package/src/closed.ts CHANGED
@@ -39,6 +39,7 @@ import {
39
39
  type Infer,
40
40
  literalOf
41
41
  } from "#fields.ts"
42
+ import type { AnyRelation, RelationField } from "#relation.ts"
42
43
  import { resolveSelection, type SelectionBinding, type SelectionInput } from "#relation.ts"
43
44
  import type { LiteralSpec } from "#spec.ts"
44
45
 
@@ -53,7 +54,7 @@ type PayloadField = Exclude<AnyField, { readonly fresh: true }>
53
54
  * unspellable — the sealed shape mints the synthetic `id` itself (ordinal
54
55
  * 0 of the matchable fields), so a declared column named `id` would be
55
56
  * shadowed by the synthetic slot everywhere the shape resolves by name
56
- * (`matchFieldsOf`, the projected face, `spec.rs`'s resolver). The wall is
57
+ * (`sealedFieldsOf`, the projected face, `spec.rs`'s resolver). The wall is
57
58
  * typed here and judged again at construction in {@link mintClosed} — the
58
59
  * runtime twin for untyped callers, warmer and earlier than the engine's
59
60
  * `DuplicateFieldName` at `Db.create`.
@@ -193,6 +194,48 @@ interface AnyClosed {
193
194
  readonly columns: Readonly<Record<string, PayloadField>>
194
195
  }
195
196
 
197
+ /**
198
+ * THE relation-kind discriminant — the ONE spelling of "is this schema
199
+ * member closed?" (the type tier's twin is the `AnyClosed` conditional
200
+ * arms). A closed relation's runtime description carries its handle
201
+ * roster; an ordinary relation's never does. Every runtime closed/ordinary
202
+ * fork in the SDK judges through this predicate — never a re-spelled
203
+ * structural probe.
204
+ */
205
+ function isClosedMember(member: AnyRelation | AnyClosed): member is AnyClosed {
206
+ return "handles" in member.data
207
+ }
208
+
209
+ /**
210
+ * The SEALED field list of a schema member — THE one reader of "what
211
+ * fields does this owner expose": an ordinary relation's declared fields;
212
+ * a closed relation's sealed shape — the synthetic `id` (the value's own
213
+ * roster-carrying descriptor, by identity) at ordinal 0, then the declared
214
+ * payload columns at declared index + 1 (the sealed shift, mirroring the
215
+ * engine's `SchemaDescriptor::sealed_fields`). A `ClosedColumn` is
216
+ * structurally a `RelationField`, so both kinds read uniformly.
217
+ */
218
+ function sealedFieldsOf(member: AnyRelation | AnyClosed): readonly RelationField[] {
219
+ if (isClosedMember(member)) {
220
+ return Object.freeze([Object.freeze({ name: "id", field: member.id }), ...member.data.columns])
221
+ }
222
+ return member.data.fields
223
+ }
224
+
225
+ /**
226
+ * One sealed field by name — derived from {@link sealedFieldsOf}, so the
227
+ * closed synthetic `id` resolves everywhere a name is looked up (no reader
228
+ * can silently lack the `id` arm). `undefined` when the name is foreign
229
+ * (the type tiers make that unwritable; the engine re-judges at
230
+ * `Db.create`).
231
+ */
232
+ function sealedFieldOf(member: AnyRelation | AnyClosed, fieldName: string): AnyField | undefined {
233
+ const declared = sealedFieldsOf(member).find(function byName(candidate) {
234
+ return candidate.name === fieldName
235
+ })
236
+ return declared?.field
237
+ }
238
+
196
239
  /** Narrows the two-tier second argument: a handle tuple (bare tier) or a column block (payload tier). */
197
240
  function isHandleTuple(
198
241
  shape: readonly [string, ...string[]] | Record<string, PayloadField>
@@ -219,7 +262,8 @@ function handleKeysOwn<Handles extends string>(
219
262
  * The trusted seam of the axiom-readback mint: every handle carries an own
220
263
  * frozen row and every row carries every declared column as an own
221
264
  * property — verified before the record is admitted as the typed
222
- * {@link Axioms} (the `refsComplete` analog of `relation()`).
265
+ * {@link Axioms} (the trusted-admission-seam pattern its home is
266
+ * `isTypedScope` in query/lower.ts).
223
267
  */
224
268
  function axiomsMinted<Handles extends string, Cols extends Record<string, PayloadField>>(
225
269
  record: Readonly<Record<string, object>>,
@@ -237,38 +281,22 @@ function axiomsMinted<Handles extends string, Cols extends Record<string, Payloa
237
281
  })
238
282
  }
239
283
 
240
- /**
241
- * Reads one handle's ground axiom row for lowering. The typed payload
242
- * surface makes absence unrepresentable ({@link Axioms} carries every
243
- * handle's row); the refusal below guards the one ill-typed path — payload
244
- * columns with the bare tier's absent axioms — which no public spelling
245
- * reaches.
246
- */
247
- function groundRow<Handles extends string, Cols extends Record<string, PayloadField>>(
248
- name: string,
249
- axioms: Axioms<Handles, Cols> | undefined,
250
- handle: Handles
251
- ): Readonly<Record<string, unknown>> {
252
- if (axioms === undefined) {
253
- throw errors.new(`closed relation ${name}: payload columns declared without ground axioms`)
254
- }
255
- return axioms[handle]
256
- }
257
-
258
284
  /**
259
285
  * Mints the axiom-readback record: one own frozen row per handle (the bare
260
286
  * tier's rows are empty — it declares no columns), each row a fresh copy of
261
- * its ground axiom.
287
+ * its ground axiom. Both tiers supply a REAL axioms record ({@link
288
+ * closedBare} mints its empty rows), so the columns-without-axioms state is
289
+ * unrepresentable here — no undefined arm exists to guard.
262
290
  */
263
291
  function mintAxioms<Handles extends string, Cols extends Record<string, PayloadField>>(
264
292
  name: string,
265
293
  handles: readonly Handles[],
266
294
  cols: readonly ClosedColumn[],
267
- axioms: Axioms<Handles, Cols> | undefined
295
+ axioms: Axioms<Handles, Cols>
268
296
  ): Axioms<Handles, Cols> {
269
297
  const out: Record<string, object> = {}
270
298
  for (const handle of handles) {
271
- const row = axioms === undefined ? Object.freeze({}) : Object.freeze({ ...groundRow(name, axioms, handle) })
299
+ const row = Object.freeze({ ...axioms[handle] })
272
300
  Object.defineProperty(out, handle, { value: row, enumerable: true })
273
301
  }
274
302
  Object.freeze(out)
@@ -321,12 +349,29 @@ function closed<const Name extends string, const Cols extends PayloadColumns, Ha
321
349
  return closedPayload(name, shape, axioms)
322
350
  }
323
351
 
324
- /** The bare tier's precisely-typed builder: no columns, no axioms. */
352
+ /**
353
+ * The bare tier's precisely-typed builder: no columns, and the axioms
354
+ * record is the EMPTY-ROW record over the handle roster (one own frozen
355
+ * `{}` per handle, `__proto__`-safe own-property definition) — the same
356
+ * representation the payload tier carries, so `mintClosed` never sees a
357
+ * tier fork and the columns-without-axioms state stops being spellable.
358
+ */
325
359
  function closedBare<Name extends string, Handles extends string>(
326
360
  name: Name,
327
361
  handles: readonly [Handles, ...Handles[]]
328
362
  ): Closed<Name, Handles, Record<never, never>> {
329
- return mintClosed<Name, Handles, Record<never, never>>(name, handles, {}, undefined)
363
+ const empty: Record<string, object> = {}
364
+ for (const handle of handles) {
365
+ /** A duplicated name mints one row; the roster's own duplicate refusal in {@link mintClosed} stays the judge. */
366
+ if (!Object.hasOwn(empty, handle)) {
367
+ Object.defineProperty(empty, handle, { value: Object.freeze({}), enumerable: true })
368
+ }
369
+ }
370
+ Object.freeze(empty)
371
+ if (!axiomsMinted<Handles, Record<never, never>>(empty, handles, [])) {
372
+ throw errors.new(`closed relation ${name}: bare-tier axiom-row minting incomplete`)
373
+ }
374
+ return mintClosed<Name, Handles, Record<never, never>>(name, handles, {}, empty)
330
375
  }
331
376
 
332
377
  /**
@@ -379,7 +424,7 @@ function mintClosed<Name extends string, Handles extends string, Cols extends Re
379
424
  name: Name,
380
425
  handles: readonly Handles[],
381
426
  columns: Cols,
382
- axioms: Axioms<Handles, Cols> | undefined
427
+ axioms: Axioms<Handles, Cols>
383
428
  ): Closed<Name, Handles, Cols> {
384
429
  if (handles.length === 0) {
385
430
  throw errors.new(`closed relation ${name}: at least one handle is required (an empty vocabulary declares nothing)`)
@@ -405,8 +450,8 @@ function mintClosed<Name extends string, Handles extends string, Cols extends Re
405
450
  }
406
451
  Object.freeze(cols)
407
452
  const rows: ClosedRow[] = handleList.map(function lowerRow(handle) {
453
+ const row: Readonly<Record<string, unknown>> = axioms[handle]
408
454
  const values = cols.map(function lowerAxiomLiteral(column) {
409
- const row = groundRow(name, axioms, handle)
410
455
  return Object.freeze(literalOf(column.field, row[column.name]))
411
456
  })
412
457
  return Object.freeze({ handle, values: Object.freeze(values) })
@@ -471,4 +516,4 @@ export type {
471
516
  PayloadField,
472
517
  SelectedClosed
473
518
  }
474
- export { closed }
519
+ export { closed, isClosedMember, sealedFieldOf, sealedFieldsOf }