-
Notifications
You must be signed in to change notification settings - Fork 1
/
in_memory_docstore_client.clj
155 lines (141 loc) · 6.86 KB
/
in_memory_docstore_client.clj
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
(ns common-clj.components.docstore-client.in-memory-docstore-client
(:require [com.stuartsierra.component :as component]
[common-clj.components.config.protocol :as config.protocol]
[common-clj.components.docstore-client.protocol
:refer [DocstoreClient] :as docstore-client.protocol]
[schema.core :as s]))
(defn- assoc-if
[m k v]
(if v (assoc m k v) m))
(def ^:private cmp->cmp-fn
"Maps comparison-operators symbols to comparison functions
Symbols yet to support:
#{:le :lt :ge :gt :begins-with :between :ne
:not-null :null :contains :not-contains :in}"
{:eq =})
(defn- init-store [dynamo-tables]
(reduce
(fn [acc [table-name {:keys [primary-key secondary-key]}]]
(let [schema (assoc-if {:primary-key primary-key}
:secondary-key
secondary-key)]
(assoc acc table-name {:schema schema
:data {}})))
{}
dynamo-tables))
(s/defrecord InMemoryDocstoreClient []
component/Lifecycle
(start [{:keys [config] :as component}]
(let [{:keys [dynamo-tables]} (config.protocol/get-config config)]
(assoc component :store (atom (init-store dynamo-tables)))))
(stop [component]
(assoc component :store nil))
DocstoreClient
(put-item! [{:keys [store] :as component} table-name v]
(let [table (-> store deref table-name)
[primary-key-name primary-key-type] (-> table :schema :primary-key)
[secondary-key-name secondary-key-type] (-> table :schema :secondary-key)
primary-key-value (get v primary-key-name)
secondary-key-value (get v secondary-key-name)]
(when-not table
(throw (ex-info "Can't do operations on non-existent table"
{:table table-name
:type :non-existent-table})))
(docstore-client.protocol/put-item! component
table-name
(assoc-if {primary-key-name primary-key-value}
secondary-key-name
secondary-key-value)
v)))
(put-item! [{:keys [store]} table-name k v]
(let [table (-> store deref table-name)
[primary-key-name primary-key-type] (-> table :schema :primary-key)
[secondary-key-name secondary-key-type] (-> table :schema :secondary-key)
primary-key-value (get k primary-key-name)
secondary-key-value (or (get k secondary-key-name)
(get v secondary-key-name))]
(when-not table
(throw (ex-info "Can't do operations on non-existent table"
{:table table-name
:type :non-existent-table})))
(when-not primary-key-value
(throw (ex-info "Missing primary key on item"
{:primary-key primary-key-name
:type :missing-primary-key})))
(when (and secondary-key-name (not secondary-key-value))
(throw (ex-info "Missing secondary key on item"
{:secondary-key secondary-key-name
:type :missing-secondary-key})))
(if-not secondary-key-name
(swap! store (fn [tables]
(update-in tables [table-name :data]
#(assoc % primary-key-value v))))
(swap! store (fn [tables]
(update-in tables [table-name :data primary-key-value]
#(assoc % secondary-key-value v)))))
v))
(maybe-get-item [component table-name k options]
(try
(docstore-client.protocol/get-item component table-name k options)
(catch Exception e
(when-not (= :not-found (-> e ex-data :type))
(throw e)))))
(get-item [{:keys [store]} table-name k {:keys [schema-resp]}]
(let [table (-> store deref table-name)
[primary-key-name primary-key-type] (-> table :schema :primary-key)
[secondary-key-name secondary-key-type] (-> table :schema :secondary-key)
primary-key-value (get k primary-key-name)
secondary-key-value (get k secondary-key-name)]
(when-not table
(throw (ex-info "Can't do operations on non-existent table"
{:table table-name
:type :non-existent-table})))
(when-not primary-key-value
(throw (ex-info "Missing primary key"
{:primary-key primary-key-name
:type :missing-primary-key})))
(when (and secondary-key-name (not secondary-key-value))
(throw (ex-info "Missing secondary key"
{:secondary-key secondary-key-name
:type :missing-secondary-key})))
(let [result
(if-not secondary-key-name
(get-in table [:data primary-key-value])
(get-in table [:data primary-key-value secondary-key-value]))]
(when-not result
(throw (ex-info "Not found" {:type :not-found})))
(s/validate schema-resp result))))
(query [{:keys [store]} table-name key-conditions {:keys [schema-resp]}]
(let [table (-> store deref table-name)
[primary-key-name primary-key-type] (-> table :schema :primary-key)
[secondary-key-name] (-> table :schema :secondary-key)
primary-key-value (get key-conditions
primary-key-name)]
(when-not table
(throw (ex-info "Can't do operations on non-existent table"
{:table table-name
:type :non-existent-table})))
(when-not primary-key-value
(throw (ex-info "Missing primary key"
{:primary-key primary-key-name
:type :missing-primary-key})))
(let [result
(if-not secondary-key-name
(filterv (comp not nil?)
[(->> table
:data
(filter (fn [[k v]]
(= k primary-key-value)))
first
second)])
(->> table
:data
(filter (fn [[k v]]
(= k primary-key-value)))
first
second
vals
vec))]
(s/validate (s/maybe schema-resp) result)))))
(defn new-docstore-client []
(map->InMemoryDocstoreClient {}))