Last active
January 23, 2020 10:58
-
-
Save jeroenvandijk/85eb96d68c31c4e48f99 to your computer and use it in GitHub Desktop.
(A) method to dump a datomic database schema
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns datomic.schema-dump | |
(:require | |
[datomic.api :as d] | |
[clojure.pprint])) | |
(defmethod clojure.pprint/simple-dispatch datomic.db.DbId [v] (pr v)) | |
(defmethod clojure.pprint/simple-dispatch datomic.function.Function [v] (pr v)) | |
(defn database-url [name] | |
(str "datomic:mem://" name)) | |
(defn unique-database-url [] | |
(database-url (d/squuid))) | |
(defn unique-empty-conn [] | |
(let [db-url (unique-database-url)] | |
(d/create-database db-url) | |
(d/connect db-url))) | |
(defn- partition-ident [db eid] | |
(:db/ident (d/entity db (d/part eid)))) | |
(defn not-datomic-entity [ident] | |
(or | |
(= ident :fressian/tag) | |
(let [ns (namespace ident)] | |
(or (nil? ns) | |
(not (re-matches #"db(?:[\./].+)?" ns)))))) | |
;; With inspiration from http://aan.io/dumping-datomic-schema/ | |
(defn dump-schema [db] | |
(let [part-order (zipmap [:db.part/db :db.part/tx :db.part/user] (range))] | |
(->> | |
(d/q '[:find [?e ...] | |
:where | |
[?e :db/ident ?v] | |
[(datomic.schema-dump/not-datomic-entity ?v)]] | |
db) | |
(group-by (fn [eid] (partition-ident db eid))) | |
(sort-by (fn [[part _]] | |
(str (part-order part (name part))))) | |
(mapv (fn [[part eids]] | |
[part | |
(let [tmp-id-idx (atom 0)] | |
(->> (sort eids) | |
(mapv | |
(fn [eid] | |
(let [ent (d/entity db eid)] | |
(cond-> | |
(select-keys ent [:db/ident | |
:db/valueType | |
:db/cardinality | |
:db/doc | |
:db/isComponent | |
:db/fulltext | |
:db/unique | |
:db/fn]) | |
true (assoc :db/id (d/tempid part (swap! tmp-id-idx dec))) | |
(:db/valueType ent) (assoc :db.install/_attribute :db.part/db) | |
(:db/fn ent) (assoc-in [:db/fn :fnref] nil) | |
)) | |
))))]))))) | |
(defn write-schema-file [schema-target-file db] | |
(let [schema (dump-schema db)] | |
(spit schema-target-file | |
(with-out-str | |
(binding [*print-length* nil] | |
(clojure.pprint/pprint schema)))))) | |
(comment | |
(write-schema-file "resources/db/schema.edn" my-db) | |
) | |
(defn read-schema-file [file] | |
(try | |
(clojure.edn/read-string | |
{:readers {'db/id #'datomic.db/id-literal | |
'db/fn (fn [x] | |
(assoc (datomic.function/construct x) :fnref nil)) | |
}} | |
(slurp file)) | |
(catch Exception e | |
(throw (ex-info (str "Error while reading " (str file) ", " (.getMessage e)) {:file file}))))) | |
(defn schema-from-file | |
([] | |
(schema-from-file (clojure.java.io/resource "db/schema.edn"))) | |
([schema-file] | |
(read-schema-file schema-file))) | |
(defn load-from-schema [] | |
(let [conn (unique-empty-conn) | |
grouped-txns (schema-from-file)] | |
(doseq [[part txns] grouped-txns] | |
(when-not (#{:db.part/db :db.part/tx :db.part/user} part) | |
@(d/transact conn [{:db/id (d/tempid :db.part/db) | |
:db.install/_partition :db.part/db | |
:db/ident part}])) | |
@(d/transact conn txns)) | |
conn)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns datomic.schema-test | |
(:require [midje.sweet :refer :all] | |
[adgoji.datomic.schema :as schema] | |
[datomic.api :as d])) | |
;; NOTE: schema/unique-database-conn returns a new database connection | |
;; where all migrations have been applied. | |
;; To detect problems with dumping: | |
(fact "schema dumps are the same each time" | |
(let [schema-1 (schema/dump-schema (d/db (schema/unique-database-conn))) | |
schema-2 (schema/dump-schema (d/db (schema/unique-database-conn))) | |
schema-diff (clojure.data/diff schema-1 schema-2)] | |
(butlast schema-diff) => [nil nil])) | |
(fact "Latest schema has been saved" | |
(let [saved-schema (schema/schema-from-file) | |
extracted-schema (schema/dump-schema (d/db (schema/unique-database-conn))) | |
schema-diff (clojure.data/diff saved-schema extracted-schema)] | |
(= saved-schema extracted-schema) => true | |
(butlast schema-diff) => [nil nil])) | |
(fact "Schema can be loaded" | |
(let [loaded-schema (schema/dump-schema (d/db (schema/load-from-schema))) | |
extracted-schema (schema/dump-schema (d/db (schema/unique-database-conn))) | |
schema-diff (clojure.data/diff loaded-schema extracted-schema)] | |
(= loaded-schema extracted-schema) => true | |
(butlast schema-diff) => [nil nil])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment