; Phase 2 — projections: fold a stream into a read model, resume incrementally.

(persist-test
  "project empty stream returns seed value"
  (persist/project-fold
    (persist/open)
    "s"
    (fn (acc e) (+ acc 1))
    0)
  0)
(persist-test
  "project empty stream seq is 0"
  (persist/project-seq
    (persist/project (persist/open) "s" (fn (a e) a) 0))
  0)
(persist-test
  "project counts events"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (persist/project-fold
        b
        "s"
        (fn (acc e) (+ acc 1))
        0)))
  3)
(persist-test
  "project sums event data"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "ledger" "credit" 0 {:amt 10})
      (persist/append b "ledger" "credit" 1 {:amt 5})
      (persist/append b "ledger" "debit" 2 {:amt 3})
      (persist/project-fold
        b
        "ledger"
        (fn
          (bal e)
          (if
            (equal? (persist/event-type e) "credit")
            (+ bal (get (persist/event-data e) :amt))
            (- bal (get (persist/event-data e) :amt))))
        0)))
  12)
(persist-test
  "project tracks last seq"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (persist/project-seq (persist/project b "s" (fn (a e) a) 0))))
  2)
(persist-test
  "resume folds only the tail"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (let
        ((p1 (persist/project b "s" (fn (acc e) (+ acc 1)) 0)))
        (begin
          (persist/append b "s" "x" 0 {})
          (persist/project-value
            (persist/project-resume
              b
              "s"
              (fn (acc e) (+ acc 1))
              p1))))))
  3)
(persist-test
  "resume with no new events is a no-op"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (let
        ((p1 (persist/project b "s" (fn (acc e) (+ acc 1)) 0)))
        (persist/project-value
          (persist/project-resume b "s" (fn (acc e) (+ acc 1)) p1)))))
  1)
(persist-test
  "resume advances seq"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (let
        ((p1 (persist/project b "s" (fn (a e) a) 0)))
        (begin
          (persist/append b "s" "x" 0 {})
          (persist/append b "s" "x" 0 {})
          (persist/project-seq
            (persist/project-resume b "s" (fn (a e) a) p1))))))
  3)
(persist-test
  "full project equals seed-resume from zero"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (equal?
        (persist/project b "s" (fn (acc e) (+ acc 1)) 0)
        (persist/project-resume
          b
          "s"
          (fn (acc e) (+ acc 1))
          {:value 0 :seq 0}))))
  true)
