-
-
Save IwanKaramazow/260e1f1c25bd0d4bc8a9eb7f910b8fa2 to your computer and use it in GitHub Desktop.
Query Diffing!
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 listdetail.core | |
(:require [goog.dom :as gdom] | |
[om.next :as om :refer-macros [defui]] | |
[om.dom :as dom])) | |
(enable-console-print!) | |
(def app-state {:projects [{:id 1 :title "Learn Haskell"} {:id 2 :title "Learn Scheme"}]}) | |
;; parser | |
(defmulti read om/dispatch) | |
(defmethod read :projects | |
[{:keys [state query]} key _] | |
(let [st @state] | |
{:value (om/db->tree query (get st key) st)})) | |
(defmethod read :project/detail | |
[{:keys [ast state query]} key {:keys [id]}] | |
(when id | |
(let [st @state | |
val (om/db->tree query [:project/by-id id] st) | |
available (keys val) | |
diffed-query (-> | |
(into [] (clojure.set/difference (set query) (set available))) | |
(conj :id))] | |
(if (= available query) | |
{:value val} | |
{:value val | |
:remote (assoc ast :query diffed-query)})))) | |
;; components | |
(defui ProjectListItem | |
static om/Ident | |
(ident [this {:keys [id]}] | |
[:project/by-id id]) | |
static om/IQuery | |
(query [_] | |
[:id :title]) | |
Object | |
(render [this] | |
(let [{:keys [id title]} (om/props this) | |
{:keys [select] } (om/get-computed this)] | |
(dom/li #js {:onClick (fn [e] | |
(select id))} title)))) | |
(def projectListItem (om/factory ProjectListItem)) | |
(defn project-list [projects select] | |
(dom/div nil | |
(dom/h3 nil "Project list:") | |
(dom/ul nil | |
(map #(projectListItem (om/computed % {:select select})) projects)))) | |
(defui ProjectDetail | |
static om/Ident | |
(ident [this {:keys [id]}] | |
[:project/by-id id]) | |
static om/IQuery | |
(query [_] | |
[:id :title :description]) | |
Object | |
(render [this] | |
(let [{:keys [id title description]} (om/props this)] | |
(dom/div nil | |
(dom/h3 nil "Project Detail") | |
(if (nil? id) | |
(dom/div nil "No project selected.") | |
(dom/div nil | |
(dom/div nil "Selected project: " id) | |
(dom/div nil "Title: " title) | |
(dom/div nil "Description: " description))))))) | |
(def project-detail (om/factory ProjectDetail)) | |
(defn select-project [component] | |
(fn [id] | |
(om/update-query! component | |
(fn [{:keys [query params] :as q}] | |
(update q :params assoc :id id)) ))) | |
(defui Root | |
static om/IQueryParams | |
(params [this] | |
{:id nil}) | |
static om/IQuery | |
(query [_] | |
`[{:projects ~(om/get-query ProjectListItem)} | |
({:project/detail ~(om/get-query ProjectDetail)} {:id ~'?id})]) | |
Object | |
(render [this] | |
(let [{:keys [projects project/detail]} (om/props this)] | |
(dom/div nil | |
(project-list projects (select-project this)) | |
(project-detail detail))))) | |
;; fake backend | |
(def fake-database (atom {:projects [[:project/by-id 1] [:project/by-id 2]], :project/by-id {1 {:id 1, :title "Learn Haskell" :description "How do I get started with Haskell?"}, 2 {:id 2, :title "Learn Scheme" :description "Lisp rocks!"}}})) | |
(defmulti backend-read om/dispatch) | |
(defmethod backend-read :project/detail | |
[{:keys [database query]} key {:keys [id]}] | |
(let [db @database] | |
{:value (om/db->tree query [:project/by-id id] db)})) | |
(def backend-parser (om/parser {:read backend-read})) | |
;; fake a send to the fake backend | |
(defn send [{:keys [remote]} merge] | |
(merge (backend-parser {:database fake-database} remote))) | |
;; do not throw away the app state when merging | |
(defn deep-merge [& xs] | |
"Merges nested maps without overwriting existing keys." | |
(if (every? map? xs) | |
(apply merge-with deep-merge xs) | |
(last xs))) | |
;;reconciler | |
(def reconciler | |
(om/reconciler | |
{:state app-state | |
:parser (om/parser {:read read}) | |
:send send | |
:merge-tree deep-merge})) | |
(om/add-root! reconciler | |
Root (gdom/getElement "app")) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment