@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.
Files changed (290) hide show
  1. package/COOKBOOK.md +224 -95
  2. package/README.md +114 -45
  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 -41
  16. package/dist/changes.d.ts.map +1 -1
  17. package/dist/changes.js +86 -110
  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 +20 -27
  24. package/dist/codec.d.ts.map +1 -1
  25. package/dist/codec.js +48 -22
  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 -58
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +27 -29
  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 +7 -7
  123. package/dist/query/compute.d.ts.map +1 -1
  124. package/dist/query/compute.js +7 -16
  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 +31 -17
  130. package/dist/query/lower.d.ts.map +1 -1
  131. package/dist/query/lower.js +260 -368
  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 +13 -8
  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 -43
  158. package/dist/runtime.d.ts.map +1 -1
  159. package/dist/runtime.js +41 -241
  160. package/dist/runtime.js.map +1 -1
  161. package/dist/scalar.d.ts +36 -106
  162. package/dist/scalar.d.ts.map +1 -1
  163. package/dist/scalar.js +36 -185
  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 -197
  195. package/src/closed.ts +5 -5
  196. package/src/codec.ts +77 -51
  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 +102 -109
  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 +13 -22
  223. package/src/query/find.ts +8 -8
  224. package/src/query/lower.ts +323 -414
  225. package/src/query/run.ts +42 -21
  226. package/src/query/scope.ts +37 -38
  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 -346
  232. package/src/scalar.ts +76 -336
  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 -196
  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/migration.d.ts +0 -31
  253. package/dist/migration.d.ts.map +0 -1
  254. package/dist/migration.js +0 -47
  255. package/dist/migration.js.map +0 -1
  256. package/dist/native.d.ts +0 -562
  257. package/dist/native.d.ts.map +0 -1
  258. package/dist/native.js +0 -123
  259. package/dist/native.js.map +0 -1
  260. package/dist/query/description.d.ts +0 -41
  261. package/dist/query/description.d.ts.map +0 -1
  262. package/dist/query/description.js +0 -311
  263. package/dist/query/description.js.map +0 -1
  264. package/dist/query/parse-ir.d.ts +0 -10
  265. package/dist/query/parse-ir.d.ts.map +0 -1
  266. package/dist/query/parse-ir.js +0 -280
  267. package/dist/query/parse-ir.js.map +0 -1
  268. package/dist/runtime-codes.d.ts +0 -2
  269. package/dist/runtime-codes.d.ts.map +0 -1
  270. package/dist/runtime-codes.js +0 -18
  271. package/dist/runtime-codes.js.map +0 -1
  272. package/dist/runtime-errors.d.ts +0 -118
  273. package/dist/runtime-errors.d.ts.map +0 -1
  274. package/dist/runtime-errors.js +0 -98
  275. package/dist/runtime-errors.js.map +0 -1
  276. package/dist/runtime-native.d.ts +0 -141
  277. package/dist/runtime-native.d.ts.map +0 -1
  278. package/dist/runtime-native.js +0 -5
  279. package/dist/runtime-native.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 -243
  283. package/src/internal/log.ts +0 -48
  284. package/src/migration.ts +0 -61
  285. package/src/native.ts +0 -736
  286. package/src/query/description.ts +0 -424
  287. package/src/query/parse-ir.ts +0 -291
  288. package/src/runtime-codes.ts +0 -17
  289. package/src/runtime-errors.ts +0 -109
  290. package/src/runtime-native.ts +0 -189
package/src/codec.ts CHANGED
@@ -1,41 +1,26 @@
1
1
  import { Effect, Schema as EffectSchema, Result } from "effect"
2
- import { membersAgree } from "#closed.ts"
3
- import { schemaTables } from "#compile.ts"
4
- import { dbNative } from "#db-native.ts"
5
- import { AuthoringError } from "#errors.ts"
6
- import type { AnyField } from "#fields.ts"
7
- import { lower } from "#lower.ts"
8
- import { type AnyRelation, type Fact, relationDescriptor, relationFields } from "#relation.ts"
9
- import type { CellValue } from "#rows.ts"
10
- import { factOfCells, flatRowsOf } from "#rows.ts"
11
- import { nativeOperationWith, runtimeHandle } from "#runtime.ts"
12
- import { argumentError, DbError } from "#runtime-errors.ts"
13
- import type { AnySchema } from "#schema.ts"
14
- import { schemaDescriptor } from "#schema.ts"
15
- import type { Rel } from "#shape.ts"
16
- import { f64BitsHex } from "#spec.ts"
17
- import { fieldValue, recordValue } from "#values.ts"
2
+ import { membersAgree } from "./closed.ts"
3
+ import { compiledOf, schemaTables } from "./compile.ts"
4
+ import { AuthoringError, argumentError, DbError } from "./errors.ts"
5
+ import { type AnyField, fieldDescriptor, type Infer } from "./fields.ts"
6
+ import { addon } from "./native/addon.ts"
7
+ import { call } from "./native/op.ts"
8
+ import { type AnyRelation, type Fact, relationDescriptor, relationFields } from "./relation.ts"
9
+ import type { CellValue } from "./rows.ts"
10
+ import { factOfCells, flatRowsOf } from "./rows.ts"
11
+ import { runtimeHandle } from "./runtime.ts"
12
+ import type { AnySchema } from "./schema.ts"
13
+ import { schemaDescriptor } from "./schema.ts"
14
+ import type { Rel } from "./shape.ts"
15
+ import { f64BitsHex } from "./spec.ts"
16
+ import { fieldValue, recordValue } from "./values.ts"
18
17
 
19
18
  /**
20
- * Boundary row codecs, derived from the core relation descriptors — never a
21
- * second hand-maintained field roster.
22
- *
23
- * Two layers:
24
- *
25
- * 1. The CANONICAL native row codec: `encodeRows`/`decodeRows` run the
26
- * same native implementation the engine, log and migrations
27
- * share (owned bytes in, owned typed rows out; untrusted input cannot
28
- * inject native capabilities). Effect-only, `NativeRuntime` required.
29
- * 2. The schema-tagged JSON VALUE form for HTTP/export boundaries
30
- * (chapter 30): every `f64` — finite included — is
31
- * `{"$f64":"<16 lowercase hex digits>"}` of canonical binary64 bits;
32
- * integers are canonical decimal strings; `Uuid` is canonical UUID;
33
- * bytes use ONE strict lowercase-hex encoding; intervals are
34
- * `{start,end}` in their element encoding; closed references are handle
35
- * names. `JSON.stringify` of raw numbers is NOT the database value
36
- * wire codec — it loses infinities/NaN and cannot encode BigInt.
37
- * Decoders reject malformed widths, unknown tags and noncanonical
38
- * representations. These are pure bounded per-row functions.
19
+ * Row codecs derived from the relation descriptors: the canonical native row codec
20
+ * (`encodeRows`/`decodeRows`, the engine's own bytes) and the schema-tagged JSON value form for
21
+ * HTTP/export boundaries, where an `f64` is `{"$f64":"<16 hex>"}` of its canonical bits (raw JSON
22
+ * numbers lose infinities and NaN), integers are decimal strings, bytes are lowercase hex and
23
+ * closed references are handle names. Decoders reject anything noncanonical.
39
24
  */
40
25
 
41
26
  /** The typed row shape: a schema plus one of its relations. */
@@ -58,7 +43,7 @@ function checkedRowShape<R extends AnyRelation>(operation: string, input: RowSha
58
43
  if (relationId === undefined || !membersAgree(schema.relations[relation.name], relation)) {
59
44
  throw new AuthoringError({ message: `${operation}: relation is not declared in the schema` })
60
45
  }
61
- return { relation, relationId, spec: lower(schema) }
46
+ return { relation, relationId, schema: compiledOf(schema).handle }
62
47
  }
63
48
 
64
49
  function invalid(operation: string): DbError {
@@ -141,7 +126,8 @@ function decodeTaggedF64(value: unknown): number | undefined {
141
126
  }
142
127
 
143
128
  /** Decode representation, then judge the value through the shared interpreter. */
144
- function decodeBoundaryValue(context: string, field: AnyField, input: unknown): unknown {
129
+ function decodeBoundaryValue<F extends AnyField>(context: string, field: F, input: unknown): Infer<F>
130
+ function decodeBoundaryValue(context: string, field: AnyField, input: unknown): Infer<AnyField> {
145
131
  if ("closed" in field) return fieldValue(context, field, input)
146
132
  let decoded: unknown = input
147
133
  switch (field.kind) {
@@ -167,6 +153,35 @@ function decodeBoundaryValue(context: string, field: AnyField, input: unknown):
167
153
  return fieldValue(context, field, decoded)
168
154
  }
169
155
 
156
+ /** The host-value schema, using the same interpreter as facts and row codecs. */
157
+ function fieldSchema<F extends AnyField>(field: F) {
158
+ const descriptor = fieldDescriptor("fieldSchema", field)
159
+ return EffectSchema.declare((value: unknown): value is Infer<F> => {
160
+ try {
161
+ fieldValue("fieldSchema", descriptor, value)
162
+ return true
163
+ } catch {
164
+ return false
165
+ }
166
+ })
167
+ }
168
+
169
+ /** Encode one field's host value in the canonical JSON-boundary form. */
170
+ function encodeBoundaryField<F extends AnyField>(field: F, value: Infer<F>): Result.Result<unknown, DbError> {
171
+ return Result.try({
172
+ try: () => encodeBoundaryValue("encodeBoundaryField", fieldDescriptor("encodeBoundaryField", field), value),
173
+ catch: (cause) => argumentError("encodeBoundaryField", cause)
174
+ })
175
+ }
176
+
177
+ /** Strict JSON-boundary decoding, returning the field's canonical host value. */
178
+ function decodeBoundaryField<F extends AnyField>(field: F, input: unknown): Result.Result<Infer<F>, DbError> {
179
+ return Result.try({
180
+ try: () => decodeBoundaryValue("decodeBoundaryField", fieldDescriptor("decodeBoundaryField", field), input),
181
+ catch: (cause) => argumentError("decodeBoundaryField", cause)
182
+ })
183
+ }
184
+
170
185
  /** Pure schema-tagged JSON encoding of complete rows. */
171
186
  function encodeBoundaryRows<R extends AnyRelation>(
172
187
  relation: R,
@@ -241,7 +256,7 @@ function rowSchema<R extends AnyRelation>(relation: R) {
241
256
  }
242
257
 
243
258
  /**
244
- * The canonical native row codec (chapter 35 roster): owned bytes
259
+ * The canonical native row codec: owned bytes
245
260
  * out, owned typed rows back in — the same implementation log sealing and
246
261
  * migrations use. Binding parameters is ingestion: input must stay stable
247
262
  * through execution, and no native work starts before the checked owned
@@ -251,8 +266,8 @@ const encodeRows = Effect.fn("encodeRows")(function* <R extends AnyRelation>(
251
266
  shape: RowShape<R>,
252
267
  rows: Iterable<Fact<R>>
253
268
  ) {
254
- const runtime = yield* runtimeHandle()
255
- const { relation, relationId, spec } = yield* Effect.try({
269
+ const runtime = yield* runtimeHandle
270
+ const { relation, relationId, schema } = yield* Effect.try({
256
271
  try: () => checkedRowShape("encodeRows", shape),
257
272
  catch: (cause) => argumentError("encodeRows", cause)
258
273
  })
@@ -260,30 +275,41 @@ const encodeRows = Effect.fn("encodeRows")(function* <R extends AnyRelation>(
260
275
  try: () => flatRowsOf(relation, rows as Iterable<object>),
261
276
  catch: (cause) => argumentError("encodeRows", cause)
262
277
  })
263
- return yield* nativeOperationWith(
278
+ return yield* call(
264
279
  "encodeRows",
265
- (callback) => dbNative.runtimeEncodeRows(runtime, spec, relationId, flat.rows, flat.cells, callback),
266
- dbNative.runtimeBytesTake,
267
- (bytes) => bytes
280
+ (callback) => addon.runtimeEncodeRows(runtime, schema, relationId, flat.rows, flat.cells, callback),
281
+ addon.runtimeBytesTake
268
282
  )
269
283
  })
270
284
 
271
285
  const decodeRows = Effect.fn("decodeRows")(function* <R extends AnyRelation>(shape: RowShape<R>, input: Uint8Array) {
272
- const runtime = yield* runtimeHandle()
273
- const { relation, relationId, spec } = yield* Effect.try({
286
+ const runtime = yield* runtimeHandle
287
+ const { relation, relationId, schema } = yield* Effect.try({
274
288
  try: () => checkedRowShape("decodeRows", shape),
275
289
  catch: (cause) => argumentError("decodeRows", cause)
276
290
  })
277
291
  if (!(input instanceof Uint8Array) || !(input.buffer instanceof ArrayBuffer)) {
278
292
  return yield* Effect.fail(invalid("decodeRows"))
279
293
  }
280
- return yield* nativeOperationWith(
294
+ return yield* call(
281
295
  "decodeRows",
282
- (callback) => dbNative.runtimeDecodeRows(runtime, spec, relationId, input, callback),
283
- dbNative.runtimeRowsTake,
284
- (rows) => Object.freeze(rows.map((row) => factOfCells(relation, row as readonly CellValue[])))
296
+ (callback) => addon.runtimeDecodeRows(runtime, schema, relationId, input, callback),
297
+ (lease) =>
298
+ ((rows) => Object.freeze(rows.map((row) => factOfCells(relation, row as readonly CellValue[]))))(
299
+ addon.runtimeRowsTake(lease)
300
+ )
285
301
  )
286
302
  })
287
303
 
288
304
  export type { RowShape }
289
- export { decodeBoundaryRows, decodeRows, encodeBoundaryRows, encodeRows, rowSchema, rowShape }
305
+ export {
306
+ decodeBoundaryField,
307
+ decodeBoundaryRows,
308
+ decodeRows,
309
+ encodeBoundaryField,
310
+ encodeBoundaryRows,
311
+ encodeRows,
312
+ fieldSchema,
313
+ rowSchema,
314
+ rowShape
315
+ }
package/src/compile.ts CHANGED
@@ -1,88 +1,67 @@
1
- import { Effect } from "effect"
2
- import { isClosedMember, membersAgree } from "#closed.ts"
3
- import { dbNative } from "#db-native.ts"
4
- import { SdkInvariantError } from "#errors.ts"
5
- import { isImmutable, snapshotData } from "#immutable.ts"
6
- import type { SchemaClasses } from "#law.ts"
7
- import { lower } from "#lower.ts"
8
- import type { SealedDescriptor } from "#native.ts"
9
- import type { AnyRelation } from "#relation.ts"
10
- import { nativeOperationWith, runtimeHandle } from "#runtime.ts"
11
- import { argumentError } from "#runtime-errors.ts"
12
- import type { AnySchema, Schema as SchemaDeclaration, SchemaRelations } from "#schema.ts"
13
- import { schemaDescriptor } from "#schema.ts"
14
- import { type KeyStatement, type Statement, statementDescriptor } from "#statements.ts"
15
-
16
1
  /**
17
- * `SchemaId` — the engine's canonical schema fingerprint as lowercase hex.
18
- * Independent of database identity; ordinary structural text. Native
19
- * boundaries verify the fingerprint wherever it grants admission.
2
+ * A schema is compiled by the engine when it is defined. The compiled handle, descriptor and
3
+ * fingerprint ride with the schema value; the engine's diagnostics come back as authoring errors
4
+ * that name the schema's own relations and statements.
20
5
  */
21
- type SchemaId = string
6
+ import { Schema as EffectSchema } from "effect"
7
+ import { isClosedMember, membersAgree } from "./closed.ts"
8
+ import { AuthoringError, internalError } from "./errors.ts"
9
+ import { isImmutable } from "./immutable.ts"
10
+ import { lower } from "./lower.ts"
11
+ import type { SchemaRef } from "./native/addon.ts"
12
+ import { addon } from "./native/addon.ts"
13
+ import type { SchemaDescriptorOut, SchemaDiagnostic } from "./native/binding.d.ts"
14
+ import type { AnyRelation } from "./relation.ts"
15
+ import type { AnySchema } from "./schema.ts"
16
+ import { type KeyStatement, renderStatement, type Statement, statementDescriptor } from "./statements.ts"
22
17
 
23
- /**
24
- * `CompiledSchema<S>` — bounded detached immutable descriptor data plus the
25
- * canonical `schemaId`. NOT a tenant handle or a second
26
- * user-authored schema: it needs no native finalizer, holds no native
27
- * resource, and open/create/build compile through the same implementation —
28
- * prior compilation is optional, never a mandatory prepare ceremony.
29
- */
30
- interface CompiledSchema<S extends AnySchema> {
31
- readonly schema: S
18
+ /** The engine's schema fingerprint: 64 lowercase hex digits, independent of any database. */
19
+ const SchemaId = EffectSchema.String.check(EffectSchema.isPattern(/^[0-9a-f]{64}$/)).pipe(
20
+ EffectSchema.brand("SchemaId")
21
+ )
22
+ type SchemaId = typeof SchemaId.Type
23
+
24
+ interface Compiled {
25
+ readonly handle: SchemaRef
26
+ readonly descriptor: SchemaDescriptorOut
32
27
  readonly schemaId: SchemaId
33
- readonly descriptor: SealedDescriptor
34
28
  }
35
29
 
36
30
  /**
37
- * Pure declaration-order tables shared by the whole core surface: relation
38
- * ids (declaration order = ids), materialized statement ids (closed
39
- * relations' auto-handle keys FIRST in relation-declaration order, then
40
- * declared statements in declaration order with `mirrors` occupying two
41
- * consecutive slots, source-first — the theory's `StatementId` law).
42
- * Every declared statement retains its own native identity; no key is
43
- * privileged by its position in the declaration.
31
+ * Declaration-order tables: relation ids, and each declared statement's first materialized
32
+ * statement id (closed relations' id keys come first; `mirrors` takes two consecutive ids).
44
33
  */
45
34
  interface SchemaTables {
46
35
  readonly relationIds: ReadonlyMap<string, number>
47
36
  readonly statementIds: ReadonlyMap<Statement, number>
48
37
  }
49
38
 
50
- function declaredWidth(statement: Statement): number {
51
- return statement.kind === "mirrors" ? 2 : 1
52
- }
53
-
54
39
  function tablesOf(theory: AnySchema): SchemaTables {
55
40
  const relationIds = new Map<string, number>()
56
41
  const statementIds = new Map<Statement, number>()
57
- let autoKeys = 0
58
- Object.entries(theory.relations).forEach(function assignRelation([name, member], ordinal) {
42
+ let offset = 0
43
+ Object.entries(theory.relations).forEach(([name, member], ordinal) => {
59
44
  relationIds.set(name, ordinal)
60
- if (isClosedMember(member)) {
61
- autoKeys += 1
62
- }
45
+ if (isClosedMember(member)) offset += 1
63
46
  })
64
- let offset = autoKeys
65
47
  for (const statement of theory.statements) {
66
48
  statementIds.set(statement, offset)
67
- offset += declaredWidth(statement)
49
+ offset += statement.kind === "mirrors" ? 2 : 1
68
50
  }
69
51
  return Object.freeze({ relationIds, statementIds })
70
52
  }
71
53
 
72
- const compiledCache = new WeakMap<AnySchema, SchemaTables>()
54
+ const tablesCache = new WeakMap<AnySchema, SchemaTables>()
73
55
 
74
- /** Memoized pure tables (per schema value identity; no native work). */
75
56
  function schemaTables(theory: AnySchema): SchemaTables {
76
- const cached = compiledCache.get(theory)
77
- if (cached !== undefined) {
78
- return cached
79
- }
57
+ const cached = tablesCache.get(theory)
58
+ if (cached !== undefined) return cached
80
59
  const built = tablesOf(theory)
81
- if (isImmutable(theory)) compiledCache.set(theory, built)
60
+ if (isImmutable(theory)) tablesCache.set(theory, built)
82
61
  return built
83
62
  }
84
63
 
85
- /** Resolve a logical key declaration, never an opaque constructor token. */
64
+ /** Resolves a key declaration to the schema's own statement and its statement id. */
86
65
  function declaredKey<R extends AnyRelation>(
87
66
  theory: AnySchema,
88
67
  input: KeyStatement<R>
@@ -104,68 +83,67 @@ function declaredKey(
104
83
  return undefined
105
84
  }
106
85
 
107
- function admitSchemaId(fingerprint: string): SchemaId {
108
- if (typeof fingerprint !== "string" || !/^[0-9a-f]{64}$/.test(fingerprint)) {
109
- throw new SdkInvariantError({ message: "Schema.compile: the engine returned no canonical fingerprint" })
86
+ function explain(theory: AnySchema, diagnostic: SchemaDiagnostic): string {
87
+ if (diagnostic._tag === "Schema") {
88
+ const cited = [diagnostic.statement, diagnostic.conflict].flatMap((cite) =>
89
+ cite === undefined ? [] : [cite.spelling]
90
+ )
91
+ return cited.length === 0 ? diagnostic.message : `${diagnostic.message} — ${cited.join("; ")}`
110
92
  }
111
- return fingerprint
93
+ const relations = Object.keys(theory.relations)
94
+ return diagnostic.issues
95
+ .map((issue) => {
96
+ const at = [
97
+ issue.relation === undefined ? undefined : `relation ${relations[issue.relation] ?? issue.relation}`,
98
+ issue.row === undefined ? undefined : `row ${issue.row}`,
99
+ issue.statement === undefined
100
+ ? undefined
101
+ : (() => {
102
+ const statement = theory.statements[issue.statement]
103
+ return statement === undefined ? `statement ${issue.statement}` : renderStatement(statement)
104
+ })()
105
+ ].filter((part) => part !== undefined)
106
+ return at.length === 0 ? issue.message : `${issue.message} — ${at.join(", ")}`
107
+ })
108
+ .join("; ")
112
109
  }
113
110
 
114
- /**
115
- * Effectful native schema admission/compilation: a
116
- * schema declaration is pure metadata and never a claim its theory has been
117
- * admitted. Runs on the shared executor, requires the
118
- * acquired {@link NativeRuntime}, and yields detached immutable descriptor
119
- * data plus the canonical schema identity. No database is opened and no
120
- * native finalizer is created.
121
- */
122
- const compile = Effect.fn("Schema.compile")(function* <S extends AnySchema>(schema: S) {
123
- const owned = yield* Effect.try({
124
- try: () => schemaDescriptor(schema),
125
- catch: (cause) => argumentError("Schema.compile", cause)
126
- })
127
- const spec = yield* Effect.try({ try: () => lower(owned), catch: (cause) => argumentError("Schema.compile", cause) })
128
- const handle = yield* runtimeHandle()
129
- const descriptor = yield* nativeOperationWith(
130
- "Schema.compile",
131
- (callback) => dbNative.runtimeSchemaCompile(handle, spec, callback),
132
- dbNative.runtimeSchemaTake,
133
- (value) => value
134
- )
135
- const ownedDescriptor = snapshotData(descriptor)
136
- const compiled: CompiledSchema<S> = Object.freeze({
137
- get schema() {
138
- return snapshotData(owned)
139
- },
140
- schemaId: admitSchemaId(descriptor.fingerprint),
141
- get descriptor() {
142
- return snapshotData(ownedDescriptor)
111
+ const decodeSchemaId = EffectSchema.decodeUnknownOption(SchemaId)
112
+
113
+ /** Compiles `theory` with the engine; an engine refusal throws `AuthoringError`. */
114
+ function compileSchema(theory: AnySchema): Compiled {
115
+ const compiled = addon.compileSchema(JSON.stringify(lower(theory)))
116
+ switch (compiled._tag) {
117
+ case "Compiled": {
118
+ const schemaId = decodeSchemaId(compiled.descriptor.fingerprint)
119
+ if (schemaId._tag === "None") throw internalError("compileSchema: the engine returned no fingerprint")
120
+ return Object.freeze({ handle: compiled.schema, descriptor: compiled.descriptor, schemaId: schemaId.value })
143
121
  }
144
- })
145
- return compiled
146
- })
122
+ case "Invalid":
123
+ throw new AuthoringError({ message: `schema ${theory.name}: ${explain(theory, compiled.diagnostic)}` })
124
+ case "Malformed":
125
+ throw internalError(`compileSchema: ${compiled.path}: ${compiled.message}`)
126
+ }
127
+ }
147
128
 
148
- /**
149
- * The declaration-tier `Schema<Rels, Classes>` TYPE (from `#schema.ts`),
150
- * re-aliased LOCALLY so the one name carries both meanings through a
151
- * SINGLE export specifier below — a local `type` + `const` merge is the
152
- * plain TypeScript type/value merge, with no same-name pair of export
153
- * declarations for any checker to refuse (the earlier
154
- * `export type { Schema } from "#schema.ts"` beside `export { Schema }`
155
- * spelled the type meaning twice at the barrel; this spelling cannot).
156
- */
157
- type Schema<Rels extends SchemaRelations, Classes extends SchemaClasses = SchemaClasses> = SchemaDeclaration<
158
- Rels,
159
- Classes
160
- >
129
+ const compiledSchemas = new WeakMap<AnySchema, Compiled>()
161
130
 
162
- /**
163
- * The core `Schema` namespace (import as `BumbleSchema` when Effect Schema
164
- * is also in scope). The `Schema<Rels>` type remains the pure
165
- * declaration from `#schema.ts` (the local alias above); this value owns
166
- * the effectful half. One exported name, two meanings.
167
- */
168
- const Schema = Object.freeze({ compile })
131
+ /** Records the compiled form of a schema value `schema()` produced. */
132
+ function registerCompiled(theory: AnySchema): void {
133
+ compiledSchemas.set(theory, compileSchema(theory))
134
+ }
135
+
136
+ /** Whether `value` is a schema value `schema()` produced (and so has a compiled form). */
137
+ function isCompiledSchema(value: unknown): value is AnySchema {
138
+ return typeof value === "object" && value !== null && compiledSchemas.has(value as AnySchema)
139
+ }
140
+
141
+ /** The engine's compiled form of `theory`; every schema value `schema()` produced has one. */
142
+ function compiledOf(theory: AnySchema): Compiled {
143
+ const compiled = compiledSchemas.get(theory)
144
+ if (compiled === undefined) throw internalError("compiledOf: the schema was not produced by schema()")
145
+ return compiled
146
+ }
169
147
 
170
- export type { CompiledSchema, SchemaId, SchemaTables }
171
- export { declaredKey, Schema, schemaTables }
148
+ export type { Compiled, SchemaTables }
149
+ export { compiledOf, declaredKey, isCompiledSchema, registerCompiled, SchemaId, schemaTables }