; persist/kv — the kv facet: current-state values, no history. For things
; whose history does NOT matter (stock counts, config, profiles, session
; blobs) and where projections materialize their read models.
; Requires: lib/persist/backend.sx.

(define persist/kv-get (fn (b key) (persist/backend-kv-get b key)))
(define
  persist/kv-put
  (fn (b key val) (begin (persist/backend-kv-put b key val) val)))
(define persist/kv-delete (fn (b key) (persist/backend-kv-delete b key)))
(define persist/kv-has? (fn (b key) (persist/backend-kv-has? b key)))
(define persist/kv-keys (fn (b) (persist/backend-kv-keys b)))

; get with a default when the key is absent
(define
  persist/kv-get-or
  (fn
    (b key dflt)
    (if (persist/kv-has? b key) (persist/kv-get b key) dflt)))

; read-modify-write: apply f to the current value (or dflt if absent), store result
(define
  persist/kv-update
  (fn
    (b key dflt f)
    (persist/kv-put b key (f (persist/kv-get-or b key dflt)))))

; compare-and-swap: set key to new ONLY if its current value equals expected.
; Returns new on success, or a conflict value {:conflict true :expected :actual}
; the caller can re-read and retry on. The kv analogue of log append-expect.
(define
  persist/kv-cas
  (fn
    (b key expected new)
    (let
      ((actual (persist/kv-get b key)))
      (if (equal? actual expected) (persist/kv-put b key new) {:actual actual :expected expected :conflict true}))))

; create-only: put a value only if the key is absent; conflict if it exists
(define
  persist/kv-put-new
  (fn
    (b key val)
    (if (persist/kv-has? b key) {:actual (persist/kv-get b key) :conflict true :reason "exists"} (persist/kv-put b key val))))
