@bjornpagen/bumbledb 1.0.1 → 1.2.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 +176 -36
- package/README.md +70 -26
- package/dist/capacity.d.ts +15 -55
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js +63 -12
- package/dist/capacity.js.map +1 -1
- package/dist/changes.d.ts +28 -6
- package/dist/changes.d.ts.map +1 -1
- package/dist/changes.js +119 -71
- package/dist/changes.js.map +1 -1
- package/dist/closed.d.ts +23 -51
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +110 -168
- package/dist/closed.js.map +1 -1
- package/dist/codec.d.ts +8 -14
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +113 -188
- package/dist/codec.js.map +1 -1
- package/dist/compile.d.ts +17 -18
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +41 -20
- package/dist/compile.js.map +1 -1
- package/dist/db-native.d.ts +76 -41
- package/dist/db-native.d.ts.map +1 -1
- package/dist/db-native.js +8 -0
- package/dist/db-native.js.map +1 -1
- package/dist/db.d.ts +61 -26
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +152 -85
- package/dist/db.js.map +1 -1
- package/dist/errors.d.ts +11 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +13 -1
- package/dist/errors.js.map +1 -1
- package/dist/face.d.ts +19 -25
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +30 -24
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +13 -26
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +89 -116
- package/dist/fields.js.map +1 -1
- package/dist/immutable.d.ts +10 -0
- package/dist/immutable.d.ts.map +1 -0
- package/dist/immutable.js +75 -0
- package/dist/immutable.js.map +1 -0
- package/dist/index.d.ts +16 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/internal/log.d.ts +6 -4
- package/dist/internal/log.d.ts.map +1 -1
- package/dist/internal/log.js +3 -1
- package/dist/internal/log.js.map +1 -1
- package/dist/law.d.ts +11 -11
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +1 -1
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +11 -6
- package/dist/lower.js.map +1 -1
- package/dist/migration.d.ts +2 -3
- package/dist/migration.d.ts.map +1 -1
- package/dist/migration.js +5 -5
- package/dist/migration.js.map +1 -1
- package/dist/native.d.ts +2 -2
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +1 -1
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js.map +1 -1
- package/dist/query/description.d.ts +33 -0
- package/dist/query/description.d.ts.map +1 -0
- package/dist/query/description.js +302 -0
- package/dist/query/description.js.map +1 -0
- package/dist/query/lower.d.ts +60 -4
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +126 -161
- package/dist/query/lower.js.map +1 -1
- package/dist/query/parse-ir.d.ts +7 -2
- package/dist/query/parse-ir.d.ts.map +1 -1
- package/dist/query/parse-ir.js +240 -53
- package/dist/query/parse-ir.js.map +1 -1
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +8 -10
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +3 -4
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +5 -10
- package/dist/query/scope.js.map +1 -1
- package/dist/relation.d.ts +22 -48
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +30 -82
- package/dist/relation.js.map +1 -1
- package/dist/result.d.ts +10 -25
- package/dist/result.d.ts.map +1 -1
- package/dist/result.js +7 -12
- package/dist/result.js.map +1 -1
- package/dist/rows.d.ts +11 -14
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +49 -237
- package/dist/rows.js.map +1 -1
- package/dist/runtime-codes.d.ts +1 -1
- package/dist/runtime-codes.d.ts.map +1 -1
- package/dist/runtime-codes.js +1 -2
- package/dist/runtime-codes.js.map +1 -1
- package/dist/runtime-errors.d.ts +27 -15
- package/dist/runtime-errors.d.ts.map +1 -1
- package/dist/runtime-errors.js +44 -8
- package/dist/runtime-errors.js.map +1 -1
- package/dist/runtime-native.d.ts +16 -34
- package/dist/runtime-native.d.ts.map +1 -1
- package/dist/runtime-native.js.map +1 -1
- package/dist/runtime.d.ts +11 -28
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +14 -54
- package/dist/runtime.js.map +1 -1
- package/dist/schema.d.ts +9 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +85 -24
- package/dist/schema.js.map +1 -1
- package/dist/selection.d.ts +27 -0
- package/dist/selection.d.ts.map +1 -0
- package/dist/selection.js +104 -0
- package/dist/selection.js.map +1 -0
- package/dist/shape.d.ts +6 -9
- package/dist/shape.d.ts.map +1 -1
- package/dist/statements.d.ts +17 -52
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +92 -111
- package/dist/statements.js.map +1 -1
- package/dist/values.d.ts +25 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +203 -0
- package/dist/values.js.map +1 -0
- package/pack-provenance.json +3 -3
- package/package.json +4 -4
- package/src/capacity.ts +86 -76
- package/src/changes.ts +225 -94
- package/src/closed.ts +161 -314
- package/src/codec.ts +123 -213
- package/src/compile.ts +61 -38
- package/src/db-native.ts +73 -68
- package/src/db.ts +268 -165
- package/src/errors.ts +16 -1
- package/src/face.ts +44 -74
- package/src/fields.ts +100 -146
- package/src/immutable.ts +76 -0
- package/src/index.ts +38 -31
- package/src/internal/log.ts +4 -5
- package/src/law.ts +14 -14
- package/src/lower.ts +13 -10
- package/src/migration.ts +5 -12
- package/src/native.ts +2 -1
- package/src/query/atom.ts +1 -0
- package/src/query/description.ts +394 -0
- package/src/query/lower.ts +139 -173
- package/src/query/parse-ir.ts +247 -54
- package/src/query/run.ts +15 -9
- package/src/query/scope.ts +10 -18
- package/src/relation.ts +58 -142
- package/src/result.ts +16 -45
- package/src/rows.ts +57 -250
- package/src/runtime-codes.ts +1 -2
- package/src/runtime-errors.ts +48 -8
- package/src/runtime-native.ts +13 -46
- package/src/runtime.ts +51 -119
- package/src/schema.ts +99 -29
- package/src/selection.ts +124 -0
- package/src/shape.ts +9 -9
- package/src/statements.ts +138 -189
- package/src/values.ts +223 -0
package/src/runtime-native.ts
CHANGED
|
@@ -34,7 +34,7 @@ export interface RepositoryLockHandle {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/** Resource kinds installed in native worker tables. */
|
|
37
|
-
export type NativeKind = "snapshot" | "result" | "cursor" | "draft" | "changes" | "repository-lock"
|
|
37
|
+
export type NativeKind = "snapshot" | "prepared" | "result" | "cursor" | "draft" | "changes" | "repository-lock"
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* Checked capability into the native registry. JS tokens validate
|
|
@@ -96,28 +96,13 @@ export type LogTakeWire =
|
|
|
96
96
|
readonly digest: Uint8Array
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
export interface PolicyWire {
|
|
100
|
-
readonly inputBytes: bigint
|
|
101
|
-
readonly workingBytes: bigint
|
|
102
|
-
readonly scratchBytes: bigint
|
|
103
|
-
readonly resultBytes: bigint
|
|
104
|
-
readonly rows: bigint
|
|
105
|
-
readonly workUnits: bigint
|
|
106
|
-
readonly timeoutMs: number
|
|
107
|
-
}
|
|
108
|
-
|
|
109
99
|
export interface OptionsWire {
|
|
110
|
-
readonly workers
|
|
111
|
-
readonly queueCapacity
|
|
112
|
-
readonly cleanupCapacity
|
|
113
|
-
readonly ownerCapacity
|
|
114
|
-
readonly nativeHandleCapacity
|
|
115
|
-
readonly
|
|
116
|
-
readonly workingBytes: bigint
|
|
117
|
-
readonly scratchBytes: bigint
|
|
118
|
-
readonly resultBytes: bigint
|
|
119
|
-
readonly chunkBytes: bigint
|
|
120
|
-
readonly cleanupTimeoutMs: number
|
|
100
|
+
readonly workers?: number | undefined
|
|
101
|
+
readonly queueCapacity?: number | undefined
|
|
102
|
+
readonly cleanupCapacity?: number | undefined
|
|
103
|
+
readonly ownerCapacity?: number | undefined
|
|
104
|
+
readonly nativeHandleCapacity?: number | undefined
|
|
105
|
+
readonly cleanupTimeoutMs?: number | undefined
|
|
121
106
|
}
|
|
122
107
|
|
|
123
108
|
export interface InspectionWire {
|
|
@@ -128,10 +113,6 @@ export interface InspectionWire {
|
|
|
128
113
|
readonly owners: bigint
|
|
129
114
|
readonly databases: bigint
|
|
130
115
|
readonly natives: bigint
|
|
131
|
-
readonly inputBytes: bigint
|
|
132
|
-
readonly workingBytes: bigint
|
|
133
|
-
readonly scratchBytes: bigint
|
|
134
|
-
readonly resultBytes: bigint
|
|
135
116
|
}
|
|
136
117
|
|
|
137
118
|
export type CloseWire =
|
|
@@ -142,8 +123,8 @@ export type CloseWire =
|
|
|
142
123
|
interface RuntimeNative {
|
|
143
124
|
runtimeErrorCodes(): readonly string[]
|
|
144
125
|
runtimeOpen(options: OptionsWire): RuntimeHandle
|
|
145
|
-
runtimeReady(runtime: RuntimeHandle,
|
|
146
|
-
runtimeHash(runtime: RuntimeHandle,
|
|
126
|
+
runtimeReady(runtime: RuntimeHandle, callback: () => void): OperationHandle
|
|
127
|
+
runtimeHash(runtime: RuntimeHandle, bytes: Uint8Array, callback: () => void): OperationHandle
|
|
147
128
|
runtimeTake(operation: OperationHandle): Uint8Array | null
|
|
148
129
|
runtimeCancel(operation: OperationHandle, callback: (report: CloseWire) => void): void
|
|
149
130
|
runtimeClose(runtime: RuntimeHandle, callback: (report: CloseWire) => void): void
|
|
@@ -156,20 +137,14 @@ interface RuntimeNative {
|
|
|
156
137
|
* Predelivery: no JS take; cursor stays on row1 so retry does not skip.
|
|
157
138
|
*/
|
|
158
139
|
runtimeArmPublicationCancel(runtime: RuntimeHandle): void
|
|
159
|
-
runtimeDirectoryAcquire(
|
|
160
|
-
runtime: RuntimeHandle,
|
|
161
|
-
policy: PolicyWire,
|
|
162
|
-
path: string,
|
|
163
|
-
callback: () => void
|
|
164
|
-
): OperationHandle
|
|
140
|
+
runtimeDirectoryAcquire(runtime: RuntimeHandle, path: string, callback: () => void): OperationHandle
|
|
165
141
|
runtimeDirectoryTake(operation: OperationHandle): DirectoryHandle
|
|
166
|
-
runtimeDirectoryBegin(owner: DirectoryHandle
|
|
142
|
+
runtimeDirectoryBegin(owner: DirectoryHandle): OperationHandle
|
|
167
143
|
runtimeDirectoryCheck(operation: OperationHandle): void
|
|
168
144
|
runtimeDirectoryEnd(operation: OperationHandle): void
|
|
169
145
|
runtimeDirectoryClose(owner: DirectoryHandle, remove: boolean, callback: (report: CloseWire) => void): void
|
|
170
146
|
runtimeDirectoryDbOpen(
|
|
171
147
|
owner: DirectoryHandle,
|
|
172
|
-
policy: PolicyWire,
|
|
173
148
|
childName: string,
|
|
174
149
|
spec: SchemaSpec,
|
|
175
150
|
create: boolean,
|
|
@@ -178,12 +153,11 @@ interface RuntimeNative {
|
|
|
178
153
|
runtimeDbTake(operation: OperationHandle): ManagedDbOutcome
|
|
179
154
|
runtimeManagedDbClose(db: DbHandle, callback: (report: CloseWire) => void): void
|
|
180
155
|
|
|
181
|
-
// --- successor log grammar on the executor (
|
|
156
|
+
// --- successor log grammar on the executor (hashing over
|
|
182
157
|
// whole canonical change payloads; C06 through C09) ---
|
|
183
158
|
runtimeLogCommandSeal(
|
|
184
159
|
runtime: RuntimeHandle,
|
|
185
160
|
schema: LogSchemaHandle,
|
|
186
|
-
policy: PolicyWire,
|
|
187
161
|
metadata: LogCommandMetadata,
|
|
188
162
|
changes: Uint8Array,
|
|
189
163
|
result: Uint8Array | null,
|
|
@@ -193,14 +167,12 @@ interface RuntimeNative {
|
|
|
193
167
|
runtimeLogCommandParse(
|
|
194
168
|
runtime: RuntimeHandle,
|
|
195
169
|
schema: LogSchemaHandle,
|
|
196
|
-
policy: PolicyWire,
|
|
197
170
|
bytes: Uint8Array,
|
|
198
171
|
limits: LogLimits,
|
|
199
172
|
callback: () => void
|
|
200
173
|
): OperationHandle
|
|
201
174
|
runtimeLogDecisionDecode(
|
|
202
175
|
runtime: RuntimeHandle,
|
|
203
|
-
policy: PolicyWire,
|
|
204
176
|
bytes: Uint8Array,
|
|
205
177
|
parent: LogDecisionStamp | null,
|
|
206
178
|
limits: LogLimits,
|
|
@@ -208,12 +180,7 @@ interface RuntimeNative {
|
|
|
208
180
|
): OperationHandle
|
|
209
181
|
runtimeLogTake(operation: OperationHandle): LogTakeWire
|
|
210
182
|
/** L14 mint: `Runtime::mint_repository_lock` stamps `NativeKind::RepositoryLock` at take. */
|
|
211
|
-
logRepositoryLockAcquire(
|
|
212
|
-
runtime: RuntimeHandle,
|
|
213
|
-
policy: PolicyWire,
|
|
214
|
-
directory: string,
|
|
215
|
-
callback: () => void
|
|
216
|
-
): OperationHandle
|
|
183
|
+
logRepositoryLockAcquire(runtime: RuntimeHandle, directory: string, callback: () => void): OperationHandle
|
|
217
184
|
logRepositoryLockTake(operation: OperationHandle): RepositoryLockHandle
|
|
218
185
|
logRepositoryLockRelease(owner: RepositoryLockHandle, callback: (report: CloseWire) => void): void
|
|
219
186
|
}
|
package/src/runtime.ts
CHANGED
|
@@ -1,43 +1,21 @@
|
|
|
1
1
|
import { Context, Duration, Effect, Exit, Layer } from "effect"
|
|
2
2
|
import type { CloseReport, OutstandingWork } from "#runtime-errors.ts"
|
|
3
3
|
import { CloseFailure, DbError, dbError } from "#runtime-errors.ts"
|
|
4
|
-
import type {
|
|
5
|
-
CloseWire,
|
|
6
|
-
OperationHandle,
|
|
7
|
-
OptionsWire,
|
|
8
|
-
PolicyWire,
|
|
9
|
-
RepositoryLockHandle,
|
|
10
|
-
RuntimeHandle
|
|
11
|
-
} from "#runtime-native.ts"
|
|
4
|
+
import type { CloseWire, OperationHandle, OptionsWire, RepositoryLockHandle, RuntimeHandle } from "#runtime-native.ts"
|
|
12
5
|
import { runtimeNative } from "#runtime-native.ts"
|
|
13
6
|
|
|
14
|
-
export interface ExecutionPolicy {
|
|
15
|
-
readonly inputBytes: bigint
|
|
16
|
-
readonly workingBytes: bigint
|
|
17
|
-
readonly scratchBytes: bigint
|
|
18
|
-
readonly resultBytes: bigint
|
|
19
|
-
readonly rows: bigint
|
|
20
|
-
readonly workUnits: bigint
|
|
21
|
-
readonly timeout: Duration.Input
|
|
22
|
-
}
|
|
23
|
-
|
|
24
7
|
export interface NativeRuntimeOptions {
|
|
25
|
-
readonly workers
|
|
26
|
-
readonly queueCapacity
|
|
27
|
-
readonly cleanupCapacity
|
|
28
|
-
readonly ownerCapacity
|
|
29
|
-
readonly nativeHandleCapacity
|
|
30
|
-
readonly
|
|
31
|
-
readonly workingBytes: bigint
|
|
32
|
-
readonly scratchBytes: bigint
|
|
33
|
-
readonly resultBytes: bigint
|
|
34
|
-
readonly chunkBytes: bigint
|
|
35
|
-
readonly cleanupTimeout: Duration.Input
|
|
8
|
+
readonly workers?: number
|
|
9
|
+
readonly queueCapacity?: number
|
|
10
|
+
readonly cleanupCapacity?: number
|
|
11
|
+
readonly ownerCapacity?: number
|
|
12
|
+
readonly nativeHandleCapacity?: number
|
|
13
|
+
readonly cleanupTimeout?: Duration.Input
|
|
36
14
|
}
|
|
37
15
|
|
|
38
16
|
interface RuntimeService {
|
|
39
17
|
readonly close: () => Effect.Effect<CloseReport>
|
|
40
|
-
readonly inspect: (
|
|
18
|
+
readonly inspect: () => Effect.Effect<OutstandingWork, DbError>
|
|
41
19
|
}
|
|
42
20
|
|
|
43
21
|
const owners = new WeakMap<RuntimeService, RuntimeHandle>()
|
|
@@ -51,43 +29,23 @@ function count(value: number, operation: string): number {
|
|
|
51
29
|
return value
|
|
52
30
|
}
|
|
53
31
|
|
|
54
|
-
function bytes(value: bigint, operation: string): bigint {
|
|
55
|
-
if (typeof value !== "bigint" || value < 0n || value > 0xffffffffffffffffn) throw invalid(operation)
|
|
56
|
-
return value
|
|
57
|
-
}
|
|
58
|
-
|
|
59
32
|
function millis(value: Duration.Input, operation: string): number {
|
|
60
33
|
const duration = Duration.toMillis(value)
|
|
61
34
|
if (!Number.isFinite(duration) || duration < 0 || duration > 0xffffffff) throw invalid(operation)
|
|
62
35
|
return Math.ceil(duration)
|
|
63
36
|
}
|
|
64
37
|
|
|
65
|
-
export function policyWire(work: ExecutionPolicy, operation: string): PolicyWire {
|
|
66
|
-
return {
|
|
67
|
-
inputBytes: bytes(work.inputBytes, operation),
|
|
68
|
-
workingBytes: bytes(work.workingBytes, operation),
|
|
69
|
-
scratchBytes: bytes(work.scratchBytes, operation),
|
|
70
|
-
resultBytes: bytes(work.resultBytes, operation),
|
|
71
|
-
rows: bytes(work.rows, operation),
|
|
72
|
-
workUnits: bytes(work.workUnits, operation),
|
|
73
|
-
timeoutMs: millis(work.timeout, operation)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
38
|
function options(value: NativeRuntimeOptions): OptionsWire {
|
|
78
39
|
const operation = "NativeRuntime.acquire"
|
|
79
40
|
return {
|
|
80
|
-
workers: count(value.workers, operation),
|
|
81
|
-
queueCapacity: count(value.queueCapacity, operation),
|
|
82
|
-
cleanupCapacity: count(value.cleanupCapacity, operation),
|
|
83
|
-
ownerCapacity: count(value.ownerCapacity, operation),
|
|
84
|
-
nativeHandleCapacity:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
resultBytes: bytes(value.resultBytes, operation),
|
|
89
|
-
chunkBytes: bytes(value.chunkBytes, operation),
|
|
90
|
-
cleanupTimeoutMs: count(millis(value.cleanupTimeout, operation), operation)
|
|
41
|
+
workers: value.workers === undefined ? undefined : count(value.workers, operation),
|
|
42
|
+
queueCapacity: value.queueCapacity === undefined ? undefined : count(value.queueCapacity, operation),
|
|
43
|
+
cleanupCapacity: value.cleanupCapacity === undefined ? undefined : count(value.cleanupCapacity, operation),
|
|
44
|
+
ownerCapacity: value.ownerCapacity === undefined ? undefined : count(value.ownerCapacity, operation),
|
|
45
|
+
nativeHandleCapacity:
|
|
46
|
+
value.nativeHandleCapacity === undefined ? undefined : count(value.nativeHandleCapacity, operation),
|
|
47
|
+
cleanupTimeoutMs:
|
|
48
|
+
value.cleanupTimeout === undefined ? undefined : count(millis(value.cleanupTimeout, operation), operation)
|
|
91
49
|
}
|
|
92
50
|
}
|
|
93
51
|
|
|
@@ -169,14 +127,6 @@ function afterClose<A, E, R>(
|
|
|
169
127
|
return effect.pipe(Effect.onExit(() => Effect.die(new CloseFailure({ operation, report }))))
|
|
170
128
|
}
|
|
171
129
|
|
|
172
|
-
/** Independent caps intersect: a delivery request cannot enlarge `work.resultBytes`. */
|
|
173
|
-
export function deliveryResultBytes(requested: bigint, work: ExecutionPolicy): bigint {
|
|
174
|
-
if (typeof requested !== "bigint" || requested < 0n) {
|
|
175
|
-
throw invalid("deliveryResultBytes")
|
|
176
|
-
}
|
|
177
|
-
return requested < work.resultBytes ? requested : work.resultBytes
|
|
178
|
-
}
|
|
179
|
-
|
|
180
130
|
function close(handle: RuntimeHandle): Effect.Effect<CloseReport> {
|
|
181
131
|
return drain("NativeRuntime.close", (callback) => runtimeNative.runtimeClose(handle, callback))
|
|
182
132
|
}
|
|
@@ -257,54 +207,41 @@ const acquire = Effect.fn("NativeRuntime.acquire")(function* (configuration: Nat
|
|
|
257
207
|
const wire = options(configuration)
|
|
258
208
|
handle = runtimeNative.runtimeOpen(wire)
|
|
259
209
|
const owner = handle
|
|
260
|
-
const lease = runtimeNative.runtimeReady(
|
|
261
|
-
|
|
262
|
-
{
|
|
263
|
-
inputBytes: 0n,
|
|
264
|
-
workingBytes: 0n,
|
|
265
|
-
scratchBytes: 0n,
|
|
266
|
-
resultBytes: 0n,
|
|
267
|
-
rows: 0n,
|
|
268
|
-
workUnits: 1n,
|
|
269
|
-
timeoutMs: wire.cleanupTimeoutMs
|
|
270
|
-
},
|
|
271
|
-
() => {
|
|
272
|
-
if (signal.aborted) {
|
|
273
|
-
try {
|
|
274
|
-
runtimeNative.runtimeClose(owner, (report) => {
|
|
275
|
-
stash.report = closeReport("NativeRuntime.acquire.cancel", report)
|
|
276
|
-
})
|
|
277
|
-
} catch (cause) {
|
|
278
|
-
stash.report = { kind: "failed", error: failure("NativeRuntime.acquire.cancel", cause) }
|
|
279
|
-
}
|
|
280
|
-
return
|
|
281
|
-
}
|
|
210
|
+
const lease = runtimeNative.runtimeReady(owner, () => {
|
|
211
|
+
if (signal.aborted) {
|
|
282
212
|
try {
|
|
283
|
-
runtimeNative.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
inspect: Effect.fn("NativeRuntime.inspect")(function* (work) {
|
|
287
|
-
yield* nativeOperation(
|
|
288
|
-
"NativeRuntime.inspect",
|
|
289
|
-
(callback) =>
|
|
290
|
-
runtimeNative.runtimeReady(owner, policyWire(work, "NativeRuntime.inspect"), callback),
|
|
291
|
-
() => undefined
|
|
292
|
-
)
|
|
293
|
-
return runtimeNative.runtimeInspect(owner)
|
|
294
|
-
})
|
|
295
|
-
}
|
|
296
|
-
owners.set(service, owner)
|
|
297
|
-
resume(Effect.succeed(service))
|
|
213
|
+
runtimeNative.runtimeClose(owner, (report) => {
|
|
214
|
+
stash.report = closeReport("NativeRuntime.acquire.cancel", report)
|
|
215
|
+
})
|
|
298
216
|
} catch (cause) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
217
|
+
stash.report = { kind: "failed", error: failure("NativeRuntime.acquire.cancel", cause) }
|
|
218
|
+
}
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
runtimeNative.runtimeTake(lease)
|
|
223
|
+
const service: RuntimeService = {
|
|
224
|
+
close: () => close(owner),
|
|
225
|
+
inspect: Effect.fn("NativeRuntime.inspect")(function* () {
|
|
226
|
+
yield* nativeOperation(
|
|
227
|
+
"NativeRuntime.inspect",
|
|
228
|
+
(callback) => runtimeNative.runtimeReady(owner, callback),
|
|
229
|
+
() => undefined
|
|
303
230
|
)
|
|
304
|
-
|
|
231
|
+
return runtimeNative.runtimeInspect(owner)
|
|
232
|
+
})
|
|
305
233
|
}
|
|
234
|
+
owners.set(service, owner)
|
|
235
|
+
resume(Effect.succeed(service))
|
|
236
|
+
} catch (cause) {
|
|
237
|
+
const error = failure("NativeRuntime.acquire", cause)
|
|
238
|
+
resume(
|
|
239
|
+
close(owner).pipe(
|
|
240
|
+
Effect.flatMap((report) => afterClose("NativeRuntime.acquire", report, Effect.fail(error)))
|
|
241
|
+
)
|
|
242
|
+
)
|
|
306
243
|
}
|
|
307
|
-
)
|
|
244
|
+
})
|
|
308
245
|
} catch (cause) {
|
|
309
246
|
const error = failure("NativeRuntime.acquire", cause)
|
|
310
247
|
resume(
|
|
@@ -333,7 +270,7 @@ const acquire = Effect.fn("NativeRuntime.acquire")(function* (configuration: Nat
|
|
|
333
270
|
export class NativeRuntime extends Context.Service<NativeRuntime, RuntimeService>()(
|
|
334
271
|
"@bjornpagen/bumbledb/NativeRuntime"
|
|
335
272
|
) {
|
|
336
|
-
static layer(options: NativeRuntimeOptions): Layer.Layer<NativeRuntime, DbError> {
|
|
273
|
+
static layer(options: NativeRuntimeOptions = {}): Layer.Layer<NativeRuntime, DbError> {
|
|
337
274
|
return Layer.effect(NativeRuntime, acquire(options))
|
|
338
275
|
}
|
|
339
276
|
}
|
|
@@ -374,17 +311,12 @@ function joinLockRelease(operation: string, owner: RepositoryLockHandle): Effect
|
|
|
374
311
|
*/
|
|
375
312
|
export const internalAcquireRepositoryLock = Effect.fn("internalAcquireRepositoryLock")(function* (
|
|
376
313
|
operation: string,
|
|
377
|
-
directory: string
|
|
378
|
-
work: ExecutionPolicy
|
|
314
|
+
directory: string
|
|
379
315
|
) {
|
|
380
316
|
if (directory.length === 0) {
|
|
381
317
|
return yield* Effect.fail(invalid(operation))
|
|
382
318
|
}
|
|
383
319
|
const runtime = yield* runtimeHandle()
|
|
384
|
-
const wire = yield* Effect.try({
|
|
385
|
-
try: () => policyWire(work, operation),
|
|
386
|
-
catch: () => invalid(operation)
|
|
387
|
-
})
|
|
388
320
|
const closeOp = `${operation}.repositoryLock`
|
|
389
321
|
return yield* Effect.uninterruptibleMask((restore) =>
|
|
390
322
|
Effect.gen(function* () {
|
|
@@ -406,7 +338,7 @@ export const internalAcquireRepositoryLock = Effect.fn("internalAcquireRepositor
|
|
|
406
338
|
const owner = yield* restore(
|
|
407
339
|
nativeOperationWith(
|
|
408
340
|
operation,
|
|
409
|
-
(callback) => runtimeNative.logRepositoryLockAcquire(runtime,
|
|
341
|
+
(callback) => runtimeNative.logRepositoryLockAcquire(runtime, directory, callback),
|
|
410
342
|
runtimeNative.logRepositoryLockTake,
|
|
411
343
|
(value) => value
|
|
412
344
|
)
|
|
@@ -421,7 +353,7 @@ export const internalAcquireRepositoryLock = Effect.fn("internalAcquireRepositor
|
|
|
421
353
|
})
|
|
422
354
|
|
|
423
355
|
/** Internal first executor consumer; not a replacement row codec or public hash API. */
|
|
424
|
-
export const hashChunk = Effect.fn("bumbledb.hashChunk")(function* (input: Uint8Array
|
|
356
|
+
export const hashChunk = Effect.fn("bumbledb.hashChunk")(function* (input: Uint8Array) {
|
|
425
357
|
const runtime = yield* NativeRuntime
|
|
426
358
|
const handle = owners.get(runtime)
|
|
427
359
|
if (handle === undefined) return yield* Effect.fail(invalid("hashChunk"))
|
|
@@ -429,7 +361,7 @@ export const hashChunk = Effect.fn("bumbledb.hashChunk")(function* (input: Uint8
|
|
|
429
361
|
"hashChunk",
|
|
430
362
|
(callback) => {
|
|
431
363
|
if (!(input instanceof Uint8Array) || !(input.buffer instanceof ArrayBuffer)) throw invalid("hashChunk")
|
|
432
|
-
return runtimeNative.runtimeHash(handle,
|
|
364
|
+
return runtimeNative.runtimeHash(handle, input, callback)
|
|
433
365
|
},
|
|
434
366
|
(value) => {
|
|
435
367
|
if (value === null) throw dbError("hashChunk", { _tag: "Internal" })
|
package/src/schema.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from "node:util"
|
|
1
2
|
import { AuthoringError, SdkInvariantError } from "#errors.ts"
|
|
2
3
|
/**
|
|
3
4
|
* `schema` — assembles relations and statements into a theory value (the
|
|
@@ -17,13 +18,15 @@ import { AuthoringError, SdkInvariantError } from "#errors.ts"
|
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
import type { AnyClosed } from "#closed.ts"
|
|
20
|
-
import { isClosedMember, sealedFieldOf } from "#closed.ts"
|
|
21
|
-
import type {
|
|
21
|
+
import { isClosedMember, memberDescriptor, membersAgree, sealedFieldOf } from "#closed.ts"
|
|
22
|
+
import type { AnyFace } from "#face.ts"
|
|
22
23
|
import { assertDeclarationOrderKey, assertDeclarationRecord, rosterOf } from "#fields.ts"
|
|
24
|
+
import { descriptorCache, isImmutable } from "#immutable.ts"
|
|
23
25
|
import { type ClassesOf, classesComplete, computeClasses, type LawfulStatements, type SchemaClasses } from "#law.ts"
|
|
24
26
|
import type { AnyRelation } from "#relation.ts"
|
|
25
27
|
import type { LiteralSetSpec, LiteralSpec } from "#spec.ts"
|
|
26
|
-
import {
|
|
28
|
+
import { renderStatement, type Statement, statementDescriptor } from "#statements.ts"
|
|
29
|
+
import { arrayValue, recordValue } from "#values.ts"
|
|
27
30
|
|
|
28
31
|
interface ImpliedKeys {
|
|
29
32
|
readonly rendered: ReadonlySet<string>
|
|
@@ -54,7 +57,7 @@ function collectImplied(name: string, relations: SchemaRelations): ImpliedKeys {
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
function statementOwners(statement: Statement): readonly SchemaRelation[] {
|
|
57
|
-
const data = statement
|
|
60
|
+
const data = statement
|
|
58
61
|
if (data.kind === "key") {
|
|
59
62
|
return [data.owner]
|
|
60
63
|
}
|
|
@@ -69,9 +72,9 @@ function verifyMembership(name: string, relations: SchemaRelations, statement: S
|
|
|
69
72
|
message: `schema ${name}: relation ${owner.name} is not declared in this schema — ${rendered}`
|
|
70
73
|
})
|
|
71
74
|
}
|
|
72
|
-
if (member
|
|
75
|
+
if (!membersAgree(member, owner)) {
|
|
73
76
|
throw new AuthoringError({
|
|
74
|
-
message: `schema ${name}: statement references a different relation
|
|
77
|
+
message: `schema ${name}: statement references a different relation declaration named ${owner.name} than the one this schema declares — ${rendered}`
|
|
75
78
|
})
|
|
76
79
|
}
|
|
77
80
|
}
|
|
@@ -86,7 +89,7 @@ function bindingLiterals(set: LiteralSetSpec): readonly LiteralSpec[] {
|
|
|
86
89
|
|
|
87
90
|
function verifyBindingHandles(
|
|
88
91
|
name: string,
|
|
89
|
-
face:
|
|
92
|
+
face: AnyFace,
|
|
90
93
|
binding: { readonly field: string; readonly set: LiteralSetSpec },
|
|
91
94
|
rendered: string
|
|
92
95
|
): void {
|
|
@@ -109,7 +112,7 @@ function verifyBindingHandles(
|
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
function verifyHandles(name: string, statement: Statement, rendered: string): void {
|
|
112
|
-
const data = statement
|
|
115
|
+
const data = statement
|
|
113
116
|
if (data.kind === "key") {
|
|
114
117
|
return
|
|
115
118
|
}
|
|
@@ -122,11 +125,11 @@ function verifyHandles(name: string, statement: Statement, rendered: string): vo
|
|
|
122
125
|
|
|
123
126
|
function closedTargetOf(statements: readonly Statement[], owner: string, field: string): string | undefined {
|
|
124
127
|
for (const statement of statements) {
|
|
125
|
-
const data = statement
|
|
128
|
+
const data = statement
|
|
126
129
|
if (data.kind !== "containment" && data.kind !== "mirrors") {
|
|
127
130
|
continue
|
|
128
131
|
}
|
|
129
|
-
const pairs: Array<readonly [
|
|
132
|
+
const pairs: Array<readonly [AnyFace, AnyFace]> = [[data.source, data.target]]
|
|
130
133
|
if (data.kind === "mirrors") {
|
|
131
134
|
pairs.push([data.target, data.source])
|
|
132
135
|
}
|
|
@@ -148,7 +151,7 @@ function closedTargetOf(statements: readonly Statement[], owner: string, field:
|
|
|
148
151
|
|
|
149
152
|
function verifyClosedReferences(name: string, statements: readonly Statement[]): void {
|
|
150
153
|
for (const statement of statements) {
|
|
151
|
-
const data = statement
|
|
154
|
+
const data = statement
|
|
152
155
|
if (data.kind === "key") {
|
|
153
156
|
continue
|
|
154
157
|
}
|
|
@@ -164,7 +167,7 @@ function verifyClosedReferences(name: string, statements: readonly Statement[]):
|
|
|
164
167
|
function verifyClosedReferenceBinding(
|
|
165
168
|
name: string,
|
|
166
169
|
statements: readonly Statement[],
|
|
167
|
-
face:
|
|
170
|
+
face: AnyFace,
|
|
168
171
|
binding: { readonly field: string; readonly set: LiteralSetSpec },
|
|
169
172
|
rendered: string
|
|
170
173
|
): void {
|
|
@@ -213,7 +216,7 @@ function verifyTargetKeys(
|
|
|
213
216
|
): void {
|
|
214
217
|
const declared = new Map<string, Array<readonly string[]>>()
|
|
215
218
|
for (const statement of statements) {
|
|
216
|
-
const data = statement
|
|
219
|
+
const data = statement
|
|
217
220
|
if (data.kind !== "key") {
|
|
218
221
|
continue
|
|
219
222
|
}
|
|
@@ -225,7 +228,7 @@ function verifyTargetKeys(
|
|
|
225
228
|
}
|
|
226
229
|
}
|
|
227
230
|
for (const statement of statements) {
|
|
228
|
-
const data = statement
|
|
231
|
+
const data = statement
|
|
229
232
|
if (data.kind === "key") {
|
|
230
233
|
continue
|
|
231
234
|
}
|
|
@@ -251,7 +254,7 @@ function verifyTargetKeys(
|
|
|
251
254
|
*/
|
|
252
255
|
function verifyTargetKeyFace(
|
|
253
256
|
name: string,
|
|
254
|
-
face:
|
|
257
|
+
face: AnyFace,
|
|
255
258
|
implied: ReadonlyMap<string, ReadonlyArray<readonly string[]>>,
|
|
256
259
|
declared: ReadonlyMap<string, ReadonlyArray<readonly string[]>>,
|
|
257
260
|
rendered: string
|
|
@@ -310,25 +313,92 @@ interface Schema<Rels extends SchemaRelations, Classes extends SchemaClasses = S
|
|
|
310
313
|
|
|
311
314
|
type AnySchema = Schema<SchemaRelations>
|
|
312
315
|
|
|
316
|
+
/**
|
|
317
|
+
* Logical schema equivalence, including the ordered native ordinals and
|
|
318
|
+
* host decoding domains. Schema display names do not change the theory.
|
|
319
|
+
* A database/snapshot still has its own resource identity and lifetime.
|
|
320
|
+
*/
|
|
321
|
+
function schemasAgree(leftInput: AnySchema, rightInput: AnySchema): boolean {
|
|
322
|
+
const left = schemaDescriptor(leftInput)
|
|
323
|
+
const right = schemaDescriptor(rightInput)
|
|
324
|
+
if (left === right) return true
|
|
325
|
+
const cacheable = isImmutable(left) && isImmutable(right)
|
|
326
|
+
const cached = schemaComparisons.get(left)?.get(right)
|
|
327
|
+
if (cacheable && cached !== undefined) return cached
|
|
328
|
+
const names = Object.keys(left.relations)
|
|
329
|
+
const otherNames = Object.keys(right.relations)
|
|
330
|
+
const equal =
|
|
331
|
+
names.length === otherNames.length &&
|
|
332
|
+
names.every((name, index) => {
|
|
333
|
+
const member = right.relations[name]
|
|
334
|
+
return name === otherNames[index] && member !== undefined && membersAgree(left.relations[name], member)
|
|
335
|
+
}) &&
|
|
336
|
+
isDeepStrictEqual(left.statements, right.statements) &&
|
|
337
|
+
isDeepStrictEqual(left.classes, right.classes)
|
|
338
|
+
if (cacheable) {
|
|
339
|
+
let comparisons = schemaComparisons.get(left)
|
|
340
|
+
if (comparisons === undefined) {
|
|
341
|
+
comparisons = new WeakMap()
|
|
342
|
+
schemaComparisons.set(left, comparisons)
|
|
343
|
+
}
|
|
344
|
+
comparisons.set(right, equal)
|
|
345
|
+
}
|
|
346
|
+
return equal
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const schemaComparisons = new WeakMap<AnySchema, WeakMap<AnySchema, boolean>>()
|
|
350
|
+
|
|
351
|
+
function schemaDescriptor<S extends AnySchema>(input: S): S
|
|
352
|
+
function schemaDescriptor(input: unknown): AnySchema
|
|
353
|
+
function schemaDescriptor(input: unknown): AnySchema {
|
|
354
|
+
return checkedSchema(input)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const checkedSchema = descriptorCache((input): AnySchema => {
|
|
358
|
+
const raw = recordValue("schema", input, ["name", "relations", "statements", "classes"])
|
|
359
|
+
if (typeof raw.name !== "string") throw new AuthoringError({ message: "schema: expected a name" })
|
|
360
|
+
const relations = ownRelations(raw.name, raw.relations)
|
|
361
|
+
const statements = arrayValue("schema statements", raw.statements, (_, statement) => statementDescriptor(statement))
|
|
362
|
+
const result = schema(raw.name, relations, statements)
|
|
363
|
+
const classes = recordValue("schema classes", raw.classes, Object.keys(result.classes))
|
|
364
|
+
for (const [name, fields] of Object.entries(result.classes)) {
|
|
365
|
+
const supplied = recordValue(`schema classes.${name}`, classes[name], Object.keys(fields))
|
|
366
|
+
for (const [field, value] of Object.entries(fields)) {
|
|
367
|
+
if (supplied[field] !== value)
|
|
368
|
+
throw new AuthoringError({ message: `schema classes.${name}.${field}: incorrect class` })
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return result
|
|
372
|
+
})
|
|
373
|
+
|
|
313
374
|
type EvaluatedClasses<C extends SchemaClasses> = C extends SchemaClasses
|
|
314
375
|
? { readonly [N in keyof C]: { readonly [F in keyof C[N]]: C[N][F] } }
|
|
315
376
|
: never
|
|
316
377
|
|
|
378
|
+
function ownRelations<R extends SchemaRelations>(name: string, input: R): R
|
|
379
|
+
function ownRelations(name: string, input: unknown): SchemaRelations
|
|
380
|
+
function ownRelations(name: string, input: unknown): SchemaRelations {
|
|
381
|
+
if (typeof input !== "object" || input === null)
|
|
382
|
+
throw new AuthoringError({ message: `schema ${name}: expected relations` })
|
|
383
|
+
assertDeclarationRecord(`schema ${name} relations`, input)
|
|
384
|
+
return Object.freeze(
|
|
385
|
+
Object.fromEntries(Object.entries(input).map(([name, member]) => [name, memberDescriptor(member)]))
|
|
386
|
+
)
|
|
387
|
+
}
|
|
388
|
+
|
|
317
389
|
function schema<const Rels extends SchemaRelations, const Stmts extends readonly Statement[]>(
|
|
318
390
|
name: string,
|
|
319
391
|
relations: Rels,
|
|
320
392
|
statements: Stmts & LawfulStatements<Rels, Stmts>
|
|
321
393
|
): Schema<Rels, EvaluatedClasses<ClassesOf<Rels, Stmts>>> {
|
|
322
|
-
|
|
394
|
+
assertDeclarationOrderKey("schema", name)
|
|
395
|
+
const ownedRelations = ownRelations(name, relations)
|
|
396
|
+
const ownedStatements = arrayValue("schema statements", statements, (_, statement) => statementDescriptor(statement))
|
|
397
|
+
const implied = collectImplied(name, ownedRelations)
|
|
323
398
|
const seen = new Set<string>()
|
|
324
|
-
for (const statement of
|
|
325
|
-
if (!isStatement(statement)) {
|
|
326
|
-
throw new AuthoringError({
|
|
327
|
-
message: `schema ${name}: a statement is minted only by key/contained/mirrors/capacity — a structural literal skips the construction-time arity and roster walls`
|
|
328
|
-
})
|
|
329
|
-
}
|
|
399
|
+
for (const statement of ownedStatements) {
|
|
330
400
|
const rendered = renderStatement(statement)
|
|
331
|
-
verifyMembership(name,
|
|
401
|
+
verifyMembership(name, ownedRelations, statement, rendered)
|
|
332
402
|
if (implied.rendered.has(rendered)) {
|
|
333
403
|
throw new AuthoringError({
|
|
334
404
|
message: `schema ${name}: ${rendered} is redundant here (closedness already implies it) — and rejected as a duplicate`
|
|
@@ -340,14 +410,14 @@ function schema<const Rels extends SchemaRelations, const Stmts extends readonly
|
|
|
340
410
|
seen.add(rendered)
|
|
341
411
|
verifyHandles(name, statement, rendered)
|
|
342
412
|
}
|
|
343
|
-
verifyClosedReferences(name,
|
|
344
|
-
verifyTargetKeys(name,
|
|
345
|
-
const classes = computeClasses(name,
|
|
346
|
-
if (!classesComplete<EvaluatedClasses<ClassesOf<Rels, Stmts>>>(classes,
|
|
413
|
+
verifyClosedReferences(name, ownedStatements)
|
|
414
|
+
verifyTargetKeys(name, ownedStatements, implied.roster)
|
|
415
|
+
const classes = computeClasses(name, ownedRelations, ownedStatements)
|
|
416
|
+
if (!classesComplete<EvaluatedClasses<ClassesOf<Rels, Stmts>>>(classes, ownedRelations)) {
|
|
347
417
|
throw new SdkInvariantError({ message: `schema ${name}: class-map construction incomplete` })
|
|
348
418
|
}
|
|
349
|
-
return Object.freeze({ name, relations, statements: Object.freeze(
|
|
419
|
+
return Object.freeze({ name, relations: ownedRelations, statements: Object.freeze(ownedStatements), classes })
|
|
350
420
|
}
|
|
351
421
|
|
|
352
422
|
export type { AnySchema, Schema, SchemaRelation, SchemaRelations }
|
|
353
|
-
export { schema }
|
|
423
|
+
export { schema, schemaDescriptor, schemasAgree }
|