Skip to content

Instantly share code, notes, and snippets.

@danneu

danneu/1-db.clj

Last active Aug 29, 2015
Embed
What would you like to do?
My Datomic boilerplate. (resources/schema.edn, resources/data-functions.edn, src/xxx/db.clj)
(ns xxx.db
(:require [clojure.java.io :as io]
[clojure.string :as str]
[datomic.api :as d])
(:import [datomic Util]
[java.util Date]))
;; Datomic utils ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn read-all
"Read all forms in f, where f is any resource that can
be opened by io/reader"
[f]
(Util/readAll (io/reader f)))
(defn transact-all
"Load and run all transactions from f, where f is any
resource that can be opened by io/reader."
[conn f]
(doseq [txd (read-all f)]
@(d/transact conn txd))
:done)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def uri "datomic:free://localhost:4334/my-db-name")
(defn create-database
"Recreates db with schema, returns db connection."
[]
(d/delete-database uri)
(d/create-database uri)
(let [conn (d/connect uri)]
(transact-all conn "resources/schema.edn")
(transact-all conn "resources/data-functions.edn")
;(transact-all conn "resources/seed.edn")
conn))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn get-conn [] (d/connect uri))
(defn get-db [] (d/db (get-conn)))
(defn gen-tempid []
(d/tempid :db.part/user))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Look up indexed attribute.
;; (find-by :user/uid 42) => {:db/id 118217941}
;; (find-by :user/uid nil) => nil
;; (find-by :user/uid 43) => nil (Not found)
(def find-by
(fn _
([a v] (_ (get-db) a v))
([db a v]
(when-not (nil? v)
(->> (d/datoms db :avet a v)
(d/q '[:find ?e :where [?e]])
ffirst
(d/entity db))))))
;; Look up unindexed attribute.
;; (find-by :user/favColor "blue")
(def find-by-dumb
(fn _
([a v] (_ (get-db) a v))
([db a v]
(->> (d/q '[:find ?e
:in $ ?a ?v
:where [?e ?a ?v]]
db a v)
ffirst
(d/entity db)
))))
;; Look up all entities with this indexed attribute.
;; (find-all-by :user/uid) => Returns all users
(def find-all-by
(fn _
([attr] (_ (get-db) attr))
([db attr]
(->> (d/datoms db :avet attr)
(d/q '[:find ?e :where [?e]])
(map first)
(map (partial d/entity db))))))
;; Look up all entities with this unindexed attribute.
(def find-all-by-dumb
(fn _
([a]
(let [db (get-db)]
(->> (d/q '[:find ?e
:in $ ?a
:where [?e ?a]]
db a)
(apply concat)
(map (partial d/entity db)))))
([a v]
(let [db (get-db)]
(->> (d/q '[:find ?e
:in $ ?a ?v
:where [?e ?a ?v]]
db a v)
(apply concat)
(map (partial d/entity db)))))))
;; Count all entities with this indexed attribute
;; (get-count :user/uid) => Returns total user count
(def get-count
(fn _
([attr] (_ attr (get-db)))
([attr db]
(->> (d/datoms db :avet attr)
seq
count))))
[
;; --- :addUID ---
;; Adds an autoincrementing uid to this entity.
;;
;; (let [user-tid (gen-tempid)]
;; @(d/transact (get-conn) [[:addUID user-tid :user/uid]
;; {:db/id user-tid
;; :user/uname "Fred"}]))
;;
;; This will find the highest value of :user/uid in the database
;; and then increment it so that Fred now has the highest :user/uid.
{:db/id #db/id[:db.part/user]
:db/ident :addUID
:db/fn #db/fn
{:lang :clojure
:params [db new-eid attr]
:code (let [res (datomic.api/q
'[:find (max ?uid)
:in $ ?attr
:where [_ ?attr ?uid]]
db
attr)
new-uid (inc (or (ffirst res) 0))]
[[:db/add new-eid attr new-uid]])}}
;; Similar to :addUID except that it generates a random 5-char string.
;; It will regenerate strings until it finds a unique one within the scope of given attr.
;; [[:addAlnum tid :user/alnum]] will create [[:db/add tid :user/alnum <new-alnum>]] where
;; <new-alnum> is unique only in the scope of all :user/alnum in the db.
{:db/id #db/id[:db.part/user]
:db/ident :addAlnum
:db/fn #db/fn
{:lang :clojure
:params [db new-eid attr]
:code (let [rand-char (fn []
(->> (concat "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789")
rand-nth))
gen-uid (fn []
(clojure.string/join (take 5 (repeatedly rand-char))))
find-by (fn [a v]
(->> (d/datoms db :avet a v)
(d/q '[:find ?e :where [?e]])
ffirst))]
(loop [new-uid (gen-uid)]
(if (find-by attr new-uid)
(recur (gen-uid))
[[:db/add new-eid attr new-uid]])))}}
]
[
;; Users
;; - :user/uid (one String) unique identity
;; - :user/uname (one String) unique value
;; - :user/email (one String) unique value
;; - :user/digest (one String)
;; :user/uid
{:db/id #db/id [:db.part/db]
:db/ident :user/uid
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db
;;
:db/unique :db.unique/identity
}
;; :user/uname
{:db/id #db/id [:db.part/db]
:db/ident :user/uid
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db
;;
:db/unique :db.unique/value
:db/fulltext true
}
;; ...
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.