@bjornpagen/bumbledb 0.1.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.
- package/COOKBOOK.md +1450 -0
- package/README.md +69 -30
- package/dist/closed.d.ts +157 -38
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +232 -47
- package/dist/closed.js.map +1 -1
- package/dist/count.d.ts +64 -17
- package/dist/count.d.ts.map +1 -1
- package/dist/count.js +37 -14
- package/dist/count.js.map +1 -1
- package/dist/db.d.ts +27 -8
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +33 -10
- package/dist/db.js.map +1 -1
- package/dist/exhume.d.ts +12 -11
- package/dist/exhume.d.ts.map +1 -1
- package/dist/exhume.js +7 -6
- package/dist/exhume.js.map +1 -1
- package/dist/face.d.ts +135 -30
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +44 -19
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +130 -130
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +60 -94
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +29 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -14
- package/dist/index.js.map +1 -1
- package/dist/law.d.ts +224 -0
- package/dist/law.d.ts.map +1 -0
- package/dist/law.js +224 -0
- package/dist/law.js.map +1 -0
- package/dist/lower.d.ts +17 -7
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +66 -24
- package/dist/lower.js.map +1 -1
- package/dist/marshal.d.ts +36 -21
- package/dist/marshal.d.ts.map +1 -1
- package/dist/marshal.js +41 -25
- package/dist/marshal.js.map +1 -1
- package/dist/native.d.ts +6 -2
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +2 -2
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +370 -174
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +75 -172
- package/dist/query/atom.js.map +1 -1
- package/dist/query/lower.d.ts +312 -109
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +906 -387
- package/dist/query/lower.js.map +1 -1
- package/dist/query/predicate.d.ts +70 -88
- package/dist/query/predicate.d.ts.map +1 -1
- package/dist/query/predicate.js +118 -72
- package/dist/query/predicate.js.map +1 -1
- package/dist/query/run.d.ts +19 -16
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +31 -24
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +178 -127
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +111 -108
- package/dist/query/scope.js.map +1 -1
- package/dist/query/select.d.ts +102 -80
- package/dist/query/select.d.ts.map +1 -1
- package/dist/query/select.js +39 -34
- package/dist/query/select.js.map +1 -1
- package/dist/relation.d.ts +48 -38
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +24 -19
- package/dist/relation.js.map +1 -1
- package/dist/schema.d.ts +41 -3
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +34 -9
- package/dist/schema.js.map +1 -1
- package/dist/spec.d.ts +7 -5
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +91 -36
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +42 -12
- package/dist/statements.js.map +1 -1
- package/package.json +4 -3
- package/src/closed.ts +448 -95
- package/src/count.ts +112 -18
- package/src/db.ts +45 -17
- package/src/exhume.ts +12 -11
- package/src/face.ts +211 -41
- package/src/fields.ts +199 -234
- package/src/index.ts +78 -61
- package/src/law.ts +519 -0
- package/src/lower.ts +82 -27
- package/src/marshal.ts +48 -30
- package/src/native.ts +8 -4
- package/src/query/atom.ts +525 -374
- package/src/query/lower.ts +1469 -538
- package/src/query/predicate.ts +208 -161
- package/src/query/run.ts +35 -25
- package/src/query/scope.ts +264 -218
- package/src/query/select.ts +168 -93
- package/src/relation.ts +47 -47
- package/src/schema.ts +69 -18
- package/src/spec.ts +7 -5
- package/src/statements.ts +124 -41
- package/dist/brand.d.ts +0 -59
- package/dist/brand.d.ts.map +0 -1
- package/dist/brand.js +0 -47
- package/dist/brand.js.map +0 -1
- package/src/brand.ts +0 -82
package/src/count.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cardinality-window counts — exactly five constructors, and nothing else
|
|
3
|
-
* (`docs/architecture/70-api.md` § the canonical-utterance law). The
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
3
|
+
* (`docs/architecture/70-api.md` § the canonical-utterance law). The five
|
|
4
|
+
* constructors PARTITION the legal windows, and the ban table is enforced
|
|
5
|
+
* REPRESENTATIONALLY, stronger than Rust's expansion errors, in two tiers:
|
|
6
|
+
*
|
|
7
|
+
* - **The type tier**: a banned spelling written as a LITERAL does not
|
|
8
|
+
* compile — `exactly(0n)`, `between(n, n)`, `between(0n, hi)`,
|
|
9
|
+
* `atLeast(0n)`, `atLeast(1n)`, `atMost(0n)`, and every negative bound
|
|
10
|
+
* are type errors naming the canonical form (`{n..n}`, `{0..0}`,
|
|
11
|
+
* `{0..hi}`-via-between, `{0..*}`, `{1..*}` have NO argument shape that
|
|
12
|
+
* produces them), and no sixth constructor exists at all.
|
|
13
|
+
* - **The construction tier**: a bound the type level cannot judge — a
|
|
14
|
+
* COMPUTED `bigint`, whose literal identity is erased, or an inverted
|
|
15
|
+
* `between(lo, hi)` order, which type-level bigints cannot compare — is
|
|
16
|
+
* judged here at construction with the same canonical-naming errors; and
|
|
17
|
+
* past both tiers the engine's own spec validation remains the law for a
|
|
18
|
+
* hostile FFI caller (the standing two-tier ban enforcement).
|
|
19
|
+
*
|
|
8
20
|
* Bounds are `bigint` (u64 crosses as bigint always, PRD-04's law).
|
|
9
21
|
*/
|
|
10
22
|
|
|
@@ -36,14 +48,87 @@ interface Count {
|
|
|
36
48
|
|
|
37
49
|
/** Stamps one admitted window as a frozen `Count` value. */
|
|
38
50
|
function admit(window: WindowSpec): Count {
|
|
39
|
-
|
|
51
|
+
const count: Count = { window, [admitted]: true }
|
|
52
|
+
return Object.freeze(count)
|
|
40
53
|
}
|
|
41
54
|
|
|
55
|
+
/**
|
|
56
|
+
* The legible banned-spelling verdict: intersected into a count
|
|
57
|
+
* constructor's parameter when the LITERAL argument spells a banned window,
|
|
58
|
+
* naming the canonical form — the compile-time face of the ban table.
|
|
59
|
+
*/
|
|
60
|
+
interface BannedWindow<Canonical extends string> {
|
|
61
|
+
readonly "banned window spelling — the canonical-utterance law names the one legal form": Canonical
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** `true` exactly when the literal bigint `N` is negative (out of the u64 count domain). */
|
|
65
|
+
type IsNegative<N extends bigint> = `${N}` extends `-${string}` ? true : false
|
|
66
|
+
|
|
67
|
+
/** The ban verdict on `exactly(n)`: negatives are out of domain; `{0}` is the exclusion, written `none`. */
|
|
68
|
+
type ExactlyBan<N extends bigint> = bigint extends N
|
|
69
|
+
? unknown
|
|
70
|
+
: IsNegative<N> extends true
|
|
71
|
+
? BannedWindow<"window counts are u64 — a negative count is out of domain">
|
|
72
|
+
: N extends 0n
|
|
73
|
+
? BannedWindow<"`{0}` is the exclusion — write none">
|
|
74
|
+
: unknown
|
|
75
|
+
|
|
76
|
+
/** The ban verdict on `atLeast(lo)`: `{0..*}` is vacuous; `{1..*}` is the bare containment respelled. */
|
|
77
|
+
type AtLeastBan<N extends bigint> = bigint extends N
|
|
78
|
+
? unknown
|
|
79
|
+
: IsNegative<N> extends true
|
|
80
|
+
? BannedWindow<"window counts are u64 — a negative count is out of domain">
|
|
81
|
+
: N extends 0n
|
|
82
|
+
? BannedWindow<"`{0..*}` is vacuous — it provably says nothing; delete the statement">
|
|
83
|
+
: N extends 1n
|
|
84
|
+
? BannedWindow<"`{1..*}` says only what the bare containment says — write contained(source, target)">
|
|
85
|
+
: unknown
|
|
86
|
+
|
|
87
|
+
/** The ban verdict on `atMost(hi)`: `{0..0}` is the exclusion, written `none`. */
|
|
88
|
+
type AtMostBan<N extends bigint> = bigint extends N
|
|
89
|
+
? unknown
|
|
90
|
+
: IsNegative<N> extends true
|
|
91
|
+
? BannedWindow<"window counts are u64 — a negative count is out of domain">
|
|
92
|
+
: N extends 0n
|
|
93
|
+
? BannedWindow<"`{0..0}` — the exclusion is written `{0}`: use none">
|
|
94
|
+
: unknown
|
|
95
|
+
|
|
96
|
+
/** The ban verdict on a `between` floor of zero: `{0..hi}` is the ceiling respelled (`atMost(hi)`). */
|
|
97
|
+
type BetweenFloorBan<Lo extends bigint> = Lo extends 0n
|
|
98
|
+
? BannedWindow<"`{0..hi}` — a ceiling is written atMost(hi)">
|
|
99
|
+
: unknown
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The ban verdict on `between(lo, hi)`, judged on the second bound once
|
|
103
|
+
* both literals are known: `{n..n}` is the exact count respelled
|
|
104
|
+
* (`exactly(n)`, or `none` at 0), and `{0..hi}` is the ceiling respelled
|
|
105
|
+
* (`atMost(hi)` — the five constructors PARTITION the legal windows, so
|
|
106
|
+
* the one ceiling window keeps its one spelling). Bound ORDER (`{hi..lo}`
|
|
107
|
+
* inverted) is not type-expressible — bigint literals have no type-level
|
|
108
|
+
* comparison — so inversion stays a construction error below.
|
|
109
|
+
*/
|
|
110
|
+
type BetweenBan<Lo extends bigint, Hi extends bigint> = bigint extends Lo
|
|
111
|
+
? unknown
|
|
112
|
+
: bigint extends Hi
|
|
113
|
+
? unknown
|
|
114
|
+
: IsNegative<Lo> extends true
|
|
115
|
+
? BannedWindow<"window counts are u64 — a negative bound is out of domain">
|
|
116
|
+
: IsNegative<Hi> extends true
|
|
117
|
+
? BannedWindow<"window counts are u64 — a negative bound is out of domain">
|
|
118
|
+
: Lo extends Hi
|
|
119
|
+
? Hi extends Lo
|
|
120
|
+
? Lo extends 0n
|
|
121
|
+
? BannedWindow<"`{0..0}` — the exclusion is written `{0}`: use none">
|
|
122
|
+
: BannedWindow<"`{n..n}` — an exact count is written `{n}`: use exactly(n)">
|
|
123
|
+
: BetweenFloorBan<Lo>
|
|
124
|
+
: BetweenFloorBan<Lo>
|
|
125
|
+
|
|
42
126
|
/**
|
|
43
127
|
* `{n}` — THE exact-count spelling, n ≥ 1. `exactly(0)` is the exclusion
|
|
44
|
-
* respelled
|
|
128
|
+
* respelled: unwritable as a literal ({@link ExactlyBan} names `none`),
|
|
129
|
+
* rejected at construction when computed.
|
|
45
130
|
*/
|
|
46
|
-
function exactly(n:
|
|
131
|
+
function exactly<const N extends bigint>(n: N & ExactlyBan<N>): Count {
|
|
47
132
|
if (n < 0n) {
|
|
48
133
|
throw errors.new(`window counts are u64: exactly(${n}) is out of domain`)
|
|
49
134
|
}
|
|
@@ -57,11 +142,15 @@ function exactly(n: bigint): Count {
|
|
|
57
142
|
const none: Count = admit(exclusion)
|
|
58
143
|
|
|
59
144
|
/**
|
|
60
|
-
* `{lo..hi}` — both bounds explicit,
|
|
61
|
-
* count respelled
|
|
62
|
-
*
|
|
145
|
+
* `{lo..hi}` — both bounds explicit, 1 ≤ lo < hi. `lo === hi` is the exact
|
|
146
|
+
* count respelled and `lo === 0` is the ceiling respelled: unwritable as
|
|
147
|
+
* literals ({@link BetweenBan} names `exactly(n)`, `none` at `{0..0}`, or
|
|
148
|
+
* `atMost(hi)` at a zero floor — the five constructors PARTITION the legal
|
|
149
|
+
* windows), rejected at construction when computed; an inverted window is
|
|
150
|
+
* unsatisfiable and rejected at construction (bigint literals carry no
|
|
151
|
+
* type-level order).
|
|
63
152
|
*/
|
|
64
|
-
function between(lo:
|
|
153
|
+
function between<const Lo extends bigint, const Hi extends bigint>(lo: Lo, hi: Hi & BetweenBan<Lo, Hi>): Count {
|
|
65
154
|
if (lo < 0n || hi < 0n) {
|
|
66
155
|
throw errors.new(`window counts are u64: between(${lo}, ${hi}) is out of domain`)
|
|
67
156
|
}
|
|
@@ -76,15 +165,19 @@ function between(lo: bigint, hi: bigint): Count {
|
|
|
76
165
|
}
|
|
77
166
|
throw errors.new(`\`{${lo}..${lo}}\` — an exact count is written \`{${lo}}\`: use exactly(${lo})`)
|
|
78
167
|
}
|
|
168
|
+
if (lo === 0n) {
|
|
169
|
+
throw errors.new(`\`{0..${hi}}\` — a ceiling is written atMost: use atMost(${hi})`)
|
|
170
|
+
}
|
|
79
171
|
return admit(Object.freeze({ kind: "range", lo, hi }))
|
|
80
172
|
}
|
|
81
173
|
|
|
82
174
|
/**
|
|
83
175
|
* `{lo..*}` — a floor with no ceiling, lo ≥ 2: `atLeast(1)` says only what
|
|
84
|
-
* the bare containment says
|
|
85
|
-
*
|
|
176
|
+
* the bare containment says and `atLeast(0)` is vacuous — both unwritable
|
|
177
|
+
* as literals ({@link AtLeastBan} names the canonical form), rejected at
|
|
178
|
+
* construction when computed.
|
|
86
179
|
*/
|
|
87
|
-
function atLeast(lo:
|
|
180
|
+
function atLeast<const N extends bigint>(lo: N & AtLeastBan<N>): Count {
|
|
88
181
|
if (lo < 0n) {
|
|
89
182
|
throw errors.new(`window counts are u64: atLeast(${lo}) is out of domain`)
|
|
90
183
|
}
|
|
@@ -100,10 +193,11 @@ function atLeast(lo: bigint): Count {
|
|
|
100
193
|
}
|
|
101
194
|
|
|
102
195
|
/**
|
|
103
|
-
* `{0..hi}` — a ceiling, hi ≥ 1: `atMost(0)` is the exclusion respelled
|
|
104
|
-
*
|
|
196
|
+
* `{0..hi}` — a ceiling, hi ≥ 1: `atMost(0)` is the exclusion respelled —
|
|
197
|
+
* unwritable as a literal ({@link AtMostBan} names `none`), rejected at
|
|
198
|
+
* construction when computed.
|
|
105
199
|
*/
|
|
106
|
-
function atMost(hi:
|
|
200
|
+
function atMost<const N extends bigint>(hi: N & AtMostBan<N>): Count {
|
|
107
201
|
if (hi < 0n) {
|
|
108
202
|
throw errors.new(`window counts are u64: atMost(${hi}) is out of domain`)
|
|
109
203
|
}
|
package/src/db.ts
CHANGED
|
@@ -32,11 +32,10 @@
|
|
|
32
32
|
|
|
33
33
|
import * as path from "node:path"
|
|
34
34
|
import * as errors from "@superbuilders/errors"
|
|
35
|
-
import { phantom } from "#brand.ts"
|
|
36
35
|
import type { Exhumed } from "#exhume.ts"
|
|
37
36
|
import { exhumeStore } from "#exhume.ts"
|
|
38
37
|
import { lower } from "#lower.ts"
|
|
39
|
-
import { factOf, isMintedFresh, type KeyFact, keyRowOf, type Minted, recordOf, rowOf } from "#marshal.ts"
|
|
38
|
+
import { factOf, isFreshField, isMintedFresh, type KeyFact, keyRowOf, type Minted, recordOf, rowOf } from "#marshal.ts"
|
|
40
39
|
|
|
41
40
|
import type {
|
|
42
41
|
DbHandle,
|
|
@@ -51,7 +50,8 @@ import type {
|
|
|
51
50
|
ViolationFact as WireViolationFact
|
|
52
51
|
} from "#native.ts"
|
|
53
52
|
import { native } from "#native.ts"
|
|
54
|
-
import type {
|
|
53
|
+
import type { SelectColumn } from "#query/atom.ts"
|
|
54
|
+
import type { Query } from "#query/lower.ts"
|
|
55
55
|
import { lowerQuery } from "#query/lower.ts"
|
|
56
56
|
import { decodeAnswers, wireParams } from "#query/run.ts"
|
|
57
57
|
import type { ParamEntry, ParamsRecord } from "#query/scope.ts"
|
|
@@ -68,8 +68,8 @@ type MemberRelation<Rels extends SchemaRelations> = Extract<Rels[keyof Rels], An
|
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* The key object of a key-statement-selected `get`: exactly the selected
|
|
71
|
-
* `key()` statement's projection fields, each
|
|
72
|
-
*
|
|
71
|
+
* `key()` statement's projection fields, each at the relation's own BARE
|
|
72
|
+
* structural value type — the {@link KeyFact} rule generalized from the
|
|
73
73
|
* primary key to ANY declared key statement.
|
|
74
74
|
*/
|
|
75
75
|
type DeclaredKeyFact<R extends AnyRelation, Projection extends readonly string[]> = {
|
|
@@ -194,7 +194,7 @@ type WitnessedWriteResult<Rels extends SchemaRelations, R> =
|
|
|
194
194
|
interface Tx<Rels extends SchemaRelations> {
|
|
195
195
|
/**
|
|
196
196
|
* Records one insert. Omitted fresh fields are MINTED through the
|
|
197
|
-
* engine's alloc lane and returned
|
|
197
|
+
* engine's alloc lane and returned as bare bigints; supplying them instead
|
|
198
198
|
* preserves identity (the resupply idiom). Returns the relation's
|
|
199
199
|
* fresh cells, minted or resupplied.
|
|
200
200
|
*/
|
|
@@ -236,7 +236,7 @@ interface ReadScope<Rels extends SchemaRelations> {
|
|
|
236
236
|
* open and the generation read.
|
|
237
237
|
*/
|
|
238
238
|
readonly generation: bigint
|
|
239
|
-
/** Full-relation export in row-id order, decoded to
|
|
239
|
+
/** Full-relation export in row-id order, decoded to bare structural facts. */
|
|
240
240
|
scan<R extends MemberRelation<Rels>>(relation: R): Fact<R>[]
|
|
241
241
|
/**
|
|
242
242
|
* Committed-state point lookup through the relation's primary key
|
|
@@ -258,12 +258,22 @@ interface ReadScope<Rels extends SchemaRelations> {
|
|
|
258
258
|
/**
|
|
259
259
|
* Executes a prepared query against this scope's snapshot with the
|
|
260
260
|
* typed params object; returns the answer SET as plain rows with
|
|
261
|
-
*
|
|
261
|
+
* bare structural values (no order — the host sorts). This is the ONE
|
|
262
262
|
* execution spelling ({@link Prepared} carries no `execute`).
|
|
263
263
|
*/
|
|
264
264
|
execute<Row, Params extends ParamsRecord>(prepared: Prepared<Rels, Row, Params>, params: Params): Row[]
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
/**
|
|
268
|
+
* The module-private inference slot of {@link Prepared}: an optional symbol
|
|
269
|
+
* property (never set at runtime) that keeps the prepared value's `Row` and
|
|
270
|
+
* `Params` type arguments load-bearing, so `execute` infers the typed rows
|
|
271
|
+
* and the typed params object from the value alone — the query module's
|
|
272
|
+
* `inferred` pattern, local to this module. A type-level carrier only:
|
|
273
|
+
* values stay bare, nothing is asserted.
|
|
274
|
+
*/
|
|
275
|
+
const preparedTypes: unique symbol = Symbol("bumbledb.prepared.types")
|
|
276
|
+
|
|
267
277
|
/**
|
|
268
278
|
* One prepared query as a plain VALUE: explicit visible compilation
|
|
269
279
|
* (`db.prepare(q)` lowers, pins the plan, and surfaces every engine roster
|
|
@@ -281,7 +291,7 @@ interface Prepared<Rels extends SchemaRelations, Row, Params extends ParamsRecor
|
|
|
281
291
|
* re-prepare.
|
|
282
292
|
*/
|
|
283
293
|
staleness(snap: ReadScope<Rels>): Staleness
|
|
284
|
-
readonly [
|
|
294
|
+
readonly [preparedTypes]?: { readonly row: Row; readonly params: Params }
|
|
285
295
|
}
|
|
286
296
|
|
|
287
297
|
/**
|
|
@@ -424,7 +434,7 @@ function impliedKeyEntries(theory: AnySchema): StatementEntry[] {
|
|
|
424
434
|
continue
|
|
425
435
|
}
|
|
426
436
|
for (const declared of member.data.fields) {
|
|
427
|
-
if (declared.field
|
|
437
|
+
if (isFreshField(declared.field)) {
|
|
428
438
|
entries.push({
|
|
429
439
|
kind: "functionality",
|
|
430
440
|
statement: undefined,
|
|
@@ -642,7 +652,7 @@ function mintFreshCells(
|
|
|
642
652
|
): Record<string, FactValue> {
|
|
643
653
|
const fresh: Record<string, FactValue> = {}
|
|
644
654
|
for (const declared of relation.data.fields) {
|
|
645
|
-
if (!declared.field
|
|
655
|
+
if (!isFreshField(declared.field)) {
|
|
646
656
|
continue
|
|
647
657
|
}
|
|
648
658
|
let cell = values[declared.name]
|
|
@@ -1338,7 +1348,7 @@ function openDb<Rels extends SchemaRelations>(handle: DbHandle, theory: Schema<R
|
|
|
1338
1348
|
Object.freeze({
|
|
1339
1349
|
handle: preparedHandle,
|
|
1340
1350
|
owner,
|
|
1341
|
-
params: q.data.
|
|
1351
|
+
params: q.data.params,
|
|
1342
1352
|
select: q.data.select
|
|
1343
1353
|
})
|
|
1344
1354
|
)
|
|
@@ -1409,16 +1419,31 @@ process.once("exit", function closeCachedStores() {
|
|
|
1409
1419
|
}
|
|
1410
1420
|
})
|
|
1411
1421
|
|
|
1422
|
+
/**
|
|
1423
|
+
* The engine twin of the schema-level class wall, as a matchable value
|
|
1424
|
+
* (`errors.is`): the shared lowering rejected a spec whose statement pairs
|
|
1425
|
+
* faces with disagreeing newtype labels — the faces of a dependency agree
|
|
1426
|
+
* on their newtype, or neither carries one. UNREACHABLE through the typed
|
|
1427
|
+
* builder (the SDK computes every label from the laws, so its lowered
|
|
1428
|
+
* specs cohere by construction); a raw spec handed to the bridge is the
|
|
1429
|
+
* one road here, and the runtime referee that proves the engine judges
|
|
1430
|
+
* what the types claim.
|
|
1431
|
+
*/
|
|
1432
|
+
const ErrNewtypeMismatch = errors.new(
|
|
1433
|
+
"bumbledb newtypeMismatch: a statement pairs faces whose newtypes disagree — the faces of a dependency agree on their newtype, or neither carries one"
|
|
1434
|
+
)
|
|
1435
|
+
|
|
1412
1436
|
/**
|
|
1413
1437
|
* The one admission path both verbs share: canonical-path cache lookup
|
|
1414
1438
|
* first (a hit returns the SAME `Db` value for the identical theory, a
|
|
1415
1439
|
* typed fingerprint error for a different one, and a typed refusal for
|
|
1416
1440
|
* `create` — the store a cache entry proves initialized is exactly what
|
|
1417
1441
|
* create refuses). On a miss: lower the theory, run one bridge call, and
|
|
1418
|
-
* wrap the
|
|
1419
|
-
* validation, every issue in one message)
|
|
1420
|
-
*
|
|
1421
|
-
*
|
|
1442
|
+
* wrap the domain refusals — `schemaError` (spec resolution + schema
|
|
1443
|
+
* validation, every issue in one message), `newtypeMismatch` (the
|
|
1444
|
+
* coherence wall, {@link ErrNewtypeMismatch}), and `fingerprintMismatch`
|
|
1445
|
+
* (a different theory cannot open the store) — into typed errors carrying
|
|
1446
|
+
* the engine's message intact.
|
|
1422
1447
|
*/
|
|
1423
1448
|
function admit<Rels extends SchemaRelations>(
|
|
1424
1449
|
verb: "create" | "open",
|
|
@@ -1448,6 +1473,9 @@ function admit<Rels extends SchemaRelations>(
|
|
|
1448
1473
|
return native.dbOpen(canonical, spec)
|
|
1449
1474
|
})
|
|
1450
1475
|
if (!opened.ok) {
|
|
1476
|
+
if (opened.kind === "newtypeMismatch") {
|
|
1477
|
+
throw errors.wrap(ErrNewtypeMismatch, `${verb} ${canonical}: ${opened.message}`)
|
|
1478
|
+
}
|
|
1451
1479
|
throw errors.new(`bumbledb ${opened.kind} (${verb} ${canonical}): ${opened.message}`)
|
|
1452
1480
|
}
|
|
1453
1481
|
const manifest = bridged("fetch bumbledb manifest", function fetchManifest() {
|
|
@@ -1516,4 +1544,4 @@ export type {
|
|
|
1516
1544
|
WitnessedWriteResult,
|
|
1517
1545
|
WriteResult
|
|
1518
1546
|
}
|
|
1519
|
-
export { abandon, Db }
|
|
1547
|
+
export { abandon, Db, ErrNewtypeMismatch }
|
package/src/exhume.ts
CHANGED
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
* is read back for rebirth (exhume the old store, create the successor
|
|
9
9
|
* under the new theory, copy by NAME, re-derive).
|
|
10
10
|
*
|
|
11
|
-
* DELIBERATELY
|
|
12
|
-
* The caller's schema is the wrong theory for an exhumed store BY
|
|
11
|
+
* DELIBERATELY SCHEMA-FREE: no schema type appears anywhere on this
|
|
12
|
+
* surface. The caller's schema is the wrong theory for an exhumed store BY
|
|
13
13
|
* DEFINITION (a store the current theory could open would never need
|
|
14
|
-
* exhuming), so every value crosses
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* the
|
|
14
|
+
* exhuming), so every value crosses TYPED at its bare structural form
|
|
15
|
+
* ({@link FactValue} — bigint/string/boolean/bytes/interval, never
|
|
16
|
+
* `unknown`) and every fact is keyed by field NAME. The SDK never
|
|
17
|
+
* reconstructs a `Schema` value from the descriptor — that inverse mapping
|
|
18
|
+
* is deliberately out of scope; the rebirth tool keys by name.
|
|
18
19
|
*
|
|
19
20
|
* ZERO CLOSABLES: no value here carries a close, dispose, or release
|
|
20
21
|
* spelling. The engine-side handle (and the store's exclusive advisory
|
|
@@ -57,9 +58,9 @@ const ErrExhumeFormatMismatch = errors.new(
|
|
|
57
58
|
const ErrExhumeCorruption = errors.new("bumbledb exhume: the persisted schema descriptor fails its integrity gates")
|
|
58
59
|
|
|
59
60
|
/**
|
|
60
|
-
* One exhumed fact as a plain name-keyed record of
|
|
61
|
-
* deliberately
|
|
62
|
-
* str, `boolean` for bool, `Uint8Array` for bytes<N>, a `{ start, end }`
|
|
61
|
+
* One exhumed fact as a plain name-keyed record of bare structural values
|
|
62
|
+
* — deliberately schema-free (module doc): `bigint` for u64/i64, `string`
|
|
63
|
+
* for str, `boolean` for bool, `Uint8Array` for bytes<N>, a `{ start, end }`
|
|
63
64
|
* bigint pair for intervals. Closed-relation rows open with the synthetic
|
|
64
65
|
* `id` field, exactly as the descriptor's sealed field list declares.
|
|
65
66
|
*/
|
|
@@ -105,8 +106,8 @@ interface ExhumedRelation {
|
|
|
105
106
|
* persisted descriptor: relations in engine-id order (declaration order
|
|
106
107
|
* mints every id), each with its ordered field descriptions and closed
|
|
107
108
|
* roster — enough for a caller to key facts by name and re-insert them
|
|
108
|
-
* into a differently-fingerprinted successor store. No
|
|
109
|
-
*
|
|
109
|
+
* into a differently-fingerprinted successor store. No schema type appears
|
|
110
|
+
* here (module doc: the surface is schema-free; rows are typed bare).
|
|
110
111
|
*/
|
|
111
112
|
interface ExhumedDescriptor {
|
|
112
113
|
readonly relations: readonly ExhumedRelation[]
|