Created
June 17, 2017 20:24
-
-
Save bbktsk/ba527eca247c5dd5cc24321e71912af0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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