-
Notifications
You must be signed in to change notification settings - Fork 1
/
db.clj
141 lines (118 loc) · 4.01 KB
/
db.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
(ns wormbase.db
(:require
[clojure.java.io :as io]
[clojure.string :as str]
[datomic.api :as d]
[environ.core :as environ]
[mount.core :as mount]
[wormbase.util :as wu]))
(def ^:dynamic *wb-db-uri* nil)
(def ^{:dynamic true
:doc "Incremetn this number each time a schema change is made"}
schema-version 1)
(defn connect
"Connects to the datomic database."
[uri]
(d/connect uri))
(defn checked-connect
"Version of connect that checks that the datomic URI matches prefixes.
Designed to be used with `mount/start-with` for testing/development."
[uri allowed-uri-prefixes]
(if (some (partial str/starts-with? uri) allowed-uri-prefixes)
(connect uri)
(throw (ex-info
(str "Refusing to connect - "
"URI did not match any permitted prefix.")
{:uri uri
:allowed-uri-prefixes allowed-uri-prefixes
:type :connection-error}))))
(defn checked-delete
[uri]
(when (str/starts-with? uri "datomic:men")
(d/delete-database uri)))
(defn scratch-connect [uri]
(d/delete-database uri)
(d/create-database uri)
(checked-connect uri ["datomic:mem" "datomic:dev"]))
(mount/defstate conn
:start (binding [*wb-db-uri* (environ/env :wb-db-uri)]
(if (str/starts-with? *wb-db-uri* "datomic:mem")
(scratch-connect *wb-db-uri*)
(connect *wb-db-uri*)))
:stop (d/release conn))
(defn connected? []
(let [states (mount/running-states)
state-key (pr-str #'conn)]
(states state-key)))
;; factoring out so can be mocked in tests.
(defn db
[conn]
(d/db conn))
(defn connection []
conn)
;; end factoring
(defn wrap-datomic
"Annotates request with datomic connection and current db."
[request-handler]
(fn [request]
(when-not (connected?)
(mount/start #'conn))
(let [cx (connection)]
(-> request
(assoc :conn cx :db (db cx))
(request-handler)))))
(defn invert-tx
([log tx provenance fact-mapper]
(let [t (d/tx->t tx)]
(if-let [datoms (some-> (d/tx-range log t (inc t)) first :data)]
(transduce
(comp
(remove (fn [[e _ _ tx _]]
(= e tx)))
(map (fn [[e a v tx added?]]
(let [fact (fact-mapper e a v tx added?)]
(cond
(vector? fact) fact
(true? fact) [(if added? :db/retract :db/add) e a v]
(not (nil? fact)) (throw (ex-info "fact-mapper returned invalid type"
{:tx tx
:type ::invert-tx-problem
:return-type (type fact)}))))))
(remove nil?))
conj
[provenance]
datoms)
(throw (ex-info "No tx to invert"
{:tx tx
:type ::invert-tx-problem
:range (d/tx-range log t (inc t))})))))
([log tx provenance]
(invert-tx log tx provenance (constantly true))))
(defn extract-id [tx-result identity-kw]
(some->> (:tx-data tx-result)
(map :e)
(map (partial d/entity (:db-after tx-result)))
(map identity-kw)
(filter identity)
(set)
(vec)
(first)))
(defn ident-exists? [db ident]
(pos-int? (d/entid db ident)))
(defn edn-definition [edn-name ident]
(let [ident-match? #(= (:db/ident %) ident)]
(->> (str "schema/" edn-name ".edn")
(io/resource)
(wu/read-edn)
(filter ident-match?)
(first))))
;; convenience aliases to read schema items from resources by keyword.
(def seed-data-schema (partial edn-definition "seed-data"))
(def attr-schema (partial edn-definition "definitions"))
(def txfn-schema (partial edn-definition "tx-fns"))
(defn fmt-pull-result [db result]
(->> result
(wu/elide-importer-info)
(wu/elide-db-internals db)))
(defn pull [db expr & args]
(fmt-pull-result db (apply d/pull db expr args)))