What would be the preferred way to select one spec from multi-spec? E.g.
(defmulti entity :entity)
(s/def ::e1
(s/keys :req [:e1/attr1
:e1/attr2
:e1/attrN]))
(defmethod entity :e1 [_] ::e1)
(s/def ::e2
(s/merge
::e1
(s/keys :req [:e2/attr1
:e2/attr2
:e2/attrN])))
(defmethod entity :e2 [_] ::e2)
(s/def ::entity (s/multi-spec entity :entity))
How to spec a function that accepts only ::e2
entity as an argument? ... or how to generate only ::e2
entity values?
Can't do (s/cat :e2 ::e2)
or (s/gen ::e2)
because ::e2
doesn't have the required :entity
tag. Also, can't add :req-un [:e1/entity]
and :req-un [:e2/entity]
to ::e1
and ::e2
because it would clash in the s/merge
.
The simplest way I've found is to use s/and
, e.g:
(gen/generate (s/gen (s/and ::entity ::e2)))
But it is still hard to generate data for functions that accept homogeneous collection of any entity:
(s/and (s/coll-of ::entity :min-count 1)
#(->> % (map :entity) (apply =)))
It would be easier if you could pass the entity tag to select the specific entity spec or it's generator, e.g. generate random entity and based on it's entity tag generate other elements.
In other words, I am looking for a way to get ::e2
entity spec via :e2
tag somehow, without maintaining a global helper map...
Or is there any other solution?