-
Notifications
You must be signed in to change notification settings - Fork 2
Om Next Remotes
CONTAIN INCORRECT OR MISLEADING INFORMATION. THIS DOCUMENT IS BASED ON OM-1.0-ALPHA.**
This is a continuation of the Om Next Overview, concentrating on how remote interactions work.
You must understand all of the stuff discussed in the query and mutation parts of the overview. Reading the overview docs of Relay is also recommended.
Om Next gives a homogenous picture for both the server and client-side. Everything you leared about parsing and mutation is identical when it comes to the server-side story: Query fragments can be sent to the server to be satisfied instead of grabbing the data in app-local state. Thus, you client-side picture is really more like this (loving the ASCII graphics):
app-local state
+-------------------+ +----------------------+
| UI-related data | | |
| | | Parsing, reading, |
| |<-------- network comms ------>| mutation |
| Data (cached) | (query and results) | |
| from a server | | |
+-------------------+ +----------------------+
So the first thing to realize is that you can use the same skills you acquired on the client side to write the query and mutation handling on the server. If you're lucky enough to have a Datomic back-end then passing query fragments straight to your database is trivial (adding in security, of course).
This should start to clear up what you are doing with mutations as well. If a mutation goes to the server, and includes (follow-up) reads, then the server can fufill all of those requests in a single round-trip.
A mutation on the client indicates remote interaction via something similar (WARNING API CHANGING):
(defmethod mutate 'change-something
[{:keys [state ref]} _ new-props]
{:serverA true
:action ;; OPTIMISTIC UPDATE
(fn []
...immediate local app-state changed...
})
where the mutation does two things: immediate application of state change, and queues up the remote.
Remember that your API call to the mutate also includes remotes. This allows the network request to include the reads necessary to make sure the final app state cache is up-to-date.
WARNING: API IN FLUX. TREAT AS CONCEPTUAL!!!!
Using a remote is as simple as adding more keys to the response of your client read:
(defn read :datakey [e k p] {
:value current-cached-result-data
:serverA query-fragment
:serverB query-fragment
... })
The parser is actually run once for local rendering, and then once for each remote. The code above returns the same value for all calls (local parse ignores remote keywords, and remote parse ignores values). Once the sends have been gathered from these parser runs Om will forward the specified query fragments to your communication code.
Communication is up to you. The hook upgive a map to the reconciler when you create it that names the various remotes as keys, and provides a function to be called to handle the communication.
(def reconciler
(om/reconciler
{:state app-state
:parser my-parser
:send (fn [remote-query-map merge-callback] ...)
:remotes [:serverA :serverB]
}))
This tells Om the abstract names of your remotes (:serverA and :serverB), and your supplied send function takes two arguments: A remote query map (keyed by abstract remote name, value is the query to send) and a merge-callback.
You send the queries off to the respective server, and as each response arrives you can pass the result into the merge-callback.
Note that the default merge algorithm is rather naive. You may need to supply the reconciler with :merge-tree
and possibly merge-refs
, migrate
, and id-key
.