ryoakg
4/17/2016 - 12:58 PM

prismatic-schema-example.clj

;;; `boot repl` to go
(set-env! :dependencies '[[prismatic/schema "1.1.0"]])
(require '[schema.core :as s])


;;; Atomic values
(s/validate java.math.BigDecimal 99999999999999.999M)

(s/validate #"\A\d{4}\z" "0123")
(s/validate #"\A\d{4}\z" "01234")       ;Value does not match !!

(s/validate (s/enum :a :b) :a)
(s/validate (s/enum :a :b) :c)          ;Value does not match !!

(s/validate (s/maybe s/Keyword) :a)
(s/validate (s/maybe s/Keyword) nil)
(s/validate (s/maybe s/Keyword) 1)      ;Value does not match !!

(s/validate (s/eq :a) :a)
(s/validate (s/eq :a) :b)               ;Value does not match !!


;;; Map
(s/validate {:a s/Num} {:a 1})
(s/validate {:a s/Num} {:a "1"})        ;Value does not match !!

;; succeed
(s/validate {:a s/Any} {:a 1})
(s/validate {:a s/Any} {:a "a"})

;; {:a missing-required-key} !!
(s/validate {:a s/Any} {})
(s/validate {(s/required-key :a) s/Any} {})

;; {:b disallowed-key} !!
(s/validate {:a s/Any} {:a 1 :b 2})

;; succeed
(s/validate {(s/optional-key :a) s/Any} {})
(s/validate {(s/optional-key :a) s/Any} {:a 1})


;;; Seq
(s/validate [s/Num] [1])
(s/validate [s/Num] [1 2])
(s/validate [s/Num] [1 2 "3"])          ;Value does not match !!

(def seq-schema
  [(s/one s/Str "s1")              ;=> implies the first element.
   s/Num                           ;=> implies all follewing elements.
   ])
(s/validate seq-schema ["1" 2])
(s/validate seq-schema ["1" 2 3])
(s/validate seq-schema ["1" 2 3 4])
(s/validate seq-schema ["1" 2 3 4 "5"]) ;Value does not match !!

(def valid-seq-schema
  [(s/one s/Str "s1")
   (s/one s/Num "ns")
   (s/optional s/Keyword "k")])
(s/validate valid-seq-schema ["1" 3 :k]) ;=> ["1" 3 :k]
(s/validate valid-seq-schema ["1" 3]) ;=> ["1" 3]

(def invalid-seq-schema
  [(s/one s/Str "s1")
   (s/optional s/Keyword "k")
   (s/one s/Num "ns")])
(s/validate invalid-seq-schema ["1" :k 3])
;; [#schema.core.One{:schema java.lang.String, :optional? false, :name "s"}
;;  #schema.core.One{:schema Keyword, :optional? true, :name "k"}
;;  #schema.core.One{:schema java.lang.Number, :optional? false, :name "s2"}]
;; is not a valid sequence schema; a valid sequence schema consists of
;; zero or more `one` elements, followed by zero or more `optional`
;; elements, followed by an optional schema that will match the
;; remaining elements.


;;; Record
(s/defrecord SomeRec
    [a :- Long
     b :- [s/Str]])

(s/validate SomeRec (SomeRec. 1 ["a"]))
(s/validate SomeRec (SomeRec. "1" ["a"])) ;Value does not match !!
(s/validate SomeRec (SomeRec. 1 "a"))     ;Value does not match !!


;;; AND
(let [schema (-> s/Int
                 (s/constrained #(<= 1 % 12) "月")
                 (s/constrained #(= 0 (mod % 3)) "3で割り切れる"))]
  [(s/check schema 1)
   (s/check schema 0)
   (s/check schema 12)])
;; => [(not ("3で割り切れる" 1)) (not ("月" 0)) nil]

;;; OR
(let [schema (s/conditional integer? (-> s/Int (s/constrained #(<= 0 % 6) "曜日"))
                            keyword? (s/enum :* :sun :mon :tue :wed :thu :fri :sat))]
  [(s/check schema 1)
   (s/check schema :sun)
   (s/check schema :foo)
   (s/check schema "foo")])
;; => [nil nil (not (#{:wed :* :sat :tue :fri :sun :mon :thu} :foo)) (not (some-matching-condition? "foo"))]

;;; predicate
(let [schema (s/pred #(#{1 "1" :1} %) "1です")]
  [(s/check schema 1)
   (s/check schema "1")
   (s/check schema :1)
   (s/check schema "foo")])
;; => [nil nil nil (not ("1です" "foo"))]


;;; Function
(s/defn some-function :- s/Int
  [a :- s/Num]
  (+ a 1))

(s/with-fn-validation (some-function 1)) ;=> 2
(s/with-fn-validation (some-function "1")) ;=> Input to some-function does not match !!
(s/with-fn-validation (some-function 1.1)) ;=> Output of some-function does not match