Created
November 2, 2015 09:44
-
-
Save remvee/936b21e03add793e55e6 to your computer and use it in GitHub Desktop.
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 #^{:author "Remco van 't Veer" | |
:doc | |
"Basic validation framework for maps. The constructed validator | |
functions take two arguments the before- and after state of the map. | |
They return a map of errors where keys are, typically, keys of the | |
input map and values are lists of keyworded errors or maps of keyword | |
errors to some relevant argument. For example: | |
((validator (not-blank :nr) | |
(numeric :nr) | |
(less-than 10 :count)) | |
{} {:count 20}) | |
Returns: | |
{:count [{:less-than 10}], :nr [:not-blank :numeric]}"} | |
remvee.validations | |
(:use [clojure.test])) | |
(defn not-blank | |
"Attribute may not be nil or empty string validation." | |
[k] | |
(fn [_ v] | |
(when (or (nil? (k v)) | |
(= "" (k v))) | |
{k [:not-blank]}))) | |
(defn numeric | |
"Attribute must be numeric validation." | |
[k] | |
(fn [_ v] | |
(when (not (number? (k v))) | |
{k [:numeric]}))) | |
(defn less-than | |
"Attribute must be less then validation." | |
[amount k] | |
(fn [_ v] | |
(when (and (number? (k v)) | |
(< amount (k v))) | |
{k [{:less-than amount}]}))) | |
(defn unique | |
"Attribute must be uniq to collection returned by collfn." | |
{:test #(are [before after coll expected-errors] | |
(= expected-errors ((unique (fn [] coll) :id) before after)) | |
nil ; before | |
{} ; after | |
[] ; coll | |
nil ; errors | |
nil ; before | |
{:id 1} ; after | |
[] ; coll | |
nil ; errors | |
nil ; before | |
{:id 2} ; after | |
[{:id 1}] ; coll | |
nil ; errors | |
{:id 1} ; before | |
{:id 1 :foo 1} ; after | |
[{:id 1}] ; coll | |
nil ; errors | |
nil ; before | |
{:id 1} ; after | |
[{:id 1}] ; coll | |
{:id [:unique]} ; errors | |
{:id 1 :bar 1} ; before | |
{:id 1 :foo 1} ; after | |
[{:id 1}] ; coll | |
{:id [:unique]} ; errors | |
)} | |
[collfn k] | |
(fn [a b] | |
(when (some #(= (k b) (k %)) | |
(filter (partial not= a) | |
(collfn))) | |
{k [:unique]}))) | |
(defn validator | |
"Return function to collect errors with validators. The errors from | |
the validators will be merged with concat." | |
{:test #(are [input errs] | |
(= errs ((validator (not-blank :name) | |
(not-blank :nr) | |
(numeric :nr) | |
(less-than 10 :count)) | |
{} input)) | |
{:nr 1, :name "test", :count 5} | |
nil | |
{:foo "bar"} | |
{:name [:not-blank], :nr [:not-blank :numeric]} | |
{:nr "foo"} | |
{:name [:not-blank], :nr [:numeric]} | |
{:nr 1, :name "test", :count 11} | |
{:count [{:less-than 10}]})} | |
[& validators] | |
(reduce (fn [c f] | |
(fn [a b] | |
(merge-with concat | |
(c a b) | |
(f a b)))) | |
(fn [_ _] nil) | |
validators)) | |
(defn meta-errors-validator | |
"Return a validator function which decorates the result map with a | |
meta map with error entry." | |
[& validators] | |
(let [f (apply validator validators)] | |
(fn [a b] | |
(if-let [e (f a b)] | |
(with-meta b (merge (meta b) {:errors e})) | |
b)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment