(the Android client support has not been looked at yet)
Efforts have not been made to maintain backwards compatibility with v2 init and auth functions, as these changed dramatically on the upstream side with the switch to Google ownership and have new requirement for use. However, all the regular data access and mutation functions should work as before.
This is currently working in production with some hacks.
See matchbox.auth
for the hacked CLJS auth. The goal is to make this more idomatic to the rest of the library.
See matchbox.core/init!
for a fairly smooth isomorphic init.
[thosmos/matchbox "0.1.0-SNAPSHOT"]
[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.