Skip to content

Instantly share code, notes, and snippets.

@aaronc
Last active August 29, 2015 14:11
Show Gist options
  • Save aaronc/0654151190b9145dd473 to your computer and use it in GitHub Desktop.
Save aaronc/0654151190b9145dd473 to your computer and use it in GitHub Desktop.
freactive observable collections

Two data types - observable-map and observable-vector - will be provided that implement an IObservableCollection protocol. observable-maps's and observable-vector's will basically wrap an atom (or atom-like structure such as a cursor) with operations that allow it to be updated in an "observable" way.

The IObservableCollection protocol will be the minimum necessary functionality required to bind a collection to an items-view. It will be completely orthogonal to the other functionality provided by observable-map's and observable-vector's so that database collections, etc. can also implement IObservableCollection and be bound to items-view's without necessarily supporting operations of observable-map's and observable-vector's such as assoc! and conj!.

;; observable-map's can be created with initial data
(observable-map {:a 1 :b 2})
;; or by passing in an atom (or an IAtom structure like a cursor)
(def my-data (atom {:some-map {:a 1 :b 2} :some-vector [1 2 3]}))
(def some-map (observable-map (cursor my-data :some-map)))
;; observable-map's would support the ITransientMap operations
(assoc! some-map :c 3)
(dissoc! some-map :a)
;; as well as the update! function which works like
;; (swap! my-atom update-in path f ...)
(update! some-map :c inc)

;; observable-vector's could be created similarly:
(observable-vector [1 2 3])
;; or
(def some-vector (observable-vector (cursor my-data :some-vector)))
;; and would have the same operations as ITransientVector
(conj! some-vector 4)
(assoc! some-vector 0 0)
(pop! some-vector)
;; as well as supporting update!
(update! some-vector 0 inc)

;; all assoc!, conj!, dissoc! and pop! operations will automatically
;; be contained within a transaction, but they can be batched using with-tx
(with-tx some-coll
  (assoc! some-coll :d 4)
  (assoc! some-coll :b -2))

Both observable-map's and observable-vector's will support the IObservableCollection protocol:

(defprotocol IObservableCollection
  "Defines the minimum protocol required for an observable collection
  to be bound to an items-view"
  (get-cursor [coll key-or-index]
    "Gets a cursor for the element in the collection at the provided
    key-or-index. A cursor to an item behaves like a reactive atom - it
    will implement deref, swap!, add-watch, remove-watch.")
  (get-keys [coll]
    "Returns a sequence (possibly lazy) of keys curently in the collection
    that can be passed as arguments to get-cursor to get a cursor to the
    actual item.")
  (add-collection-watch [coll key f]
    "Adds a collection watch to the observable collection. f is a function
    taking 4 arguments: the key, the collection, the sequence of keys or
    indices that were removed, the sequence of keys or indices that were removed.")
  (remove-collection-watch [coll key]))

Item cursors should also implement an IItemCursor protocol which will have a single function get-key that returns the key or index of the cursor in the collection (that could be used as an argument to get-cursor):

(defprotocol IItemCursor
  (get-key [cursor}))

observable-map's and observable-vector's will also implement an additional protocol ITransactableCollection which may be useful for things like logging transactions but not necessary for binding to an items-view:

(defprotocol ITransactableCollection
  (add-tx-watch [coll key f]
    "Where f is a functional taking 3 arguments:
      the key, the collection, a sequence of changes in the form of:
        [[key1 new-value1]
         [key2 new-value2]
         [key3] ;; missing new value indicates the element was removed
         ]
    Subject to change")
  (remove-tx-watch [coll key))
@aaronc
Copy link
Author

aaronc commented Dec 18, 2014

PLEASE post comments here: aaronc/freactive#23

Gist does not support notifications on comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment