Skip to content

Instantly share code, notes, and snippets.

@vvvvalvalval
Last active September 19, 2018 06:09
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save vvvvalvalval/9330ac436a8cc1424da1 to your computer and use it in GitHub Desktop.
Save vvvvalvalval/9330ac436a8cc1424da1 to your computer and use it in GitHub Desktop.
Mocking datomic.Connection for fast in-memory testing
(ns bs.utils.mock-connection
"Utilities for using Datomic"
(:require [datomic.api :as d])
(:use clojure.repl clojure.pprint)
(:import (java.util.concurrent BlockingQueue LinkedBlockingDeque)
(datomic Connection)))
(defrecord MockConnection
[dbAtom, ^BlockingQueue txQueue]
Connection
(db [this] @(.dbAtom this))
(transact [this tx-data] (doto (datomic.promise/settable-future)
(deliver (let [tx-res
(loop []
(let [db-atom (.dbAtom this)
old-val @db-atom
tx-res (d/with old-val tx-data)
new-val (:db-after tx-res)]
(if (compare-and-set! db-atom old-val new-val)
tx-res
(recur))
))]
(.add ^BlockingQueue (.txQueue this) tx-res)
tx-res))
))
(transactAsync [this tx-data] (.transact this tx-data))
(gcStorage [this olderThan])
(requestIndex [this])
(release [this])
(sync [this] (doto (datomic.promise/settable-future)
(deliver (.db this))))
(syncExcise [this t] (.sync this))
(syncIndex [this t] (.sync this))
(syncSchema [this t] (.sync this))
(sync [this t] (.sync this))
(txReportQueue [this] (.txQueue this)))
(defn ^Connection mock-conn
"Creates a mocked version of datomic.Connection which uses db/with internally.
Only supports datomic.api/db, datomic.api/transact and datomic.api/transact-async operations.
Sync and housekeeping methods are implemented as noops. #log() is not supported."
[db]
(MockConnection. (atom db) (LinkedBlockingDeque.)))
(comment ;; How fast is it ?
(def mem-db (bs.dev/local-db)) ;; creates a mem db, loads the schema and some fixture data in it. Takes about 20ms on my dev laptop.
(time (dotimes [i 1000]
(let [conn (mock-conn mem-db)]
@(d/transact conn [{:db/id (d/tempid :db.part/user)
:bouser/firstName (str "Valentinnnnn_" i)
:bouser/lastName (str "Valentinnnnn_" i)
:bouser/level "bandsquare"
:bouser/email (str "val.vvalval" i "@gmail.com")
}]))))
;; "Elapsed time: 2027.881 msecs". So this is a x10 improvement.
;; the schema and fixture data are quite small (35 attributes, 103 datoms), so I expect this will get more compelling as the application grows.
)
@vvvvalvalval
Copy link
Author

Now available on Clojars: https://github.com/vvvvalvalval/datomock

@bhurlow
Copy link

bhurlow commented Sep 6, 2018

nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment