Skip to content

Instantly share code, notes, and snippets.

@bbktsk
Created June 17, 2017 20:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bbktsk/ba527eca247c5dd5cc24321e71912af0 to your computer and use it in GitHub Desktop.
Save bbktsk/ba527eca247c5dd5cc24321e71912af0 to your computer and use it in GitHub Desktop.
(ns wmcng.fake
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [clojure.string :as str]
[om.dom :as dom]
[om.next :as om :refer-macros [defui]]
[untangled.client.core :as uc]
[untangled.client.data-fetch :as df]
[untangled.client.logging :as log]
[untangled.client.mutations :refer [defmutation]]
[untangled.client.network :as net]))
(defui ^:once Person
static uc/InitialAppState
(initial-state [this props]
props)
static om/IQuery
(query [this] [::id ::name ::age])
static om/Ident
(ident [this props] [::person-by-id (::id props)])
Object
(render [this]
(let [{:keys [::id ::name ::age]} (om/props this)]
(dom/li nil (str id ": " name ", age " (or age "not loaded yet"))))))
(def person (om/factory Person {:keyfn ::id}))
(defui ^:once People
static uc/InitialAppState
(initial-state [this props]
{::people []})
static om/IQuery
(query [this] [{[::people '_] (om/get-query Person)}])
static om/Ident
(ident [this props] [::people :root])
Object
(render [this]
(let [{:keys [::people]} (om/props this)]
(dom/div nil
(if (seq people)
(dom/ul nil (map person people))
(dom/p nil "No people loaded"))
(dom/div nil "Press inital load first, then one of load ages.")
(dom/button #js {:onClick #(om/transact! this `[(initial-load)])} "Initial load")
(dom/button #js {:onClick #(om/transact! this `[(load-ages-good-api)])} "Load ages")))))
(defmutation initial-load
"Initial load of data. Since the corresponding API endpoint does not return ::age, remove it from the query."
[params]
(action [{:keys [state] :as env}]
(df/load-action state ::people Person {:remote :remote
:without #{::age}}))
(remote [{:keys [state] :as env}]
(df/remote-load env)))
(defmutation load-ages-good-api
"Follow-up load of ::age for all Persons. This API endpoint returns only ::id and ::age, so remove ::name from the query."
[params]
(action [{:keys [state] :as env}]
(df/load-action state ::people Person {:remote :remote
:without #{::name}}))
(remote [{:keys [state] :as env}]
(df/remote-load env)))
(defrecord FakeRestRemote [url request-transform global-error-callback complete-app transit-handlers]
net/NetworkBehavior
(serialize-requests? [this] true)
net/UntangledNetwork
(send [this edn ok-fn error-fn]
(let [ast (om/query->ast edn)
;; determine if the query is the initial load (does not contain ::age)
age-requested? (some #(= ::age %) (map :key (get-in ast [:children 0 :children])))
;; Here I simulate two different API endpoints. First one returns initial data,
;; other one adds ::age to the initial data.
;; For the second one, there are two versions: the active one is "how things should look like",
;; the other one, commented-out is "how things look like for me now".
;; Note that this is quite simplified, but the core of the issue is this:
;; the first endpoint returns items identified with ::id, which is used as an ident.
;; the second endpoint returns extra data that need to be added to items we got from the first one,
;; but identifies items by ::name instead of ::id.
;; If I had access to app database, converting from the commented-out response to the "good one"
;; is easy.
;; Using ::name as an ident is not a good solution, in the real app there's need for ::id as ident.
result (if-not age-requested?
;; This is faked result of the rest api call for the initial load.
;; Note that ::age is missing
{::people [{::id 1 ::name "Adam"}
{::id 2 ::name "Ben"}]}
;; This is how a good API should respond to request for ::age
{::people [{::id 1 ::age 11}
{::id 2 ::age 22}]}
;; However, the API I have to use returns map keyed by ::name
;; {::people [{::name "Adam" ::age 11}
;; {::name "Ben" ::age 22}]}
)]
(ok-fn result)))
(start [this app]))
(defonce app (atom (uc/new-untangled-client :networking (map->FakeRestRemote {}))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment