persist: projections — fold stream into read model, incremental resume + 9 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m9s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m9s
project.sx: projection state {:value :seq}; persist/project folds the whole
stream, persist/project-resume folds only the tail so read models update
incrementally. Pure step (value event)->value. 37/37.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
30
lib/persist/project.sx
Normal file
30
lib/persist/project.sx
Normal file
@@ -0,0 +1,30 @@
|
||||
; persist/project — a projection folds a stream's events into a read model.
|
||||
; A projection state is {:value v :seq s} where s is the last seq folded in,
|
||||
; so a projection can resume incrementally from where it left off (replay only
|
||||
; the tail). step : (value event) -> value. Determinism: step must be pure —
|
||||
; time lives on the event (event-at), never a clock here.
|
||||
; Requires: lib/persist/event.sx, lib/persist/log.sx.
|
||||
|
||||
; fold the tail (events with seq > prior's seq) onto a prior projection state
|
||||
(define
|
||||
persist/project-resume
|
||||
(fn
|
||||
(b stream step prior)
|
||||
(let
|
||||
((tail (persist/read-from b stream (+ 1 (get prior :seq)))))
|
||||
(reduce (fn (acc e) {:value (step (get acc :value) e) :seq (persist/event-seq e)}) prior tail))))
|
||||
|
||||
; project the whole stream from seed
|
||||
(define
|
||||
persist/project
|
||||
(fn (b stream step seed) (persist/project-resume b stream step {:value seed :seq 0})))
|
||||
|
||||
(define persist/project-value (fn (p) (get p :value)))
|
||||
(define persist/project-seq (fn (p) (get p :seq)))
|
||||
|
||||
; convenience: project and return just the value
|
||||
(define
|
||||
persist/project-fold
|
||||
(fn
|
||||
(b stream step seed)
|
||||
(persist/project-value (persist/project b stream step seed))))
|
||||
Reference in New Issue
Block a user