Skip to content

Instantly share code, notes, and snippets.

@robert-stuttaford
Last active April 27, 2018 15:10
Show Gist options
  • Save robert-stuttaford/39d43c011e498542bcf8 to your computer and use it in GitHub Desktop.
Save robert-stuttaford/39d43c011e498542bcf8 to your computer and use it in GitHub Desktop.
Handy protocols for working with Datomic
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Connection
(defprotocol DatomicConnection
(as-conn [_]))
(extend-protocol DatomicConnection
datomic.Connection
(as-conn [c] c)
datomic.db.Db
(as-conn ([db] (-> db :id str as-conn)))
java.lang.String
(as-conn [db-uri] (d/connect db-uri)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Transaction Log
(defprotocol DatomicTransactionLog
(as-tx-log [_]))
(extend-protocol DatomicTransactionLog
datomic.Connection
(as-tx-log [c] (d/log c))
datomic.db.Db
(as-tx-log [db] (-> db as-conn as-tx-log))
java.lang.String
(as-tx-log [s] (-> s as-conn as-tx-log)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Database
(defprotocol DatabaseReference
(as-db [_] [_ _]))
(def sync-timeout-ms (* 10 1000))
(extend-protocol DatabaseReference
datomic.db.Db
(as-db
([db] db))
datomic.Connection
(as-db
([conn] (d/db conn))
([conn t] (let [db-value-or-timeout (-> (d/sync conn t)
(deref sync-timeout-ms :timeout))]
(cond
(= (type db-value-or-timeout) datomic.db.Db)
db-value-or-timeout
(= db-value-or-timeout :timeout)
(throw
(ex-info "Datomic timed out during sync attempt."
{:waited-ms sync-timeout-ms}))
:else
(throw
(ex-info "An unknown error occured while Datomic was trying to sync."
{}))))))
java.lang.String
(as-db
([db-uri] (as-db (as-conn db-uri)))
([db-uri t] (as-db (as-conn db-uri) t))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Entity
(defprotocol EntityReference
(id [_])
(entity [_ db]))
(extend-protocol EntityReference
datomic.query.EntityMap
(id [e] (:db/id e))
(entity [e db] e)
java.lang.Long
(id [id] id)
(entity [id db] (d/entity (as-db db) id))
;; these two are for working with maps composed for a transaction
clojure.lang.PersistentArrayMap
(id [m] (:db/id m))
(entity [m db] (entity (id m) (as-db db)))
clojure.lang.PersistentHashMap
(id [m] (:db/id m))
(entity [m db] (entity (id m) (as-db db)))
;; nice for when working with the output of d/datoms and d/seek-datoms
datomic.db.Datum
(id [[e]] e)
(entity [[e] db] (entity e (as-db db)))
;; nice for reaching schema or enum entities quickly,
;; however doesn't return a numeral for id like the rest do
clojure.lang.Keyword
(id [kw] kw)
(entity [kw db] (let [db (as-db db)]
(entity (d/entid db kw) (as-db db))))
;; these two are when you have a naked entity (or schema entity) id
java.lang.Long
(id [id] id)
(entity [id db] (d/entity (as-db db) id))
java.lang.Integer
(id [id] id)
(entity [id db] (d/entity (as-db db) id))
;; lookup refs. doesn't work with id, because we don't get the db there.
clojure.lang.PersistentVector
(id [lookup] (throw "Can't infer id for lookup."))
(entity [lookup db] (d/entity (as-db db) lookup)))
@yayitswei
Copy link

yayitswei commented Dec 16, 2016

(defprotocol DatabaseReference
  (as-db [_] [_ _]))

@robert-stuttaford
Copy link
Author

Thank you!

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