@bjornpagen/bumbledb 0.14.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.
- package/COOKBOOK.md +58 -62
- package/README.md +82 -56
- package/dist/capacity.d.ts +24 -136
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js +18 -40
- package/dist/capacity.js.map +1 -1
- package/dist/closed.d.ts +0 -156
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +0 -104
- package/dist/closed.js.map +1 -1
- package/dist/db.d.ts +93 -290
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +713 -556
- package/dist/db.js.map +1 -1
- package/dist/face.d.ts +0 -133
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +0 -33
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +1 -145
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +2 -91
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +13 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -20
- package/dist/index.js.map +1 -1
- package/dist/law.d.ts +111 -93
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +23 -27
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts +9 -35
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +8 -53
- package/dist/lower.js.map +1 -1
- package/dist/marshal.d.ts +0 -65
- package/dist/marshal.d.ts.map +1 -1
- package/dist/marshal.js +0 -72
- package/dist/marshal.js.map +1 -1
- package/dist/native.d.ts +97 -390
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +39 -61
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +10 -276
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +1 -96
- package/dist/query/atom.js.map +1 -1
- package/dist/query/find.d.ts +10 -76
- package/dist/query/find.d.ts.map +1 -1
- package/dist/query/find.js +0 -30
- package/dist/query/find.js.map +1 -1
- package/dist/query/lower.d.ts +64 -146
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +19 -256
- package/dist/query/lower.js.map +1 -1
- package/dist/query/parse-ir.d.ts +0 -7
- package/dist/query/parse-ir.d.ts.map +1 -1
- package/dist/query/parse-ir.js +1 -13
- package/dist/query/parse-ir.js.map +1 -1
- package/dist/query/run.d.ts +0 -36
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +0 -44
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +24 -180
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +2 -66
- package/dist/query/scope.js.map +1 -1
- package/dist/relation.d.ts +2 -50
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +2 -37
- package/dist/relation.js.map +1 -1
- package/dist/schema.d.ts +13 -63
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +118 -92
- package/dist/schema.js.map +1 -1
- package/dist/spec.d.ts +1 -140
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js +1 -68
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +6 -137
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +16 -119
- package/dist/statements.js.map +1 -1
- package/package.json +3 -3
- package/src/capacity.ts +26 -140
- package/src/closed.ts +5 -206
- package/src/db.ts +997 -854
- package/src/face.ts +0 -142
- package/src/fields.ts +4 -172
- package/src/index.ts +32 -35
- package/src/law.ts +201 -129
- package/src/lower.ts +8 -53
- package/src/marshal.ts +1 -85
- package/src/native.ts +192 -413
- package/src/query/atom.ts +26 -313
- package/src/query/find.ts +24 -110
- package/src/query/lower.ts +132 -377
- package/src/query/parse-ir.ts +1 -14
- package/src/query/run.ts +0 -45
- package/src/query/scope.ts +25 -186
- package/src/relation.ts +2 -66
- package/src/schema.ts +143 -122
- package/src/spec.ts +1 -160
- package/src/statements.ts +22 -174
- package/dist/exhume.d.ts +0 -143
- package/dist/exhume.d.ts.map +0 -1
- package/dist/exhume.js +0 -166
- package/dist/exhume.js.map +0 -1
- package/src/exhume.ts +0 -267
package/src/lower.ts
CHANGED
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
* data (`#spec.ts`), which the napi bridge marshals verbatim. Lowering is
|
|
4
4
|
* TOTAL on well-typed inputs — no validation lives here beyond what the
|
|
5
5
|
* types and the construction boundaries already guarantee — and it is the
|
|
6
|
-
* only place statement internals are read for the wire.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* only place statement internals are read for the wire. In particular,
|
|
7
|
+
* lowering never emits an engine-refused containment target: it accepts
|
|
8
|
+
* only `schema` outputs, and `schema`'s target-key wall already
|
|
9
|
+
* refused any non-key target projection (60-containment-parity —
|
|
10
|
+
* totality INHERITED, not re-checked). Ordering is declaration order
|
|
11
|
+
* throughout, and every output object is built with one fixed key order,
|
|
12
|
+
* so serialization is deterministic (byte-stable).
|
|
9
13
|
*/
|
|
10
14
|
|
|
11
15
|
import * as errors from "@superbuilders/errors"
|
|
@@ -27,12 +31,6 @@ import type {
|
|
|
27
31
|
} from "#spec.ts"
|
|
28
32
|
import type { Statement } from "#statements.ts"
|
|
29
33
|
|
|
30
|
-
/**
|
|
31
|
-
* Lowers one field descriptor's structural type to the wire
|
|
32
|
-
* {@link ValueTypeSpec}: the S1 kind tags map 1:1 onto the `ValueType`
|
|
33
|
-
* vocabulary (`str` spells `string`, `bytes` spells `fixedBytes` with its
|
|
34
|
-
* width label as `len`; intervals carry element and width labels through).
|
|
35
|
-
*/
|
|
36
34
|
function valueTypeOf(field: AnyField): ValueTypeSpec {
|
|
37
35
|
switch (field.kind) {
|
|
38
36
|
case "bool":
|
|
@@ -50,16 +48,6 @@ function valueTypeOf(field: AnyField): ValueTypeSpec {
|
|
|
50
48
|
}
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
/**
|
|
54
|
-
* Lowers one field descriptor to its {@link FieldSpec}: the structural
|
|
55
|
-
* type, the structural fresh mark (`fresh` is the literal `true` exactly
|
|
56
|
-
* on a fresh-marked u64 — on an unmarked one the property holds the marked
|
|
57
|
-
* descriptor, never `true`), and the wire's `newtype` — the COMPUTED class
|
|
58
|
-
* name `schema()` derived from the statement list (the laws type the
|
|
59
|
-
* columns), `undefined` on a bare field. The engine reads newtypes for
|
|
60
|
-
* handle resolution and the coherence check only and DROPS them at
|
|
61
|
-
* descriptor lowering — class names are never fingerprinted.
|
|
62
|
-
*/
|
|
63
51
|
function lowerField(name: string, field: AnyField, newtype: string | undefined): FieldSpec {
|
|
64
52
|
return {
|
|
65
53
|
name,
|
|
@@ -69,7 +57,6 @@ function lowerField(name: string, field: AnyField, newtype: string | undefined):
|
|
|
69
57
|
}
|
|
70
58
|
}
|
|
71
59
|
|
|
72
|
-
/** Lowers one face to a `SideSpec`: names only, σ as (field, set) pairs. */
|
|
73
60
|
function lowerFace(face: FaceData): SideSpec {
|
|
74
61
|
return {
|
|
75
62
|
relation: face.owner.name,
|
|
@@ -80,12 +67,6 @@ function lowerFace(face: FaceData): SideSpec {
|
|
|
80
67
|
}
|
|
81
68
|
}
|
|
82
69
|
|
|
83
|
-
/**
|
|
84
|
-
* Lowers one statement. `mirrors` stays ONE spec statement
|
|
85
|
-
* (`bidirectional: true`) — the engine performs the `==` lowering to two
|
|
86
|
-
* adjacent containments, `source <= target` first, exactly as the macro
|
|
87
|
-
* does.
|
|
88
|
-
*/
|
|
89
70
|
function lowerStatement(statement: Statement): StatementSpec {
|
|
90
71
|
const data = statement.data
|
|
91
72
|
switch (data.kind) {
|
|
@@ -116,13 +97,6 @@ function lowerStatement(statement: Statement): StatementSpec {
|
|
|
116
97
|
}
|
|
117
98
|
}
|
|
118
99
|
|
|
119
|
-
/**
|
|
120
|
-
* Lowers one ordinary relation to its `RelationSpec` fragment: fields in
|
|
121
|
-
* declaration order, each carrying its law-computed class name as the
|
|
122
|
-
* `newtype` (`classes` — the schema's class record for this relation;
|
|
123
|
-
* bare fields carry `undefined`), `closed: undefined` (the option is the
|
|
124
|
-
* kind — one sum, R7).
|
|
125
|
-
*/
|
|
126
100
|
function lowerRelation(relation: AnyRelation, classes: RelationClasses): RelationSpec {
|
|
127
101
|
const fields: FieldSpec[] = relation.data.fields.map(function lowerDeclared(declared) {
|
|
128
102
|
return lowerField(declared.name, declared.field, classes[declared.name])
|
|
@@ -130,16 +104,6 @@ function lowerRelation(relation: AnyRelation, classes: RelationClasses): Relatio
|
|
|
130
104
|
return { name: relation.name, fields, closed: undefined }
|
|
131
105
|
}
|
|
132
106
|
|
|
133
|
-
/**
|
|
134
|
-
* Lowers one closed relation to its `RelationSpec` fragment: declared
|
|
135
|
-
* intrinsic columns only (the engine materializes the synthetic `id`) and
|
|
136
|
-
* the fused closedness sum (R7) — the handle newtype (the COMPUTED class
|
|
137
|
-
* name of the id's generator class, `"Kind.id"`, always present: a closed
|
|
138
|
-
* id is a generator; every referencing field shares it by law, which is
|
|
139
|
-
* how the engine resolves a handle literal back to its roster) together
|
|
140
|
-
* with the ground axioms in declaration order (row id = index); the
|
|
141
|
-
* literals were already lowered at `closed()` construction.
|
|
142
|
-
*/
|
|
143
107
|
function lowerClosed(member: AnyClosed, classes: RelationClasses): RelationSpec {
|
|
144
108
|
const fields: FieldSpec[] = member.data.columns.map(function lowerColumn(column) {
|
|
145
109
|
return lowerField(column.name, column.field, classes[column.name])
|
|
@@ -154,17 +118,8 @@ function lowerClosed(member: AnyClosed, classes: RelationClasses): RelationSpec
|
|
|
154
118
|
return { name: member.name, fields, closed: { newtype, rows } }
|
|
155
119
|
}
|
|
156
120
|
|
|
157
|
-
/** The frozen empty class record a relation outside the schema's map lowers under (nothing classed). */
|
|
158
121
|
const noClasses: RelationClasses = Object.freeze({})
|
|
159
122
|
|
|
160
|
-
/**
|
|
161
|
-
* Lowers a whole theory to the `SchemaSpec` the bridge takes: relations in
|
|
162
|
-
* record declaration order, DECLARED statements only in written order (the
|
|
163
|
-
* engine materializes the fresh-implied and closed auto-keys itself), and
|
|
164
|
-
* every field's `newtype` slot fed from the schema's law-computed class
|
|
165
|
-
* map — the ONE domain authority (fingerprint-neutral: the engine drops
|
|
166
|
-
* newtypes at descriptor lowering).
|
|
167
|
-
*/
|
|
168
123
|
function lower(theory: AnySchema): SchemaSpec {
|
|
169
124
|
const relations: RelationSpec[] = Object.entries(theory.relations).map(function lowerMember([name, member]) {
|
|
170
125
|
const classes = theory.classes[name] ?? noClasses
|
|
@@ -176,4 +131,4 @@ function lower(theory: AnySchema): SchemaSpec {
|
|
|
176
131
|
return { relations, statements: theory.statements.map(lowerStatement) }
|
|
177
132
|
}
|
|
178
133
|
|
|
179
|
-
export { lower
|
|
134
|
+
export { lower }
|
package/src/marshal.ts
CHANGED
|
@@ -33,42 +33,14 @@ import { isIntervalValue, literalShapeError, rosterOf } from "#fields.ts"
|
|
|
33
33
|
import type { FactValue } from "#native.ts"
|
|
34
34
|
import type { AnyRelation, Fact, FreshKeys, RelationData } from "#relation.ts"
|
|
35
35
|
|
|
36
|
-
/**
|
|
37
|
-
* The fresh-mark probe: `true` exactly for a `.fresh`-marked u64 descriptor
|
|
38
|
-
* (the S1 kernel's one structural mark — an unmarked u64's `fresh` property
|
|
39
|
-
* holds the MARKED descriptor, so the probe compares against the literal
|
|
40
|
-
* `true`, never truthiness).
|
|
41
|
-
*/
|
|
42
36
|
function isFreshField(field: AnyField): boolean {
|
|
43
37
|
return "fresh" in field && field.fresh === true
|
|
44
38
|
}
|
|
45
39
|
|
|
46
|
-
/**
|
|
47
|
-
* The key object `get` reads through. THE PRIMARY-KEY RULE: `get` always
|
|
48
|
-
* reads through the PRIMARY candidate key — the first-declared one in the
|
|
49
|
-
* engine's materialized statement order (fresh-implied keys first, closed
|
|
50
|
-
* auto-keys second, declared `key()` statements last), so a fresh-bearing
|
|
51
|
-
* relation's primary key is always its fresh field. When `R` carries a
|
|
52
|
-
* fresh field the type demands exactly that field; otherwise the primary
|
|
53
|
-
* key lives in the schema's statement list, which the type system cannot
|
|
54
|
-
* see (the schema's statement list is not carried in the schema's type,
|
|
55
|
-
* only in the KeyStatement values themselves), so the type admits any partial fact
|
|
56
|
-
* and the projection is verified at runtime — a missing key field throws
|
|
57
|
-
* naming the projection.
|
|
58
|
-
*/
|
|
59
40
|
type KeyFact<R extends AnyRelation> = [FreshKeys<R>] extends [never]
|
|
60
41
|
? Partial<Fact<R>>
|
|
61
42
|
: { [K in FreshKeys<R>]: Fact<R>[K] }
|
|
62
43
|
|
|
63
|
-
/**
|
|
64
|
-
* Reprojects any host object to a string-indexed record — the boundary
|
|
65
|
-
* through which generic fact objects (whose type parameters carry no index
|
|
66
|
-
* signature) enter the name-directed marshaling below, without a cast. An
|
|
67
|
-
* ALLOCATION-FREE IDENTITY (the admission predicate is the type
|
|
68
|
-
* reprojection; the value passes through untouched): every consumer
|
|
69
|
-
* downstream — `rowOf`, `keyRowOf`, the query param marshal — only READS
|
|
70
|
-
* properties, so no copy is warranted.
|
|
71
|
-
*/
|
|
72
44
|
function recordOf(fact: object): Readonly<Record<string, unknown>> {
|
|
73
45
|
if (!isStringIndexed(fact)) {
|
|
74
46
|
throw errors.new("fact object is not string-indexable")
|
|
@@ -76,13 +48,6 @@ function recordOf(fact: object): Readonly<Record<string, unknown>> {
|
|
|
76
48
|
return fact
|
|
77
49
|
}
|
|
78
50
|
|
|
79
|
-
/**
|
|
80
|
-
* The trusted admission seam of {@link recordOf}: every JS object IS
|
|
81
|
-
* string-indexable (property reads on absent names yield `undefined`,
|
|
82
|
-
* which every consumer already guards), so the predicate verifies the one
|
|
83
|
-
* checkable fact — objecthood — and admits the value at the indexed type
|
|
84
|
-
* without a copy or a cast.
|
|
85
|
-
*/
|
|
86
51
|
function isStringIndexed(value: object): value is Readonly<Record<string, unknown>> {
|
|
87
52
|
return typeof value === "object" || typeof value === "function"
|
|
88
53
|
}
|
|
@@ -106,14 +71,6 @@ function closedCellOf(context: string, closed: ClosedRoster, name: string): Fact
|
|
|
106
71
|
return BigInt(id)
|
|
107
72
|
}
|
|
108
73
|
|
|
109
|
-
/**
|
|
110
|
-
* The read half of the closed bijection: one u64 row id back to its handle
|
|
111
|
-
* NAME (`Number(cell)` is safe — the sealed extension holds at most 256
|
|
112
|
-
* rows, engine law). An id outside the roster THROWS pointed, never a
|
|
113
|
-
* silent fallback and never `undefined`: the state is reachable only in a
|
|
114
|
-
* store whose closed-typed column was never pinned by its containment law,
|
|
115
|
-
* and the error names that missing piece.
|
|
116
|
-
*/
|
|
117
74
|
function handleOf(context: string, closed: ClosedRoster, cell: FactValue): string {
|
|
118
75
|
if (typeof cell !== "bigint") {
|
|
119
76
|
throw literalShapeError(context, `a ${closed.name} handle id (bigint)`, cell)
|
|
@@ -127,17 +84,6 @@ function handleOf(context: string, closed: ClosedRoster, cell: FactValue): strin
|
|
|
127
84
|
return handle
|
|
128
85
|
}
|
|
129
86
|
|
|
130
|
-
/**
|
|
131
|
-
* Marshals one host cell at its field position to the natural wire value,
|
|
132
|
-
* schema-directed by the field descriptor's structural kind (never
|
|
133
|
-
* guessed). A closed-referencing cell arrives as its handle NAME and
|
|
134
|
-
* lowers through {@link closedCellOf} — the arm precedes the switch
|
|
135
|
-
* because a closed reference is structurally a u64 descriptor plus the
|
|
136
|
-
* roster (the same precedence `Infer` pins at the type level). Everything
|
|
137
|
-
* else is bare, so the runtime values ARE the wire's natural JS values;
|
|
138
|
-
* widths and domain labels are the engine's own judgment at the write
|
|
139
|
-
* boundary.
|
|
140
|
-
*/
|
|
141
87
|
function cellOf(context: string, field: AnyField, value: unknown): FactValue {
|
|
142
88
|
const roster = rosterOf(field)
|
|
143
89
|
if (roster !== undefined) {
|
|
@@ -164,13 +110,7 @@ function cellOf(context: string, field: AnyField, value: unknown): FactValue {
|
|
|
164
110
|
if (typeof value !== "string") {
|
|
165
111
|
throw literalShapeError(context, "string", value)
|
|
166
112
|
}
|
|
167
|
-
|
|
168
|
-
* A lone surrogate would be lossily replaced with U+FFFD at the
|
|
169
|
-
* bridge's UTF-8 crossing — the stored fact would differ from the
|
|
170
|
-
* written one, and distinct JS strings would collapse to one fact.
|
|
171
|
-
* The bijection law refuses it here, the one seam every write and
|
|
172
|
-
* lookup lowers through.
|
|
173
|
-
*/
|
|
113
|
+
|
|
174
114
|
if (!value.isWellFormed()) {
|
|
175
115
|
throw literalShapeError(context, "well-formed string", value)
|
|
176
116
|
}
|
|
@@ -191,11 +131,6 @@ function cellOf(context: string, field: AnyField, value: unknown): FactValue {
|
|
|
191
131
|
}
|
|
192
132
|
}
|
|
193
133
|
|
|
194
|
-
/**
|
|
195
|
-
* Marshals one complete fact object to its positional row, in field
|
|
196
|
-
* declaration order (= ordinal ids). Every declared field must be present.
|
|
197
|
-
* Mint with `tx.reserve` first; insert takes complete facts.
|
|
198
|
-
*/
|
|
199
134
|
function rowOf(relation: RelationData, fact: Readonly<Record<string, unknown>>): FactValue[] {
|
|
200
135
|
return relation.fields.map(function marshalCell(declared) {
|
|
201
136
|
const value = fact[declared.name]
|
|
@@ -206,12 +141,6 @@ function rowOf(relation: RelationData, fact: Readonly<Record<string, unknown>>):
|
|
|
206
141
|
})
|
|
207
142
|
}
|
|
208
143
|
|
|
209
|
-
/**
|
|
210
|
-
* Marshals a key object through a key statement's projection, in the
|
|
211
|
-
* statement's projection order (what the engine's keyed point reads take).
|
|
212
|
-
* A key field absent from the object throws naming the primary projection
|
|
213
|
-
* (the {@link KeyFact} rule's runtime half).
|
|
214
|
-
*/
|
|
215
144
|
function keyRowOf(
|
|
216
145
|
relation: RelationData,
|
|
217
146
|
projection: readonly string[],
|
|
@@ -234,12 +163,6 @@ function keyRowOf(
|
|
|
234
163
|
})
|
|
235
164
|
}
|
|
236
165
|
|
|
237
|
-
/**
|
|
238
|
-
* The read-side trusted seam: a decoded row carrying every declared field
|
|
239
|
-
* IS a fact of its relation — the engine admitted the row, and the values
|
|
240
|
-
* are BARE structural values, so nothing is asserted beyond presence (no
|
|
241
|
-
* brand exists to re-derive; the store is the proof carrier).
|
|
242
|
-
*/
|
|
243
166
|
function isCompleteFact<R extends AnyRelation>(
|
|
244
167
|
relation: R,
|
|
245
168
|
decoded: Readonly<Record<string, FactValue>>
|
|
@@ -249,13 +172,6 @@ function isCompleteFact<R extends AnyRelation>(
|
|
|
249
172
|
})
|
|
250
173
|
}
|
|
251
174
|
|
|
252
|
-
/**
|
|
253
|
-
* Unmarshals one positional row to the relation's named, frozen fact object
|
|
254
|
-
* of bare structural values — the inverse of {@link rowOf},
|
|
255
|
-
* ordinal-directed by the same declaration order. Closed-referencing cells
|
|
256
|
-
* lift id → handle NAME through {@link handleOf} (the read half of the
|
|
257
|
-
* bijection), so every fact a user sees speaks the roster's vocabulary.
|
|
258
|
-
*/
|
|
259
175
|
function factOf<R extends AnyRelation>(relation: R, row: readonly FactValue[]): Fact<R> {
|
|
260
176
|
const data = relation.data
|
|
261
177
|
if (row.length !== data.fields.length) {
|