A little Clojure wrapper for Datomic
I wrote yesterday about getting started with Datomic in a lein based project. Probably because I am not up to speed with Datomic idioms, a lot of the data boilerplate bugs me so I wrote a little wrapper to hide all of this from my view. Starting with a some code by Michael Nygard I saw on the Datomic newsgroup I wrapped creating database attributes and adding data to the data store. I formated the following code in a funky way to make it fit on this web page:
(ns datomic-test.core (:use [datomic.api :as api])) (defn attribute [id t c doc] ; by Michael Nygard {:db/id (api/tempid :db.part/db) :db/ident id :db/valueType t :db/cardinality c :db/doc doc :db.install/_attribute :db.part/db}) (defn string-singleton-attribute [conn id doc] @(api/transact conn [(attribute id :db.type/string :db.cardinality/one doc)])) (defn string-multiple-attribute [conn id doc] @(api/transact conn [(attribute id :db.type/string :db.cardinality/many doc)])) (defn long-singleton-attribute [conn id doc] @(api/transact conn [(attribute id :db.type/long :db.cardinality/one doc)])) (defn long-multiple-attribute [conn id doc] @(api/transact conn [(attribute id :db.type/long :db.cardinality/many doc)])) (defn do-tx-user [conn data-seq] (let [data (for [data data-seq] (assoc data :db/id (api/tempid :db.part/user)))] @(api/transact conn data)))Michael's code wraps schema attribute definitions like I showed in the file data/schema.dtm in yesterday's blog. The function do-tx-user takes a seq of maps, adds the user database partition specification to each map, and runs a transaction. With this wrapper, I don't use a separate schema input data file anymore. Here is the example I showed yesterday using the wrapper:
(ns datomic-test.test.core (:use [datomic-test.core]) (:use [clojure.test])) (use '[datomic.api :only [q db] :as api]) (use 'clojure.pprint) ;;(def uri "datomic:free://localhost:4334//news") (def uri "datomic:mem://news") (api/create-database uri) (def conn (api/connect uri)) ;; create two singleton string attributes and a number ;; attribute and add them to the :db.part/db partition: (string-singleton-attribute conn :news/title "A news story's title") (string-singleton-attribute conn :news/url "A news story's URL") (long-singleton-attribute conn :news/reader-count "Number of readers") ;; add some data to the :db.part/user partition: (do-tx-user conn [{:news/title "Rain Today", :news/url "http://test.com/news1", :news/reader-count 11} {:news/title "Sunshine tomorrow", :news/url "http://test.com/news2", :news/reader-count 8}]) (def results (q '[:find ?n :where [?n :news/title]] (db conn))) (println (count results)) (doseq [result results] (let [id (first result) entity (-> conn db (api/entity id))] (println (:news/title entity) (:news/reader-count entity))))Since I use many different tools, I sometimes like to figure out the subset of APIs, etc. that I need and wrap them in a form that is easier for me to remember and use. This may be a bad habit because I can end up permanently using a subset of tool functionality.
Comments
Post a Comment