@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.
- package/COOKBOOK.md +155 -136
- package/README.md +3 -7
- package/dist/capacity.d.ts +14 -1
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js.map +1 -1
- package/dist/db.d.ts +77 -109
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +121 -339
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +11 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -10
- package/dist/index.js.map +1 -1
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +8 -1
- package/dist/lower.js.map +1 -1
- package/dist/native.d.ts +69 -50
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +162 -122
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +26 -22
- package/dist/query/atom.js.map +1 -1
- package/dist/query/find.d.ts +18 -35
- package/dist/query/find.d.ts.map +1 -1
- package/dist/query/find.js +13 -32
- package/dist/query/find.js.map +1 -1
- package/dist/query/lower.d.ts +113 -122
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +336 -260
- package/dist/query/lower.js.map +1 -1
- package/dist/query/parse-ir.d.ts +12 -0
- package/dist/query/parse-ir.d.ts.map +1 -0
- package/dist/query/parse-ir.js +71 -0
- package/dist/query/parse-ir.js.map +1 -0
- package/dist/query/run.d.ts +2 -2
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +2 -13
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +4 -16
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +1 -6
- package/dist/query/scope.js.map +1 -1
- package/dist/schema.js +2 -2
- package/dist/schema.js.map +1 -1
- package/dist/statements.d.ts +15 -9
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +14 -9
- package/dist/statements.js.map +1 -1
- package/package.json +2 -2
- package/src/capacity.ts +24 -1
- package/src/db.ts +182 -443
- package/src/index.ts +9 -23
- package/src/lower.ts +8 -1
- package/src/native.ts +69 -42
- package/src/query/atom.ts +255 -165
- package/src/query/find.ts +39 -80
- package/src/query/lower.ts +578 -432
- package/src/query/parse-ir.ts +82 -0
- package/src/query/run.ts +2 -14
- package/src/query/scope.ts +3 -21
- package/src/schema.ts +2 -2
- package/src/statements.ts +33 -17
- package/dist/order.d.ts +0 -87
- package/dist/order.d.ts.map +0 -1
- package/dist/order.js +0 -153
- package/dist/order.js.map +0 -1
- package/dist/query/predicate.d.ts +0 -91
- package/dist/query/predicate.d.ts.map +0 -1
- package/dist/query/predicate.js +0 -156
- package/dist/query/predicate.js.map +0 -1
- package/src/order.ts +0 -234
- package/src/query/predicate.ts +0 -269
package/src/query/predicate.ts
DELETED
|
@@ -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 }
|