Skip to content

Commit

Permalink
Tests, default conformity attribute, and numerous doc changes
Browse files Browse the repository at this point in the history
 - Also removed "requires" dependencies for the time being.
  • Loading branch information
Ryan Neufeld committed Oct 26, 2012
1 parent 42de9ce commit fe1f765
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 63 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ pom.xml
.lein-deps-sum
.lein-failures
.lein-plugins
dev
4 changes: 3 additions & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.4.0"]
[com.datomic/datomic-free "0.8.3551"]])
[com.datomic/datomic-free "0.8.3551"]]
:profiles {:dev {:dependencies [[org.clojure/tools.namespace "0.2.0"]]
:source-paths ["dev"]}})
85 changes: 44 additions & 41 deletions src/conformity.clj
Original file line number Diff line number Diff line change
@@ -1,61 +1,64 @@
(ns conformity
(:use [datomic.api :only [q db] :as d]))

(defn- has-attribute?
"Does database have an attribute named attr-name?"
(def default-conformity-attribute :confirmity/conformed-norms)

(defn has-attribute?
"Check if a database has an attribute named attr-name"
[db attr-name]
(-> (d/entity db attr-name)
:db.install/_attribute
boolean))

(defn- ensure-conformity-attribute
"Ensure that conformity-attr, a keyword-valued attribute used
as a value on transactions to track named norms, is
installed in database."
(defn ensure-conformity-attribute
"Ensure that conformity-attr, a keyword-valued attribute,
is installed in database."
[conn conformity-attr]
(when-not (has-attribute? (db conn) conformity-attr)
(d/transact conn [{:db/id #db/id [:db.part/db]
:db/ident conformity-attr
:db/valueType :db.type/keyword
:db/cardinality :db.cardinality/one
:db/doc "Name of schema installed by this transaction"
:db/index true
:db.install/_attribute :db.part/db}])))
:db/ident conformity-attr
:db/valueType :db.type/keyword
:db/cardinality :db.cardinality/one
:db/doc "Name of schema installed by this transaction"
:db/index true
:db.install/_attribute :db.part/db}])))

(defn conforms-to?
"Does database have a schema named norm installed?
Uses conformity-attr (an attribute added to transactions!) to track
which schema names are installed."
[db conformity-attr norm]
(and (has-attribute? db conformity-attr)
(-> (q '[:find ?e
:in $ ?sa ?sn
:where [?e ?sa ?sn ?e]]
db conformity-attr norm)
seq boolean)))
"Does database have a norm installed?
conformity-attr (optional) the keyword name of the attribute used to track
conformity
norm the keyword name of the norm you want to check"
([db norm] (conforms-to? db default-conformity-attribute norm))
([db conformity-attr norm]
(and (has-attribute? db conformity-attr)
(-> (q '[:find ?e
:in $ ?sa ?sn
:where [?e ?sa ?sn ?e]]
db conformity-attr norm)
seq boolean))))

(defn ensure-conforms
"Ensure that norms represented as datoms are conformed-to (installed), be they
schema, data or otherwise.
conformity-attr the keyword-valued attribute in which
enacted norms will be recorded
conformity-attr (optional) the keyword-valued attribute where conformity
tracks enacted norms.
norm-map a map from norm names to data maps.
the data map contains two keys:
the data map contains one keys:
:txes - the data to install
:requires - a list of other norms to conform to
norms the names of norms to conform to"
[conn conformity-attr norm-map & names]
(ensure-conformity-attribute conn conformity-attr)
(doseq [norm names]
(when-not (conforms-to? (db conn) conformity-attr norm)
(let [{:keys [requires txes]} (get norm-map norm)]
(apply ensure-conforms conn conformity-attr norm-map requires)
(if txes
(doseq [tx txes]
;; hrm, could mark the last tx specially
(d/transact conn (cons {:db/id (d/tempid :db.part/tx)
conformity-attr norm}
tx)))
(throw (ex-info (str "No data provided for norm" norm)
{:schema/missing norm})))))))
norm-names A collection of names of norms to conform to"
([conn norm-map norm-names] (ensure-conforms conn default-conformity-attribute norm-map norm-names))
([conn conformity-attr norm-map norm-names]
(ensure-conformity-attribute conn conformity-attr)
(doseq [norm norm-names]
(when-not (conforms-to? (db conn) conformity-attr norm)
(let [{txes :txes} (get norm-map norm)]
(if txes
(doseq [tx txes]
;; hrm, could mark the last tx specially
(d/transact conn (cons {:db/id (d/tempid :db.part/tx)
conformity-attr norm}
tx)))
(throw (ex-info (str "No data provided for norm " norm)
{:schema/missing norm}))))))))
61 changes: 40 additions & 21 deletions test/conformity_test.clj
Original file line number Diff line number Diff line change
@@ -1,38 +1,57 @@
(ns conformity-test
(:use clojure.test
conformity
[datomic.api :only [db] :as d]))
[datomic.api :only [q db] :as d]))

(def uri "datomic:mem://test")
(defn fresh-conn []
(d/delete-database uri)
(d/create-database uri)
(d/connect uri))

(def sample-norms-map {:test/norm-1 {:txes [[]]}})
(def sample-norms (keys sample-norms-map))
(def sample-norms-map {:test/norm-1
{:txes [[{:db/id #db/id [:db.part/db]
:db/ident :test/attribute
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db/fulltext false
:db/index false
:db.install/_attribute :db.part/db}]]}})

(deftest test-ensure-conforms
(testing "installs all norm expected"
(let [conn (fresh-conn)]
(ensure-conforms conn sample-norms-map [:test/norm-1])
(is (= 1 (count (q '[:find ?e :where [?e :db/ident :test/attribute]] (db conn)))))))

(testing "throws exception if norm-map lacks transactions for a norm"
(let [conn (fresh-conn)]
(is (thrown-with-msg? clojure.lang.ExceptionInfo #"No data provided for norm :test/norm-2"
(ensure-conforms conn {:test/norm-2 {}} [:test/norm-2]))))))

(deftest test-conforms-to?
(testing "returns true if a norm is already installed"
(let [conn (fresh-conn)]
(ensure-conformity-attribute conn :test/conformity)
(ensure-conforms conn :test/conformity {}))
(is ))
(ensure-conforms conn sample-norms-map [:test/norm-1])
(is (= true (conforms-to? (db conn) :test/norm-1)))))

(testing "returns false if a norm has not been installed"
(is false))
(let [conn (fresh-conn)]
(ensure-conformity-attribute conn default-conformity-attribute)
(is (= false (conforms-to? (db conn) :test/norm-1)))))

(testing "returns false if conformity-attr does not exist"
(is false)))

(deftest test-ensure-conforms
(testing "installs all norm expected" (is false))
(testing "throws exception if norm-map lacks transactions for a norm" (is false)))

;; How do you test private functions?
(def has-attribute? (ns-resolve 'conform 'has-attribute?))
(deftest test-has-attribute?
(testing "is true when attribute exists in db" (is false))
(testing "is false when attribute isn't in db" (is false)))
(let [conn (fresh-conn)]
(is (= false (conforms-to? (db conn) :test/norm-1))))))

(def ensure-conformity-attribute (ns-resolve 'conform 'ensure-conform-attribute))
(deftest test-ensure-conform-attribute
(testing "it adds the conformity attribute if it is absent")
(testing "it does nothing if the conformity attribute exists"))
(testing "it adds the conformity attribute if it is absent"
(let [conn (fresh-conn)]
(ensure-conformity-attribute conn :test/conformity)
(is (= true (has-attribute? (db conn) :test/conformity)))))

(testing "it does nothing if the conformity attribute exists"
(defn count-txes [conn] (count (q '[:find ?tx :where [?tx :db/txInstant _]] (db conn))))
(let [conn (fresh-conn)]
(ensure-conformity-attribute conn :test/conformity)
(is (= (count-txes conn) (do (ensure-conformity-attribute conn :test/conformity) (count-txes conn)))))))

0 comments on commit fe1f765

Please sign in to comment.