@bjornpagen/bumbledb 0.9.0 → 0.11.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 (73) hide show
  1. package/COOKBOOK.md +155 -136
  2. package/README.md +3 -7
  3. package/dist/capacity.d.ts +14 -1
  4. package/dist/capacity.d.ts.map +1 -1
  5. package/dist/capacity.js.map +1 -1
  6. package/dist/db.d.ts +77 -109
  7. package/dist/db.d.ts.map +1 -1
  8. package/dist/db.js +121 -339
  9. package/dist/db.js.map +1 -1
  10. package/dist/index.d.ts +11 -16
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +7 -10
  13. package/dist/index.js.map +1 -1
  14. package/dist/lower.d.ts.map +1 -1
  15. package/dist/lower.js +8 -1
  16. package/dist/lower.js.map +1 -1
  17. package/dist/native.d.ts +69 -50
  18. package/dist/native.d.ts.map +1 -1
  19. package/dist/native.js.map +1 -1
  20. package/dist/query/atom.d.ts +162 -122
  21. package/dist/query/atom.d.ts.map +1 -1
  22. package/dist/query/atom.js +26 -22
  23. package/dist/query/atom.js.map +1 -1
  24. package/dist/query/find.d.ts +18 -35
  25. package/dist/query/find.d.ts.map +1 -1
  26. package/dist/query/find.js +13 -32
  27. package/dist/query/find.js.map +1 -1
  28. package/dist/query/lower.d.ts +113 -122
  29. package/dist/query/lower.d.ts.map +1 -1
  30. package/dist/query/lower.js +336 -260
  31. package/dist/query/lower.js.map +1 -1
  32. package/dist/query/parse-ir.d.ts +12 -0
  33. package/dist/query/parse-ir.d.ts.map +1 -0
  34. package/dist/query/parse-ir.js +71 -0
  35. package/dist/query/parse-ir.js.map +1 -0
  36. package/dist/query/run.d.ts +2 -2
  37. package/dist/query/run.d.ts.map +1 -1
  38. package/dist/query/run.js +2 -13
  39. package/dist/query/run.js.map +1 -1
  40. package/dist/query/scope.d.ts +4 -16
  41. package/dist/query/scope.d.ts.map +1 -1
  42. package/dist/query/scope.js +1 -6
  43. package/dist/query/scope.js.map +1 -1
  44. package/dist/schema.js +2 -2
  45. package/dist/schema.js.map +1 -1
  46. package/dist/statements.d.ts +15 -9
  47. package/dist/statements.d.ts.map +1 -1
  48. package/dist/statements.js +14 -9
  49. package/dist/statements.js.map +1 -1
  50. package/package.json +2 -2
  51. package/src/capacity.ts +24 -1
  52. package/src/db.ts +182 -443
  53. package/src/index.ts +9 -23
  54. package/src/lower.ts +8 -1
  55. package/src/native.ts +69 -42
  56. package/src/query/atom.ts +255 -165
  57. package/src/query/find.ts +39 -80
  58. package/src/query/lower.ts +578 -432
  59. package/src/query/parse-ir.ts +82 -0
  60. package/src/query/run.ts +2 -14
  61. package/src/query/scope.ts +3 -21
  62. package/src/schema.ts +2 -2
  63. package/src/statements.ts +33 -17
  64. package/dist/order.d.ts +0 -87
  65. package/dist/order.d.ts.map +0 -1
  66. package/dist/order.js +0 -153
  67. package/dist/order.js.map +0 -1
  68. package/dist/query/predicate.d.ts +0 -91
  69. package/dist/query/predicate.d.ts.map +0 -1
  70. package/dist/query/predicate.js +0 -156
  71. package/dist/query/predicate.js.map +0 -1
  72. package/src/order.ts +0 -234
  73. package/src/query/predicate.ts +0 -269
@@ -1,269 +0,0 @@
1
- /**
2
- * Stratified recursion — engine recursion as values, mirroring the IR's
3
- * cut exactly (`ir::Program`/`PredicateDef`/`AtomSource::Idb`;
4
- * `docs/architecture/20-query-ir.md` § engine recursion):
5
- *
6
- * program(S, (p) => {
7
- * const reach = p.rec("reach")
8
- * reach.rule((r) => {
9
- * const n = v(Node)
10
- * return r.match(Node, { id: n.id }).where(r.eq(n.id, r.param("root"))).find({ c: n.id })
11
- * })
12
- * reach.rule((r) => {
13
- * const e = v(Parent)
14
- * return r.match(Parent, { child: e.child, parent: e.parent }).idb(reach, { c: e.parent }).find({ c: e.child })
15
- * })
16
- * return p.output((r) => {
17
- * const post = v(Posting)
18
- * return r.match(Posting, { account: post.account, minor: post.minor })
19
- * .idb(reach, { c: post.account }).find({ total: r.sum(post.minor) })
20
- * })
21
- * })
22
- *
23
- * `p.rec(name)` declares one recursive predicate (declaration order = its
24
- * dense `PredId`); `rec.rule(...)` attaches one clause — its builder's
25
- * `idb` accepts ONLY the rec itself (the self-recursion cut as a
26
- * type-level boundary: mutual recursion is unwritable) and its `find` head
27
- * projects bound variables only (aggregation/measure through a cycle is
28
- * unrepresentable — the strata judge's roster, made unwritable);
29
- * `p.output(...)` seals the recs and builds the output rules, whose `idb`
30
- * folds any FINISHED stratum by NAMED record over its head keys (recipe
31
- * 25's form). The rec value `.rule` returns carries the params its rules
32
- * used — thread it into the output's `idb` and the program's inferred
33
- * `Params` stays exactly the params the rules use. Everything deeper —
34
- * strata legality, signature sealing, the three oracles — is the ENGINE's
35
- * judge, surfacing typed at prepare.
36
- */
37
-
38
- import * as errors from "@superbuilders/errors"
39
- import type { SchemaClasses } from "#law.ts"
40
- import type { RecData } from "#query/atom.ts"
41
- import type {
42
- AnyRuleValue,
43
- HeadOf,
44
- HeadShape,
45
- OutputRuleScope,
46
- ParamsOf,
47
- ProgramState,
48
- Query,
49
- RawScope,
50
- RecRef,
51
- RecRuleScope,
52
- RowOf,
53
- RuleValue
54
- } from "#query/lower.ts"
55
- import { makeOutputRuleScope, makeQuery, makeRawScope } from "#query/lower.ts"
56
- import type { Flatten, ParamsRecord, ShapeOf } from "#query/scope.ts"
57
- import { fieldJoins, inferred, renderFieldKind } from "#query/scope.ts"
58
- import type { Schema, SchemaRelations } from "#schema.ts"
59
-
60
- /**
61
- * One recursive predicate HANDLE: `rec.rule(...)` attaches a clause and
62
- * returns the SAME rec under a widened params type (the runtime data is
63
- * shared — either handle is the self-reference; the returned one carries
64
- * the rules' params for the output to thread) and under the head signature
65
- * the FIRST rule sealed (every later rule derives the same head — the
66
- * runtime alignment check's law), so a threaded handle's `idb` joins are
67
- * arity- and domain-checked against the head.
68
- */
69
- interface Rec<
70
- Rels extends SchemaRelations,
71
- Name extends string,
72
- P extends ParamsRecord,
73
- Head extends HeadShape = undefined,
74
- Classes extends SchemaClasses = SchemaClasses
75
- > extends RecRef<Name, P, Head> {
76
- rule<RV extends AnyRuleValue>(
77
- build: (r: RecRuleScope<Rels, Name, Classes>) => RV
78
- ): Rec<Rels, Name, Flatten<P & ParamsOf<RV>>, Head extends undefined ? HeadOf<RV> : Head, Classes>
79
- readonly [inferred]?: { readonly params: P; readonly head: Head }
80
- }
81
-
82
- /** One output-rule builder function. */
83
- type OutputBuild<Rels extends SchemaRelations, Classes extends SchemaClasses = SchemaClasses> = (
84
- r: OutputRuleScope<Rels, Classes>
85
- ) => AnyRuleValue
86
-
87
- /** A build function's rule value. */
88
- type BuiltRule<F> = F extends (r: never) => infer RV ? RV : never
89
-
90
- /** The union row of a tuple of output builds. */
91
- type OutputRow<Builds extends readonly OutputBuild<SchemaRelations, SchemaClasses>[]> = RowOf<BuiltRule<Builds[number]>>
92
-
93
- /** The intersected params record of a tuple of output builds. */
94
- type OutputParams<Builds extends readonly OutputBuild<SchemaRelations, SchemaClasses>[]> = ShapeOf<
95
- ParamsOf<BuiltRule<Builds[number]>>
96
- >
97
-
98
- /**
99
- * The program scope: declare recs, attach their rules, then declare the
100
- * output — which seals the recs (a later `rec`/`rule` is a construction
101
- * error) and returns the program as an ordinary query value.
102
- */
103
- interface ProgramScope<Rels extends SchemaRelations, Classes extends SchemaClasses = SchemaClasses> {
104
- /** Declares one recursive predicate; declaration order = its dense `PredId`. */
105
- rec<const Name extends string>(name: Name): Rec<Rels, Name, Record<never, never>, undefined, Classes>
106
- /**
107
- * Declares the output predicate (one rule per build; multiple rules =
108
- * set union) and seals the program. Must be what the `program()`
109
- * callback returns.
110
- */
111
- output<const Builds extends readonly OutputBuild<Rels, Classes>[]>(
112
- ...builds: Builds
113
- ): Query<Rels, OutputRow<Builds>, OutputParams<Builds>, Classes>
114
- }
115
-
116
- /** The runtime rec-handle shape beneath the typed `Rec` face. */
117
- interface RawRec<Name extends string> {
118
- readonly name: Name
119
- readonly data: RecData
120
- rule(build: (r: RawScope) => RuleValue<never, never>): RawRec<Name>
121
- }
122
-
123
- /** Builds the runtime rec handle over shared rec data. */
124
- function makeRawRec<Name extends string>(state: ProgramState, name: Name, data: RecData): RawRec<Name> {
125
- const rec: RawRec<Name> = {
126
- name,
127
- data,
128
- rule(build) {
129
- if (state.sealed) {
130
- throw errors.new(
131
- `rec ${name}: the program's output is already declared — recursive rules attach before p.output`
132
- )
133
- }
134
- const built = build(makeRawScope({ kind: "rec", self: data, classes: state.classes, theory: state.theory }))
135
- const head = data.rules[0]
136
- if (head !== undefined) {
137
- const declared = head.finds.map(function columnName(column) {
138
- return column.name
139
- })
140
- const candidate = built.rule.finds.map(function columnName(column) {
141
- return column.name
142
- })
143
- if (declared.join(", ") !== candidate.join(", ")) {
144
- throw errors.new(
145
- `rec ${name}: every rule derives the same head — rule 0 projects (${declared.join(", ")}), this rule projects (${candidate.join(", ")})`
146
- )
147
- }
148
- // The law-class wall on the sealed head: names alone do not
149
- // align value spaces. Every rule must bind each head column
150
- // at a classed mint slot that JOINS rule 0's (the sealing rule
151
- // — the one slot every downstream idb pairing class-checks
152
- // against), under the same fieldJoins judgment every reuse
153
- // site enforces; otherwise a later rule feeds (say) bare
154
- // weights into a column the idb joins as Node ids.
155
- built.rule.finds.forEach(function verifyHeadSlot(column, position) {
156
- const lead = head.finds[position]
157
- if (lead === undefined) {
158
- return
159
- }
160
- if (lead.slot !== undefined && column.slot !== undefined && !fieldJoins(lead.slot, column.slot)) {
161
- throw errors.new(
162
- `rec ${name}: every rule derives the same head — the head column ${lead.name} is bound at ${renderFieldKind(lead.slot)} in rule 0 but at ${renderFieldKind(column.slot)} in this rule (a head column joins only class-equal slots; bare pairs only with bare)`
163
- )
164
- }
165
- })
166
- }
167
- data.rules.push(built.rule)
168
- return makeRawRec<Name>(state, name, data)
169
- }
170
- }
171
- Object.freeze(rec)
172
- return rec
173
- }
174
-
175
- /**
176
- * The rec handles' trusted admission seam (the pattern's home is
177
- * `isTypedScope` in query/lower.ts):
178
- * the checkable fact — the handle owns exactly the rec data it names — is
179
- * verified before the raw handle is admitted at its typed face.
180
- */
181
- function isRecHandle<
182
- Rels extends SchemaRelations,
183
- Name extends string,
184
- P extends ParamsRecord,
185
- Classes extends SchemaClasses
186
- >(data: RecData, rec: RawRec<Name>): rec is RawRec<Name> & Rec<Rels, Name, P, undefined, Classes> {
187
- return rec.data === data
188
- }
189
-
190
- /** Builds one typed rec handle over shared rec data. */
191
- function makeRec<
192
- Rels extends SchemaRelations,
193
- Name extends string,
194
- P extends ParamsRecord,
195
- Classes extends SchemaClasses
196
- >(state: ProgramState, name: Name, data: RecData): Rec<Rels, Name, P, undefined, Classes> {
197
- const raw = makeRawRec<Name>(state, name, data)
198
- if (!isRecHandle<Rels, Name, P, Classes>(data, raw)) {
199
- throw errors.new(`rec ${name}: handle construction incomplete`)
200
- }
201
- return raw
202
- }
203
-
204
- /**
205
- * Builds a stratified program over a schema. The callback declares recs
206
- * and their rules through the scope and MUST return `p.output(...)` — the
207
- * sealed program is an ordinary query value: `db.prepare` lowers it to
208
- * the one `ProgramIr` shape the engine executes under the per-stratum
209
- * fixpoint driver.
210
- */
211
- function program<
212
- Rels extends SchemaRelations,
213
- Classes extends SchemaClasses,
214
- Q extends Query<Rels, unknown, ParamsRecord, Classes>
215
- >(theory: Schema<Rels, Classes>, build: (p: ProgramScope<Rels, Classes>) => Q): Q {
216
- const state: ProgramState = { recs: [], classes: theory.classes, theory, sealed: false }
217
- const names = new Set<string>()
218
- const made: { query: unknown } = { query: undefined }
219
- const scope: ProgramScope<Rels, Classes> = {
220
- rec<const Name extends string>(name: Name): Rec<Rels, Name, Record<never, never>, undefined, Classes> {
221
- if (state.sealed) {
222
- throw errors.new(`program: the output is already declared — rec ${name} would be unreachable`)
223
- }
224
- if (names.has(name)) {
225
- throw errors.new(
226
- `program: a rec named ${name} is already declared — rec names are the self-recursion cut's identity`
227
- )
228
- }
229
- names.add(name)
230
- const data: RecData = { name, rules: [] }
231
- state.recs.push(data)
232
- return makeRec<Rels, Name, Record<never, never>, Classes>(state, name, data)
233
- },
234
- output<const Builds extends readonly OutputBuild<Rels, Classes>[]>(
235
- ...builds: Builds
236
- ): Query<Rels, OutputRow<Builds>, OutputParams<Builds>, Classes> {
237
- if (state.sealed) {
238
- throw errors.new("program: output is declared once — multiple rules are multiple builds of the one output")
239
- }
240
- state.sealed = true
241
- for (const rec of state.recs) {
242
- if (rec.rules.length === 0) {
243
- throw errors.new(
244
- `program: rec ${rec.name} has no rules — a predicate with no defining clause seals no signature`
245
- )
246
- }
247
- Object.freeze(rec.rules)
248
- }
249
- if (builds.length === 0) {
250
- throw errors.new("program: the output needs at least one rule")
251
- }
252
- const rules = builds.map(function buildRule(buildOne) {
253
- return buildOne(makeOutputRuleScope<Rels, Classes>(state)).rule
254
- })
255
- const q = makeQuery<Rels, OutputRow<Builds>, OutputParams<Builds>, Classes>(theory, state.recs, rules)
256
- made.query = q
257
- return q
258
- }
259
- }
260
- Object.freeze(scope)
261
- const result = build(scope)
262
- if (made.query !== result) {
263
- throw errors.new("program: the build callback must return p.output(...) — the sealed program IS the query value")
264
- }
265
- return result
266
- }
267
-
268
- export type { OutputBuild, ProgramScope, Rec }
269
- export { program }