|
1 |
| -(ns hitchhiker.sqlite |
| 1 | +(ns hitchhiker.jdbc |
2 | 2 | (:require [clojure.java.jdbc :as jdbc]
|
3 | 3 | [clojure.edn :as edn]
|
4 | 4 | [clojure.string :as str]
|
|
8 | 8 | [taoensso.nippy :as nippy])
|
9 | 9 | (:import [java.sql SQLException]))
|
10 | 10 |
|
| 11 | +;;; References in a Relational DB |
| 12 | +;;; |
| 13 | +;;; The SQLite backend uses a simple relational model to keep track of |
| 14 | +;;; keys and their references. Each key is listed in hh_keys, and whenever |
| 15 | +;;; we'd like to have some key point to another, we call add-refs with the |
| 16 | +;;; "pointer" key and a list of pointee keys. For each pointee, add-refs will |
| 17 | +;;; add a `(pointer, pointee)` tuple in hh_refs. |
| 18 | +;;; |
| 19 | +;;; hh_keys |
| 20 | +;;; k the name of the key |
| 21 | +;;; v a binary blob representing the value of `k` |
| 22 | +;;; |
| 23 | +;;; hh_refs |
| 24 | +;;; pointer the name of the pointer key |
| 25 | +;;; pointee the name of the pointee key |
| 26 | +;;; |
| 27 | +;;; To delete a key, use `drop-key` which also takes care of deleting any |
| 28 | +;;; keys that are only hanging around because they point to the key being |
| 29 | +;;; deleted. |
| 30 | +;;; |
| 31 | + |
11 | 32 | (defn underscore [x]
|
12 | 33 | (str/replace (str x) "-" "_"))
|
13 | 34 |
|
|
18 | 39 | {:entities underscore})
|
19 | 40 |
|
20 | 41 | :hh-ref (jdbc/create-table-ddl :hh-ref
|
21 |
| - [[:parent :string "references hh_key(k) on delete cascade"] |
22 |
| - [:child :string "references hh_key(k) on delete cascade"]] |
| 42 | + [[:pointer :string "references hh_key(k) on delete cascade"] |
| 43 | + [:pointee :string "references hh_key(k) on delete cascade"]] |
23 | 44 | {:entities underscore})
|
24 | 45 |
|
25 |
| - :hh-ref-by-parent "create index if not exists hh_ref_by_parent on hh_ref (parent);" |
26 |
| - :hh-ref-by-child "create index if not exists hh_ref_by_child on hh_ref (child);"}) |
| 46 | + :hh-ref-by-pointer "create index if not exists hh_ref_by_pointer on hh_ref (pointer);" |
| 47 | + :hh-ref-by-pointee "create index if not exists hh_ref_by_pointee on hh_ref (pointee);"}) |
27 | 48 |
|
28 | 49 | (def query
|
29 | 50 | {:table-exists? "select 1 from sqlite_master where type='table' and name=?"
|
30 | 51 | :index-exists? "select 1 from sqlite_master where type='index' and name=?"
|
31 | 52 | :find-key "select * from hh_key where k=?"
|
32 | 53 | :dead-keys "select k
|
33 | 54 | from hh_key
|
34 |
| - where k not in ( select child from hh_ref )"}) |
| 55 | + where k not in ( select pointee from hh_ref )"}) |
35 | 56 |
|
36 |
| -(defn drop-ref [db key] |
| 57 | +(defn drop-key [db key] |
37 | 58 | (jdbc/delete! db :hh-key ["k = ?" key]
|
38 | 59 | {:entities underscore})
|
39 | 60 |
|
40 | 61 | (let [dead-keys (jdbc/query db (query :dead-keys))]
|
41 | 62 | (doseq [{:keys [k] :as dead-key} dead-keys]
|
42 |
| - (drop-ref db k)))) |
| 63 | + (drop-key db k)))) |
43 | 64 |
|
44 | 65 |
|
45 | 66 | (defn db-spec [subname]
|
|
93 | 114 | :exists? table-exists?
|
94 | 115 | :create! create-table})
|
95 | 116 |
|
96 |
| - (ensure {:items [:hh-ref-by-parent :hh-ref-by-child] |
| 117 | + (ensure {:items [:hh-ref-by-pointer :hh-ref-by-pointee] |
97 | 118 | :exists? index-exists?
|
98 | 119 | :create! create-index})
|
99 | 120 |
|
|
126 | 147 | (defn delete-key [db k]
|
127 | 148 | (jdbc/delete! :hh-key ["k = ?" k]))
|
128 | 149 |
|
129 |
| -(defn add-refs [db {:keys [parent children]}] |
130 |
| - (let [mk-ref (fn [child] |
131 |
| - [parent child])] |
| 150 | +(defn add-refs [db {:keys [pointer pointees]}] |
| 151 | + (let [mk-ref (fn [pointee] |
| 152 | + [pointer pointee])] |
132 | 153 | (try
|
133 |
| - (jdbc/insert-multi! db :hh-ref (for [child children] |
134 |
| - {:parent parent |
135 |
| - :child child}) |
| 154 | + (jdbc/insert-multi! db :hh-ref (for [pointee pointees] |
| 155 | + {:pointer pointer |
| 156 | + :pointee pointee}) |
136 | 157 | {:entities underscore})
|
137 | 158 | (catch Exception e
|
138 |
| - (throw (ex-info "Failed to link parent with children" |
139 |
| - {:parent parent |
140 |
| - :children children} |
| 159 | + (throw (ex-info "Failed to link pointer with pointees" |
| 160 | + {:pointer pointer |
| 161 | + :pointee pointees} |
141 | 162 | e))))))
|
142 | 163 |
|
143 | 164 | (defn synthesize-storage-addr
|
|
199 | 220 | redis-key (nippy/thaw-from-in! data-input)]
|
200 | 221 | (sqlite-addr last-key redis-key)))
|
201 | 222 |
|
202 |
| -(defrecord SQLiteBackend [db] |
| 223 | +(defrecord JDBCBackend [db] |
203 | 224 | core/IBackend
|
204 | 225 | (new-session [_] (atom {:writes 0
|
205 | 226 | :deletes 0}))
|
|
219 | 240 | (binding [*db* tx]
|
220 | 241 | (add-node db {:k key, :v node})
|
221 | 242 | (when (core/index-node? node)
|
222 |
| - (add-refs db {:parent key |
223 |
| - :children (for [child (:children node) |
224 |
| - :let [child-key @(:storage-addr child)]] |
225 |
| - child-key)})))) |
| 243 | + (add-refs db {:pointer key |
| 244 | + :pointees (for [pointee (:pointees node) |
| 245 | + :let [pointee-key @(:storage-addr pointee)]] |
| 246 | + pointee-key)})))) |
226 | 247 |
|
227 | 248 | (seed-cache! key (doto (promise)
|
228 | 249 | (deliver node)))
|
|
0 commit comments