[matchbox "0.0.9"]
Matchbox offers more than just bindings:
- Atom/Zipper/Cursor-ish abstraction over Firebase references
- Clojure data in/out
- Uniform API for JVM and JS platforms
- Optional sequence abstraction - work with lists not sorted maps
- Optional core.async based API
- Multiplexed children event channels and/or callbacks
- Registry for listeners simplifies scoped or global cleanup
Quick spin to get some basic flavour:
(require '[matchbox.core :as m])
(def root (m/connect "https://<app>.firebaseio.com"))
(m/auth-anon root)
(m/listen-children
root [:users :mike :friends]
(fn [[event-type data]] (prn data)))
(def mikes-friends (m/get-in root [:users :mike :friends]))
(m/reset! mikes-friends [{:name "Kid A"} {:name "Kid B"}])
(m/conj! mikes-friends {:name "Jean"})
(m/deref
mikes-friends
(fn [key value]
(m/reset-in! root [:users :mike :num-friends]
(count value))))
(m/unauth)
Take a look at the quick intro to for a lightning tour.
For those who want to dive right in, reagent-figwheel has a +firebase
option bake some sensible Matchbox plumbing right into your next app.
For brevity, comparing to the JS Firebase API only.
Notes:
- Almost all functions accept callbacks, and those callbacks will be intercepted to receive hydrated data.
- This list is not complete, notably it does not cover connectivity control and hooks, queries, auth, logging and other aspects also wrapped by Matchbox.
Matchbox | Firebase.js | Differences |
---|---|---|
connect |
Firebase. |
Supports optional korks as second parameter |
get-in |
.child |
Supports symbols, keywords and sequences also (korks) |
parent |
.parent |
- |
deref |
.once |
Fixed to a "value" subscription |
deref-list |
.once |
Returns ordered values rather than a map. Query compatible. |
reset! |
.set |
Data automatically serialized in a sensible manner |
reset-with-priority! |
.setWithPriority |
.. |
merge! |
.update |
.. |
conj! |
.push |
.. |
swap! |
.transaction |
Always applied locally, supports additional arguments. |
dissoc! or remove! |
.remove |
- |
set-priority! |
.setPriority |
- |
listen-to |
.on |
Stored in registry for easy unsubscription |
listen-list |
.on |
Like deref-list for listen-to |
listen-children |
.on |
Listen to all child events, multiplexed. |
Additionally, there are up to three variations of most functions:
*-in
variants take an optional second parameter ofkorks
, to refer directly to a child. These exist for all "ending-with-a-bang" functions, as well asderef
andderef-list
.*<
variants return a channel of results instead of taking a callback. These exist for all functions that would take a callback.*-in<
combine decoration of (1) and (2), and exist where applicable.
The last two, if they exist are defined in matchbox.async
. This is so that
Matchbox can be used without a core.async
dependency.
-
There are ClojureScript demos for reagent and om in the
examples
directory.The demos can be launched by executing
boot dev
in theexamples
folder, and opening http://localhost:3000 in a browser. -
If you'd like to use
re-frame
, there is a realtime chat app showcase.
-
swap!
takes callback in non-standard waySince we support passing additional arguments to an update function, we can't use an optional argument for the callback.
Our solution draws inspiration from "kwargs" style signatures:
(eg. `(my-function :has "keyword" :style "arguments")`).
Coming back to
swap!
, we support:callback callback-fn
at end of arg list:(m/swap! r f) ;; call (f <val>), no callback (m/swap! r f b c) ;; call (f <val> b c), no callback (m/swap! r f :callback cb) ;; call (f <val>), with callback `cb` (m/swap! r f b c :callback cb) ;; call (f <val> b c), with callback `cb`
Note that
:callback
MUST appear as the second-last argument. -
JVM callbacks on side thread
Depending on your environment and config, callbacks may be triggered on another thread.
This can be confusing when debugging with
prn
in callbacks, as*out*
will not be to the REPL's writer. We providematchbox.utils/prn
as a simple helper to ensure output is visible. -
Serialization
Data | Storage | Reads back as it writes? |
---|---|---|
{} , nameable keys |
JSON | Not unless all keys are keywords (rest are coerced) |
{} , richer keys |
Not supported | N/A |
[] |
JSON with numeric keys | Yes |
#{} |
JSON with numeric keys | No, reads back as a vector |
"string" |
string | Yes |
:a/keyword |
":a/keyword" | Yes |
Number | Number | Pretty much, with nits for java.math.* types |
Record | JSON | No, reads back as vanilla map |
(def)Type | JSON | No, reads back as vanilla map |
Other | Depends on platform | Expect useless strings (JS) or serious downcasting (JVM) |
See more info here
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.