This repository has been archived by the owner on Aug 18, 2019. It is now read-only.
/
tempid.cljc
118 lines (99 loc) · 3.72 KB
/
tempid.cljc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
(ns com.fulcrologic.fulcro.algorithms.tempid
"Functions for making and consuming Fulcro temporary IDs."
(:refer-clojure :exclude [uuid])
(:require
[taoensso.timbre :as log]
[clojure.walk :refer [prewalk-replace]])
#?(:clj (:import [java.io Writer])))
(def tag "fulcro/tempid")
;; =============================================================================
;; ClojureScript
#?(:cljs
(deftype TempId [^:mutable id ^:mutable __hash]
Object
(toString [this]
(pr-str this))
IEquiv
(-equiv [this other]
(and (instance? TempId other)
(= (. this -id) (. other -id))))
IHash
(-hash [this]
(when (nil? __hash)
(set! __hash (hash id)))
__hash)
IPrintWithWriter
(-pr-writer [_ writer _]
(write-all writer "#" tag "[\"" id "\"]"))))
#?(:cljs
(defn tempid
"Create a new tempid."
([]
(tempid (random-uuid)))
([id]
(TempId. id nil))))
;; =============================================================================
;; Clojure
#?(:clj
(defrecord TempId [id]
Object
(toString [this]
(pr-str this))))
#?(:clj
(defmethod print-method TempId [^TempId x ^Writer writer]
(.write writer (str "#" tag "[\"" (.id x) "\"]"))))
#?(:clj
(defn tempid
"Create a new tempid."
([]
(tempid (java.util.UUID/randomUUID)))
([uuid]
(TempId. uuid))))
(defn tempid?
"Returns true if the given `x` is a tempid."
#?(:cljs {:tag boolean})
[x]
(instance? TempId x))
(defn result->tempid->realid
"Find and combine all of the tempid remappings from a standard fulcro transaction response."
[tx-result]
(let [get-tempids (fn [m] (or (get m :tempids)))]
(->> (filter (comp symbol? first) tx-result)
(map (comp get-tempids second))
(reduce merge {}))))
(defn resolve-tempids
"Replaces all tempids in `data-structure` using the `tid->rid` map. This is just a deep
walk that replaces every possible match of `tid` with `rid`.
`tid->rid` must be a map, as this function optimizes away resolution by checking if
the map is empty.
Returns the data structure with everything replaced."
[data-structure tid->rid]
(if (empty? tid->rid)
data-structure
(prewalk-replace tid->rid data-structure)))
(defn resolve-tempids!
"Resolve all of the mutation tempid remappings in the `tx-result` against the given `app`.
app - The fulcro app
tx-result - The transaction result (the body map, not the internal tx node).
This function rewrites all tempids in the app state and runtime transaction queues.
NOTE: This function assumes that tempids are distinctly recognizable (e.g. are TempIds or
guids). It is unsafe to use this function if you're using something else for temporary IDs
as this function might rewrite things that are not IDs."
[{:com.fulcrologic.fulcro.application/keys [state-atom runtime-atom]} tx-result]
(let [tid->rid (result->tempid->realid tx-result)]
(swap! state-atom resolve-tempids tid->rid)
(swap! runtime-atom
(fn [r]
(-> r
(update :com.fulcrologic.fulcro.transactions/submission-queue resolve-tempids tid->rid)
(update :com.fulcrologic.fulcro.transactions/active-queue resolve-tempids tid->rid)
(update :com.fulcrologic.fulcro.transactions/send-queues resolve-tempids tid->rid))))))
(defn uuid
"Generate a UUID. With no args returns a random UUID. with an arg (numeric)
it generates a stable one based on that number (useful for testing). Works in cljc."
#?(:clj ([] (java.util.UUID/randomUUID)))
#?(:clj ([n]
(java.util.UUID/fromString
(format "ffffffff-ffff-ffff-ffff-%012d" n))))
#?(:cljs ([] (random-uuid)))
#?(:cljs ([& args] (cljs.core/uuid (apply str args)))))