@bjornpagen/bumbledb 0.15.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 +33 -49
- package/README.md +3 -3
- 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 +7 -223
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +147 -396
- 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 +11 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -13
- 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 +25 -290
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +6 -66
- 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 +2 -2
- package/src/capacity.ts +26 -140
- package/src/closed.ts +5 -206
- package/src/db.ts +203 -692
- package/src/face.ts +0 -142
- package/src/fields.ts +4 -172
- package/src/index.ts +9 -15
- package/src/law.ts +201 -129
- package/src/lower.ts +8 -53
- package/src/marshal.ts +1 -85
- package/src/native.ts +47 -323
- 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/db.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* A store read is one callback: `db.read((instance, witness) => …)`. The
|
|
9
9
|
* instance is invalid the moment the callback returns; the witness is a
|
|
10
10
|
* cloneable token and may escape. There is no handle-shaped read and no
|
|
11
|
-
* `using snap = db.read
|
|
11
|
+
* `using snap = db.read`. Builder, owned instance, and witness
|
|
12
12
|
* implement `Symbol.dispose`. Prepared plans are plain values whose
|
|
13
13
|
* engine-side half is reclaimed by a GC finalizer — reclamation only,
|
|
14
14
|
* never correctness.
|
|
@@ -38,43 +38,38 @@ import { bridged, bridgedAsync, errorFromThrow, native } from "#native.ts";
|
|
|
38
38
|
import { lowerQuery } from "#query/lower.ts";
|
|
39
39
|
import { decodeAnswers, wireParams } from "#query/run.ts";
|
|
40
40
|
import { isStatement } from "#statements.ts";
|
|
41
|
-
function isColumnBatch(value) {
|
|
42
|
-
return !(Symbol.iterator in value);
|
|
43
|
-
}
|
|
44
|
-
function rowsOf(relation, facts) {
|
|
45
|
-
const rows = [];
|
|
46
|
-
for (const fact of facts) {
|
|
47
|
-
rows.push(rowOf(relation.data, recordOf(fact)));
|
|
48
|
-
}
|
|
49
|
-
return rows;
|
|
50
|
-
}
|
|
51
41
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
42
|
+
* The flat projector: every fact's cells land in ONE row-major
|
|
43
|
+
* `FactValue` array (length rows×arity) — no JS array per fact exists
|
|
44
|
+
* anywhere between the caller's objects and the native crossing
|
|
45
|
+
* (proposals/one-representation/20, V1) — and the row count is counted
|
|
46
|
+
* while projecting (the {@link FlatCollection} law: the stated count is
|
|
47
|
+
* what the bridge verifies against `rows × arity`, exactly, for every
|
|
48
|
+
* arity). The per-cell judgment is `cellOf` — the one cell judge `rowOf`
|
|
49
|
+
* also speaks (closed handle→id, well-formedness, interval shape) — and
|
|
50
|
+
* the missing-field refusal is `rowOf`'s, byte for byte; only the output
|
|
51
|
+
* form differs (flat, never per-row).
|
|
54
52
|
*/
|
|
55
|
-
function
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
53
|
+
function rowsOf(relation, facts) {
|
|
54
|
+
const data = relation.data;
|
|
55
|
+
const cells = [];
|
|
56
|
+
let rows = 0n;
|
|
57
|
+
for (const fact of facts) {
|
|
58
|
+
rows += 1n;
|
|
59
|
+
const record = recordOf(fact);
|
|
60
|
+
for (const declared of data.fields) {
|
|
61
|
+
const value = record[declared.name];
|
|
62
|
+
if (value === undefined) {
|
|
63
|
+
throw errors.new(`relation ${data.name}: fact is missing field ${declared.name}`);
|
|
64
|
+
}
|
|
65
|
+
cells.push(cellOf(`relation ${data.name} field ${declared.name}`, declared.field, value));
|
|
68
66
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
72
|
-
});
|
|
67
|
+
}
|
|
68
|
+
return { rows, cells };
|
|
73
69
|
}
|
|
74
|
-
function mutateCollection(relation, facts,
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
: applyRows(rowsOf(relation, facts));
|
|
70
|
+
function mutateCollection(relation, facts, apply) {
|
|
71
|
+
const flat = rowsOf(relation, facts);
|
|
72
|
+
const report = apply(flat.rows, flat.cells);
|
|
78
73
|
return Object.freeze({ submitted: report.submitted, changed: report.changed });
|
|
79
74
|
}
|
|
80
75
|
function freshRangeOf(wire) {
|
|
@@ -111,43 +106,16 @@ function freshRangeOf(wire) {
|
|
|
111
106
|
}
|
|
112
107
|
});
|
|
113
108
|
}
|
|
114
|
-
/**
|
|
115
|
-
* The runtime discriminant of {@link Abandon} values — a property probe is
|
|
116
|
-
* how `write`/`writeFrom` distinguish "abort without committing" from an
|
|
117
|
-
* ordinary callback result, never a guess about the host's own value shapes.
|
|
118
|
-
*/
|
|
119
109
|
const abandonMark = Symbol("bumbledb.abandon");
|
|
120
|
-
/**
|
|
121
|
-
* Wraps a payload in the {@link Abandon} sentinel — the one way a write
|
|
122
|
-
* callback declines to commit: `return abandon(payload)` aborts the delta
|
|
123
|
-
* (nothing is committed, not even an empty commit) and the write resolves
|
|
124
|
-
* to `{ tag: "abandoned", abandoned: payload }`, from `write` and `writeFrom`
|
|
125
|
-
* alike (R10).
|
|
126
|
-
*/
|
|
127
110
|
function abandon(payload) {
|
|
128
111
|
return Object.freeze({ [abandonMark]: true, payload });
|
|
129
112
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Narrows a write callback result to the abandon sentinel. The probe is
|
|
132
|
-
* the private {@link abandonMark} symbol only {@link abandon} sets, and
|
|
133
|
-
* `R`'s `Abandon` arm is the only way a sentinel can flow out of the
|
|
134
|
-
* callback — so the narrowed payload type is sound by construction.
|
|
135
|
-
*/
|
|
136
113
|
function isAbandon(value) {
|
|
137
114
|
return typeof value === "object" && value !== null && abandonMark in value;
|
|
138
115
|
}
|
|
139
|
-
/**
|
|
140
|
-
* The abandon outcome's trusted admission seam: the value's shape is the
|
|
141
|
-
* checkable half (the sentinel mark only {@link abandon} mints, and the
|
|
142
|
-
* outcome carrying that sentinel's own payload), and the sentinel's
|
|
143
|
-
* existence IS the proof `R` carries an `Abandon` arm — so the outcome is
|
|
144
|
-
* admitted at the conditional {@link AbandonedArm} face the type tier
|
|
145
|
-
* cannot resolve over an open `R`.
|
|
146
|
-
*/
|
|
147
116
|
function isAbandonedOutcome(outcome, sentinel) {
|
|
148
117
|
return isAbandon(sentinel) && outcome.abandoned === sentinel.payload;
|
|
149
118
|
}
|
|
150
|
-
/** Builds the abandoned write outcome from the callback's own sentinel (the R10 arm's one mint). */
|
|
151
119
|
function abandonedOutcome(sentinel) {
|
|
152
120
|
const outcome = Object.freeze({ tag: "abandoned", abandoned: sentinel.payload });
|
|
153
121
|
if (!isAbandonedOutcome(outcome, sentinel)) {
|
|
@@ -156,26 +124,63 @@ function abandonedOutcome(sentinel) {
|
|
|
156
124
|
return outcome;
|
|
157
125
|
}
|
|
158
126
|
const witnessTypes = Symbol("bumbledb.witness.types");
|
|
159
|
-
/**
|
|
160
|
-
* The module-private inference slot of {@link Prepared}: an optional symbol
|
|
161
|
-
* property (never set at runtime) that keeps the prepared value's `Row` and
|
|
162
|
-
* `Params` type arguments load-bearing, so `execute` infers the typed rows
|
|
163
|
-
* and the typed params object from the value alone — the query module's
|
|
164
|
-
* `inferred` pattern, local to this module. A type-level carrier only:
|
|
165
|
-
* values stay bare, nothing is asserted.
|
|
166
|
-
*/
|
|
167
127
|
const preparedTypes = Symbol("bumbledb.prepared.types");
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
128
|
+
function decodeOffendingFact(member, relation, fact) {
|
|
129
|
+
const declared = sealedFieldsOf(member);
|
|
130
|
+
const decoded = {};
|
|
131
|
+
for (const cell of fact.fields) {
|
|
132
|
+
const cited = declared.find(function byName(candidate) {
|
|
133
|
+
return candidate.name === cell.name;
|
|
134
|
+
});
|
|
135
|
+
const roster = rosterOf(cited?.field);
|
|
136
|
+
decoded[cell.name] =
|
|
137
|
+
roster !== undefined
|
|
138
|
+
? handleOf(`violation fact ${fact.relation} field ${cell.name}`, roster, cell.value)
|
|
139
|
+
: cell.value;
|
|
140
|
+
}
|
|
141
|
+
return Object.freeze({ relation, fact: Object.freeze(decoded) });
|
|
142
|
+
}
|
|
143
|
+
function violationFromEntry(entry, wire, facts) {
|
|
144
|
+
const canonical = wire.canonical;
|
|
145
|
+
if (entry.kind === "functionality") {
|
|
146
|
+
if (!("statement" in entry)) {
|
|
147
|
+
return Object.freeze({ kind: "functionality", statement: undefined, canonical, facts });
|
|
148
|
+
}
|
|
149
|
+
return Object.freeze({ kind: "functionality", statement: entry.statement, canonical, facts });
|
|
150
|
+
}
|
|
151
|
+
if (entry.kind === "capacity") {
|
|
152
|
+
if (wire.kind !== "capacity") {
|
|
153
|
+
throw errors.new(`bumbledb violation ${wire.statementId} is a capacity slot without a measure`);
|
|
154
|
+
}
|
|
155
|
+
return Object.freeze({
|
|
156
|
+
kind: "capacity",
|
|
157
|
+
statement: entry.statement,
|
|
158
|
+
canonical,
|
|
159
|
+
measure: wire.measure,
|
|
160
|
+
facts
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
if (wire.kind !== "containment") {
|
|
164
|
+
throw errors.new(`bumbledb violation ${wire.statementId} is a containment slot without a direction`);
|
|
165
|
+
}
|
|
166
|
+
if (entry.kind === "mirrors") {
|
|
167
|
+
return Object.freeze({
|
|
168
|
+
kind: "containment",
|
|
169
|
+
statement: entry.statement,
|
|
170
|
+
canonical,
|
|
171
|
+
direction: wire.direction,
|
|
172
|
+
orientation: entry.orientation,
|
|
173
|
+
facts
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return Object.freeze({
|
|
177
|
+
kind: "containment",
|
|
178
|
+
statement: entry.statement,
|
|
179
|
+
canonical,
|
|
180
|
+
direction: wire.direction,
|
|
181
|
+
facts
|
|
182
|
+
});
|
|
183
|
+
}
|
|
179
184
|
function materializedEntries(theory) {
|
|
180
185
|
const entries = impliedKeyEntries(theory);
|
|
181
186
|
for (const statement of theory.statements) {
|
|
@@ -183,13 +188,6 @@ function materializedEntries(theory) {
|
|
|
183
188
|
}
|
|
184
189
|
return entries;
|
|
185
190
|
}
|
|
186
|
-
/**
|
|
187
|
-
* The engine-materialized implied keys, in the engine's pinned order: one
|
|
188
|
-
* auto-key per fresh field (relation declaration order, then field order),
|
|
189
|
-
* then one closed auto-key `R(id) -> R` per closed relation (declaration
|
|
190
|
-
* order). These slots carry no SDK statement value — the engine owns them
|
|
191
|
-
* (`schema()` rejects an explicit duplicate).
|
|
192
|
-
*/
|
|
193
191
|
function impliedKeyEntries(theory) {
|
|
194
192
|
const entries = [];
|
|
195
193
|
for (const member of Object.values(theory.relations)) {
|
|
@@ -217,12 +215,6 @@ function impliedKeyEntries(theory) {
|
|
|
217
215
|
}
|
|
218
216
|
return entries;
|
|
219
217
|
}
|
|
220
|
-
/**
|
|
221
|
-
* One declared statement's materialized slots: a key or capacity statement
|
|
222
|
-
* occupies one, a `mirrors` occupies two adjacent slots (the engine lowers
|
|
223
|
-
* `==` to two containments, `source <= target` first), both owned by the
|
|
224
|
-
* one SDK value.
|
|
225
|
-
*/
|
|
226
218
|
function declaredEntries(statement) {
|
|
227
219
|
const data = statement.data;
|
|
228
220
|
switch (data.kind) {
|
|
@@ -259,26 +251,9 @@ function declaredEntries(statement) {
|
|
|
259
251
|
function isThenable(value) {
|
|
260
252
|
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
261
253
|
}
|
|
262
|
-
/**
|
|
263
|
-
* Narrows a keyed-get middle argument to a statement value (vs a key
|
|
264
|
-
* object) through the statement module's admission brand — a
|
|
265
|
-
* REPRESENTATION, never a shape probe: fact cell shapes are structurally
|
|
266
|
-
* OPEN (an interval value carrying an excess `kind` property is a legal
|
|
267
|
-
* cell), so no property probe could ever be sound here, but no host-built
|
|
268
|
-
* key object can spell the module-private brand symbol.
|
|
269
|
-
*/
|
|
270
254
|
function isStatementValue(value) {
|
|
271
255
|
return isStatement(value);
|
|
272
256
|
}
|
|
273
|
-
/**
|
|
274
|
-
* THE one selector dispatch of the `get` overload pair (primary-key vs
|
|
275
|
-
* key-statement, `docs/architecture/70-api.md` § the freeze): judges the
|
|
276
|
-
* middle argument once and hands the narrowed pieces to the chosen
|
|
277
|
-
* continuation. `Db.get` and the read scope's `get` both dispatch through
|
|
278
|
-
* here, so the two mismatch refusals speak with one voice and the symmetry
|
|
279
|
-
* rule (`db.get(...) === db.read(snap => snap.get(...))`) holds by
|
|
280
|
-
* construction.
|
|
281
|
-
*/
|
|
282
257
|
function selectKeyRead(keyOrStatement, declaredKey, byStatement, byPrimary) {
|
|
283
258
|
if (declaredKey !== undefined) {
|
|
284
259
|
if (!isStatementValue(keyOrStatement)) {
|
|
@@ -291,16 +266,6 @@ function selectKeyRead(keyOrStatement, declaredKey, byStatement, byPrimary) {
|
|
|
291
266
|
}
|
|
292
267
|
return byPrimary(keyOrStatement);
|
|
293
268
|
}
|
|
294
|
-
/**
|
|
295
|
-
* Builds the id-resolution tables from the manifest, verifying the SDK's
|
|
296
|
-
* positional mirror against the engine's reported order — any drift
|
|
297
|
-
* (count, kind, id, or membership) is a construction-time failure, never a
|
|
298
|
-
* silent misattribution of a violation to the wrong statement value. The
|
|
299
|
-
* declaration-ordinal law the query lowering leans on is verified in the
|
|
300
|
-
* same walks: relation ids and sealed field ids both equal declaration
|
|
301
|
-
* order, so a constructed `Tables` IS the proof and `prepare` inherits it
|
|
302
|
-
* structurally — never a silently misaddressed query.
|
|
303
|
-
*/
|
|
304
269
|
function tablesOf(theory, manifest) {
|
|
305
270
|
const entries = materializedEntries(theory);
|
|
306
271
|
if (entries.length !== manifest.statements.length) {
|
|
@@ -382,14 +347,7 @@ const witnessReclaimer = new FinalizationRegistry(function reclaimWitness(handle
|
|
|
382
347
|
return;
|
|
383
348
|
}
|
|
384
349
|
});
|
|
385
|
-
/** The private engine halves of this module's prepared values. */
|
|
386
350
|
const preparedPlans = new WeakMap();
|
|
387
|
-
/**
|
|
388
|
-
* Reclaims the engine-side plan of a garbage-collected {@link Prepared}
|
|
389
|
-
* value. RECLAMATION ONLY, never correctness: a plan the collector never
|
|
390
|
-
* visits is idle engine memory until process exit, and a failure to close
|
|
391
|
-
* is swallowed (there is no one left to care — the owning value is gone).
|
|
392
|
-
*/
|
|
393
351
|
const planReclaimer = new FinalizationRegistry(function reclaimPlan(handle) {
|
|
394
352
|
const closed = errors.trySync(function closePlan() {
|
|
395
353
|
native.preparedClose(handle);
|
|
@@ -404,32 +362,6 @@ const ErrUseAfterScope = errors.new("bumbledb useAfterScope: a stashed read inst
|
|
|
404
362
|
const ErrForeignPrepared = errors.new("bumbledb foreignPrepared: a prepared query met a foreign instance");
|
|
405
363
|
const ErrForeignWitness = errors.new("bumbledb foreignWitness: a witness met a foreign store");
|
|
406
364
|
function catalogMethods(theory, tables, owner, assertLive, ops) {
|
|
407
|
-
function resolveOrdinary(relation) {
|
|
408
|
-
const entry = tables.relations.get(relation.name);
|
|
409
|
-
if (entry === undefined || entry.member !== relation) {
|
|
410
|
-
throw errors.new(`relation ${relation.name} is not a member of schema ${theory.name}`);
|
|
411
|
-
}
|
|
412
|
-
if (isClosedMember(relation)) {
|
|
413
|
-
throw errors.new(`relation ${relation.name} is closed — its extension is schema data (axioms), never scanned or written`);
|
|
414
|
-
}
|
|
415
|
-
return entry;
|
|
416
|
-
}
|
|
417
|
-
function declaredKeyOf(relation, statement) {
|
|
418
|
-
const statementId = tables.statements.findIndex(function byIdentity(candidate) {
|
|
419
|
-
return "statement" in candidate && candidate.statement === statement;
|
|
420
|
-
});
|
|
421
|
-
const entry = tables.statements[statementId];
|
|
422
|
-
if (entry === undefined) {
|
|
423
|
-
throw errors.new(`keyed get statement is not a declared statement of schema ${theory.name} — statement identity is the membership rule`);
|
|
424
|
-
}
|
|
425
|
-
if (entry.kind !== "functionality") {
|
|
426
|
-
throw errors.new("keyed get takes a key() statement — containments and capacity statements key nothing");
|
|
427
|
-
}
|
|
428
|
-
if (entry.owner !== relation.name) {
|
|
429
|
-
throw errors.new(`keyed get statement keys ${entry.owner}, not ${relation.name} — the statement must be a declared key of the relation it reads`);
|
|
430
|
-
}
|
|
431
|
-
return Object.freeze({ statementId, projection: entry.projection });
|
|
432
|
-
}
|
|
433
365
|
function planOf(prepared) {
|
|
434
366
|
const plan = preparedPlans.get(prepared);
|
|
435
367
|
if (plan === undefined) {
|
|
@@ -442,16 +374,16 @@ function catalogMethods(theory, tables, owner, assertLive, ops) {
|
|
|
442
374
|
}
|
|
443
375
|
function contains(relation, fact) {
|
|
444
376
|
assertLive();
|
|
445
|
-
const entry =
|
|
377
|
+
const entry = ordinaryEntry(tables, theory, relation);
|
|
446
378
|
return bridged("bumbledb instance contains", function readContains() {
|
|
447
379
|
return ops.contains(entry.id, rowOf(relation.data, recordOf(fact)));
|
|
448
380
|
});
|
|
449
381
|
}
|
|
450
382
|
function get(relation, keyOrStatement, declaredKey) {
|
|
451
383
|
assertLive();
|
|
452
|
-
const entry =
|
|
384
|
+
const entry = ordinaryEntry(tables, theory, relation);
|
|
453
385
|
return selectKeyRead(keyOrStatement, declaredKey, function byStatement(statement, key) {
|
|
454
|
-
const selected = declaredKeyOf(relation, statement);
|
|
386
|
+
const selected = declaredKeyOf(tables, theory, relation, statement);
|
|
455
387
|
const row = bridged("bumbledb instance get", function readGet() {
|
|
456
388
|
return ops.get(entry.id, selected.statementId, keyRowOf(relation.data, selected.projection, recordOf(key)));
|
|
457
389
|
});
|
|
@@ -469,7 +401,7 @@ function catalogMethods(theory, tables, owner, assertLive, ops) {
|
|
|
469
401
|
}
|
|
470
402
|
function scan(relation) {
|
|
471
403
|
assertLive();
|
|
472
|
-
const entry =
|
|
404
|
+
const entry = ordinaryEntry(tables, theory, relation);
|
|
473
405
|
const rows = bridged("bumbledb instance scan", function readScan() {
|
|
474
406
|
return ops.scan(entry.id);
|
|
475
407
|
});
|
|
@@ -477,6 +409,13 @@ function catalogMethods(theory, tables, owner, assertLive, ops) {
|
|
|
477
409
|
return factOf(relation, row);
|
|
478
410
|
});
|
|
479
411
|
}
|
|
412
|
+
function count(relation) {
|
|
413
|
+
assertLive();
|
|
414
|
+
const entry = ordinaryEntry(tables, theory, relation);
|
|
415
|
+
return bridged("bumbledb instance count", function readCount() {
|
|
416
|
+
return ops.count(entry.id);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
480
419
|
function execute(prepared, params) {
|
|
481
420
|
assertLive();
|
|
482
421
|
const plan = planOf(prepared);
|
|
@@ -508,7 +447,7 @@ function catalogMethods(theory, tables, owner, assertLive, ops) {
|
|
|
508
447
|
planReclaimer.register(prepared, outcome.prepared);
|
|
509
448
|
return prepared;
|
|
510
449
|
}
|
|
511
|
-
return { scan, get, contains, execute, prepare };
|
|
450
|
+
return { scan, count, get, contains, execute, prepare };
|
|
512
451
|
}
|
|
513
452
|
function ordinaryEntry(tables, theory, relation) {
|
|
514
453
|
const entry = tables.relations.get(relation.name);
|
|
@@ -520,23 +459,23 @@ function ordinaryEntry(tables, theory, relation) {
|
|
|
520
459
|
}
|
|
521
460
|
return entry;
|
|
522
461
|
}
|
|
523
|
-
function
|
|
524
|
-
function
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
throw errors.new(`keyed get statement is not a declared statement of schema ${theory.name} — statement identity is the membership rule`);
|
|
531
|
-
}
|
|
532
|
-
if (entry.kind !== "functionality") {
|
|
533
|
-
throw errors.new("keyed get takes a key() statement — containments and capacity statements key nothing");
|
|
534
|
-
}
|
|
535
|
-
if (entry.owner !== relation.name) {
|
|
536
|
-
throw errors.new(`keyed get statement keys ${entry.owner}, not ${relation.name} — the statement must be a declared key of the relation it reads`);
|
|
537
|
-
}
|
|
538
|
-
return Object.freeze({ statementId, projection: entry.projection });
|
|
462
|
+
function declaredKeyOf(tables, theory, relation, statement) {
|
|
463
|
+
const statementId = tables.statements.findIndex(function byIdentity(candidate) {
|
|
464
|
+
return "statement" in candidate && candidate.statement === statement;
|
|
465
|
+
});
|
|
466
|
+
const entry = tables.statements[statementId];
|
|
467
|
+
if (entry === undefined) {
|
|
468
|
+
throw errors.new(`keyed get statement is not a declared statement of schema ${theory.name} — statement identity is the membership rule`);
|
|
539
469
|
}
|
|
470
|
+
if (entry.kind !== "functionality") {
|
|
471
|
+
throw errors.new("keyed get takes a key() statement — containments and capacity statements key nothing");
|
|
472
|
+
}
|
|
473
|
+
if (entry.owner !== relation.name) {
|
|
474
|
+
throw errors.new(`keyed get statement keys ${entry.owner}, not ${relation.name} — the statement must be a declared key of the relation it reads`);
|
|
475
|
+
}
|
|
476
|
+
return Object.freeze({ statementId, projection: entry.projection });
|
|
477
|
+
}
|
|
478
|
+
function overlayMethods(theory, tables, assertLive, reads) {
|
|
540
479
|
function contains(relation, fact) {
|
|
541
480
|
assertLive();
|
|
542
481
|
const entry = ordinaryEntry(tables, theory, relation);
|
|
@@ -553,7 +492,7 @@ function overlayMethods(theory, tables, assertLive, reads) {
|
|
|
553
492
|
assertLive();
|
|
554
493
|
const entry = ordinaryEntry(tables, theory, relation);
|
|
555
494
|
return selectKeyRead(keyOrStatement, declaredKey, function byStatement(statement, key) {
|
|
556
|
-
return readThroughKey(relation, entry, declaredKeyOf(relation, statement), recordOf(key));
|
|
495
|
+
return readThroughKey(relation, entry, declaredKeyOf(tables, theory, relation, statement), recordOf(key));
|
|
557
496
|
}, function byPrimary(key) {
|
|
558
497
|
const primaryKey = entry.primaryKey;
|
|
559
498
|
if (primaryKey === undefined) {
|
|
@@ -575,6 +514,9 @@ function createReadInstance(nativeHandle, theory, tables, owner) {
|
|
|
575
514
|
scan(relationId) {
|
|
576
515
|
return native.instanceScan(state.handle, relationId);
|
|
577
516
|
},
|
|
517
|
+
count(relationId) {
|
|
518
|
+
return native.instanceCount(state.handle, relationId);
|
|
519
|
+
},
|
|
578
520
|
contains(relationId, values) {
|
|
579
521
|
return native.instanceContains(state.handle, relationId, values);
|
|
580
522
|
},
|
|
@@ -600,12 +542,6 @@ function createReadInstance(nativeHandle, theory, tables, owner) {
|
|
|
600
542
|
instanceStates.set(instance, state);
|
|
601
543
|
return instance;
|
|
602
544
|
}
|
|
603
|
-
/**
|
|
604
|
-
* Constructs one open `Db` over an already-admitted handle: builds the
|
|
605
|
-
* id-resolution tables once and closes over them — the `Db` owns handle
|
|
606
|
-
* and tables and nothing else. Handle lifetime is the process's: the store
|
|
607
|
-
* cache holds the environment handle until the exit hook closes it.
|
|
608
|
-
*/
|
|
609
545
|
function openDb(handle, theory, manifest) {
|
|
610
546
|
const tables = tablesOf(theory, manifest);
|
|
611
547
|
/** This store's identity token: read scopes and prepared values carry it, so cross-store use is a typed refusal. */
|
|
@@ -613,111 +549,26 @@ function openDb(handle, theory, manifest) {
|
|
|
613
549
|
function isMemberName(name) {
|
|
614
550
|
return tables.relations.has(name);
|
|
615
551
|
}
|
|
616
|
-
function resolveOrdinary(relation) {
|
|
617
|
-
const entry = tables.relations.get(relation.name);
|
|
618
|
-
if (entry === undefined || entry.member !== relation) {
|
|
619
|
-
throw errors.new(`relation ${relation.name} is not a member of schema ${theory.name}`);
|
|
620
|
-
}
|
|
621
|
-
if (isClosedMember(relation)) {
|
|
622
|
-
throw errors.new(`relation ${relation.name} is closed — its extension is schema data (axioms), never scanned or written`);
|
|
623
|
-
}
|
|
624
|
-
return entry;
|
|
625
|
-
}
|
|
626
|
-
function offendingFactOf(fact) {
|
|
627
|
-
const entry = tables.relations.get(fact.relation);
|
|
628
|
-
if (entry === undefined || !isMemberName(fact.relation)) {
|
|
629
|
-
throw errors.new(`bumbledb violation cites unknown relation ${fact.relation}`);
|
|
630
|
-
}
|
|
631
|
-
const declared = sealedFieldsOf(entry.member);
|
|
632
|
-
const decoded = {};
|
|
633
|
-
for (const cell of fact.fields) {
|
|
634
|
-
const cited = declared.find(function byName(candidate) {
|
|
635
|
-
return candidate.name === cell.name;
|
|
636
|
-
});
|
|
637
|
-
const roster = rosterOf(cited?.field);
|
|
638
|
-
decoded[cell.name] =
|
|
639
|
-
roster !== undefined
|
|
640
|
-
? handleOf(`violation fact ${fact.relation} field ${cell.name}`, roster, cell.value)
|
|
641
|
-
: cell.value;
|
|
642
|
-
}
|
|
643
|
-
return Object.freeze({ relation: fact.relation, fact: Object.freeze(decoded) });
|
|
644
|
-
}
|
|
645
552
|
function violationOf(wire) {
|
|
646
553
|
const entry = tables.statements[wire.statementId];
|
|
647
554
|
if (entry === undefined) {
|
|
648
555
|
throw errors.new(`bumbledb violation cites unknown statement id ${wire.statementId}`);
|
|
649
556
|
}
|
|
650
|
-
const facts = Object.freeze(wire.facts.map(
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
return Object.freeze({ kind: "functionality", statement: undefined, canonical, facts });
|
|
655
|
-
}
|
|
656
|
-
return Object.freeze({ kind: "functionality", statement: entry.statement, canonical, facts });
|
|
657
|
-
}
|
|
658
|
-
if (entry.kind === "capacity") {
|
|
659
|
-
if (wire.kind !== "capacity") {
|
|
660
|
-
throw errors.new(`bumbledb violation ${wire.statementId} is a capacity slot without a measure`);
|
|
557
|
+
const facts = Object.freeze(wire.facts.map(function offending(fact) {
|
|
558
|
+
const rel = tables.relations.get(fact.relation);
|
|
559
|
+
if (rel === undefined || !isMemberName(fact.relation)) {
|
|
560
|
+
throw errors.new(`bumbledb violation cites unknown relation ${fact.relation}`);
|
|
661
561
|
}
|
|
662
|
-
return
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
canonical,
|
|
666
|
-
measure: wire.measure,
|
|
667
|
-
facts
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
|
-
if (wire.kind !== "containment") {
|
|
671
|
-
throw errors.new(`bumbledb violation ${wire.statementId} is a containment slot without a direction`);
|
|
672
|
-
}
|
|
673
|
-
if (entry.kind === "mirrors") {
|
|
674
|
-
return Object.freeze({
|
|
675
|
-
kind: "containment",
|
|
676
|
-
statement: entry.statement,
|
|
677
|
-
canonical,
|
|
678
|
-
direction: wire.direction,
|
|
679
|
-
orientation: entry.orientation,
|
|
680
|
-
facts
|
|
681
|
-
});
|
|
682
|
-
}
|
|
683
|
-
return Object.freeze({
|
|
684
|
-
kind: "containment",
|
|
685
|
-
statement: entry.statement,
|
|
686
|
-
canonical,
|
|
687
|
-
direction: wire.direction,
|
|
688
|
-
facts
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
/**
|
|
692
|
-
* Resolves a key-statement-selected read: the statement must be the
|
|
693
|
-
* IDENTICAL `key()` value this schema declared (identity is the
|
|
694
|
-
* membership rule) and must key `relation` — its materialized statement
|
|
695
|
-
* id comes from the positional mirror, so the engine point-reads through
|
|
696
|
-
* exactly the declared projection.
|
|
697
|
-
*/
|
|
698
|
-
function declaredKeyOf(relation, statement) {
|
|
699
|
-
const statementId = tables.statements.findIndex(function byIdentity(candidate) {
|
|
700
|
-
return "statement" in candidate && candidate.statement === statement;
|
|
701
|
-
});
|
|
702
|
-
const entry = tables.statements[statementId];
|
|
703
|
-
if (entry === undefined) {
|
|
704
|
-
throw errors.new(`keyed get statement is not a declared statement of schema ${theory.name} — statement identity is the membership rule`);
|
|
705
|
-
}
|
|
706
|
-
if (entry.kind !== "functionality") {
|
|
707
|
-
throw errors.new("keyed get takes a key() statement — containments and capacity statements key nothing");
|
|
708
|
-
}
|
|
709
|
-
if (entry.owner !== relation.name) {
|
|
710
|
-
throw errors.new(`keyed get statement keys ${entry.owner}, not ${relation.name} — the statement must be a declared key of the relation it reads`);
|
|
711
|
-
}
|
|
712
|
-
return Object.freeze({ statementId, projection: entry.projection });
|
|
562
|
+
return decodeOffendingFact(rel.member, fact.relation, fact);
|
|
563
|
+
}));
|
|
564
|
+
return violationFromEntry(entry, wire, facts);
|
|
713
565
|
}
|
|
714
566
|
function pointReadsOf(assertLive, reads) {
|
|
715
567
|
function contains(relation, fact) {
|
|
716
568
|
assertLive();
|
|
717
|
-
const entry =
|
|
569
|
+
const entry = ordinaryEntry(tables, theory, relation);
|
|
718
570
|
return reads.contains(entry.id, rowOf(relation.data, recordOf(fact)));
|
|
719
571
|
}
|
|
720
|
-
/** One keyed point read through an already-resolved key, decoded to a fact (`undefined` on a miss). */
|
|
721
572
|
function readThroughKey(relation, entry, selected, key) {
|
|
722
573
|
const row = reads.get(entry.id, selected.statementId, keyRowOf(relation.data, selected.projection, key));
|
|
723
574
|
if (row === null) {
|
|
@@ -727,9 +578,9 @@ function openDb(handle, theory, manifest) {
|
|
|
727
578
|
}
|
|
728
579
|
function get(relation, keyOrStatement, declaredKey) {
|
|
729
580
|
assertLive();
|
|
730
|
-
const entry =
|
|
581
|
+
const entry = ordinaryEntry(tables, theory, relation);
|
|
731
582
|
return selectKeyRead(keyOrStatement, declaredKey, function byStatement(statement, key) {
|
|
732
|
-
return readThroughKey(relation, entry, declaredKeyOf(relation, statement), recordOf(key));
|
|
583
|
+
return readThroughKey(relation, entry, declaredKeyOf(tables, theory, relation, statement), recordOf(key));
|
|
733
584
|
}, function byPrimary(key) {
|
|
734
585
|
const primaryKey = entry.primaryKey;
|
|
735
586
|
if (primaryKey === undefined) {
|
|
@@ -791,32 +642,6 @@ function openDb(handle, theory, manifest) {
|
|
|
791
642
|
});
|
|
792
643
|
return (captured ?? result);
|
|
793
644
|
}
|
|
794
|
-
function scan(relation) {
|
|
795
|
-
return read(function scanInScope(instance) {
|
|
796
|
-
return instance.scan(relation);
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
|
-
function get(relation, keyOrStatement, declaredKey) {
|
|
800
|
-
let found;
|
|
801
|
-
read(function getInScope(instance) {
|
|
802
|
-
found = selectKeyRead(keyOrStatement, declaredKey, function byStatement(statement, key) {
|
|
803
|
-
return instance.get(relation, statement, key);
|
|
804
|
-
}, function byPrimary(key) {
|
|
805
|
-
return instance.get(relation, key);
|
|
806
|
-
});
|
|
807
|
-
});
|
|
808
|
-
return found;
|
|
809
|
-
}
|
|
810
|
-
function contains(relation, fact) {
|
|
811
|
-
return read(function containsInScope(instance) {
|
|
812
|
-
return instance.contains(relation, fact);
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
|
-
function execute(prepared, params) {
|
|
816
|
-
return read(function executeInScope(instance) {
|
|
817
|
-
return instance.execute(prepared, params);
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
645
|
function makeTx(resolveTx) {
|
|
821
646
|
const txState = { spent: false };
|
|
822
647
|
function assertLive() {
|
|
@@ -840,30 +665,27 @@ function openDb(handle, theory, manifest) {
|
|
|
840
665
|
});
|
|
841
666
|
function insert(relation, facts) {
|
|
842
667
|
assertLive();
|
|
843
|
-
const entry =
|
|
668
|
+
const entry = ordinaryEntry(tables, theory, relation);
|
|
844
669
|
const txHandle = resolveTx();
|
|
845
|
-
return mutateCollection(relation, facts, function
|
|
670
|
+
return mutateCollection(relation, facts, function applyCells(rows, cells) {
|
|
846
671
|
return bridged("bumbledb tx insert", function record() {
|
|
847
|
-
return native.txInsert(txHandle, entry.id, rows);
|
|
848
|
-
});
|
|
849
|
-
}, function applyColumns(columns) {
|
|
850
|
-
return bridged("bumbledb tx insert", function recordColumns() {
|
|
851
|
-
return native.txInsertColumns(txHandle, entry.id, columns);
|
|
672
|
+
return native.txInsert(txHandle, entry.id, rows, cells);
|
|
852
673
|
});
|
|
853
674
|
});
|
|
854
675
|
}
|
|
855
676
|
function remove(relation, facts) {
|
|
856
677
|
assertLive();
|
|
857
|
-
const entry =
|
|
678
|
+
const entry = ordinaryEntry(tables, theory, relation);
|
|
858
679
|
const txHandle = resolveTx();
|
|
680
|
+
const flat = rowsOf(relation, facts);
|
|
859
681
|
const report = bridged("bumbledb tx delete", function record() {
|
|
860
|
-
return native.txDelete(txHandle, entry.id,
|
|
682
|
+
return native.txDelete(txHandle, entry.id, flat.rows, flat.cells);
|
|
861
683
|
});
|
|
862
684
|
return Object.freeze({ submitted: report.submitted, changed: report.changed });
|
|
863
685
|
}
|
|
864
686
|
function reserve(relation, field, count) {
|
|
865
687
|
assertLive();
|
|
866
|
-
const entry =
|
|
688
|
+
const entry = ordinaryEntry(tables, theory, relation);
|
|
867
689
|
const declared = relation.data.fields.find(function byName(candidate) {
|
|
868
690
|
return candidate.name === field;
|
|
869
691
|
});
|
|
@@ -983,25 +805,11 @@ function openDb(handle, theory, manifest) {
|
|
|
983
805
|
return Object.freeze({
|
|
984
806
|
schema: theory,
|
|
985
807
|
read,
|
|
986
|
-
scan,
|
|
987
|
-
get,
|
|
988
|
-
contains,
|
|
989
|
-
execute,
|
|
990
808
|
write,
|
|
991
809
|
writeFrom,
|
|
992
810
|
prepare
|
|
993
811
|
});
|
|
994
812
|
}
|
|
995
|
-
/**
|
|
996
|
-
* The engine twin of the schema-level class wall, as a matchable value
|
|
997
|
-
* (`errors.is`): the shared lowering rejected a spec whose statement pairs
|
|
998
|
-
* faces with disagreeing newtype labels — the faces of a dependency agree
|
|
999
|
-
* on their newtype, or neither carries one. UNREACHABLE through the typed
|
|
1000
|
-
* builder (the SDK computes every label from the laws, so its lowered
|
|
1001
|
-
* specs cohere by construction); a raw spec handed to the bridge is the
|
|
1002
|
-
* one road here, and the runtime referee that proves the engine judges
|
|
1003
|
-
* what the types claim.
|
|
1004
|
-
*/
|
|
1005
813
|
const ErrNewtypeMismatch = errors.new("bumbledb newtypeMismatch: a statement pairs faces whose newtypes disagree — the faces of a dependency agree on their newtype, or neither carries one");
|
|
1006
814
|
const ErrSchemaError = errors.new("bumbledb schemaError: the declaration failed validation");
|
|
1007
815
|
const ErrFingerprintMismatch = errors.new("bumbledb fingerprintMismatch: the store's schema does not match this theory");
|
|
@@ -1050,65 +858,14 @@ function mapViolationWithoutStore(theory, wire) {
|
|
|
1050
858
|
if (entry === undefined) {
|
|
1051
859
|
throw errors.new(`bumbledb violation cites unknown statement id ${wire.statementId}`);
|
|
1052
860
|
}
|
|
1053
|
-
function offending(fact) {
|
|
861
|
+
const facts = Object.freeze(wire.facts.map(function offending(fact) {
|
|
1054
862
|
const member = theory.relations[fact.relation];
|
|
1055
863
|
if (member === undefined || !(fact.relation in theory.relations)) {
|
|
1056
864
|
throw errors.new(`bumbledb violation cites unknown relation ${fact.relation}`);
|
|
1057
865
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
const cited = declared.find(function byName(candidate) {
|
|
1062
|
-
return candidate.name === cell.name;
|
|
1063
|
-
});
|
|
1064
|
-
const roster = rosterOf(cited?.field);
|
|
1065
|
-
decoded[cell.name] =
|
|
1066
|
-
roster !== undefined
|
|
1067
|
-
? handleOf(`violation fact ${fact.relation} field ${cell.name}`, roster, cell.value)
|
|
1068
|
-
: cell.value;
|
|
1069
|
-
}
|
|
1070
|
-
return Object.freeze({ relation: fact.relation, fact: Object.freeze(decoded) });
|
|
1071
|
-
}
|
|
1072
|
-
const facts = Object.freeze(wire.facts.map(offending));
|
|
1073
|
-
const canonical = wire.canonical;
|
|
1074
|
-
if (entry.kind === "functionality") {
|
|
1075
|
-
if (!("statement" in entry)) {
|
|
1076
|
-
return Object.freeze({ kind: "functionality", statement: undefined, canonical, facts });
|
|
1077
|
-
}
|
|
1078
|
-
return Object.freeze({ kind: "functionality", statement: entry.statement, canonical, facts });
|
|
1079
|
-
}
|
|
1080
|
-
if (entry.kind === "capacity") {
|
|
1081
|
-
if (wire.kind !== "capacity") {
|
|
1082
|
-
throw errors.new(`bumbledb violation ${wire.statementId} is a capacity slot without a measure`);
|
|
1083
|
-
}
|
|
1084
|
-
return Object.freeze({
|
|
1085
|
-
kind: "capacity",
|
|
1086
|
-
statement: entry.statement,
|
|
1087
|
-
canonical,
|
|
1088
|
-
measure: wire.measure,
|
|
1089
|
-
facts
|
|
1090
|
-
});
|
|
1091
|
-
}
|
|
1092
|
-
if (wire.kind !== "containment") {
|
|
1093
|
-
throw errors.new(`bumbledb violation ${wire.statementId} is a containment slot without a direction`);
|
|
1094
|
-
}
|
|
1095
|
-
if (entry.kind === "mirrors") {
|
|
1096
|
-
return Object.freeze({
|
|
1097
|
-
kind: "containment",
|
|
1098
|
-
statement: entry.statement,
|
|
1099
|
-
canonical,
|
|
1100
|
-
direction: wire.direction,
|
|
1101
|
-
orientation: entry.orientation,
|
|
1102
|
-
facts
|
|
1103
|
-
});
|
|
1104
|
-
}
|
|
1105
|
-
return Object.freeze({
|
|
1106
|
-
kind: "containment",
|
|
1107
|
-
statement: entry.statement,
|
|
1108
|
-
canonical,
|
|
1109
|
-
direction: wire.direction,
|
|
1110
|
-
facts
|
|
1111
|
-
});
|
|
866
|
+
return decodeOffendingFact(member, fact.relation, fact);
|
|
867
|
+
}));
|
|
868
|
+
return violationFromEntry(entry, wire, facts);
|
|
1112
869
|
}
|
|
1113
870
|
async function openStore(storePath, theory) {
|
|
1114
871
|
const canonical = path.resolve(storePath);
|
|
@@ -1152,6 +909,9 @@ function wrapOwned(nativeHandle, theory) {
|
|
|
1152
909
|
scan(relationId) {
|
|
1153
910
|
return native.ownedScan(nativeHandle, relationId);
|
|
1154
911
|
},
|
|
912
|
+
count(relationId) {
|
|
913
|
+
return native.ownedCount(nativeHandle, relationId);
|
|
914
|
+
},
|
|
1155
915
|
contains(relationId, values) {
|
|
1156
916
|
return native.ownedContains(nativeHandle, relationId, values);
|
|
1157
917
|
},
|
|
@@ -1213,21 +973,18 @@ function wrapBuilder(nativeHandle, theory) {
|
|
|
1213
973
|
load(relation, facts) {
|
|
1214
974
|
assertLive();
|
|
1215
975
|
const entry = ordinaryEntry(tables, theory, relation);
|
|
1216
|
-
return mutateCollection(relation, facts, function
|
|
1217
|
-
return bridged("bumbledb builder load", function
|
|
1218
|
-
return native.instanceBuilderLoad(nativeHandle, entry.id, rows);
|
|
1219
|
-
});
|
|
1220
|
-
}, function applyColumns(columns) {
|
|
1221
|
-
return bridged("bumbledb builder load", function loadColumns() {
|
|
1222
|
-
return native.instanceBuilderLoadColumns(nativeHandle, entry.id, columns);
|
|
976
|
+
return mutateCollection(relation, facts, function applyCells(rows, cells) {
|
|
977
|
+
return bridged("bumbledb builder load", function loadCells() {
|
|
978
|
+
return native.instanceBuilderLoad(nativeHandle, entry.id, rows, cells);
|
|
1223
979
|
});
|
|
1224
980
|
});
|
|
1225
981
|
},
|
|
1226
982
|
delete(relation, facts) {
|
|
1227
983
|
assertLive();
|
|
1228
984
|
const entry = ordinaryEntry(tables, theory, relation);
|
|
985
|
+
const flat = rowsOf(relation, facts);
|
|
1229
986
|
const report = bridged("bumbledb builder delete", function remove() {
|
|
1230
|
-
return native.instanceBuilderDelete(nativeHandle, entry.id,
|
|
987
|
+
return native.instanceBuilderDelete(nativeHandle, entry.id, flat.rows, flat.cells);
|
|
1231
988
|
});
|
|
1232
989
|
return Object.freeze({ submitted: report.submitted, changed: report.changed });
|
|
1233
990
|
},
|
|
@@ -1311,15 +1068,9 @@ const InstanceBuilder = Object.freeze({
|
|
|
1311
1068
|
* hold the `Db` this process opened.
|
|
1312
1069
|
*/
|
|
1313
1070
|
const Db = Object.freeze({
|
|
1314
|
-
/** Creates a fresh durable store at `path` from the schema. */
|
|
1315
1071
|
async create(storePath, theory) {
|
|
1316
1072
|
return createStore(storePath, theory);
|
|
1317
1073
|
},
|
|
1318
|
-
/**
|
|
1319
|
-
* Opens an existing durable store at `path` with the same theory.
|
|
1320
|
-
* Format 8 open never back-fills a descriptor. A second open of a
|
|
1321
|
-
* still-live path is `EnvironmentLocked`.
|
|
1322
|
-
*/
|
|
1323
1074
|
async open(storePath, theory) {
|
|
1324
1075
|
return openStore(storePath, theory);
|
|
1325
1076
|
},
|
|
@@ -1338,5 +1089,5 @@ const Db = Object.freeze({
|
|
|
1338
1089
|
return openFromHandle(dbHandle, rec.theory);
|
|
1339
1090
|
}
|
|
1340
1091
|
});
|
|
1341
|
-
export { abandon, Db, ErrAsyncCallback, ErrForeignPrepared, ErrForeignWitness,
|
|
1092
|
+
export { abandon, Db, ErrAsyncCallback, ErrFingerprintMismatch, ErrForeignPrepared, ErrForeignWitness, ErrIrError, ErrNewtypeMismatch, ErrSchemaError, ErrSpentHandle, ErrUseAfterScope, InstanceBuilder };
|
|
1342
1093
|
//# sourceMappingURL=db.js.map
|