@bjornpagen/bumbledb 0.4.0 → 0.5.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 +181 -47
- package/README.md +4 -2
- package/dist/closed.d.ts +30 -2
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +66 -20
- package/dist/closed.js.map +1 -1
- package/dist/db.d.ts +33 -6
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +87 -70
- package/dist/db.js.map +1 -1
- package/dist/exhume.d.ts.map +1 -1
- package/dist/exhume.js +1 -14
- package/dist/exhume.js.map +1 -1
- package/dist/face.d.ts +1 -1
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +2 -1
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +18 -1
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +44 -16
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +11 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/law.d.ts +2 -1
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +15 -14
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +1 -7
- package/dist/lower.js.map +1 -1
- package/dist/marshal.d.ts.map +1 -1
- package/dist/marshal.js +15 -27
- package/dist/marshal.js.map +1 -1
- package/dist/native.d.ts +21 -2
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +20 -3
- package/dist/native.js.map +1 -1
- package/dist/order.d.ts +36 -0
- package/dist/order.d.ts.map +1 -0
- package/dist/order.js +135 -0
- package/dist/order.js.map +1 -0
- package/dist/query/atom.d.ts +18 -15
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +9 -16
- package/dist/query/atom.js.map +1 -1
- package/dist/query/lower.d.ts +5 -8
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +87 -76
- package/dist/query/lower.js.map +1 -1
- package/dist/query/predicate.d.ts.map +1 -1
- package/dist/query/predicate.js +34 -2
- package/dist/query/predicate.js.map +1 -1
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +1 -2
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +2 -16
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +7 -47
- package/dist/query/scope.js.map +1 -1
- package/dist/relation.d.ts +9 -22
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +9 -28
- package/dist/relation.js.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +7 -31
- package/dist/schema.js.map +1 -1
- package/dist/statements.d.ts +5 -2
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +30 -35
- package/dist/statements.js.map +1 -1
- package/package.json +2 -5
- package/src/closed.ts +73 -28
- package/src/db.ts +122 -84
- package/src/exhume.ts +1 -15
- package/src/face.ts +4 -3
- package/src/fields.ts +58 -16
- package/src/index.ts +10 -8
- package/src/law.ts +15 -14
- package/src/lower.ts +2 -9
- package/src/marshal.ts +15 -31
- package/src/native.ts +22 -4
- package/src/order.ts +156 -0
- package/src/query/atom.ts +13 -21
- package/src/query/lower.ts +90 -91
- package/src/query/predicate.ts +39 -4
- package/src/query/run.ts +1 -3
- package/src/query/scope.ts +7 -59
- package/src/relation.ts +9 -51
- package/src/schema.ts +7 -33
- package/src/statements.ts +33 -38
package/COOKBOOK.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The cookbook — modeling intuition as schemas, in TypeScript
|
|
2
2
|
|
|
3
|
-
The bumbledb engine's
|
|
3
|
+
The bumbledb engine's 30 cookbook recipes (`bumbledb/docs/cookbook.md`),
|
|
4
4
|
translated to this SDK's structural API. **This document is illustrative,
|
|
5
5
|
never normative**: where a recipe and an engine architecture chapter disagree,
|
|
6
6
|
the chapter wins (`docs/architecture/README.md` rule 5) — the SDK is the same
|
|
@@ -37,9 +37,11 @@ import {
|
|
|
37
37
|
abandon,
|
|
38
38
|
allen,
|
|
39
39
|
bool,
|
|
40
|
+
by,
|
|
40
41
|
bytes,
|
|
41
42
|
closed,
|
|
42
43
|
contained,
|
|
44
|
+
desc,
|
|
43
45
|
eq,
|
|
44
46
|
i64,
|
|
45
47
|
interval,
|
|
@@ -116,10 +118,11 @@ const Uptime = schema("Uptime", { Service, Outage }, [
|
|
|
116
118
|
key(Outage, ["service", "window"])
|
|
117
119
|
])
|
|
118
120
|
|
|
119
|
-
// down at instant t — `r.
|
|
120
|
-
//
|
|
121
|
+
// down at instant t — `r.var` names each variable (typed by the field it
|
|
122
|
+
// first binds), and shorthand punning binds same-named columns:
|
|
121
123
|
const downAt = query(Uptime).rule((r) => {
|
|
122
|
-
const
|
|
124
|
+
const service = r.var("service")
|
|
125
|
+
const window = r.var("window")
|
|
123
126
|
return r
|
|
124
127
|
.match(Outage, { service, window })
|
|
125
128
|
.where(pointIn(r.param("t"), window))
|
|
@@ -127,7 +130,8 @@ const downAt = query(Uptime).rule((r) => {
|
|
|
127
130
|
})
|
|
128
131
|
// overlapping an incident window (one Allen mask, no operator zoo):
|
|
129
132
|
const overlapping = query(Uptime).rule((r) => {
|
|
130
|
-
const
|
|
133
|
+
const service = r.var("service")
|
|
134
|
+
const window = r.var("window")
|
|
131
135
|
return r
|
|
132
136
|
.match(Outage, { service, window })
|
|
133
137
|
.where(allen(window, ALLEN.intersects, r.param("incident")))
|
|
@@ -135,7 +139,8 @@ const overlapping = query(Uptime).rule((r) => {
|
|
|
135
139
|
})
|
|
136
140
|
// total downtime per service (the denotation's one arithmetic):
|
|
137
141
|
const downtime = query(Uptime).rule((r) => {
|
|
138
|
-
const
|
|
142
|
+
const service = r.var("service")
|
|
143
|
+
const window = r.var("window")
|
|
139
144
|
return r.match(Outage, { service, window }).select("service", r.sum(r.duration("window")))
|
|
140
145
|
})
|
|
141
146
|
```
|
|
@@ -215,7 +220,7 @@ const Optionality = schema("Optionality", { Business, MailingAddress }, [
|
|
|
215
220
|
|
|
216
221
|
// Negation is plain anti-join (no null branch exists in any operator):
|
|
217
222
|
const unaddressed = query(Optionality).rule((r) => {
|
|
218
|
-
const
|
|
223
|
+
const b = r.var("b")
|
|
219
224
|
return r
|
|
220
225
|
.match(Business, { id: b })
|
|
221
226
|
.where(not(MailingAddress, { business: b }))
|
|
@@ -255,7 +260,10 @@ const Money = schema("Money", { Currency, Account, Posting }, [
|
|
|
255
260
|
// silently. Bind the fresh id: set semantics would collapse two equal
|
|
256
261
|
// (account, currency, minor) postings without it.
|
|
257
262
|
const totals = query(Money).rule((r) => {
|
|
258
|
-
const
|
|
263
|
+
const id = r.var("id")
|
|
264
|
+
const account = r.var("account")
|
|
265
|
+
const currency = r.var("currency")
|
|
266
|
+
const minor = r.var("minor")
|
|
259
267
|
return r.match(Posting, { id, account, currency, minor }).select("account", "currency", r.sum("minor"))
|
|
260
268
|
})
|
|
261
269
|
```
|
|
@@ -292,7 +300,7 @@ const Content = schema("Content", { Region, Document, Replica }, [
|
|
|
292
300
|
|
|
293
301
|
// a bytes param self-encodes (Uint8Array by inference):
|
|
294
302
|
const byDigest = query(Content).rule((r) => {
|
|
295
|
-
const
|
|
303
|
+
const id = r.var("id")
|
|
296
304
|
return r.match(Document, { id, payload: r.param("digest") }).select("id")
|
|
297
305
|
})
|
|
298
306
|
```
|
|
@@ -334,7 +342,7 @@ const Tickets = schema("Tickets", { Priority, Ticket }, [
|
|
|
334
342
|
// that drifts without a rebuild is an ordinary relation — a vocabulary is
|
|
335
343
|
// never written, only declared.
|
|
336
344
|
const urgent = query(Tickets).rule((r) => {
|
|
337
|
-
const
|
|
345
|
+
const t = r.var("t")
|
|
338
346
|
return r.match(Ticket, { id: t, priority: "Urgent" }).select("t")
|
|
339
347
|
})
|
|
340
348
|
|
|
@@ -343,7 +351,7 @@ const urgent = query(Tickets).rule((r) => {
|
|
|
343
351
|
// ∈-set param, `r.inSet`); the array folds to the same wire set the param
|
|
344
352
|
// spelling crosses. In `.where()` selections arrays work at EVERY field kind.
|
|
345
353
|
const actionable = query(Tickets).rule((r) => {
|
|
346
|
-
const
|
|
354
|
+
const t = r.var("t")
|
|
347
355
|
return r.match(Ticket, { id: t, priority: ["Normal", "Urgent"] }).select("t")
|
|
348
356
|
})
|
|
349
357
|
```
|
|
@@ -388,7 +396,8 @@ const Review = schema("Review", { Kind, Attempt, Certificate }, [
|
|
|
388
396
|
// exactly like an ordinary one, and the atom folds at prepare into a
|
|
389
397
|
// plan-constant handle set on its sibling.
|
|
390
398
|
const masteredAttempts = query(Review).rule((r) => {
|
|
391
|
-
const
|
|
399
|
+
const a = r.var("a")
|
|
400
|
+
const k = r.var("k")
|
|
392
401
|
return r
|
|
393
402
|
.match(Attempt, { id: a, kind: k })
|
|
394
403
|
.match(Kind, { id: k, mastered: true })
|
|
@@ -451,7 +460,8 @@ const Oncall = schema("Oncall", { Severity, Incident, Escalation }, [
|
|
|
451
460
|
|
|
452
461
|
// who is being paged — the same ψ, on the read side:
|
|
453
462
|
const paged = query(Oncall).rule((r) => {
|
|
454
|
-
const
|
|
463
|
+
const i = r.var("i")
|
|
464
|
+
const s = r.var("s")
|
|
455
465
|
return r
|
|
456
466
|
.match(Escalation, { incident: i, severity: s })
|
|
457
467
|
.match(Severity, { id: s, pages: true })
|
|
@@ -468,7 +478,8 @@ plus pointwise keys realizes exact partition
|
|
|
468
478
|
(`lean/Bumbledb/Dependencies.lean: exact_partition_iff`), and the mixed-width
|
|
469
479
|
interval positions type by element domain
|
|
470
480
|
(`lean/Bumbledb/Schema.lean: Value.points_one_tag_u64`); ordering the result
|
|
471
|
-
remains a host presentation step
|
|
481
|
+
remains a host presentation step — the SDK ships the comparator (`by`/`desc`,
|
|
482
|
+
keys as data); the engine never orders.
|
|
472
483
|
|
|
473
484
|
The linked-list verdict: successor pointers are control flow smuggled into
|
|
474
485
|
data. Order is a value. The idiomatic ordered collection is an interval
|
|
@@ -496,12 +507,21 @@ const Playlists = schema("Playlists", { Playlist, Extent, Slot }, [
|
|
|
496
507
|
|
|
497
508
|
// Positional access is membership — "what plays at position ?pos":
|
|
498
509
|
const playingAt = query(Playlists).rule((r) => {
|
|
499
|
-
const
|
|
510
|
+
const slot = r.var("slot")
|
|
511
|
+
const track = r.var("track")
|
|
500
512
|
return r
|
|
501
513
|
.match(Slot, { playlist: r.param("list"), slot, track })
|
|
502
514
|
.where(pointIn(r.param("pos"), slot))
|
|
503
515
|
.select("track")
|
|
504
516
|
})
|
|
517
|
+
|
|
518
|
+
// Answers are SETS — the host sorts them, and the SDK ships the comparator:
|
|
519
|
+
// sort keys as data, a bare name ascending, `desc(...)` the flip; intervals
|
|
520
|
+
// order by (start, end). Limit is the language's own `.slice(0, n)`.
|
|
521
|
+
const inPlayOrder = [
|
|
522
|
+
{ slot: { start: 1n, end: 2n }, track: "b" },
|
|
523
|
+
{ slot: { start: 0n, end: 1n }, track: "a" }
|
|
524
|
+
].sort(by("slot", "track"))
|
|
505
525
|
```
|
|
506
526
|
|
|
507
527
|
Middle insert is honest about its cost: making room at position `k` shifts
|
|
@@ -548,7 +568,8 @@ const Ast = schema("Ast", { Kind, Node, Lit, Add, Parent }, [
|
|
|
548
568
|
])
|
|
549
569
|
|
|
550
570
|
const lhsLiteral = query(Ast).rule((r) => {
|
|
551
|
-
const
|
|
571
|
+
const l = r.var("l")
|
|
572
|
+
const v = r.var("v")
|
|
552
573
|
return r
|
|
553
574
|
.match(Add, { node: r.param("n"), lhs: l })
|
|
554
575
|
.match(Lit, { node: l, value: v })
|
|
@@ -583,7 +604,8 @@ const Graph = schema("Graph", { Person, Repo, Follows, Maintains }, [
|
|
|
583
604
|
// live in the "Person.id" class, so the reuse is lawful); `lt` keeps each
|
|
584
605
|
// pair once:
|
|
585
606
|
const mutual = query(Graph).rule((r) => {
|
|
586
|
-
const
|
|
607
|
+
const a = r.var("a")
|
|
608
|
+
const b = r.var("b")
|
|
587
609
|
return r
|
|
588
610
|
.match(Follows, { follower: a, followee: b })
|
|
589
611
|
.match(Follows, { follower: b, followee: a })
|
|
@@ -621,7 +643,11 @@ const Ecs = schema("Ecs", { Entity, Transform, Velocity, Renderable }, [
|
|
|
621
643
|
|
|
622
644
|
// The physics join is the component intersection:
|
|
623
645
|
const physics = query(Ecs).rule((r) => {
|
|
624
|
-
const
|
|
646
|
+
const entity = r.var("entity")
|
|
647
|
+
const x = r.var("x")
|
|
648
|
+
const y = r.var("y")
|
|
649
|
+
const dx = r.var("dx")
|
|
650
|
+
const dy = r.var("dy")
|
|
625
651
|
return r
|
|
626
652
|
.match(Transform, { entity, x, y })
|
|
627
653
|
.match(Velocity, { entity, dx, dy })
|
|
@@ -661,7 +687,8 @@ const Orders = schema("Orders", { State, Order, Placement, Shipment }, [
|
|
|
661
687
|
])
|
|
662
688
|
|
|
663
689
|
const shipped = query(Orders).rule((r) => {
|
|
664
|
-
const
|
|
690
|
+
const id = r.var("id")
|
|
691
|
+
const carrier = r.var("carrier")
|
|
665
692
|
return r
|
|
666
693
|
.match(Order, { id, state: "Shipped" })
|
|
667
694
|
.match(Shipment, { order: id, carrier })
|
|
@@ -731,14 +758,16 @@ const Calendar = schema("Calendar", { Rsvp, Arm, Person, Room, Event, Attendance
|
|
|
731
758
|
])
|
|
732
759
|
|
|
733
760
|
const roomConflicts = query(Calendar).rule((r) => {
|
|
734
|
-
const
|
|
761
|
+
const room = r.var("room")
|
|
762
|
+
const span = r.var("span")
|
|
735
763
|
return r
|
|
736
764
|
.match(Booking, { room, span })
|
|
737
765
|
.where(allen(span, ALLEN.intersects, r.param("want")))
|
|
738
766
|
.select("room", "span")
|
|
739
767
|
})
|
|
740
768
|
const personLoad = query(Calendar).rule((r) => {
|
|
741
|
-
const
|
|
769
|
+
const person = r.var("person")
|
|
770
|
+
const span = r.var("span")
|
|
742
771
|
return r
|
|
743
772
|
.match(Claim, { person, span })
|
|
744
773
|
.where(allen(span, ALLEN.intersects, r.param("window")))
|
|
@@ -774,7 +803,8 @@ const Pricing = schema("Pricing", { Policy, Version }, [
|
|
|
774
803
|
|
|
775
804
|
// in force on date t — one membership probe:
|
|
776
805
|
const inForce = query(Pricing).rule((r) => {
|
|
777
|
-
const
|
|
806
|
+
const rate_bps = r.var("rate_bps")
|
|
807
|
+
const valid = r.var("valid")
|
|
778
808
|
return r
|
|
779
809
|
.match(Version, { policy: r.param("p"), rate_bps, valid })
|
|
780
810
|
.where(pointIn(r.param("t"), valid))
|
|
@@ -782,7 +812,9 @@ const inForce = query(Pricing).rule((r) => {
|
|
|
782
812
|
})
|
|
783
813
|
// clean successions (half-open makes MEETS exact, no ±1 fudge):
|
|
784
814
|
const successions = query(Pricing).rule((r) => {
|
|
785
|
-
const
|
|
815
|
+
const p = r.var("p")
|
|
816
|
+
const a = r.var("a")
|
|
817
|
+
const b = r.var("b")
|
|
786
818
|
return r
|
|
787
819
|
.match(Version, { policy: p, valid: a })
|
|
788
820
|
.match(Version, { policy: p, valid: b })
|
|
@@ -816,7 +848,8 @@ const Payroll = schema("Payroll", { FiscalYear, PayPeriod }, [
|
|
|
816
848
|
|
|
817
849
|
// the period holding date t:
|
|
818
850
|
const holding = query(Payroll).rule((r) => {
|
|
819
|
-
const
|
|
851
|
+
const seq = r.var("seq")
|
|
852
|
+
const span = r.var("span")
|
|
820
853
|
return r
|
|
821
854
|
.match(PayPeriod, { year: r.param("y"), seq, span })
|
|
822
855
|
.where(pointIn(r.param("t"), span))
|
|
@@ -864,7 +897,9 @@ const Tax = schema("Tax", { Status, Regime, Bracket, Residency, Earned }, [
|
|
|
864
897
|
// owed is host arithmetic over the bracket walk — arithmetic beyond the
|
|
865
898
|
// measure is refused (the ledger).
|
|
866
899
|
const marginal = query(Tax).rule((r) => {
|
|
867
|
-
const
|
|
900
|
+
const reg = r.var("reg")
|
|
901
|
+
const b = r.var("b")
|
|
902
|
+
const rate_bps = r.var("rate_bps")
|
|
868
903
|
return r
|
|
869
904
|
.match(Regime, { id: reg, year: r.param("y"), status: r.param("s") })
|
|
870
905
|
.match(Bracket, { regime: reg, income: b, rate_bps })
|
|
@@ -896,17 +931,21 @@ const FreeTime = schema("FreeTime", { Person, Claim }, [
|
|
|
896
931
|
|
|
897
932
|
// busy time, coalesced (adjacent segments merge — the half-open law):
|
|
898
933
|
const busy = query(FreeTime).rule((r) => {
|
|
899
|
-
const
|
|
934
|
+
const person = r.var("person")
|
|
935
|
+
const span = r.var("span")
|
|
900
936
|
return r.match(Claim, { person, span }).select("person", r.pack("span"))
|
|
901
937
|
})
|
|
902
938
|
// raw claimed time (overlaps double-count — often the wrong question):
|
|
903
939
|
const claimed = query(FreeTime).rule((r) => {
|
|
904
|
-
const
|
|
940
|
+
const person = r.var("person")
|
|
941
|
+
const span = r.var("span")
|
|
905
942
|
return r.match(Claim, { person, span }).select("person", r.sum(r.duration("span")))
|
|
906
943
|
})
|
|
907
944
|
// Coalesced totals = the two-query composition (pack, then a host fold) —
|
|
908
945
|
// aggregates never nest; free time (gaps) is the two-line host walk over
|
|
909
|
-
// sorted packed answers
|
|
946
|
+
// sorted packed answers (`rows.sort(by("person", "span"))` — the
|
|
947
|
+
// keys-as-data comparator; limit is the language's own `.slice`) — both
|
|
948
|
+
// refusals recorded in the ledger.
|
|
910
949
|
```
|
|
911
950
|
|
|
912
951
|
## The write side
|
|
@@ -940,12 +979,16 @@ const Ledger = schema("Ledger", { Account, JournalEntry, Posting }, [
|
|
|
940
979
|
|
|
941
980
|
// balances (bind the fresh id — set semantics collapses duplicates):
|
|
942
981
|
const balances = query(Ledger).rule((r) => {
|
|
943
|
-
const
|
|
982
|
+
const id = r.var("id")
|
|
983
|
+
const account = r.var("account")
|
|
984
|
+
const minor = r.var("minor")
|
|
944
985
|
return r.match(Posting, { id, account, minor }).select("account", r.sum("minor"))
|
|
945
986
|
})
|
|
946
987
|
// double-entry audit (host asserts every total is 0 — discipline, not schema):
|
|
947
988
|
const doubleEntry = query(Ledger).rule((r) => {
|
|
948
|
-
const
|
|
989
|
+
const id = r.var("id")
|
|
990
|
+
const entry = r.var("entry")
|
|
991
|
+
const minor = r.var("minor")
|
|
949
992
|
return r.match(Posting, { id, entry, minor }).select("entry", r.sum("minor"))
|
|
950
993
|
})
|
|
951
994
|
```
|
|
@@ -960,8 +1003,11 @@ final-state point reads need no earlier witness.
|
|
|
960
1003
|
The generation witness: read the model, propose a delta, commit iff the model
|
|
961
1004
|
you read is still the model. In the SDK the whole loop is `db.writeWitnessed`
|
|
962
1005
|
— retry on movement is built in (every generation move is self-inflicted by
|
|
963
|
-
the host's own interleaved writes),
|
|
964
|
-
|
|
1006
|
+
the host's own interleaved writes), capped at 64 attempts: a callback that
|
|
1007
|
+
itself issues a plain `db.write` each try re-moves the generation it is about
|
|
1008
|
+
to witness, and past the cap that interleave hazard throws the typed
|
|
1009
|
+
`ErrWitnessedLivelock` instead of spinning forever. `abandon(payload)`
|
|
1010
|
+
declines to commit without issuing anything.
|
|
965
1011
|
|
|
966
1012
|
```ts
|
|
967
1013
|
const State = closed("State", ["Queued", "Running", "Done"])
|
|
@@ -978,7 +1024,8 @@ const Jobs = schema("Jobs", { State, Job, Lease }, [
|
|
|
978
1024
|
|
|
979
1025
|
// update-where's premise — "still Queued" is the witness:
|
|
980
1026
|
const stillQueued = query(Jobs).rule((r) => {
|
|
981
|
-
const
|
|
1027
|
+
const id = r.var("id")
|
|
1028
|
+
const payload = r.var("payload")
|
|
982
1029
|
return r.match(Job, { id, state: "Queued", payload }).select("id", "payload")
|
|
983
1030
|
})
|
|
984
1031
|
|
|
@@ -1035,7 +1082,8 @@ const Rollup = schema("Rollup", { Arm, Claim, BusySpan }, [
|
|
|
1035
1082
|
// against sources it didn't actually read. The deriving query (pack IS the
|
|
1036
1083
|
// coalesce):
|
|
1037
1084
|
const deriving = query(Rollup).rule((r) => {
|
|
1038
|
-
const
|
|
1085
|
+
const person = r.var("person")
|
|
1086
|
+
const span = r.var("span")
|
|
1039
1087
|
return r.match(Claim, { person, span, arm: "Busy" }).select("person", r.pack("span"))
|
|
1040
1088
|
})
|
|
1041
1089
|
```
|
|
@@ -1069,14 +1117,16 @@ const Payments = schema("Payments", { Kind, Payment, Card, Ach }, [
|
|
|
1069
1117
|
// provably disjoint, so the executor elides cross-rule dedup — the free lunch.
|
|
1070
1118
|
const wholeDu = query(Payments)
|
|
1071
1119
|
.rule((r) => {
|
|
1072
|
-
const
|
|
1120
|
+
const id = r.var("id")
|
|
1121
|
+
const n = r.var("n")
|
|
1073
1122
|
return r
|
|
1074
1123
|
.match(Payment, { id, kind: "Card" })
|
|
1075
1124
|
.match(Card, { payment: id, last4: n })
|
|
1076
1125
|
.select("id", "n")
|
|
1077
1126
|
})
|
|
1078
1127
|
.rule((r) => {
|
|
1079
|
-
const
|
|
1128
|
+
const id = r.var("id")
|
|
1129
|
+
const n = r.var("n")
|
|
1080
1130
|
return r
|
|
1081
1131
|
.match(Payment, { id, kind: "Ach" })
|
|
1082
1132
|
.match(Ach, { payment: id, routing: n })
|
|
@@ -1148,7 +1198,7 @@ const Closure = schema("Closure", { Node, Parent }, [
|
|
|
1148
1198
|
|
|
1149
1199
|
// The loop's one query — the frontier's children, one ∈-set probe:
|
|
1150
1200
|
const step = query(Closure).rule((r) => {
|
|
1151
|
-
const
|
|
1201
|
+
const c = r.var("c")
|
|
1152
1202
|
return r.match(Parent, { child: c, parent: r.inSet("frontier") }).select("c")
|
|
1153
1203
|
})
|
|
1154
1204
|
```
|
|
@@ -1192,21 +1242,22 @@ const reach = program(Closure, (p) => {
|
|
|
1192
1242
|
const rec = p.rec("reach")
|
|
1193
1243
|
const seeded = rec
|
|
1194
1244
|
.rule((r) => {
|
|
1195
|
-
const
|
|
1245
|
+
const c = r.var("c")
|
|
1196
1246
|
return r
|
|
1197
1247
|
.match(Node, { id: c })
|
|
1198
1248
|
.where(eq(c, r.param("root")))
|
|
1199
1249
|
.select("c")
|
|
1200
1250
|
})
|
|
1201
1251
|
.rule((r) => {
|
|
1202
|
-
const
|
|
1252
|
+
const c = r.var("c")
|
|
1253
|
+
const parent = r.var("parent")
|
|
1203
1254
|
return r
|
|
1204
1255
|
.match(Parent, { child: c, parent })
|
|
1205
1256
|
.idb(rec, parent)
|
|
1206
1257
|
.select("c")
|
|
1207
1258
|
})
|
|
1208
1259
|
return p.output((r) => {
|
|
1209
|
-
const
|
|
1260
|
+
const c = r.var("c")
|
|
1210
1261
|
return r.match(Node, { id: c }).idb(seeded, c).select("c")
|
|
1211
1262
|
})
|
|
1212
1263
|
})
|
|
@@ -1249,13 +1300,14 @@ const Accounts = schema("Accounts", { Account, AccountParent, Posting }, [
|
|
|
1249
1300
|
// The two queries the host rollup composes:
|
|
1250
1301
|
// the frontier step (recipe 24's loop, verbatim):
|
|
1251
1302
|
const frontierStep = query(Accounts).rule((r) => {
|
|
1252
|
-
const
|
|
1303
|
+
const c = r.var("c")
|
|
1253
1304
|
return r.match(AccountParent, { child: c, parent: r.inSet("frontier") }).select("c")
|
|
1254
1305
|
})
|
|
1255
1306
|
// the rollup over the accumulated subtree (bind the fresh id — recipe
|
|
1256
1307
|
// 19's discipline, spent again; equal postings to one account both count):
|
|
1257
1308
|
const subtreeRollup = query(Accounts).rule((r) => {
|
|
1258
|
-
const
|
|
1309
|
+
const id = r.var("id")
|
|
1310
|
+
const minor = r.var("minor")
|
|
1259
1311
|
return r.match(Posting, { id, account: r.inSet("subtree"), minor }).select(r.sum("minor"))
|
|
1260
1312
|
})
|
|
1261
1313
|
// The engine-native form: the closure stratum converges first, then the
|
|
@@ -1264,21 +1316,24 @@ const nativeRollup = program(Accounts, (p) => {
|
|
|
1264
1316
|
const sub = p.rec("sub")
|
|
1265
1317
|
const seeded = sub
|
|
1266
1318
|
.rule((r) => {
|
|
1267
|
-
const
|
|
1319
|
+
const a = r.var("a")
|
|
1268
1320
|
return r
|
|
1269
1321
|
.match(Account, { id: a })
|
|
1270
1322
|
.where(eq(a, r.param("root")))
|
|
1271
1323
|
.select("a")
|
|
1272
1324
|
})
|
|
1273
1325
|
.rule((r) => {
|
|
1274
|
-
const
|
|
1326
|
+
const a = r.var("a")
|
|
1327
|
+
const parent = r.var("parent")
|
|
1275
1328
|
return r
|
|
1276
1329
|
.match(AccountParent, { child: a, parent })
|
|
1277
1330
|
.idb(sub, parent)
|
|
1278
1331
|
.select("a")
|
|
1279
1332
|
})
|
|
1280
1333
|
return p.output((r) => {
|
|
1281
|
-
const
|
|
1334
|
+
const id = r.var("id")
|
|
1335
|
+
const a = r.var("a")
|
|
1336
|
+
const minor = r.var("minor")
|
|
1282
1337
|
return r
|
|
1283
1338
|
.match(Posting, { id, account: a, minor })
|
|
1284
1339
|
.idb(seeded, a)
|
|
@@ -1348,7 +1403,9 @@ const MaintainedRollup = schema("MaintainedRollup", { Arm, Claim, BusySpan }, [
|
|
|
1348
1403
|
|
|
1349
1404
|
// Derive the desired rollup on the maintenance snapshot:
|
|
1350
1405
|
const deriving = query(MaintainedRollup).rule((r) => {
|
|
1351
|
-
const
|
|
1406
|
+
const source = r.var("source")
|
|
1407
|
+
const person = r.var("person")
|
|
1408
|
+
const span = r.var("span")
|
|
1352
1409
|
return r.match(Claim, { source, person, arm: "Busy", span }).select("person", r.pack("span"))
|
|
1353
1410
|
})
|
|
1354
1411
|
```
|
|
@@ -1402,7 +1459,10 @@ const Payroll = schema("Payroll", { Employee, Salary }, [
|
|
|
1402
1459
|
|
|
1403
1460
|
// The post-migration read — salaries in force at an instant:
|
|
1404
1461
|
const inForceAt = query(Payroll).rule((r) => {
|
|
1405
|
-
const
|
|
1462
|
+
const e = r.var("e")
|
|
1463
|
+
const name = r.var("name")
|
|
1464
|
+
const amount = r.var("amount")
|
|
1465
|
+
const w = r.var("w")
|
|
1406
1466
|
return r
|
|
1407
1467
|
.match(Employee, { id: e, name })
|
|
1408
1468
|
.match(Salary, { employee: e, amount, applies: w })
|
|
@@ -1468,3 +1528,77 @@ unit slots `[4,5)`, `[5,6)` satisfies both directions, because nothing forces
|
|
|
1468
1528
|
the witness rows to mirror the sidecar's segmentation — only its points. If
|
|
1469
1529
|
per-row correspondence matters, the host writes zones at slot granularity;
|
|
1470
1530
|
the schema proves disjointness and coverage either way.
|
|
1531
|
+
|
|
1532
|
+
## Point reads
|
|
1533
|
+
|
|
1534
|
+
## 30. The keyed read
|
|
1535
|
+
|
|
1536
|
+
Guarantee: validator/runtime premises — a declared key FD admits at most one
|
|
1537
|
+
fact per determinant tuple (the key phase of the commit judgment), and every
|
|
1538
|
+
keyed point read answers exactly that fact or nothing, on every scope
|
|
1539
|
+
(`ts/test/keyed-get.test.ts`; the engine half is
|
|
1540
|
+
`crates/bumbledb/tests/keyed_get.rs`).
|
|
1541
|
+
|
|
1542
|
+
The key is a **law**, and the read surface is that law made callable. The
|
|
1543
|
+
schema says `key(Program, ["grp"])` — one program per group — so "the
|
|
1544
|
+
program of a group" is a well-posed question with at most one answer, and
|
|
1545
|
+
the store already enforces that on every commit. Hold the statement VALUE:
|
|
1546
|
+
it is the read's selector below (statement identity is the membership rule).
|
|
1547
|
+
|
|
1548
|
+
```ts
|
|
1549
|
+
const Grp = relation("Grp", { id: u64.fresh, label: str })
|
|
1550
|
+
const Program = relation("Program", { id: u64.fresh, grp: u64, title: str })
|
|
1551
|
+
// The law: one program per group — the callable key.
|
|
1552
|
+
const programGrpKey = key(Program, ["grp"])
|
|
1553
|
+
|
|
1554
|
+
const KeyedRead = schema("KeyedRead", { Grp, Program }, [
|
|
1555
|
+
contained(on(Program, "grp"), on(Grp, "id")),
|
|
1556
|
+
programGrpKey
|
|
1557
|
+
])
|
|
1558
|
+
```
|
|
1559
|
+
|
|
1560
|
+
The point read is the statement handed back to `get` — one spelling on
|
|
1561
|
+
every scope (the symmetry rule): `db.get` standalone, `snap.get` inside a
|
|
1562
|
+
read scope, `tx.get` inside a write transaction, where the transaction side
|
|
1563
|
+
answers the FINAL state (base plus pending delta: read-your-writes, a
|
|
1564
|
+
pending delete answers `undefined`). The key object is typed by the
|
|
1565
|
+
statement's own projection — a wrong field name is a compile error, never a
|
|
1566
|
+
runtime shape check. The primary 2-arg form needs no statement: the fresh
|
|
1567
|
+
field IS the primary key.
|
|
1568
|
+
|
|
1569
|
+
```ts
|
|
1570
|
+
const db = await Db.create("./programs.db", KeyedRead)
|
|
1571
|
+
|
|
1572
|
+
const minted: { grp?: bigint } = {}
|
|
1573
|
+
db.write((tx) => {
|
|
1574
|
+
const g = tx.insert(Grp, { label: "algebra" })
|
|
1575
|
+
tx.insert(Program, { grp: g.id, title: "linear equations" })
|
|
1576
|
+
minted.grp = g.id
|
|
1577
|
+
})
|
|
1578
|
+
const grp = minted.grp ?? 0n
|
|
1579
|
+
|
|
1580
|
+
// db.get — the standalone keyed read through the declared law:
|
|
1581
|
+
const byGroup = db.get(Program, programGrpKey, { grp })
|
|
1582
|
+
|
|
1583
|
+
// snap.get — the same spelling inside a read scope:
|
|
1584
|
+
const viaSnap = db.read((snap) => snap.get(Program, programGrpKey, { grp }))
|
|
1585
|
+
|
|
1586
|
+
// tx.get — key-shaped read-modify-write, final-state (recipe 20's third
|
|
1587
|
+
// idiom): per-fact premises need no earlier snapshot witness.
|
|
1588
|
+
db.write((tx) => {
|
|
1589
|
+
const current = tx.get(Program, programGrpKey, { grp })
|
|
1590
|
+
if (current !== undefined) {
|
|
1591
|
+
tx.delete(Program, current)
|
|
1592
|
+
tx.insert(Program, { id: current.id, grp: current.grp, title: "linear equations II" })
|
|
1593
|
+
}
|
|
1594
|
+
})
|
|
1595
|
+
|
|
1596
|
+
// The primary 2-arg form — the fresh field is the primary key:
|
|
1597
|
+
const byId = byGroup === undefined ? undefined : db.get(Program, { id: byGroup.id })
|
|
1598
|
+
```
|
|
1599
|
+
|
|
1600
|
+
The anti-pattern this recipe retires: a scan-and-find where a key law
|
|
1601
|
+
exists — `snap.scan(Program).find((row) => row.grp === grp)` — re-derives
|
|
1602
|
+
in the host what the store already enforces. The uniqueness the fold
|
|
1603
|
+
quietly assumes IS the declared key statement; spell the law and the point
|
|
1604
|
+
read comes with it.
|
package/README.md
CHANGED
|
@@ -79,7 +79,9 @@ if (!result.ok) {
|
|
|
79
79
|
// first binding; params are typed by use; rows are typed from the select.
|
|
80
80
|
// `gt` is one of the free comparison exports.
|
|
81
81
|
const certifiedAbove = query(Review).rule((r) => {
|
|
82
|
-
const
|
|
82
|
+
const a = r.var("a")
|
|
83
|
+
const k = r.var("k")
|
|
84
|
+
const rank = r.var("rank")
|
|
83
85
|
return r
|
|
84
86
|
.match(Certificate, { attempt: a, kind: k })
|
|
85
87
|
.match(Kind, { id: k, mastered: true, rank }) // ψ on the read side too
|
|
@@ -118,7 +120,7 @@ The drizzle law governs this surface: the SDK's job at the host boundary is tran
|
|
|
118
120
|
- The structural type kernel — fields as pure structure (`bool`, `bytes`, `i64`, `u64`, `str`, `interval`, `span`), `relation()`, and `closed()` sealed rosters with typed axiom payloads. A closed reference's value type IS the handle union (`Infer` speaks it); dispatch is native `switch` narrowing with `satisfies never` exhaustiveness. Domains are never declared: `schema()` computes every field's class from the statement list.
|
|
119
121
|
- The statement algebra — `schema()`, `key`, `contained`, `mirrors`, `window`; faces via `on` (set membership is a plain array in `.where`); counts via `exactly`, `atLeast`, `atMost`, `between`, `none`; ψ-selection via `.where` on relations and closed rosters.
|
|
120
122
|
- The `Db` runtime — `Db.create`/`Db.open`, path-cached stores, transactions, typed violations, scoped snapshot reads, the witnessed write loop with `abandon`.
|
|
121
|
-
- The query surface — Datalog as values, `query(S).rule(r => ...)`: named vars, params typed by use, negation, aggregates, and the free comparison/connective exports (`eq`, `ne`, `lt`, `le`, `gt`, `ge`, `and`, `or`, `not`, `allen`/`ALLEN`, `pointIn
|
|
123
|
+
- The query surface — Datalog as values, `query(S).rule(r => ...)`: named vars, params typed by use, negation, aggregates, and the free comparison/connective exports (`eq`, `ne`, `lt`, `le`, `gt`, `ge`, `and`, `or`, `not`, `allen`/`ALLEN`, `pointIn`); set membership at a closed field is a plain array in the match record (`r.match(Ticket, { priority: ["Normal", "Urgent"] })` — closed-only there: an ordinary field's membership is a bound `r.inSet` param); stratified recursion via `program()`; `db.prepare` as a plain value.
|
|
122
124
|
- The exhume surface — `Db.exhume`, the schema-independent read path: a store's self-described shapes and raw facts by name, with typed refusals (`ErrExhumeNoDescriptor`, `ErrExhumeFormatMismatch`, `ErrExhumeCorruption`).
|
|
123
125
|
|
|
124
126
|
## Cookbook
|
package/dist/closed.d.ts
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
* shape.
|
|
31
31
|
*/
|
|
32
32
|
import { type AnyField, type ClosedIdField, type Infer } from "#fields.ts";
|
|
33
|
+
import type { AnyRelation, RelationField } from "#relation.ts";
|
|
33
34
|
import { type SelectionBinding, type SelectionInput } from "#relation.ts";
|
|
34
35
|
import type { LiteralSpec } from "#spec.ts";
|
|
35
36
|
/**
|
|
@@ -44,7 +45,7 @@ type PayloadField = Exclude<AnyField, {
|
|
|
44
45
|
* unspellable — the sealed shape mints the synthetic `id` itself (ordinal
|
|
45
46
|
* 0 of the matchable fields), so a declared column named `id` would be
|
|
46
47
|
* shadowed by the synthetic slot everywhere the shape resolves by name
|
|
47
|
-
* (`
|
|
48
|
+
* (`sealedFieldsOf`, the projected face, `spec.rs`'s resolver). The wall is
|
|
48
49
|
* typed here and judged again at construction in {@link mintClosed} — the
|
|
49
50
|
* runtime twin for untyped callers, warmer and earlier than the engine's
|
|
50
51
|
* `DuplicateFieldName` at `Db.create`.
|
|
@@ -173,6 +174,33 @@ interface AnyClosed {
|
|
|
173
174
|
readonly axioms: Readonly<Record<string, object>>;
|
|
174
175
|
readonly columns: Readonly<Record<string, PayloadField>>;
|
|
175
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* THE relation-kind discriminant — the ONE spelling of "is this schema
|
|
179
|
+
* member closed?" (the type tier's twin is the `AnyClosed` conditional
|
|
180
|
+
* arms). A closed relation's runtime description carries its handle
|
|
181
|
+
* roster; an ordinary relation's never does. Every runtime closed/ordinary
|
|
182
|
+
* fork in the SDK judges through this predicate — never a re-spelled
|
|
183
|
+
* structural probe.
|
|
184
|
+
*/
|
|
185
|
+
declare function isClosedMember(member: AnyRelation | AnyClosed): member is AnyClosed;
|
|
186
|
+
/**
|
|
187
|
+
* The SEALED field list of a schema member — THE one reader of "what
|
|
188
|
+
* fields does this owner expose": an ordinary relation's declared fields;
|
|
189
|
+
* a closed relation's sealed shape — the synthetic `id` (the value's own
|
|
190
|
+
* roster-carrying descriptor, by identity) at ordinal 0, then the declared
|
|
191
|
+
* payload columns at declared index + 1 (the sealed shift, mirroring the
|
|
192
|
+
* engine's `SchemaDescriptor::sealed_fields`). A `ClosedColumn` is
|
|
193
|
+
* structurally a `RelationField`, so both kinds read uniformly.
|
|
194
|
+
*/
|
|
195
|
+
declare function sealedFieldsOf(member: AnyRelation | AnyClosed): readonly RelationField[];
|
|
196
|
+
/**
|
|
197
|
+
* One sealed field by name — derived from {@link sealedFieldsOf}, so the
|
|
198
|
+
* closed synthetic `id` resolves everywhere a name is looked up (no reader
|
|
199
|
+
* can silently lack the `id` arm). `undefined` when the name is foreign
|
|
200
|
+
* (the type tiers make that unwritable; the engine re-judges at
|
|
201
|
+
* `Db.create`).
|
|
202
|
+
*/
|
|
203
|
+
declare function sealedFieldOf(member: AnyRelation | AnyClosed, fieldName: string): AnyField | undefined;
|
|
176
204
|
/** Bare tier: `closed("Kind", ["Checking", "Savings"])` — handles only. */
|
|
177
205
|
declare function closed<const Name extends string, const Handles extends readonly [string, ...string[]]>(name: Name, handles: Handles): Closed<Name, Handles[number], Record<never, never>>;
|
|
178
206
|
/**
|
|
@@ -189,5 +217,5 @@ declare function closed<const Name extends string, const Handles extends readonl
|
|
|
189
217
|
*/
|
|
190
218
|
declare function closed<const Name extends string, const Cols extends PayloadColumns, Handles extends string>(name: Name, columns: Cols, axioms: Axioms<Handles, Cols>): Closed<Name, Handles, Cols>;
|
|
191
219
|
export type { AnyClosed, AnySelectedClosed, AxiomRow, Axioms, Closed, ClosedColumn, ClosedCore, ClosedData, ClosedRow, ClosedSelectable, ClosedSelectionInput, PayloadField, SelectedClosed };
|
|
192
|
-
export { closed };
|
|
220
|
+
export { closed, isClosedMember, sealedFieldOf, sealedFieldsOf };
|
|
193
221
|
//# sourceMappingURL=closed.d.ts.map
|
package/dist/closed.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"closed.d.ts","sourceRoot":"","sources":["../src/closed.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"closed.d.ts","sourceRoot":"","sources":["../src/closed.ts"],"names":[],"mappings":"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"}
|