@bjornpagen/bumbledb 0.3.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 (98) hide show
  1. package/COOKBOOK.md +246 -92
  2. package/README.md +31 -16
  3. package/dist/closed.d.ts +80 -75
  4. package/dist/closed.d.ts.map +1 -1
  5. package/dist/closed.js +102 -127
  6. package/dist/closed.js.map +1 -1
  7. package/dist/db.d.ts +37 -7
  8. package/dist/db.d.ts.map +1 -1
  9. package/dist/db.js +95 -55
  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 +40 -40
  15. package/dist/face.d.ts.map +1 -1
  16. package/dist/face.js +9 -17
  17. package/dist/face.js.map +1 -1
  18. package/dist/fields.d.ts +46 -15
  19. package/dist/fields.d.ts.map +1 -1
  20. package/dist/fields.js +58 -29
  21. package/dist/fields.js.map +1 -1
  22. package/dist/index.d.ts +13 -8
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +9 -5
  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 +33 -6
  34. package/dist/marshal.d.ts.map +1 -1
  35. package/dist/marshal.js +75 -26
  36. package/dist/marshal.js.map +1 -1
  37. package/dist/native.d.ts +21 -2
  38. package/dist/native.d.ts.map +1 -1
  39. package/dist/native.js +20 -3
  40. package/dist/native.js.map +1 -1
  41. package/dist/order.d.ts +36 -0
  42. package/dist/order.d.ts.map +1 -0
  43. package/dist/order.js +135 -0
  44. package/dist/order.js.map +1 -0
  45. package/dist/query/atom.d.ts +76 -28
  46. package/dist/query/atom.d.ts.map +1 -1
  47. package/dist/query/atom.js +12 -16
  48. package/dist/query/atom.js.map +1 -1
  49. package/dist/query/lower.d.ts +5 -8
  50. package/dist/query/lower.d.ts.map +1 -1
  51. package/dist/query/lower.js +308 -72
  52. package/dist/query/lower.js.map +1 -1
  53. package/dist/query/predicate.d.ts.map +1 -1
  54. package/dist/query/predicate.js +34 -2
  55. package/dist/query/predicate.js.map +1 -1
  56. package/dist/query/run.d.ts +15 -5
  57. package/dist/query/run.d.ts.map +1 -1
  58. package/dist/query/run.js +27 -8
  59. package/dist/query/run.js.map +1 -1
  60. package/dist/query/scope.d.ts +37 -29
  61. package/dist/query/scope.d.ts.map +1 -1
  62. package/dist/query/scope.js +19 -47
  63. package/dist/query/scope.js.map +1 -1
  64. package/dist/relation.d.ts +17 -29
  65. package/dist/relation.d.ts.map +1 -1
  66. package/dist/relation.js +41 -38
  67. package/dist/relation.js.map +1 -1
  68. package/dist/schema.d.ts.map +1 -1
  69. package/dist/schema.js +7 -31
  70. package/dist/schema.js.map +1 -1
  71. package/dist/spec.d.ts +3 -2
  72. package/dist/spec.d.ts.map +1 -1
  73. package/dist/spec.js.map +1 -1
  74. package/dist/statements.d.ts +13 -4
  75. package/dist/statements.d.ts.map +1 -1
  76. package/dist/statements.js +75 -8
  77. package/dist/statements.js.map +1 -1
  78. package/package.json +2 -5
  79. package/src/closed.ts +144 -206
  80. package/src/db.ts +143 -68
  81. package/src/exhume.ts +1 -15
  82. package/src/face.ts +38 -48
  83. package/src/fields.ts +103 -49
  84. package/src/index.ts +11 -10
  85. package/src/law.ts +15 -14
  86. package/src/lower.ts +2 -9
  87. package/src/marshal.ts +82 -31
  88. package/src/native.ts +22 -4
  89. package/src/order.ts +156 -0
  90. package/src/query/atom.ts +70 -35
  91. package/src/query/lower.ts +354 -82
  92. package/src/query/predicate.ts +39 -4
  93. package/src/query/run.ts +27 -9
  94. package/src/query/scope.ts +52 -70
  95. package/src/relation.ts +54 -68
  96. package/src/schema.ts +7 -33
  97. package/src/spec.ts +3 -2
  98. package/src/statements.ts +82 -8
package/src/statements.ts CHANGED
@@ -8,10 +8,19 @@
8
8
  * Every field reference is checked against the relation it names in the
9
9
  * TYPE — existence through {@link FaceFields} (`on(R, "nope")` does not
10
10
  * compile) and STRUCTURAL compatibility through {@link SameShapes}: the two
11
- * faces' projected kind/width/element triples are read off the schema type
12
- * (the minimal kernel — descriptors are pure structure) and constrained
13
- * positionwise equal, so a u64 face against a str face, a bytes width
14
- * mismatch, or an interval element mismatch is a compile error. Domains are
11
+ * faces' projected kind/width/element/roster quadruples are read off the
12
+ * schema type (the minimal kernel — descriptors are pure structure) and
13
+ * constrained positionwise equal, so a u64 face against a str face, a
14
+ * bytes width mismatch, an interval element mismatch, or a bare column
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} —
20
+ * roster IDENTITY, positionwise: a closed vocabulary's referencing column
21
+ * is spelled with the vocabulary's own id descriptor, the ONE spelling, so
22
+ * a plain u64 column can never alias a vocabulary through a declared law
23
+ * and the SDK's descriptor-keyed closed judgments stay sound). Domains are
15
24
  * NOT compared here — there is no domain to compare at construction: the
16
25
  * statements themselves are what define the equivalence classes, and the
17
26
  * domain wall lives where they aggregate — `schema()` (the
@@ -26,8 +35,10 @@
26
35
  */
27
36
 
28
37
  import * as errors from "@superbuilders/errors"
38
+ import { isClosedMember, sealedFieldOf } from "#closed.ts"
29
39
  import type { Count } from "#count.ts"
30
40
  import { type AnyFace, type FaceData, renderFace, type SameArity, type SameShapes } from "#face.ts"
41
+ import { type ClosedRoster, rosterOf } from "#fields.ts"
31
42
  import type { AnyRelation, RelationFields } from "#relation.ts"
32
43
  import { renderWindow, type WindowSpec } from "#spec.ts"
33
44
 
@@ -98,6 +109,60 @@ interface KeyStatement<R extends AnyRelation, Projection extends readonly string
98
109
  readonly data: KeyData<R, Projection>
99
110
  }
100
111
 
112
+ /** Renders one face position's closedness for the roster-agreement diagnostics. */
113
+ function renderRosterSide(roster: ClosedRoster | undefined): string {
114
+ return roster === undefined ? "a bare column" : `a ${roster.name} reference`
115
+ }
116
+
117
+ /**
118
+ * The runtime twin of {@link SameArity} (cleanup-0.5.0 ruling 9): the two
119
+ * faces must project equally many fields, judged at CONSTRUCTION for
120
+ * untyped callers too — without it an arity-mismatched containment
121
+ * silently truncates to the shorter projection (this module's positionwise
122
+ * walk and `law.ts`'s `unionSlot` both skip unpaired positions) until
123
+ * `Db.create`'s colder engine refusal. The error carries the two faces'
124
+ * own facts: names, arities, and the rendered statement.
125
+ */
126
+ function assertArityAgreement(source: FaceData, target: FaceData, statement: Statement): void {
127
+ if (source.projection.length !== target.projection.length) {
128
+ throw errors.new(
129
+ `${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)}`
130
+ )
131
+ }
132
+ }
133
+
134
+ /**
135
+ * The runtime twin of {@link SameShapes}'s roster slot: the two faces'
136
+ * projected descriptors must agree POSITIONWISE on closedness — the same
137
+ * roster (value identity — vocabulary identity is value identity, the
138
+ * SDK's membership rule everywhere) or none. Without this wall a plain u64
139
+ * column could alias a closed vocabulary through a declared containment
140
+ * (`docs/architecture/10-data-model.md` spells the ENGINE encoding that
141
+ * way), and every descriptor-keyed closed judgment — the orderable ban,
142
+ * the name↔id marshal, answer decode — would silently miss it. The
143
+ * vocabulary's own descriptor (`Kind.id`) is the ONE spelling of a closed
144
+ * reference at this surface (the canonical-utterance law); the engine
145
+ * cannot backstop this one — the wire carries plain u64s, no rosters.
146
+ * Arity agreement ({@link assertArityAgreement}) runs first, so the
147
+ * positionwise walk here never sees an unpaired position from a well-typed
148
+ * OR an untyped caller.
149
+ */
150
+ function assertRosterAgreement(source: FaceData, target: FaceData, statement: Statement): void {
151
+ source.projection.forEach(function agreeAt(fieldName, position) {
152
+ const targetField = target.projection[position]
153
+ if (targetField === undefined) {
154
+ return
155
+ }
156
+ const sourceRoster = rosterOf(sealedFieldOf(source.owner, fieldName))
157
+ const targetRoster = rosterOf(sealedFieldOf(target.owner, targetField))
158
+ if (sourceRoster !== targetRoster) {
159
+ throw errors.new(
160
+ `${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)}`
161
+ )
162
+ }
163
+ })
164
+ }
165
+
101
166
  /**
102
167
  * `R(X) -> R` — the FD key form, composite keys as tuples. No selection
103
168
  * parameter exists (the FD-with-selection shape is unrepresentable, as in
@@ -113,7 +178,7 @@ function key<
113
178
  R extends AnyRelation,
114
179
  const Projection extends readonly [keyof RelationFields<R> & string, ...(keyof RelationFields<R> & string)[]]
115
180
  >(relation: R, fields: Projection): KeyStatement<R, Projection> {
116
- if (!("fields" in relation.data)) {
181
+ if (isClosedMember(relation)) {
117
182
  throw errors.new(
118
183
  `key(${relation.name}, ...): closedness already materializes ${relation.name}(id) -> ${relation.name} — an explicit key on a closed relation is rejected as a duplicate`
119
184
  )
@@ -145,7 +210,10 @@ function contained<A extends AnyFace, B extends AnyFace>(
145
210
  target: target.data,
146
211
  bidirectional: false
147
212
  })
148
- return Object.freeze({ data })
213
+ const statement = Object.freeze({ data })
214
+ assertArityAgreement(data.source, data.target, statement)
215
+ assertRosterAgreement(data.source, data.target, statement)
216
+ return statement
149
217
  }
150
218
 
151
219
  /**
@@ -167,7 +235,10 @@ function mirrors<A extends AnyFace, B extends AnyFace>(
167
235
  target: target.data,
168
236
  bidirectional: true
169
237
  })
170
- return Object.freeze({ data })
238
+ const statement = Object.freeze({ data })
239
+ assertArityAgreement(data.source, data.target, statement)
240
+ assertRosterAgreement(data.source, data.target, statement)
241
+ return statement
171
242
  }
172
243
 
173
244
  /**
@@ -191,7 +262,10 @@ function window<B extends AnyFace, A extends AnyFace>(
191
262
  window: count.window,
192
263
  source: source.data
193
264
  })
194
- return Object.freeze({ data })
265
+ const statement = Object.freeze({ data })
266
+ assertArityAgreement(data.source, data.target, statement)
267
+ assertRosterAgreement(data.source, data.target, statement)
268
+ return statement
195
269
  }
196
270
 
197
271
  /**