When using prismatic/schema, validation of enum on defrecord doesn't work, as shown here:
(s/defrecord Action [type :- (s/enum :a :b)])
#'user/strict-map->Action
user> (Action. "3") ; this should fail
#user.Action{:type "3"}
user> (Action. 1) ; this should fail
#user.Action{:type 1}
user> (Action. "abc") ; this should fail
#user.Action{:type "abc"}
However, when I change enum to long, it works as expected:
(s/defrecord ThisWorks [type :- long])
#'user/strict-map->ThisWorks
user> (ThisWorks. 3)
#user.ThisWorks{:type 3}
user> (ThisWorks. "abc")
ClassCastException java.lang.String cannot be cast to java.lang.Number user/eval11888 (form-init4803894880546699153.clj:1)
Does anybody know? Thank you so much.
Because you can switch on and off validation during runtime your Records aren't actually checked until you pass them into a function:
(s/defrecord Action [type :- (s/enum :a :b)])
(s/defn process-action [x :- Action])
(process-action (Action. "3")) ;; => Exception
Regarding long
magically working. This is just special clojure behavior due to primitives:
fields can have type hints, and can be primitive
note that currently a type hint of a non-primitive type will not be used to constrain the field type nor the constructor arg, but will be used to optimize its use in the class methods
constraining the field type and constructor arg is planned
(s/defrecord PrimitveRec [foo :- long])
(s/defrecord NonPrimitveRec [foo :- String])
(.? NonPrimitveRec :field #"foo" :type)
;=> (java.lang.Object)
(.? PrimitveRec :field #"foo" :type)
;=> (long)
Where .?
is from Vinyasa.