|
18 | 18 | ;; Avoid extra require in your ns
|
19 | 19 | (def materialize common/materialize)
|
20 | 20 |
|
| 21 | +(defn open-database |
| 22 | + "Opens database `filename`. |
| 23 | + If `filename` is `:memory`, returns a memory based db. |
| 24 | + open-mode can be `r` or `rw`." |
| 25 | + [filename ^String open-mode] |
| 26 | + (let [core (if (= filename :memory) |
| 27 | + (CoreMemory. (RandomAccessMemory.)) |
| 28 | + (CoreBufferedFile. (RandomAccessBufferedFile. (File. ^String filename) open-mode))) |
| 29 | + hasher (Hasher. (MessageDigest/getInstance "SHA-1"))] |
| 30 | + (Database. core hasher))) |
| 31 | + |
21 | 32 |
|
22 | 33 | (defn ^WriteArrayList db-history [^Database db]
|
23 | 34 | (WriteArrayList. (.rootCursor db)))
|
|
42 | 53 | (append-context! history nil (fn [^WriteCursor cursor]
|
43 | 54 | (conversion/v->slot! cursor new-value))))
|
44 | 55 |
|
45 |
| -(defn open-database |
46 |
| - "Opens database `filename`. |
47 |
| - If `filename` is `:memory`, returns a memory based db. |
48 |
| - open-mode can be `r` or `rw`." |
49 |
| - [filename ^String open-mode] |
50 |
| - (let [core (if (= filename :memory) |
51 |
| - (CoreMemory. (RandomAccessMemory.)) |
52 |
| - (CoreBufferedFile. (RandomAccessBufferedFile. (File. ^String filename) open-mode))) |
53 |
| - hasher (Hasher. (MessageDigest/getInstance "SHA-1"))] |
54 |
| - (Database. core hasher))) |
55 |
| - |
56 | 56 | (defn v->slot!
|
57 | 57 | "Converts a value to a slot which can be written to a cursor.
|
58 | 58 | For XITDB* types (which support ISlot), will return `-slot`,
|
|
63 | 63 | (conversion/v->slot! cursor v)))
|
64 | 64 |
|
65 | 65 | (defn xitdb-swap!
|
66 |
| - "Starts a new transaction and calls `f` with the value at root. |
67 |
| - `f` will receive a XITDBWrite* type (db) and `args`. |
| 66 | + "Starts a new transaction and calls `f` with the value at `base-keypath`. |
| 67 | + If `base-keypath` is nil, will use the root cursor. |
| 68 | + `f` will receive a XITDBWrite* type with the value at `base-keypath` and `args`. |
68 | 69 | Actions on the XITDBWrite* type (like `assoc`) will mutate it.
|
69 |
| - Return value of `f` is written at (root) cursor. |
| 70 | + Return value of `f` is written at `base-keypath` (or root) cursor. |
70 | 71 | Returns the transaction history index."
|
71 |
| - [db f & args] |
| 72 | + [db base-keypath f & args] |
72 | 73 | (let [history (db-history db)
|
73 | 74 | slot (.getSlot history -1)]
|
74 | 75 | (append-context!
|
75 | 76 | history
|
76 | 77 | slot
|
77 | 78 | (fn [^WriteCursor cursor]
|
78 |
| - (let [obj (xtypes/read-from-cursor cursor true)] |
| 79 | + (let [cursor (conversion/keypath-cursor cursor base-keypath) |
| 80 | + obj (xtypes/read-from-cursor cursor true)] |
79 | 81 | (let [retval (apply f (into [obj] args))]
|
80 | 82 | (.write cursor (v->slot! cursor retval))))))))
|
81 | 83 |
|
82 | 84 | (defn xitdb-swap-with-lock!
|
83 | 85 | "Performs the 'swap!' operation while locking `db.lock`.
|
84 | 86 | Returns the new value of the database.
|
85 | 87 | If the binding `*return-history?*` is true, returns
|
86 |
| - `[current-history-index db-before db-after]`." |
87 |
| - [xitdb f & args] |
| 88 | + `[current-history-index db-before db-after]`. |
| 89 | + If `keypath` is not empty, the result of `f` will be written to the db at `keypath` rather |
| 90 | + than db root. |
| 91 | + Similarly, if `keypath` is not empty, the returned value will be the value at `keypath`." |
| 92 | + [xitdb base-keypath f & args] |
88 | 93 | (let [^ReentrantLock lock (.-lock xitdb)]
|
89 | 94 | (when (.isHeldByCurrentThread lock)
|
90 | 95 | (throw (IllegalStateException. "swap! should not be called from swap! or reset!")))
|
91 | 96 | (try
|
92 | 97 | (.lock lock)
|
93 | 98 | (let [old-value (when *return-history?* (deref xitdb))
|
94 |
| - index (apply xitdb-swap! (into [(-> xitdb .rwdb) f] args)) |
| 99 | + index (apply xitdb-swap! (into [(-> xitdb .rwdb) base-keypath f] args)) |
95 | 100 | new-value (deref xitdb)]
|
96 | 101 | (if *return-history?*
|
97 | 102 | [index old-value new-value]
|
|
146 | 151 | (.unlock lock))))
|
147 | 152 |
|
148 | 153 | (swap [this f]
|
149 |
| - (xitdb-swap-with-lock! this f)) |
| 154 | + (xitdb-swap-with-lock! this nil f)) |
150 | 155 |
|
151 | 156 | (swap [this f a]
|
152 |
| - (xitdb-swap-with-lock! this f a)) |
| 157 | + (xitdb-swap-with-lock! this nil f a)) |
153 | 158 |
|
154 | 159 | (swap [this f a1 a2]
|
155 |
| - (xitdb-swap-with-lock! this f a1 a2)) |
| 160 | + (xitdb-swap-with-lock! this nil f a1 a2)) |
156 | 161 |
|
157 | 162 | (swap [this f x y args]
|
158 |
| - (apply xitdb-swap-with-lock! (concat [this f x y] args)))) |
| 163 | + (apply xitdb-swap-with-lock! (concat [this nil f x y] args)))) |
159 | 164 |
|
160 | 165 | (defn xit-db
|
161 | 166 | "Returns a new XITDBDatabase which can be used to query and transact data.
|
|
178 | 183 | (->XITDBDatabase tldb rwdb (ReentrantLock.)))))
|
179 | 184 |
|
180 | 185 |
|
| 186 | +(deftype XITDBCursor [xdb keypath] |
| 187 | + |
| 188 | + java.io.Closeable |
| 189 | + (close [this]) |
| 190 | + |
| 191 | + clojure.lang.IDeref |
| 192 | + (deref [this] |
| 193 | + (let [v (deref xdb)] |
| 194 | + (get-in v keypath))) |
| 195 | + |
| 196 | + clojure.lang.IAtom |
| 197 | + |
| 198 | + (reset [this new-value] |
| 199 | + (xitdb-swap-with-lock! xdb keypath (constantly new-value))) |
| 200 | + |
| 201 | + (swap [this f] |
| 202 | + (xitdb-swap-with-lock! xdb keypath f)) |
| 203 | + |
| 204 | + (swap [this f a] |
| 205 | + (xitdb-swap-with-lock! xdb keypath f a)) |
| 206 | + |
| 207 | + (swap [this f a1 a2] |
| 208 | + (xitdb-swap-with-lock! xdb keypath f a1 a2)) |
| 209 | + |
| 210 | + (swap [this f x y args] |
| 211 | + (apply xitdb-swap-with-lock! (concat [xdb keypath f x y] args)))) |
| 212 | + |
| 213 | +(defn xdb-cursor [xdb keypath] |
| 214 | + (cond |
| 215 | + (instance? XITDBCursor xdb) |
| 216 | + (XITDBCursor. (.-xdb xdb) (vec (concat (.-keypath xdb) keypath))) |
| 217 | + |
| 218 | + (instance? XITDBDatabase xdb) |
| 219 | + (XITDBCursor. xdb keypath) |
| 220 | + |
| 221 | + :else |
| 222 | + (throw (IllegalArgumentException. (str "xdb must be an instance of XITDBCursor or XITDBDatabase, got: " (type xdb)))))) |
| 223 | + |
181 | 224 |
|
0 commit comments