@bjornpagen/bumbledb 1.3.0 → 2.0.0-rc.1
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 +224 -95
- package/README.md +114 -45
- package/dist/alternatives.d.ts +5 -6
- package/dist/alternatives.d.ts.map +1 -1
- package/dist/alternatives.js +5 -6
- package/dist/alternatives.js.map +1 -1
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +85 -0
- package/dist/bin.js.map +1 -0
- package/dist/capacity.d.ts +14 -17
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js +7 -7
- package/dist/capacity.js.map +1 -1
- package/dist/changes.d.ts +32 -41
- package/dist/changes.d.ts.map +1 -1
- package/dist/changes.js +86 -110
- package/dist/changes.js.map +1 -1
- package/dist/closed.d.ts +2 -2
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +5 -5
- package/dist/closed.js.map +1 -1
- package/dist/codec.d.ts +20 -27
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +48 -22
- package/dist/codec.js.map +1 -1
- package/dist/compile.d.ts +26 -50
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +75 -64
- package/dist/compile.js.map +1 -1
- package/dist/database/database.d.ts +98 -0
- package/dist/database/database.d.ts.map +1 -0
- package/dist/database/database.js +249 -0
- package/dist/database/database.js.map +1 -0
- package/dist/database/driver.d.ts +40 -0
- package/dist/database/driver.d.ts.map +1 -0
- package/dist/database/driver.js +68 -0
- package/dist/database/driver.js.map +1 -0
- package/dist/database/fs.d.ts +12 -0
- package/dist/database/fs.d.ts.map +1 -0
- package/dist/database/fs.js +120 -0
- package/dist/database/fs.js.map +1 -0
- package/dist/database/generate.d.ts +26 -0
- package/dist/database/generate.d.ts.map +1 -0
- package/dist/database/generate.js +102 -0
- package/dist/database/generate.js.map +1 -0
- package/dist/database/hosted.d.ts +32 -0
- package/dist/database/hosted.d.ts.map +1 -0
- package/dist/database/hosted.js +44 -0
- package/dist/database/hosted.js.map +1 -0
- package/dist/database/io.d.ts +94 -0
- package/dist/database/io.d.ts.map +1 -0
- package/dist/database/io.js +35 -0
- package/dist/database/io.js.map +1 -0
- package/dist/database/mem.d.ts +26 -0
- package/dist/database/mem.d.ts.map +1 -0
- package/dist/database/mem.js +67 -0
- package/dist/database/mem.js.map +1 -0
- package/dist/database/migration.d.ts +55 -0
- package/dist/database/migration.d.ts.map +1 -0
- package/dist/database/migration.js +46 -0
- package/dist/database/migration.js.map +1 -0
- package/dist/database/s3.d.ts +36 -0
- package/dist/database/s3.d.ts.map +1 -0
- package/dist/database/s3.js +141 -0
- package/dist/database/s3.js.map +1 -0
- package/dist/db.d.ts +44 -128
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +163 -287
- package/dist/db.js.map +1 -1
- package/dist/engine.d.ts +7 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +2 -0
- package/dist/engine.js.map +1 -0
- package/dist/errors.d.ts +152 -46
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +107 -19
- package/dist/errors.js.map +1 -1
- package/dist/face.d.ts +5 -5
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +6 -6
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +4 -5
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +3 -3
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +60 -58
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -29
- package/dist/index.js.map +1 -1
- package/dist/judgment.d.ts +1 -1
- package/dist/judgment.js +1 -1
- package/dist/law.d.ts +16 -68
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +3 -3
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts +3 -3
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +35 -39
- package/dist/lower.js.map +1 -1
- package/dist/native/addon.d.ts +23 -0
- package/dist/native/addon.d.ts.map +1 -0
- package/dist/native/addon.js +15 -0
- package/dist/native/addon.js.map +1 -0
- package/dist/native/binding.d.ts +996 -0
- package/dist/native/json.d.ts +14 -0
- package/dist/native/json.d.ts.map +1 -0
- package/dist/native/json.js +73 -0
- package/dist/native/json.js.map +1 -0
- package/dist/native/load.d.ts +9 -0
- package/dist/native/load.d.ts.map +1 -0
- package/dist/native/load.js +30 -0
- package/dist/native/load.js.map +1 -0
- package/dist/native/op.d.ts +29 -0
- package/dist/native/op.d.ts.map +1 -0
- package/dist/native/op.js +50 -0
- package/dist/native/op.js.map +1 -0
- package/dist/query/atom.d.ts +13 -14
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +2 -2
- package/dist/query/atom.js.map +1 -1
- package/dist/query/compute.d.ts +7 -7
- package/dist/query/compute.d.ts.map +1 -1
- package/dist/query/compute.js +7 -16
- package/dist/query/compute.js.map +1 -1
- package/dist/query/find.d.ts +8 -8
- package/dist/query/find.d.ts.map +1 -1
- package/dist/query/find.js +1 -1
- package/dist/query/lower.d.ts +31 -17
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +260 -368
- package/dist/query/lower.js.map +1 -1
- package/dist/query/run.d.ts +5 -5
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +32 -15
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +20 -28
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +13 -8
- package/dist/query/scope.js.map +1 -1
- package/dist/query/segments.d.ts +2 -2
- package/dist/query/segments.d.ts.map +1 -1
- package/dist/query/segments.js +3 -3
- package/dist/query/segments.js.map +1 -1
- package/dist/relation.d.ts +1 -1
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +4 -4
- package/dist/relation.js.map +1 -1
- package/dist/result.d.ts +15 -22
- package/dist/result.d.ts.map +1 -1
- package/dist/result.js +30 -39
- package/dist/result.js.map +1 -1
- package/dist/rows.d.ts +9 -33
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +8 -12
- package/dist/rows.js.map +1 -1
- package/dist/runtime.d.ts +17 -43
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +41 -241
- package/dist/runtime.js.map +1 -1
- package/dist/scalar.d.ts +36 -106
- package/dist/scalar.d.ts.map +1 -1
- package/dist/scalar.js +36 -185
- package/dist/scalar.js.map +1 -1
- package/dist/schema.d.ts +7 -18
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +18 -228
- package/dist/schema.js.map +1 -1
- package/dist/selection.d.ts +4 -4
- package/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +5 -5
- package/dist/selection.js.map +1 -1
- package/dist/shape.d.ts +5 -5
- package/dist/shape.d.ts.map +1 -1
- package/dist/spec.d.ts +7 -79
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +3 -3
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +10 -10
- package/dist/statements.js.map +1 -1
- package/dist/uuid.d.ts +1 -1
- package/dist/uuid.d.ts.map +1 -1
- package/dist/uuid.js +1 -1
- package/dist/uuid.js.map +1 -1
- package/dist/values.d.ts +2 -2
- package/dist/values.d.ts.map +1 -1
- package/dist/values.js +2 -2
- package/dist/values.js.map +1 -1
- package/package.json +18 -18
- package/src/alternatives.ts +7 -8
- package/src/bin.ts +82 -0
- package/src/capacity.ts +20 -23
- package/src/changes.ts +134 -197
- package/src/closed.ts +5 -5
- package/src/codec.ts +77 -51
- package/src/compile.ts +91 -113
- package/src/database/database.ts +413 -0
- package/src/database/driver.ts +134 -0
- package/src/database/fs.ts +119 -0
- package/src/database/generate.ts +116 -0
- package/src/database/hosted.ts +102 -0
- package/src/database/io.ts +134 -0
- package/src/database/mem.ts +113 -0
- package/src/database/migration.ts +107 -0
- package/src/database/s3.ts +231 -0
- package/src/db.ts +290 -547
- package/src/engine.ts +14 -0
- package/src/errors.ts +118 -39
- package/src/face.ts +9 -9
- package/src/fields.ts +6 -7
- package/src/index.ts +102 -109
- package/src/judgment.ts +1 -1
- package/src/law.ts +18 -70
- package/src/lower.ts +61 -72
- package/src/native/addon.ts +54 -0
- package/src/native/binding.d.ts +996 -0
- package/src/native/json.ts +100 -0
- package/src/native/load.ts +31 -0
- package/src/native/op.ts +73 -0
- package/src/query/atom.ts +15 -16
- package/src/query/compute.ts +13 -22
- package/src/query/find.ts +8 -8
- package/src/query/lower.ts +323 -414
- package/src/query/run.ts +42 -21
- package/src/query/scope.ts +37 -38
- package/src/query/segments.ts +4 -4
- package/src/relation.ts +4 -4
- package/src/result.ts +53 -80
- package/src/rows.ts +18 -46
- package/src/runtime.ts +50 -346
- package/src/scalar.ts +76 -336
- package/src/schema.ts +23 -284
- package/src/selection.ts +6 -6
- package/src/shape.ts +5 -5
- package/src/spec.ts +7 -85
- package/src/statements.ts +11 -11
- package/src/uuid.ts +1 -1
- package/src/values.ts +4 -4
- package/dist/close.d.ts +0 -24
- package/dist/close.d.ts.map +0 -1
- package/dist/close.js +0 -34
- package/dist/close.js.map +0 -1
- package/dist/db-native.d.ts +0 -196
- package/dist/db-native.d.ts.map +0 -1
- package/dist/db-native.js +0 -13
- package/dist/db-native.js.map +0 -1
- package/dist/internal/log.d.ts +0 -26
- package/dist/internal/log.d.ts.map +0 -1
- package/dist/internal/log.js +0 -12
- package/dist/internal/log.js.map +0 -1
- package/dist/migration.d.ts +0 -31
- package/dist/migration.d.ts.map +0 -1
- package/dist/migration.js +0 -47
- package/dist/migration.js.map +0 -1
- package/dist/native.d.ts +0 -562
- package/dist/native.d.ts.map +0 -1
- package/dist/native.js +0 -123
- package/dist/native.js.map +0 -1
- package/dist/query/description.d.ts +0 -41
- package/dist/query/description.d.ts.map +0 -1
- package/dist/query/description.js +0 -311
- package/dist/query/description.js.map +0 -1
- package/dist/query/parse-ir.d.ts +0 -10
- package/dist/query/parse-ir.d.ts.map +0 -1
- package/dist/query/parse-ir.js +0 -280
- package/dist/query/parse-ir.js.map +0 -1
- package/dist/runtime-codes.d.ts +0 -2
- package/dist/runtime-codes.d.ts.map +0 -1
- package/dist/runtime-codes.js +0 -18
- package/dist/runtime-codes.js.map +0 -1
- package/dist/runtime-errors.d.ts +0 -118
- package/dist/runtime-errors.d.ts.map +0 -1
- package/dist/runtime-errors.js +0 -98
- package/dist/runtime-errors.js.map +0 -1
- package/dist/runtime-native.d.ts +0 -141
- package/dist/runtime-native.d.ts.map +0 -1
- package/dist/runtime-native.js +0 -5
- package/dist/runtime-native.js.map +0 -1
- package/pack-provenance.json +0 -7
- package/src/close.ts +0 -53
- package/src/db-native.ts +0 -243
- package/src/internal/log.ts +0 -48
- package/src/migration.ts +0 -61
- package/src/native.ts +0 -736
- package/src/query/description.ts +0 -424
- package/src/query/parse-ir.ts +0 -291
- package/src/runtime-codes.ts +0 -17
- package/src/runtime-errors.ts +0 -109
- package/src/runtime-native.ts +0 -189
package/src/changes.ts
CHANGED
|
@@ -1,43 +1,34 @@
|
|
|
1
1
|
import type { Scope } from "effect"
|
|
2
2
|
import { Effect, Exit, Option, Stream } from "effect"
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import type {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { type AnyRelation, type Fact, relationFields } from "
|
|
12
|
-
import type { CellValue } from "
|
|
13
|
-
import { factCellsOf, factOfCells, hostCellCharge } from "
|
|
14
|
-
import {
|
|
15
|
-
import type {
|
|
16
|
-
import {
|
|
17
|
-
import type {
|
|
18
|
-
import
|
|
19
|
-
import { bytesValue, recordValue } from "#values.ts"
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* `ChangeSet` — the engine's checked immutable delta:
|
|
23
|
-
* schema-fingerprint-bound canonical native bytes with
|
|
24
|
-
* one-command `(add, remove ∖ add)` normalization and exact same-fact
|
|
25
|
-
* add-wins. Immutable and reusable while open; sealing/submitting it later
|
|
26
|
-
* retains the SAME native value — no second JS row walk ever happens.
|
|
27
|
-
*/
|
|
28
|
-
/** Counts of distinct fact additions and removals, never input events. */
|
|
29
|
-
interface ChangeCounts {
|
|
30
|
-
readonly added: bigint
|
|
31
|
-
readonly removed: bigint
|
|
32
|
-
}
|
|
3
|
+
import { isClosedMember, membersAgree } from "./closed.ts"
|
|
4
|
+
import type { SchemaId } from "./compile.ts"
|
|
5
|
+
import { compiledOf, schemaTables } from "./compile.ts"
|
|
6
|
+
import { argumentError, DbError, dbError, internalError } from "./errors.ts"
|
|
7
|
+
import type { ChangesRef, DraftRef } from "./native/addon.ts"
|
|
8
|
+
import { addon } from "./native/addon.ts"
|
|
9
|
+
import type { ChangeCounts, ChangeKindOut, ChangeRecordOut, ChangesOut } from "./native/binding.d.ts"
|
|
10
|
+
import { call, drain, release, scoped } from "./native/op.ts"
|
|
11
|
+
import { type AnyRelation, type Fact, relationFields } from "./relation.ts"
|
|
12
|
+
import type { CellValue } from "./rows.ts"
|
|
13
|
+
import { factCellsOf, factOfCells, hostCellCharge } from "./rows.ts"
|
|
14
|
+
import { runtimeHandle } from "./runtime.ts"
|
|
15
|
+
import type { AnySchema, SchemaRelation } from "./schema.ts"
|
|
16
|
+
import { schemaDescriptor } from "./schema.ts"
|
|
17
|
+
import type { Rel } from "./shape.ts"
|
|
18
|
+
import { bytesValue, recordValue } from "./values.ts"
|
|
33
19
|
|
|
34
20
|
/** A relation-name-discriminated union of plain, fully typed facts. */
|
|
35
21
|
type ChangeRecord<S extends AnySchema> = {
|
|
36
22
|
[N in keyof S["relations"]]: S["relations"][N] extends AnyRelation
|
|
37
|
-
? { readonly relation: N; readonly kind:
|
|
23
|
+
? { readonly relation: N; readonly kind: ChangeKindOut; readonly fact: Fact<S["relations"][N]> }
|
|
38
24
|
: never
|
|
39
25
|
}[keyof S["relations"]]
|
|
40
26
|
|
|
27
|
+
/**
|
|
28
|
+
* The engine's checked immutable delta: schema-fingerprint-bound canonical native bytes with
|
|
29
|
+
* one-command `(add, remove ∖ add)` normalization and exact same-fact add-wins. Reusable while
|
|
30
|
+
* open; submitting it retains the same native value, so no second row walk happens.
|
|
31
|
+
*/
|
|
41
32
|
interface ChangeSet<S extends AnySchema> {
|
|
42
33
|
readonly schemaId: SchemaId
|
|
43
34
|
/** Distinct requested actions; use judge for effective counts against a store. */
|
|
@@ -51,26 +42,18 @@ interface ChangeSet<S extends AnySchema> {
|
|
|
51
42
|
toBytes(): Effect.Effect<Uint8Array, DbError>
|
|
52
43
|
/** Commutative add-wins composition into one command, not sequential replay. */
|
|
53
44
|
compose(other: ChangeSet<S>): Effect.Effect<ChangeSet<S>, DbError, Scope.Scope>
|
|
54
|
-
close(): Effect.Effect<CloseReport>
|
|
55
45
|
}
|
|
56
46
|
|
|
57
47
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* stable from an ingestion effect's execution start through its Exit;
|
|
63
|
-
* after successful ingestion the accepted native bytes are independent.
|
|
64
|
-
* Failure/interruption SPENDS the draft and initiates tracked drain.
|
|
65
|
-
* Concurrent/reentrant construction refuses and spends/drains the draft.
|
|
66
|
-
* `finish` consumes the draft; later ingestion or a second finish refuses
|
|
67
|
-
* through the spent capability state.
|
|
48
|
+
* A scoped, database-free change draft. Each method returns a lazy effect that reads its iterable
|
|
49
|
+
* when it runs (every rerun reads it again); accepted rows are copied, so later mutation of the
|
|
50
|
+
* input changes nothing. A failure, an interruption or concurrent use spends the draft; `finish`
|
|
51
|
+
* consumes it.
|
|
68
52
|
*/
|
|
69
53
|
interface ChangeDraft<S extends AnySchema> {
|
|
70
54
|
insert<R extends Rel<S>>(relation: R, rows: Iterable<Fact<R>>): Effect.Effect<void, DbError>
|
|
71
55
|
delete<R extends Rel<S>>(relation: R, rows: Iterable<Fact<R>>): Effect.Effect<void, DbError>
|
|
72
56
|
finish(): Effect.Effect<ChangeSet<S>, DbError, Scope.Scope>
|
|
73
|
-
close(): Effect.Effect<CloseReport>
|
|
74
57
|
}
|
|
75
58
|
|
|
76
59
|
/**
|
|
@@ -84,32 +67,19 @@ const CHUNK_BYTES = 65536n
|
|
|
84
67
|
const CHUNK_ROWS = 4096
|
|
85
68
|
|
|
86
69
|
interface DraftState {
|
|
87
|
-
readonly handle:
|
|
70
|
+
readonly handle: DraftRef
|
|
88
71
|
readonly theory: AnySchema
|
|
89
72
|
spent: boolean
|
|
90
73
|
inFlight: boolean
|
|
91
74
|
}
|
|
92
75
|
|
|
93
|
-
interface ChangesInternal {
|
|
94
|
-
readonly handle: ChangesHandle
|
|
95
|
-
readonly schemaId: SchemaId
|
|
96
|
-
closed: boolean
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const changesInternals = new WeakMap<object, ChangesInternal>()
|
|
100
|
-
|
|
101
|
-
/** Private cross-module accessor (db.apply retains the native ChangeSet). */
|
|
102
|
-
function internalChanges(value: object): ChangesInternal | undefined {
|
|
103
|
-
return changesInternals.get(value)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
76
|
function refusal(operation: string, reason: "SpentHandle" | "ClosedHandle" | "InvalidArgument"): DbError {
|
|
107
77
|
return new DbError({ operation, reason: { _tag: reason } })
|
|
108
78
|
}
|
|
109
79
|
|
|
110
80
|
interface Chunk {
|
|
111
81
|
readonly rows: bigint
|
|
112
|
-
readonly cells:
|
|
82
|
+
readonly cells: CellValue[]
|
|
113
83
|
readonly done: boolean
|
|
114
84
|
readonly leftover: object | undefined
|
|
115
85
|
}
|
|
@@ -168,16 +138,13 @@ function pullChunk(relation: AnyRelation, iterator: Iterator<object>, pending: o
|
|
|
168
138
|
return { rows, cells, done: false, leftover }
|
|
169
139
|
}
|
|
170
140
|
|
|
171
|
-
function spendAndDrain(state: DraftState
|
|
141
|
+
function spendAndDrain(state: DraftState): Effect.Effect<void> {
|
|
172
142
|
return Effect.suspend(() => {
|
|
173
143
|
if (state.spent) {
|
|
174
144
|
return Effect.void
|
|
175
145
|
}
|
|
176
146
|
state.spent = true
|
|
177
|
-
|
|
178
|
-
// diagnostic here (the ingestion failure itself is the caller's
|
|
179
|
-
// error), but native Closing accounting is never dropped.
|
|
180
|
-
return drainClose(operation, (callback) => dbNative.runtimeDraftClose(state.handle, callback)).pipe(Effect.asVoid)
|
|
147
|
+
return drain((done) => addon.runtimeDraftClose(state.handle, done)).pipe(Effect.asVoid)
|
|
181
148
|
})
|
|
182
149
|
}
|
|
183
150
|
|
|
@@ -187,7 +154,7 @@ function ingest(
|
|
|
187
154
|
relation: AnyRelation,
|
|
188
155
|
rows: Iterable<object>
|
|
189
156
|
): Effect.Effect<void, DbError> {
|
|
190
|
-
const verb = operation === "ChangeDraft.insert" ?
|
|
157
|
+
const verb = operation === "ChangeDraft.insert" ? addon.runtimeDraftInsert : addon.runtimeDraftDelete
|
|
191
158
|
return Effect.gen(function* () {
|
|
192
159
|
if (state.spent) {
|
|
193
160
|
return yield* Effect.fail(refusal(operation, "SpentHandle"))
|
|
@@ -195,7 +162,7 @@ function ingest(
|
|
|
195
162
|
if (state.inFlight) {
|
|
196
163
|
// Reentrant construction refuses AND spends/drains — there is
|
|
197
164
|
// no implicit queue.
|
|
198
|
-
yield* spendAndDrain(state
|
|
165
|
+
yield* spendAndDrain(state)
|
|
199
166
|
return yield* Effect.fail(refusal(operation, "SpentHandle"))
|
|
200
167
|
}
|
|
201
168
|
if (!membersAgree(state.theory.relations[relation.name], relation)) {
|
|
@@ -219,18 +186,19 @@ function ingest(
|
|
|
219
186
|
const chunk = yield* Effect.try({
|
|
220
187
|
try: () => pullChunk(relation, iterator, leftover),
|
|
221
188
|
catch: (cause) => argumentError(operation, cause)
|
|
222
|
-
}).pipe(Effect.catch((error) => spendAndDrain(state
|
|
189
|
+
}).pipe(Effect.catch((error) => spendAndDrain(state).pipe(Effect.andThen(Effect.fail(error)))))
|
|
223
190
|
leftover = chunk.leftover
|
|
224
191
|
done = chunk.done && leftover === undefined
|
|
225
192
|
if (chunk.rows === 0n) {
|
|
226
193
|
continue
|
|
227
194
|
}
|
|
228
195
|
yield* eventLoopTurn()
|
|
229
|
-
yield*
|
|
196
|
+
yield* call(
|
|
230
197
|
operation,
|
|
231
198
|
(callback) => verb(state.handle, relationId, chunk.rows, chunk.cells, callback),
|
|
232
|
-
|
|
233
|
-
|
|
199
|
+
(lease) => {
|
|
200
|
+
addon.runtimeStagedTake(lease)
|
|
201
|
+
}
|
|
234
202
|
).pipe(
|
|
235
203
|
Effect.catch((error) =>
|
|
236
204
|
Effect.sync(() => {
|
|
@@ -252,18 +220,18 @@ function ingest(
|
|
|
252
220
|
if (state.spent || Exit.isSuccess(exit)) {
|
|
253
221
|
return Effect.void
|
|
254
222
|
}
|
|
255
|
-
return spendAndDrain(state
|
|
223
|
+
return spendAndDrain(state)
|
|
256
224
|
})
|
|
257
225
|
})
|
|
258
226
|
}
|
|
259
227
|
|
|
260
228
|
function decodeChangeRecord<S extends AnySchema>(
|
|
261
229
|
relations: readonly SchemaRelation[],
|
|
262
|
-
record:
|
|
230
|
+
record: ChangeRecordOut
|
|
263
231
|
): ChangeRecord<S> {
|
|
264
232
|
const relation = relations[record.relation]
|
|
265
|
-
if (relation === undefined || isClosedMember(relation)
|
|
266
|
-
throw
|
|
233
|
+
if (relation === undefined || isClosedMember(relation)) {
|
|
234
|
+
throw internalError("ChangeSet.records: invalid native record descriptor")
|
|
267
235
|
}
|
|
268
236
|
// Relation id resolves through this schema's own ordered roster. The
|
|
269
237
|
// shared projector validates all field values before this union seam.
|
|
@@ -275,28 +243,25 @@ function decodeChangeRecord<S extends AnySchema>(
|
|
|
275
243
|
}
|
|
276
244
|
|
|
277
245
|
function changeRecords<S extends AnySchema>(
|
|
278
|
-
handle:
|
|
246
|
+
handle: ChangesRef,
|
|
279
247
|
relations: readonly SchemaRelation[]
|
|
280
248
|
): Stream.Stream<ChangeRecord<S>, DbError> {
|
|
281
249
|
return Stream.unwrap(
|
|
282
250
|
Effect.gen(function* () {
|
|
283
251
|
const cursor = yield* Effect.acquireRelease(
|
|
284
|
-
|
|
252
|
+
call(
|
|
285
253
|
"ChangeSet.records",
|
|
286
|
-
(callback) =>
|
|
287
|
-
|
|
288
|
-
(value) => value
|
|
254
|
+
(callback) => addon.runtimeChangesCursor(handle, callback),
|
|
255
|
+
addon.runtimeChangesCursorTake
|
|
289
256
|
),
|
|
290
|
-
(value) =>
|
|
291
|
-
releaseOwner("ChangeCursor.close", (callback) => dbNative.runtimeChangesCursorClose(value, callback)),
|
|
257
|
+
(value) => release("ChangeCursor.close", (callback) => addon.runtimeChangesCursorClose(value, callback)),
|
|
292
258
|
{ interruptible: true }
|
|
293
259
|
)
|
|
294
260
|
return Stream.paginate(undefined, () =>
|
|
295
|
-
|
|
261
|
+
call(
|
|
296
262
|
"ChangeSet.records",
|
|
297
|
-
(callback) =>
|
|
298
|
-
|
|
299
|
-
(page) => page
|
|
263
|
+
(callback) => addon.runtimeChangesCursorNext(cursor, callback),
|
|
264
|
+
addon.runtimeChangePageTake
|
|
300
265
|
).pipe(
|
|
301
266
|
Effect.map((page) =>
|
|
302
267
|
page === null
|
|
@@ -312,68 +277,59 @@ function changeRecords<S extends AnySchema>(
|
|
|
312
277
|
function acquireChanges<S extends AnySchema>(
|
|
313
278
|
theory: S,
|
|
314
279
|
schemaId: SchemaId,
|
|
315
|
-
acquire: Effect.Effect<
|
|
280
|
+
acquire: Effect.Effect<ChangesOut, DbError>
|
|
316
281
|
): Effect.Effect<ChangeSet<S>, DbError, Scope.Scope> {
|
|
317
|
-
return Effect.
|
|
318
|
-
|
|
319
|
-
(
|
|
320
|
-
Effect.suspend(() => {
|
|
321
|
-
const internal = changesInternals.get(changes)
|
|
322
|
-
if (internal === undefined) return Effect.void
|
|
323
|
-
internal.closed = true
|
|
324
|
-
return releaseOwner("ChangeSet.close", (callback) => dbNative.runtimeChangesClose(internal.handle, callback))
|
|
325
|
-
}),
|
|
326
|
-
{ interruptible: true }
|
|
282
|
+
return Effect.map(
|
|
283
|
+
scoped("ChangeSet.release", acquire, (wire) => (done) => addon.runtimeChangesClose(wire.changes, done)),
|
|
284
|
+
(wire): ChangeSet<S> => new ChangeSetLive(theory, wire, schemaId)
|
|
327
285
|
)
|
|
328
286
|
}
|
|
329
287
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
288
|
+
class ChangeSetLive<S extends AnySchema> implements ChangeSet<S> {
|
|
289
|
+
readonly #theory: S
|
|
290
|
+
readonly #handle: ChangesRef
|
|
291
|
+
readonly schemaId: SchemaId
|
|
292
|
+
readonly counts: ChangeCounts
|
|
293
|
+
readonly byteLength: bigint
|
|
294
|
+
|
|
295
|
+
constructor(theory: S, wire: ChangesOut, schemaId: SchemaId) {
|
|
296
|
+
this.#theory = theory
|
|
297
|
+
this.#handle = wire.changes
|
|
298
|
+
this.schemaId = schemaId
|
|
299
|
+
this.counts = Object.freeze({ ...wire.counts })
|
|
300
|
+
this.byteLength = wire.byteLength
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
records(): Stream.Stream<ChangeRecord<S>, DbError> {
|
|
304
|
+
return changeRecords<S>(this.#handle, Object.values(this.#theory.relations)).pipe(
|
|
305
|
+
Stream.withSpan("ChangeSet.records")
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
toBytes(): Effect.Effect<Uint8Array, DbError> {
|
|
310
|
+
const handle = this.#handle
|
|
311
|
+
return call("ChangeSet.toBytes", (done) => addon.runtimeChangesBytes(handle, done), addon.runtimeBytesTake).pipe(
|
|
312
|
+
Effect.withSpan("ChangeSet.toBytes")
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
compose(other: ChangeSet<S>): Effect.Effect<ChangeSet<S>, DbError, Scope.Scope> {
|
|
317
|
+
const left = this.#handle
|
|
318
|
+
const right = ChangeSetLive.handle(other, this.schemaId)
|
|
319
|
+
if (right === undefined) return Effect.fail(refusal("ChangeSet.compose", "InvalidArgument"))
|
|
320
|
+
return acquireChanges(
|
|
321
|
+
this.#theory,
|
|
322
|
+
this.schemaId,
|
|
323
|
+
call("ChangeSet.compose", (done) => addon.runtimeChangesCompose(left, right, done), addon.runtimeChangesTake)
|
|
324
|
+
).pipe(Effect.withSpan("ChangeSet.compose"))
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** The native change set behind `value`, when `value` is one this SDK made for `schemaId`. */
|
|
328
|
+
static handle(value: object, schemaId: SchemaId): ChangesRef | undefined {
|
|
329
|
+
if (!(#handle in value)) return undefined
|
|
330
|
+
const changes = value as unknown as ChangeSetLive<AnySchema>
|
|
331
|
+
return changes.schemaId === schemaId ? changes.#handle : undefined
|
|
373
332
|
}
|
|
374
|
-
Object.freeze(value)
|
|
375
|
-
changesInternals.set(value, internal)
|
|
376
|
-
return value
|
|
377
333
|
}
|
|
378
334
|
|
|
379
335
|
function makeDraft<S extends AnySchema>(theory: S, state: DraftState, schemaId: SchemaId): ChangeDraft<S> {
|
|
@@ -393,25 +349,18 @@ function makeDraft<S extends AnySchema>(theory: S, state: DraftState, schemaId:
|
|
|
393
349
|
return yield* Effect.fail(refusal("ChangeDraft.finish", "SpentHandle"))
|
|
394
350
|
}
|
|
395
351
|
if (state.inFlight) {
|
|
396
|
-
yield* spendAndDrain(state
|
|
352
|
+
yield* spendAndDrain(state)
|
|
397
353
|
return yield* Effect.fail(refusal("ChangeDraft.finish", "SpentHandle"))
|
|
398
354
|
}
|
|
399
355
|
// Finish CONSUMES the draft, success or failure.
|
|
400
356
|
state.spent = true
|
|
401
|
-
return yield*
|
|
357
|
+
return yield* call(
|
|
402
358
|
"ChangeDraft.finish",
|
|
403
|
-
(callback) =>
|
|
404
|
-
|
|
405
|
-
(value) => value
|
|
359
|
+
(callback) => addon.runtimeDraftFinish(state.handle, callback),
|
|
360
|
+
addon.runtimeChangesTake
|
|
406
361
|
)
|
|
407
362
|
})
|
|
408
363
|
)
|
|
409
|
-
},
|
|
410
|
-
close() {
|
|
411
|
-
return Effect.suspend(() => {
|
|
412
|
-
state.spent = true
|
|
413
|
-
return drainClose("ChangeDraft.close", (callback) => dbNative.runtimeDraftClose(state.handle, callback))
|
|
414
|
-
})
|
|
415
364
|
}
|
|
416
365
|
}
|
|
417
366
|
return Object.freeze(draft)
|
|
@@ -420,73 +369,61 @@ function makeDraft<S extends AnySchema>(theory: S, state: DraftState, schemaId:
|
|
|
420
369
|
/**
|
|
421
370
|
* `ChangeSet.builder(schema)` — lazy scoped acquisition of a
|
|
422
371
|
* database-free draft. Requires the acquired
|
|
423
|
-
* `
|
|
372
|
+
* `Bumble`; the draft's native resources release with its scope, and
|
|
424
373
|
* the scope finalizer surfaces incomplete/failed teardown as a
|
|
425
374
|
* `CloseFailure` defect.
|
|
426
375
|
*/
|
|
427
376
|
const builder = Effect.fn("ChangeSet.builder")(function* <S extends AnySchema>(schema: S) {
|
|
428
|
-
const handle = yield* runtimeHandle
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
handle: draftHandle,
|
|
441
|
-
theory: compiled.schema,
|
|
377
|
+
const handle = yield* runtimeHandle
|
|
378
|
+
const theory = yield* Effect.try({
|
|
379
|
+
try: () => schemaDescriptor(schema),
|
|
380
|
+
catch: (cause) => argumentError("ChangeSet.builder", cause)
|
|
381
|
+
})
|
|
382
|
+
const compiled = compiledOf(theory)
|
|
383
|
+
const state = yield* scoped(
|
|
384
|
+
"ChangeDraft.release",
|
|
385
|
+
Effect.try({
|
|
386
|
+
try: (): DraftState => ({
|
|
387
|
+
handle: addon.runtimeDraftOpen(handle, compiled.handle),
|
|
388
|
+
theory,
|
|
442
389
|
spent: false,
|
|
443
390
|
inFlight: false
|
|
444
|
-
}
|
|
445
|
-
const draft = makeDraft(compiled.schema, state, compiled.schemaId)
|
|
446
|
-
draftStates.set(draft, state)
|
|
447
|
-
return draft
|
|
448
|
-
}),
|
|
449
|
-
(draft) =>
|
|
450
|
-
Effect.suspend(() => {
|
|
451
|
-
const state = draftStates.get(draft)
|
|
452
|
-
if (state === undefined) {
|
|
453
|
-
return Effect.void
|
|
454
|
-
}
|
|
455
|
-
// Idempotent: repeated close joins the same native
|
|
456
|
-
// transition; the finalizer runs it unconditionally so an
|
|
457
|
-
// abandoned draft is always drained.
|
|
458
|
-
state.spent = true
|
|
459
|
-
return releaseOwner("ChangeDraft.close", (callback) => dbNative.runtimeDraftClose(state.handle, callback))
|
|
460
391
|
}),
|
|
461
|
-
|
|
392
|
+
catch: (cause) => dbError("ChangeSet.builder", cause)
|
|
393
|
+
}),
|
|
394
|
+
(owned) => (done) => {
|
|
395
|
+
owned.spent = true
|
|
396
|
+
addon.runtimeDraftClose(owned.handle, done)
|
|
397
|
+
}
|
|
462
398
|
)
|
|
399
|
+
return makeDraft(theory as S, state, compiled.schemaId)
|
|
463
400
|
})
|
|
464
401
|
|
|
465
|
-
// The draft value → state registry lets the scope finalizer reach the
|
|
466
|
-
// native handle without exposing it on the public capability.
|
|
467
|
-
const draftStates = new WeakMap<object, DraftState>()
|
|
468
|
-
|
|
469
402
|
/** Parse canonical native bytes, owning the input when the Effect starts. */
|
|
470
403
|
const fromBytes = Effect.fn("ChangeSet.fromBytes")(function* <S extends AnySchema>(schema: S, bytes: Uint8Array) {
|
|
471
404
|
const ownedBytes = yield* Effect.try({
|
|
472
405
|
try: () => bytesValue("ChangeSet.fromBytes", bytes),
|
|
473
406
|
catch: (cause) => argumentError("ChangeSet.fromBytes", cause)
|
|
474
407
|
})
|
|
475
|
-
const handle = yield* runtimeHandle
|
|
476
|
-
const
|
|
408
|
+
const handle = yield* runtimeHandle
|
|
409
|
+
const theory = yield* Effect.try({
|
|
410
|
+
try: () => schemaDescriptor(schema),
|
|
411
|
+
catch: (cause) => argumentError("ChangeSet.fromBytes", cause)
|
|
412
|
+
})
|
|
413
|
+
const compiled = compiledOf(theory)
|
|
477
414
|
return yield* acquireChanges(
|
|
478
|
-
|
|
415
|
+
theory as S,
|
|
479
416
|
compiled.schemaId,
|
|
480
|
-
|
|
417
|
+
call(
|
|
481
418
|
"ChangeSet.fromBytes",
|
|
482
|
-
(
|
|
483
|
-
|
|
484
|
-
(wire) => wire
|
|
419
|
+
(done) => addon.runtimeChangesParse(handle, compiled.handle, ownedBytes, done),
|
|
420
|
+
addon.runtimeChangesTake
|
|
485
421
|
)
|
|
486
422
|
)
|
|
487
423
|
})
|
|
488
424
|
|
|
489
425
|
const ChangeSet = Object.freeze({ builder, fromBytes })
|
|
490
426
|
|
|
491
|
-
export type { ChangeCounts
|
|
492
|
-
export {
|
|
427
|
+
export type { ChangeCounts } from "./native/binding.d.ts"
|
|
428
|
+
export type { ChangeDraft, ChangeRecord }
|
|
429
|
+
export { ChangeSet, ChangeSetLive }
|
package/src/closed.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthoringError } from "
|
|
1
|
+
import { AuthoringError } from "./errors.ts"
|
|
2
2
|
import {
|
|
3
3
|
type AnyField,
|
|
4
4
|
assertDeclarationOrderKey,
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
type Infer,
|
|
9
9
|
ownHandles,
|
|
10
10
|
signaturesAgree
|
|
11
|
-
} from "
|
|
12
|
-
import { descriptorCache } from "
|
|
11
|
+
} from "./fields.ts"
|
|
12
|
+
import { descriptorCache } from "./immutable.ts"
|
|
13
13
|
import {
|
|
14
14
|
type AnyRelation,
|
|
15
15
|
type FieldsShape,
|
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
type RelationField,
|
|
18
18
|
relationDescriptor,
|
|
19
19
|
relationFields
|
|
20
|
-
} from "
|
|
21
|
-
import { fieldValue, recordValue } from "
|
|
20
|
+
} from "./relation.ts"
|
|
21
|
+
import { fieldValue, recordValue } from "./values.ts"
|
|
22
22
|
|
|
23
23
|
type PayloadField = AnyField
|
|
24
24
|
type PayloadColumns = FieldsShape & { readonly id?: never }
|