diff --git a/CHANGELOG.md b/CHANGELOG.md index 333dbc4..99d4795 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## [0.7.6] - 2018-04-09 +### Added +- Call `spec->datomic-schema` within the `(clojure.spec.alpha/coll-of + clojure.spec.alpha/every)` case in `find-type-via-form` to further increase + performance. + ## [0.7.5] - 2018-03-21 ### Added - Call `spec->datomic-schema` within `find-type-via-form` to further increase diff --git a/README.md b/README.md index 1555d3a..04d0591 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Generate Datomic or Datascript schema from your Clojure(script) specs. [](dependency) ```clojure -[provisdom/spectomic "0.7.5"] ;; latest release +[provisdom/spectomic "0.7.6"] ;; latest release ``` [](/dependency) diff --git a/build.boot b/build.boot index cad7e19..8107e60 100644 --- a/build.boot +++ b/build.boot @@ -1,5 +1,5 @@ (def project 'provisdom/spectomic) -(def version "0.7.5") +(def version "0.7.6") (set-env! :resource-paths #{"src"} :source-paths #{"test"} diff --git a/src/provisdom/spectomic/core.clj b/src/provisdom/spectomic/core.clj index 84658e6..c13e5cf 100644 --- a/src/provisdom/spectomic/core.clj +++ b/src/provisdom/spectomic/core.clj @@ -105,13 +105,13 @@ (clojure.spec.alpha/coll-of clojure.spec.alpha/every) - (let [inner-type (find-type-via-generation (eval (second form)) custom-type-resolver)] + (let [inner-type (spec->datomic-schema (eval (second form)) custom-type-resolver)] (when (= :db.cardinality/one (:db/cardinality inner-type)) {:db/cardinality :db.cardinality/many :db/valueType (:db/valueType inner-type)})) clojure.spec.alpha/nilable - (spec->datomic-schema (second form)) + (spec->datomic-schema (eval (second form))) nil))))) @@ -133,6 +133,48 @@ :att [s {}] :att-and-schema s))))) +(defn- gen-spec-symbol + [fn-name] + (symbol (str "clojure.spec.alpha/" fn-name))) + +(defn merge-opt-keys + "Merges optional keys into requried keys using a spec's form/description" + [fspec] + (let [keymap (atom (into {} (map (fn [pair] (vec pair)) (partition 2 (rest fspec)))))] + (cond + (contains? @keymap :opt) + (swap! keymap assoc :req (vec (concat (@keymap :req) (@keymap :opt)))) + (contains? @keymap :opt-un) + (swap! keymap assoc :req-un (vec (concat (@keymap :req-un) (@keymap :opt-un))))) + (swap! keymap dissoc :opt :opt-un) + (cons (gen-spec-symbol "keys") (mapcat identity @keymap)))) + +(defn regenerate-spec + "Regenerates a spec with its optional keys merged into required keys" + [spec] + (let [fspec (s/form spec) + spec-sym (gen-spec-symbol "keys")] + (if (coll? fspec) + (if (= (first fspec) spec-sym) + (merge-opt-keys fspec) + (map + (fn [x] + (if (coll? x) + (if (= (first x) spec-sym) + (merge-opt-keys x) + x) + x)) + fspec)) + fspec))) + +(defn with-map-keys + "Extract out all the keys of composite specs and merge with the provided `schema-override-map`" + ([spec] (keys (sgen/generate (s/gen (eval (regenerate-spec spec)))))) + ([spec schema-override-map] + (map + (fn [s] (if (contains? schema-override-map s) [s (schema-override-map s)] s)) + (keys (sgen/generate (s/gen (eval (regenerate-spec spec)))))))) + (defn datomic-schema ([specs] (datomic-schema specs nil)) ([specs {:keys [custom-type-resolver] @@ -174,4 +216,12 @@ (s/or :spec qualified-keyword? :tuple (s/tuple qualified-keyword? ::spectomic/datascript-optional-field-schema))) :opts (s/? (s/nilable ::spectomic/schema-options))) - :ret ::spectomic/datascript-schema) \ No newline at end of file + :ret ::spectomic/datascript-schema) + +(comment +(defn- which-spec + [] + (if (find-ns 'clojure.spec.alpha) + 'clojure.spec.alpha + 'clojure.spec))) + diff --git a/test/provisdom/spectomic/core_test.clj b/test/provisdom/spectomic/core_test.clj index 69862cd..6776534 100644 --- a/test/provisdom/spectomic/core_test.clj +++ b/test/provisdom/spectomic/core_test.clj @@ -191,4 +191,21 @@ (deftest datascript-schema-transaction-test (let [schema (spectomic/datascript-schema test-schema-specs)] (testing "able to transact Spectomic generated schema to DataScript" - (is (ds/create-conn schema))))) \ No newline at end of file + (is (ds/create-conn schema))))) + + +(s/def :book/name string?) +(s/def :book/description string?) +(s/def ::book (s/keys :req [:book/name] :opt [:book/description])) + +(deftest datomic-schema-composite-spec-test + (let [expected-output [{:db/valueType :db.type/string + :db/cardinality :db.cardinality/one + :db/ident :book/name + :db/index true} + {:db/ident :book/description + :db/valueType :db.type/string + :db/cardinality :db.cardinality/one}] + actual-output (spectomic/datomic-schema (spectomic/with-map-keys ::book {:book/name {:db/index true}}))] + (is (= actual-output expected-output)))) +