@bjornpagen/bumbledb 1.3.1 → 2.0.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.
Files changed (290) hide show
  1. package/COOKBOOK.md +153 -77
  2. package/README.md +107 -41
  3. package/dist/alternatives.d.ts +5 -6
  4. package/dist/alternatives.d.ts.map +1 -1
  5. package/dist/alternatives.js +5 -6
  6. package/dist/alternatives.js.map +1 -1
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +85 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/capacity.d.ts +14 -17
  12. package/dist/capacity.d.ts.map +1 -1
  13. package/dist/capacity.js +7 -7
  14. package/dist/capacity.js.map +1 -1
  15. package/dist/changes.d.ts +32 -40
  16. package/dist/changes.d.ts.map +1 -1
  17. package/dist/changes.js +86 -104
  18. package/dist/changes.js.map +1 -1
  19. package/dist/closed.d.ts +2 -2
  20. package/dist/closed.d.ts.map +1 -1
  21. package/dist/closed.js +5 -5
  22. package/dist/closed.js.map +1 -1
  23. package/dist/codec.d.ts +13 -27
  24. package/dist/codec.d.ts.map +1 -1
  25. package/dist/codec.js +20 -21
  26. package/dist/codec.js.map +1 -1
  27. package/dist/compile.d.ts +26 -50
  28. package/dist/compile.d.ts.map +1 -1
  29. package/dist/compile.js +75 -64
  30. package/dist/compile.js.map +1 -1
  31. package/dist/database/database.d.ts +98 -0
  32. package/dist/database/database.d.ts.map +1 -0
  33. package/dist/database/database.js +249 -0
  34. package/dist/database/database.js.map +1 -0
  35. package/dist/database/driver.d.ts +40 -0
  36. package/dist/database/driver.d.ts.map +1 -0
  37. package/dist/database/driver.js +68 -0
  38. package/dist/database/driver.js.map +1 -0
  39. package/dist/database/fs.d.ts +12 -0
  40. package/dist/database/fs.d.ts.map +1 -0
  41. package/dist/database/fs.js +120 -0
  42. package/dist/database/fs.js.map +1 -0
  43. package/dist/database/generate.d.ts +26 -0
  44. package/dist/database/generate.d.ts.map +1 -0
  45. package/dist/database/generate.js +102 -0
  46. package/dist/database/generate.js.map +1 -0
  47. package/dist/database/hosted.d.ts +32 -0
  48. package/dist/database/hosted.d.ts.map +1 -0
  49. package/dist/database/hosted.js +44 -0
  50. package/dist/database/hosted.js.map +1 -0
  51. package/dist/database/io.d.ts +94 -0
  52. package/dist/database/io.d.ts.map +1 -0
  53. package/dist/database/io.js +35 -0
  54. package/dist/database/io.js.map +1 -0
  55. package/dist/database/mem.d.ts +26 -0
  56. package/dist/database/mem.d.ts.map +1 -0
  57. package/dist/database/mem.js +67 -0
  58. package/dist/database/mem.js.map +1 -0
  59. package/dist/database/migration.d.ts +55 -0
  60. package/dist/database/migration.d.ts.map +1 -0
  61. package/dist/database/migration.js +46 -0
  62. package/dist/database/migration.js.map +1 -0
  63. package/dist/database/s3.d.ts +36 -0
  64. package/dist/database/s3.d.ts.map +1 -0
  65. package/dist/database/s3.js +141 -0
  66. package/dist/database/s3.js.map +1 -0
  67. package/dist/db.d.ts +44 -128
  68. package/dist/db.d.ts.map +1 -1
  69. package/dist/db.js +163 -287
  70. package/dist/db.js.map +1 -1
  71. package/dist/engine.d.ts +7 -0
  72. package/dist/engine.d.ts.map +1 -0
  73. package/dist/engine.js +2 -0
  74. package/dist/engine.js.map +1 -0
  75. package/dist/errors.d.ts +152 -46
  76. package/dist/errors.d.ts.map +1 -1
  77. package/dist/errors.js +107 -19
  78. package/dist/errors.js.map +1 -1
  79. package/dist/face.d.ts +5 -5
  80. package/dist/face.d.ts.map +1 -1
  81. package/dist/face.js +6 -6
  82. package/dist/face.js.map +1 -1
  83. package/dist/fields.d.ts +4 -5
  84. package/dist/fields.d.ts.map +1 -1
  85. package/dist/fields.js +3 -3
  86. package/dist/fields.js.map +1 -1
  87. package/dist/index.d.ts +60 -57
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +27 -28
  90. package/dist/index.js.map +1 -1
  91. package/dist/judgment.d.ts +1 -1
  92. package/dist/judgment.js +1 -1
  93. package/dist/law.d.ts +16 -68
  94. package/dist/law.d.ts.map +1 -1
  95. package/dist/law.js +3 -3
  96. package/dist/law.js.map +1 -1
  97. package/dist/lower.d.ts +3 -3
  98. package/dist/lower.d.ts.map +1 -1
  99. package/dist/lower.js +35 -39
  100. package/dist/lower.js.map +1 -1
  101. package/dist/native/addon.d.ts +23 -0
  102. package/dist/native/addon.d.ts.map +1 -0
  103. package/dist/native/addon.js +15 -0
  104. package/dist/native/addon.js.map +1 -0
  105. package/dist/native/binding.d.ts +996 -0
  106. package/dist/native/json.d.ts +14 -0
  107. package/dist/native/json.d.ts.map +1 -0
  108. package/dist/native/json.js +73 -0
  109. package/dist/native/json.js.map +1 -0
  110. package/dist/native/load.d.ts +9 -0
  111. package/dist/native/load.d.ts.map +1 -0
  112. package/dist/native/load.js +30 -0
  113. package/dist/native/load.js.map +1 -0
  114. package/dist/native/op.d.ts +29 -0
  115. package/dist/native/op.d.ts.map +1 -0
  116. package/dist/native/op.js +50 -0
  117. package/dist/native/op.js.map +1 -0
  118. package/dist/query/atom.d.ts +13 -14
  119. package/dist/query/atom.d.ts.map +1 -1
  120. package/dist/query/atom.js +2 -2
  121. package/dist/query/atom.js.map +1 -1
  122. package/dist/query/compute.d.ts +4 -4
  123. package/dist/query/compute.d.ts.map +1 -1
  124. package/dist/query/compute.js +4 -4
  125. package/dist/query/compute.js.map +1 -1
  126. package/dist/query/find.d.ts +8 -8
  127. package/dist/query/find.d.ts.map +1 -1
  128. package/dist/query/find.js +1 -1
  129. package/dist/query/lower.d.ts +22 -17
  130. package/dist/query/lower.d.ts.map +1 -1
  131. package/dist/query/lower.js +230 -343
  132. package/dist/query/lower.js.map +1 -1
  133. package/dist/query/run.d.ts +5 -5
  134. package/dist/query/run.d.ts.map +1 -1
  135. package/dist/query/run.js +32 -15
  136. package/dist/query/run.js.map +1 -1
  137. package/dist/query/scope.d.ts +20 -28
  138. package/dist/query/scope.d.ts.map +1 -1
  139. package/dist/query/scope.js +7 -7
  140. package/dist/query/scope.js.map +1 -1
  141. package/dist/query/segments.d.ts +2 -2
  142. package/dist/query/segments.d.ts.map +1 -1
  143. package/dist/query/segments.js +3 -3
  144. package/dist/query/segments.js.map +1 -1
  145. package/dist/relation.d.ts +1 -1
  146. package/dist/relation.d.ts.map +1 -1
  147. package/dist/relation.js +4 -4
  148. package/dist/relation.js.map +1 -1
  149. package/dist/result.d.ts +15 -22
  150. package/dist/result.d.ts.map +1 -1
  151. package/dist/result.js +30 -39
  152. package/dist/result.js.map +1 -1
  153. package/dist/rows.d.ts +9 -33
  154. package/dist/rows.d.ts.map +1 -1
  155. package/dist/rows.js +8 -12
  156. package/dist/rows.js.map +1 -1
  157. package/dist/runtime.d.ts +17 -20
  158. package/dist/runtime.d.ts.map +1 -1
  159. package/dist/runtime.js +41 -205
  160. package/dist/runtime.js.map +1 -1
  161. package/dist/scalar.d.ts +4 -4
  162. package/dist/scalar.d.ts.map +1 -1
  163. package/dist/scalar.js +24 -8
  164. package/dist/scalar.js.map +1 -1
  165. package/dist/schema.d.ts +7 -18
  166. package/dist/schema.d.ts.map +1 -1
  167. package/dist/schema.js +18 -228
  168. package/dist/schema.js.map +1 -1
  169. package/dist/selection.d.ts +4 -4
  170. package/dist/selection.d.ts.map +1 -1
  171. package/dist/selection.js +5 -5
  172. package/dist/selection.js.map +1 -1
  173. package/dist/shape.d.ts +5 -5
  174. package/dist/shape.d.ts.map +1 -1
  175. package/dist/spec.d.ts +7 -79
  176. package/dist/spec.d.ts.map +1 -1
  177. package/dist/spec.js.map +1 -1
  178. package/dist/statements.d.ts +3 -3
  179. package/dist/statements.d.ts.map +1 -1
  180. package/dist/statements.js +10 -10
  181. package/dist/statements.js.map +1 -1
  182. package/dist/uuid.d.ts +1 -1
  183. package/dist/uuid.d.ts.map +1 -1
  184. package/dist/uuid.js +1 -1
  185. package/dist/uuid.js.map +1 -1
  186. package/dist/values.d.ts +2 -2
  187. package/dist/values.d.ts.map +1 -1
  188. package/dist/values.js +2 -2
  189. package/dist/values.js.map +1 -1
  190. package/package.json +18 -18
  191. package/src/alternatives.ts +7 -8
  192. package/src/bin.ts +82 -0
  193. package/src/capacity.ts +20 -23
  194. package/src/changes.ts +134 -191
  195. package/src/closed.ts +5 -5
  196. package/src/codec.ts +35 -49
  197. package/src/compile.ts +91 -113
  198. package/src/database/database.ts +413 -0
  199. package/src/database/driver.ts +134 -0
  200. package/src/database/fs.ts +119 -0
  201. package/src/database/generate.ts +116 -0
  202. package/src/database/hosted.ts +102 -0
  203. package/src/database/io.ts +134 -0
  204. package/src/database/mem.ts +113 -0
  205. package/src/database/migration.ts +107 -0
  206. package/src/database/s3.ts +231 -0
  207. package/src/db.ts +290 -547
  208. package/src/engine.ts +14 -0
  209. package/src/errors.ts +118 -39
  210. package/src/face.ts +9 -9
  211. package/src/fields.ts +6 -7
  212. package/src/index.ts +92 -105
  213. package/src/judgment.ts +1 -1
  214. package/src/law.ts +18 -70
  215. package/src/lower.ts +61 -72
  216. package/src/native/addon.ts +54 -0
  217. package/src/native/binding.d.ts +996 -0
  218. package/src/native/json.ts +100 -0
  219. package/src/native/load.ts +31 -0
  220. package/src/native/op.ts +73 -0
  221. package/src/query/atom.ts +15 -16
  222. package/src/query/compute.ts +7 -7
  223. package/src/query/find.ts +8 -8
  224. package/src/query/lower.ts +270 -392
  225. package/src/query/run.ts +42 -21
  226. package/src/query/scope.ts +29 -37
  227. package/src/query/segments.ts +4 -4
  228. package/src/relation.ts +4 -4
  229. package/src/result.ts +53 -80
  230. package/src/rows.ts +18 -46
  231. package/src/runtime.ts +50 -277
  232. package/src/scalar.ts +32 -12
  233. package/src/schema.ts +23 -284
  234. package/src/selection.ts +6 -6
  235. package/src/shape.ts +5 -5
  236. package/src/spec.ts +7 -85
  237. package/src/statements.ts +11 -11
  238. package/src/uuid.ts +1 -1
  239. package/src/values.ts +4 -4
  240. package/dist/close.d.ts +0 -24
  241. package/dist/close.d.ts.map +0 -1
  242. package/dist/close.js +0 -34
  243. package/dist/close.js.map +0 -1
  244. package/dist/db-native.d.ts +0 -189
  245. package/dist/db-native.d.ts.map +0 -1
  246. package/dist/db-native.js +0 -13
  247. package/dist/db-native.js.map +0 -1
  248. package/dist/internal/log.d.ts +0 -26
  249. package/dist/internal/log.d.ts.map +0 -1
  250. package/dist/internal/log.js +0 -12
  251. package/dist/internal/log.js.map +0 -1
  252. package/dist/native.d.ts +0 -562
  253. package/dist/native.d.ts.map +0 -1
  254. package/dist/native.js +0 -123
  255. package/dist/native.js.map +0 -1
  256. package/dist/query/description.d.ts +0 -41
  257. package/dist/query/description.d.ts.map +0 -1
  258. package/dist/query/description.js +0 -311
  259. package/dist/query/description.js.map +0 -1
  260. package/dist/query/parse-ir.d.ts +0 -10
  261. package/dist/query/parse-ir.d.ts.map +0 -1
  262. package/dist/query/parse-ir.js +0 -280
  263. package/dist/query/parse-ir.js.map +0 -1
  264. package/dist/runtime-codes.d.ts +0 -2
  265. package/dist/runtime-codes.d.ts.map +0 -1
  266. package/dist/runtime-codes.js +0 -19
  267. package/dist/runtime-codes.js.map +0 -1
  268. package/dist/runtime-errors.d.ts +0 -138
  269. package/dist/runtime-errors.d.ts.map +0 -1
  270. package/dist/runtime-errors.js +0 -111
  271. package/dist/runtime-errors.js.map +0 -1
  272. package/dist/runtime-native.d.ts +0 -136
  273. package/dist/runtime-native.d.ts.map +0 -1
  274. package/dist/runtime-native.js +0 -5
  275. package/dist/runtime-native.js.map +0 -1
  276. package/dist/schema-file.d.ts +0 -7
  277. package/dist/schema-file.d.ts.map +0 -1
  278. package/dist/schema-file.js +0 -24
  279. package/dist/schema-file.js.map +0 -1
  280. package/pack-provenance.json +0 -7
  281. package/src/close.ts +0 -53
  282. package/src/db-native.ts +0 -235
  283. package/src/internal/log.ts +0 -46
  284. package/src/native.ts +0 -736
  285. package/src/query/description.ts +0 -424
  286. package/src/query/parse-ir.ts +0 -293
  287. package/src/runtime-codes.ts +0 -18
  288. package/src/runtime-errors.ts +0 -122
  289. package/src/runtime-native.ts +0 -181
  290. package/src/schema-file.ts +0 -38
package/src/runtime.ts CHANGED
@@ -1,10 +1,13 @@
1
- import { Context, Duration, Effect, Exit, Layer } from "effect"
2
- import type { CloseReport, OutstandingWork } from "#runtime-errors.ts"
3
- import { CloseFailure, DbError, dbError } from "#runtime-errors.ts"
4
- import type { CloseWire, OperationHandle, OptionsWire, RuntimeHandle } from "#runtime-native.ts"
5
- import { runtimeNative } from "#runtime-native.ts"
6
-
7
- export interface NativeRuntimeOptions {
1
+ import { Context, Duration, Effect, Layer } from "effect"
2
+ import type { OutstandingWork } from "./errors.ts"
3
+ import { DbError, dbError } from "./errors.ts"
4
+ import type { RuntimeRef } from "./native/addon.ts"
5
+ import { addon } from "./native/addon.ts"
6
+ import type { RuntimeOptionsIn } from "./native/binding.d.ts"
7
+ import { call, scoped } from "./native/op.ts"
8
+
9
+ /** Sizing for the native runtime. The addon validates every count and picks the defaults. */
10
+ export interface BumbleOptions {
8
11
  readonly workers?: number
9
12
  readonly queueCapacity?: number
10
13
  readonly cleanupCapacity?: number
@@ -13,290 +16,60 @@ export interface NativeRuntimeOptions {
13
16
  readonly cleanupTimeout?: Duration.Input
14
17
  }
15
18
 
16
- interface RuntimeService {
17
- readonly close: () => Effect.Effect<CloseReport>
18
- readonly inspect: () => Effect.Effect<OutstandingWork, DbError>
19
- }
20
-
21
- const owners = new WeakMap<RuntimeService, RuntimeHandle>()
22
-
23
- function invalid(operation: string): DbError {
24
- return new DbError({ operation, reason: { _tag: "InvalidArgument" } })
25
- }
26
-
27
- function count(value: number, operation: string): number {
28
- if (!Number.isSafeInteger(value) || value <= 0 || value > 0xffffffff) throw invalid(operation)
29
- return value
30
- }
31
-
32
- function millis(value: Duration.Input, operation: string): number {
33
- const duration = Duration.toMillis(value)
34
- if (!Number.isFinite(duration) || duration < 0 || duration > 0xffffffff) throw invalid(operation)
35
- return Math.ceil(duration)
36
- }
37
-
38
- function options(value: NativeRuntimeOptions): OptionsWire {
39
- const operation = "NativeRuntime.acquire"
40
- return {
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)
19
+ function wire(options: BumbleOptions): string {
20
+ const timeout = options.cleanupTimeout === undefined ? undefined : Duration.toMillis(options.cleanupTimeout)
21
+ if (timeout !== undefined && !Number.isFinite(timeout)) {
22
+ throw new DbError({ operation: "Bumble.layer", reason: { _tag: "InvalidArgument" } })
49
23
  }
50
- }
51
-
52
- function failure(operation: string, cause: unknown): DbError {
53
- return cause instanceof DbError ? cause : dbError(operation, cause)
54
- }
55
-
56
- function closeReport(operation: string, report: CloseWire): CloseReport {
57
- // A payload-less native "failed" drain (cleanup capacity exhausted, or
58
- // owner teardown failed) decodes as the core `Internal` reason — the
59
- // same mapping the log bridge applies, so one wire arm has one meaning.
60
- // It is deliberately NOT `QueueFull`: a failed drain is never retryable
61
- // submit backpressure.
62
- return report.kind === "failed" ? { kind: "failed", error: dbError(operation, { _tag: "Internal" }) } : report
63
- }
64
-
65
- function drain(operation: string, start: (callback: (report: CloseWire) => void) => void): Effect.Effect<CloseReport> {
66
- return Effect.callback<CloseReport>((resume) => {
67
- try {
68
- start((report) => resume(Effect.succeed(closeReport(operation, report))))
69
- } catch (cause) {
70
- resume(Effect.succeed({ kind: "failed", error: failure(operation, cause) }))
71
- }
72
- }).pipe(Effect.uninterruptible)
73
- }
74
-
75
- export function finalizeClose(operation: string, report: CloseReport): Effect.Effect<void> {
76
- return report.kind === "closed" ? Effect.void : Effect.die(new CloseFailure({ operation, report }))
77
- }
78
-
79
- /**
80
- * Effect.callback's returned finalizer is interruption cleanup only
81
- * (`asyncFinalizer` runs solely on interrupt Cause). If that finalizer
82
- * dies, the original interrupt is dropped. Join the native drain here and
83
- * always succeed so the interrupt Cause is kept; attach CloseFailure via
84
- * `onExit` so both appear in the final Cause.
85
- */
86
- function joinInterruptDrain(
87
- operation: string,
88
- start: (callback: (report: CloseWire) => void) => void,
89
- stash: { report?: CloseReport }
90
- ): Effect.Effect<void> {
91
- return drain(operation, start).pipe(
92
- Effect.tap((report) => {
93
- stash.report = report
94
- return Effect.void
95
- }),
96
- Effect.asVoid
97
- )
98
- }
99
-
100
- function attachInterruptClose(
101
- operation: string,
102
- stash: { report?: CloseReport }
103
- ): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> {
104
- return (effect) =>
105
- effect.pipe(
106
- Effect.onExit((exit) => {
107
- if (!Exit.hasInterrupts(exit)) {
108
- return Effect.void
109
- }
110
- const report = stash.report
111
- if (report === undefined || report.kind === "closed") {
112
- return Effect.void
113
- }
114
- return Effect.die(new CloseFailure({ operation, report }))
115
- })
116
- )
117
- }
118
-
119
- function afterClose<A, E, R>(
120
- operation: string,
121
- report: CloseReport,
122
- effect: Effect.Effect<A, E, R>
123
- ): Effect.Effect<A, E, R> {
124
- if (report.kind === "closed") {
125
- return effect
24
+ const input: RuntimeOptionsIn = {
25
+ ...(options.workers === undefined ? {} : { workers: options.workers }),
26
+ ...(options.queueCapacity === undefined ? {} : { queueCapacity: options.queueCapacity }),
27
+ ...(options.cleanupCapacity === undefined ? {} : { cleanupCapacity: options.cleanupCapacity }),
28
+ ...(options.ownerCapacity === undefined ? {} : { ownerCapacity: options.ownerCapacity }),
29
+ ...(options.nativeHandleCapacity === undefined ? {} : { nativeHandleCapacity: options.nativeHandleCapacity }),
30
+ ...(timeout === undefined ? {} : { cleanupTimeoutMs: Math.ceil(timeout) })
126
31
  }
127
- return effect.pipe(Effect.onExit(() => Effect.die(new CloseFailure({ operation, report }))))
32
+ return JSON.stringify(input)
128
33
  }
129
34
 
130
- function close(handle: RuntimeHandle): Effect.Effect<CloseReport> {
131
- return drain("NativeRuntime.close", (callback) => runtimeNative.runtimeClose(handle, callback))
132
- }
35
+ /** The live native runtime: one worker pool and handle registry per process. */
36
+ export class Runtime {
37
+ readonly #handle: RuntimeRef
38
+ /** The runtime's outstanding native work, after every operation queued before it settles. */
39
+ readonly inspect: () => Effect.Effect<OutstandingWork, DbError>
133
40
 
134
- /** Kick `runtimeCancel` without joining. Used when the completion
135
- * callback arrives after abort: JS must not `take`; L12 drain reclaims
136
- * queued Page/Rows. A second call is native-idempotent (Committed
137
- * mutations stay; only unpublished delivery is dropped).
138
- */
139
- function startCancelDrain(operation: string, lease: OperationHandle, stash: { report?: CloseReport }): void {
140
- try {
141
- runtimeNative.runtimeCancel(lease, (report) => {
142
- stash.report = closeReport(operation, report)
41
+ constructor(handle: RuntimeRef) {
42
+ this.#handle = handle
43
+ this.inspect = Effect.fn("Bumble.inspect")(function* () {
44
+ yield* call("Bumble.inspect", (done) => addon.runtimeReady(handle, done), addon.runtimeTake)
45
+ return addon.runtimeInspect(handle) as OutstandingWork
143
46
  })
144
- } catch (cause) {
145
- stash.report = { kind: "failed", error: failure(operation, cause) }
146
47
  }
147
- }
148
-
149
- /** Registration returns the native lease before any completion can run in JS.
150
- * Interruption cancels and joins that lease, including a late successful result.
151
- * No Promise or libuv job is created for ordinary native work.
152
- */
153
- export function nativeOperation<A>(
154
- operation: string,
155
- start: (callback: () => void) => OperationHandle,
156
- accept: (value: Uint8Array | null) => A
157
- ): Effect.Effect<A, DbError> {
158
- return nativeOperationWith(operation, start, runtimeNative.runtimeTake, accept)
159
- }
160
48
 
161
- export function nativeOperationWith<A, Value>(
162
- operation: string,
163
- start: (callback: () => void) => OperationHandle,
164
- take: (operation: OperationHandle) => Value,
165
- accept: (value: Value) => A
166
- ): Effect.Effect<A, DbError> {
167
- const stash: { report?: CloseReport } = {}
168
- const cancelOp = `${operation}.cancel`
169
- return attachInterruptClose(
170
- cancelOp,
171
- stash
172
- )(
173
- Effect.callback((resume, signal) => {
174
- let lease: OperationHandle
175
- try {
176
- lease = start(() => {
177
- if (signal.aborted) {
178
- startCancelDrain(cancelOp, lease, stash)
179
- return
180
- }
181
- try {
182
- resume(Effect.succeed(accept(take(lease))))
183
- } catch (cause) {
184
- resume(Effect.fail(failure(operation, cause)))
185
- }
186
- })
187
- } catch (cause) {
188
- resume(Effect.fail(failure(operation, cause)))
189
- return
190
- }
191
- return joinInterruptDrain(cancelOp, (callback) => runtimeNative.runtimeCancel(lease, callback), stash)
192
- })
193
- )
49
+ static handle(runtime: Runtime): RuntimeRef {
50
+ return runtime.#handle
51
+ }
194
52
  }
195
53
 
196
- const acquire = Effect.fn("NativeRuntime.acquire")(function* (configuration: NativeRuntimeOptions) {
197
- return yield* Effect.acquireRelease(
198
- Effect.suspend(() => {
199
- const stash: { report?: CloseReport } = {}
200
- return attachInterruptClose(
201
- "NativeRuntime.acquire.cancel",
202
- stash
203
- )(
204
- Effect.callback<RuntimeService, DbError>((resume, signal) => {
205
- let handle: RuntimeHandle | undefined
206
- try {
207
- const wire = options(configuration)
208
- handle = runtimeNative.runtimeOpen(wire)
209
- const owner = handle
210
- const lease = runtimeNative.runtimeReady(owner, () => {
211
- if (signal.aborted) {
212
- try {
213
- runtimeNative.runtimeClose(owner, (report) => {
214
- stash.report = closeReport("NativeRuntime.acquire.cancel", report)
215
- })
216
- } catch (cause) {
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
230
- )
231
- return runtimeNative.runtimeInspect(owner)
232
- })
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
- )
243
- }
244
- })
245
- } catch (cause) {
246
- const error = failure("NativeRuntime.acquire", cause)
247
- resume(
248
- handle === undefined
249
- ? Effect.fail(error)
250
- : close(handle).pipe(
251
- Effect.flatMap((report) => afterClose("NativeRuntime.acquire", report, Effect.fail(error)))
252
- )
253
- )
254
- }
255
- return handle === undefined
256
- ? Effect.void
257
- : joinInterruptDrain(
258
- "NativeRuntime.acquire.cancel",
259
- (callback) => runtimeNative.runtimeClose(handle, callback),
260
- stash
261
- )
262
- })
263
- )
264
- }),
265
- (service) => service.close().pipe(Effect.flatMap((report) => finalizeClose("NativeRuntime.release", report))),
266
- { interruptible: true }
54
+ const acquire = Effect.fn("Bumble.layer")(function* (options: BumbleOptions) {
55
+ const input = yield* Effect.try({ try: () => wire(options), catch: (cause) => dbError("Bumble.layer", cause) })
56
+ const handle = yield* scoped(
57
+ "Bumble.release",
58
+ Effect.try({ try: () => addon.runtimeOpen(input), catch: (cause) => dbError("Bumble.layer", cause) }),
59
+ (owner) => (done) => addon.runtimeClose(owner, done)
267
60
  )
61
+ yield* call("Bumble.layer", (done) => addon.runtimeReady(handle, done), addon.runtimeTake)
62
+ return new Runtime(handle)
268
63
  })
269
64
 
270
- export class NativeRuntime extends Context.Service<NativeRuntime, RuntimeService>()(
271
- "@bjornpagen/bumbledb/NativeRuntime"
272
- ) {
273
- static layer(options: NativeRuntimeOptions = {}): Layer.Layer<NativeRuntime, DbError> {
274
- return Layer.effect(NativeRuntime, acquire(options))
65
+ /** The native runtime as an Effect service. Provide `Bumble.layer()` once in the application graph. */
66
+ export class Bumble extends Context.Service<Bumble, Runtime>()("@bjornpagen/bumbledb/Bumble") {
67
+ static layer(options: BumbleOptions = {}): Layer.Layer<Bumble, DbError> {
68
+ return Layer.effect(Bumble, acquire(options))
275
69
  }
276
70
  }
277
71
 
278
- /** Private core/log integration: captures the already acquired shared service. */
279
- export const runtimeHandle = Effect.fn("NativeRuntime.handle")(function* () {
280
- const runtime = yield* NativeRuntime
281
- const handle = owners.get(runtime)
282
- if (handle === undefined) return yield* Effect.fail(invalid("NativeRuntime.handle"))
283
- return handle
284
- })
285
-
286
- /** Internal first executor consumer; not a replacement row codec or public hash API. */
287
- export const hashChunk = Effect.fn("bumbledb.hashChunk")(function* (input: Uint8Array) {
288
- const runtime = yield* NativeRuntime
289
- const handle = owners.get(runtime)
290
- if (handle === undefined) return yield* Effect.fail(invalid("hashChunk"))
291
- return yield* nativeOperation(
292
- "hashChunk",
293
- (callback) => {
294
- if (!(input instanceof Uint8Array) || !(input.buffer instanceof ArrayBuffer)) throw invalid("hashChunk")
295
- return runtimeNative.runtimeHash(handle, input, callback)
296
- },
297
- (value) => {
298
- if (value === null) throw dbError("hashChunk", { _tag: "Internal" })
299
- return value
300
- }
301
- )
72
+ /** The provided runtime's native handle. */
73
+ export const runtimeHandle: Effect.Effect<RuntimeRef, never, Bumble> = Effect.gen(function* () {
74
+ return Runtime.handle(yield* Bumble)
302
75
  })
package/src/scalar.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  /** Query scalar nodes, with cached kind and depth. Construction is constant
2
2
  * work; native preparation binds variables and evaluates the expressions. */
3
- import { AuthoringError } from "#errors.ts"
4
- import type { ScalarExprIr } from "#native.ts"
5
- import type { ValueSpec } from "#spec.ts"
3
+ import { AuthoringError } from "./errors.ts"
4
+ import type { ScalarExprIn } from "./native/binding.d.ts"
5
+ import { valueIn } from "./native/json.ts"
6
+ import type { ValueSpec } from "./spec.ts"
6
7
 
7
8
  /** The engine's scalar result vocabulary — distinct at the type level. */
8
9
  type ScalarKind = "u64" | "i64" | "f64" | "bool"
@@ -82,7 +83,7 @@ const U64_MAX = (1n << 64n) - 1n
82
83
  const I64_MIN = -(1n << 63n)
83
84
  const I64_MAX = (1n << 63n) - 1n
84
85
 
85
- /** Constructor admissions only — not descendant visits. D27 construction-work pin. */
86
+ /** Constructor admissions only, not descendant visits. */
86
87
  let authoringWork = 0
87
88
 
88
89
  function scalarAuthoringWork(): number {
@@ -346,27 +347,46 @@ function queryVarsOf(node: ScalarNode): readonly ScalarQueryVar[] {
346
347
  }
347
348
 
348
349
  /** Lower each query variable through its existing binding. */
349
- function scalarWire(node: ScalarNode, leaf: (node: QueryVarLeaf) => number): ScalarExprIr {
350
- const walk = (expr: ScalarNode): ScalarExprIr => scalarWire(expr, leaf)
350
+ const ROUNDING = {
351
+ towardZero: "TowardZero",
352
+ nearestTiesAwayFromZero: "NearestTiesAwayFromZero",
353
+ nearestTiesToEven: "NearestTiesToEven"
354
+ } as const
355
+
356
+ const CAST = { toF64: "ToF64", toF64Exact: "ToF64Exact", toI64Exact: "ToI64Exact", toU64Exact: "ToU64Exact" } as const
357
+
358
+ const UNARY = { measure: "Measure", negate: "Negate", isNaN: "IsNaN", isFinite: "IsFinite" } as const
359
+
360
+ const BINARY = { add: "Add", subtract: "Subtract", multiply: "Multiply", divide: "Divide" } as const
361
+
362
+ /** Lowers a scalar expression to the addon's `ScalarExprIn`; `leaf` numbers the rule variables. */
363
+ function scalarWire(node: ScalarNode, leaf: (node: QueryVarLeaf) => number): ScalarExprIn {
364
+ const walk = (expr: ScalarNode): ScalarExprIn => scalarWire(expr, leaf)
351
365
  switch (node.kind) {
352
366
  case "var":
353
- return { kind: "var", var: leaf(node) }
367
+ return { kind: "Var", var: leaf(node) }
354
368
  case "literal":
355
- return { kind: "literal", value: literalWireOf(node.value) }
369
+ return { kind: "Literal", value: valueIn(literalWireOf(node.value)) }
356
370
  case "measure":
357
371
  case "negate":
358
372
  case "isNaN":
359
373
  case "isFinite":
360
- return { kind: node.kind, expr: walk(node.expr) }
374
+ return { kind: UNARY[node.kind], expr: walk(node.expr) }
361
375
  case "cast":
362
- return { kind: node.kind, cast: node.cast, expr: walk(node.expr) }
376
+ return { kind: "Cast", cast: CAST[node.cast], expr: walk(node.expr) }
363
377
  case "mulDiv":
364
- return { kind: node.kind, a: walk(node.a), b: walk(node.b), divisor: walk(node.divisor), rounding: node.rounding }
378
+ return {
379
+ kind: "MulDiv",
380
+ a: walk(node.a),
381
+ b: walk(node.b),
382
+ divisor: walk(node.divisor),
383
+ rounding: ROUNDING[node.rounding]
384
+ }
365
385
  case "add":
366
386
  case "subtract":
367
387
  case "multiply":
368
388
  case "divide":
369
- return { kind: node.kind, left: walk(node.left), right: walk(node.right) }
389
+ return { kind: BINARY[node.kind], left: walk(node.left), right: walk(node.right) }
370
390
  }
371
391
  }
372
392