Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

schema generation for composite specs #11

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion build.boot
Original file line number Diff line number Diff line change
@@ -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"}
Expand Down
56 changes: 53 additions & 3 deletions src/provisdom/spectomic/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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)))))

Expand All @@ -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]
Expand Down Expand Up @@ -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)
:ret ::spectomic/datascript-schema)

(comment
(defn- which-spec
[]
(if (find-ns 'clojure.spec.alpha)
'clojure.spec.alpha
'clojure.spec)))

19 changes: 18 additions & 1 deletion test/provisdom/spectomic/core_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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)))))
(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))))