Skip to content

Commit

Permalink
impl const
Browse files Browse the repository at this point in the history
  • Loading branch information
niquola committed Nov 12, 2020
1 parent 87f87a9 commit 0c6d0a4
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
language: clojure
script: make test
jdk:
- oraclejdk11
- oraclejdk9
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,23 @@ List of built-in types:
* zen/vector
* zen/set
* zen/map
* zen/union-map
* zen/union
* zen/case

### zen/case

`zen/case` is alternative to union type,
it is more advanced and may be applied to different maps

```edn

{:zen/tags #{'zen/schema}
:type 'zen/vector
:every {:type 'zen/case
:case [{:when {:type 'zen/string}}
{:when {:type 'zen/map}
:then {:type 'zen/map :require #{:name} :keys {:name {:type 'zen/string}}}}]}}

```

### zen/symbol

Expand Down
12 changes: 9 additions & 3 deletions pkg/zen.edn
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,15 @@
:type map
:schema-key {:key :type}
:keys {:type {:type symbol}
:confirms {:type set :every {:type symbol}}
:enum {:type vector :every {:type map
:keys {:value {:type any}}}}}
:confirms {:type set
:zen/desc "set of schemas to confirm"
:every {:type symbol}}
:const {:type map
:zen/desc "Check constant"
:keys {:value {:type any}}} ;; TODO: apply top level schema to value
:enum {:type vector
:zen/desc "Check value is in enum"
:every {:type map :keys {:value {:type any}}}}}
:require [:type]}

resource {:zen/tags #{schema}
Expand Down
39 changes: 22 additions & 17 deletions src/zen/validation.clj
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,13 @@
(when (contains? (get-in @ctx [:tags 'zen/property]) sym)
(get-symbol ctx sym))))

;; TODO:
;; * validate keys
;; * minItems/maxItems
(defmethod validate-type 'zen/map
[_ ctx acc {cfs :confirms ks :keys vls :values reqs :require eks :exclusive-keys} data]
[_ ctx acc {ks :keys vls :values reqs :require eks :exclusive-keys} data]
(if (map? data)
(let [acc (->> cfs
(reduce (fn [acc sym]
(if-let [sch (get-symbol ctx sym)]
(-> (validate-schema ctx (update-acc ctx acc {:schema [sym]}) sch data)
(restore-acc acc))
(add-error ctx acc {:message (format "Could not resolve schema '%s" sym) :type "schema"})))
acc))
acc (->> data
(let [acc (->> data
(reduce (fn [acc [k v]]
(if-let [sch (get ks k)]
(let [acc' (validate-schema ctx (update-acc ctx acc {:path [k] :schema [k]}) sch v)
Expand Down Expand Up @@ -212,20 +208,29 @@
acc
(add-error ctx acc {:message (format "Expected type of 'regex, got '%s" (pretty-type data)) :type "primitive-type"})))

(defn validate-schema [ctx acc {tp :type {sk :key} :schema-key ks :keys cfs :confirms :as schema} data]
(defn validate-schema [ctx acc {tp :type {sk :key} :schema-key const :const enum :enum cfs :confirms :as schema} data]
(try
(let [acc (if-let [sch-nm (and sk (get data sk))]
(let [acc (if const
(if (= (:value const) data)
acc
(add-error ctx acc {:message (format "Expected '%s', got '%s'" (:value const) data) :type "schema"}))
acc)
acc (->> cfs
(reduce (fn [acc sym]
(if-let [sch (get-symbol ctx sym)]
(-> (validate-schema ctx (update-acc ctx acc {:schema [sym]}) sch data)
(restore-acc acc))
(add-error ctx acc {:message (format "Could not resolve schema '%s" sym) :type "schema"})))
acc))
acc (if-let [sch-nm (and sk (get data sk))]
(if-let [sch (and sch-nm (get-symbol ctx sch-nm))]
(-> (validate-schema ctx (update-acc ctx acc {:schema [:schema-key sch-nm]}) sch data)
(restore-acc acc))
(add-error ctx acc {:message (format "Could not find schema %s" sch-nm) :type "schema"}))
acc)]
(cond
tp (validate-type tp ctx acc schema data)

(or ks cfs) (validate-type 'zen/map ctx acc schema data)

:else (add-error ctx acc {:message (format "I don't know how to eval %s" (pr-str schema)) :type "schema"})))
(if tp
(validate-type tp ctx acc schema data)
(add-error ctx acc {:message (format "I don't know how to eval %s" (pr-str schema)) :type "schema"})))
(catch Exception e
(add-error ctx acc {:message (.getMessage e)
:type "schema"}))))
Expand Down
50 changes: 47 additions & 3 deletions test/zen/validation_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
'maps-case {:zen/tags #{'zen/schema}
:type 'zen/case
:case [{:when {:type 'zen/map
:require #{:person}
:keys {:person {:type 'zen/boolean}}}
:require #{:person}
:keys {:person {:type 'zen/boolean}}}
:then {:type 'zen/map
:require #{:name}
:keys {:name {:type 'zen/string}}}}
Expand All @@ -38,6 +38,14 @@
:require #{:title}
:keys {:title {:type 'zen/string}}}}]}

'const {:zen/tags #{'zen/schema}
:type 'zen/string
:const {:value "fixed"}}

'const-map {:zen/tags #{'zen/schema}
:type 'zen/map
:keys {:fixed {:type 'zen/string}}
:const {:value {:fixed "fixed"}}}

'Address {:zen/tags #{'zen/schema}
:type 'zen/map
Expand Down Expand Up @@ -171,6 +179,10 @@
(vmatch #{'myapp/User} {:name "niquola" :identifiers [1 {:ups "ups"}]}
{:errors
[{:message "Expected type of 'map, got 1",
:type "type",
:path [:identifiers 0],
:schema ['myapp/User :identifiers :every 'myapp/Identifier]}
{:message "Expected type of 'map, got 1",
:type "type",
:path [:identifiers 0],
:schema ['myapp/User :identifiers :every]}
Expand Down Expand Up @@ -346,5 +358,37 @@
:path [],
:schema ['myapp/maps-case :case]}]})

)
(vmatch #{'myapp/const} "ups"
{:errors
[{:message "Expected 'fixed', got 'ups'",
:type "schema",
:path [],
:schema ['myapp/const]}]})

(vmatch #{'myapp/const} "fixed"
{:errors empty?})

(vmatch #{'myapp/const} 1
{:errors
[{:message "Expected 'fixed', got '1'",
:schema ['myapp/const]}
{:message "Expected type of 'string, got 'long",
:schema ['myapp/const]}]})

(vmatch #{'myapp/const-map} {:fixed "fixed"}
{:errors empty?})

(vmatch #{'myapp/const-map} {:fixed "ups"}
{:errors
[{:message "Expected '{:fixed \"fixed\"}', got '{:fixed \"ups\"}'",
:type "schema",
:path [],
:schema ['myapp/const-map]}]})

(vmatch #{'zen/schema}
{:zen/tags #{'zen/schema}
:type 'zen/string
:const {:value 1}}
{:errors [{}]})

)

0 comments on commit 0c6d0a4

Please sign in to comment.