Liking cljdoc? Tell your friends :D

sg.flybot.pullable.collection

CRUD collection abstraction — wraps any data source in a uniform interface.

Implement the DataSource protocol for your storage layer (database, API, etc.), then wrap it with collection to get ILookup, Seqable, Counted, Mutable, and Wireable. One DataSource, one Collection, then compose behavior with wrappers:

  • read-only — disables mutations, delegates reads
  • wrap-mutable — custom mutation logic (auth, ownership), delegates reads
  • validated — Malli validation of mutation input, delegates reads
  • lookup — non-enumerable keyword->value ILookup with lazy delay support

Basic Usage

;; 1. Implement DataSource for your storage
(defrecord MySource [conn]
  DataSource
  (fetch [_ query] ...)
  (list-all [_] ...)
  (create! [_ data] ...)
  (update! [_ query data] ...)
  (delete! [_ query] ...))

;; 2. Wrap in a Collection
(def posts (collection (->MySource conn) {:id-key :post/id}))

;; 3. Use standard Clojure verbs
(get posts {:post/id 3})           ; fetch by query (ILookup)
(seq posts)                        ; list all (Seqable)
(mutate! posts nil {:title "New"}) ; create
(mutate! posts {:post/id 3} data)  ; update
(mutate! posts {:post/id 3} nil)   ; delete

;; 4. Compose wrappers for different access levels
(def public     (read-only posts))
(def restricted (wrap-mutable posts auth-fn))

For in-memory use, atom-source provides a built-in DataSource with auto-incrementing IDs and transactional batch mutations via transact! / snapshot.

CRUD collection abstraction — wraps any data source in a uniform interface.

Implement the DataSource protocol for your storage layer (database, API, etc.),
then wrap it with `collection` to get ILookup, Seqable, Counted, Mutable, and
Wireable. One DataSource, one Collection, then compose behavior with wrappers:

- `read-only`     — disables mutations, delegates reads
- `wrap-mutable`  — custom mutation logic (auth, ownership), delegates reads
- `validated`     — Malli validation of mutation input, delegates reads
- `lookup`        — non-enumerable keyword->value ILookup with lazy delay support

## Basic Usage

```clojure
;; 1. Implement DataSource for your storage
(defrecord MySource [conn]
  DataSource
  (fetch [_ query] ...)
  (list-all [_] ...)
  (create! [_ data] ...)
  (update! [_ query data] ...)
  (delete! [_ query] ...))

;; 2. Wrap in a Collection
(def posts (collection (->MySource conn) {:id-key :post/id}))

;; 3. Use standard Clojure verbs
(get posts {:post/id 3})           ; fetch by query (ILookup)
(seq posts)                        ; list all (Seqable)
(mutate! posts nil {:title "New"}) ; create
(mutate! posts {:post/id 3} data)  ; update
(mutate! posts {:post/id 3} nil)   ; delete

;; 4. Compose wrappers for different access levels
(def public     (read-only posts))
(def restricted (wrap-mutable posts auth-fn))
```

For in-memory use, `atom-source` provides a built-in DataSource
with auto-incrementing IDs and transactional batch mutations via
`transact!` / `snapshot`.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close