Can you explain?
Perhaps an example is best.
(s/def ::order (s/schema [:order/id
:order/type
:order/a
:order/b
:order/c]))
(s/def :user/orders (s/coll-of ::order))
(s/def ::user (s/schema [:user/orders]))
(s/select ::user [:user/orders {:user/orders [:order/id
:order/type
;; if :order/type is :order.type/a then require :order/a
]}])
The required order keys depend on the order's type.I only require :order/a when :order/type is :order.type/a.
So it is a separate schema for order?
What do you mean?
Iโm curious (never used spec2) as well. My intuition is that you are trying to solve something with select when it should be a separate schema for order types. But I have to think about it/read a bit more ๐
Sorry, I don't understand what you mean by separate schema. Could you clarify?
using spec/or to distinguish the order types
and each order type has a separate spec that holds the context of order/a order/b etc
Oh. Yes, that is possible here. It results in really bad error messages though (if you have a bad input, every single case of the or is outputted). multi-specs output a really nice error.
In our case there may be hundreds of different "types". The explain-data is crazy ๐ต
i see
have you tried to parse explain-data to kind of narrow it down? just talking off my ass here
You can manipulate the output however you normally would ๐ The thing is, multi-specs solve this problem nicely (albeit a bit cumbersome to work with). They just don't work with select, and it seems that there is a good fit for something there.
ah I see it now!
So I was curious if there were any thoughts on how/if something like this would be a part of spec2. For us, this use case happens everywhere.
since select is just a spec too, then you would dispatch with a multimethod too right?
so it would be something like (defmulti order-type :order/type...
each returning a select
that is specifically tailored to query a variant
Not sure I follow how that'd work with the above.
me neither ๐
The main thing is that you always declare required keys "top-level." Pretty sure what you have there wouldn't work :thinking_face:
got me hooked Iโm going to play a bit with spec2 now
what do you mean with required keys?
schema keys are not required
No matter the "level" (read nesting) you're at, you're always able to select which keys are required.
(s/def ::order (s/schema [::order-id
::order-type
::order-a
::order-b
::order-c]))
(s/def ::orders (s/coll-of ::order))
(defmulti order-type ::order-type)
(defmethod order-type ::order.type-a [_]
(s/select ::order [::order-a]))
(defmethod order-type ::order.type-b [_]
(s/select ::order [::order-b]))
(s/def ::order-typed (s/multi-spec order-type ::order-type))
(s/valid? ::order-typed {::order-type ::order.type-b ::order-b "foo"})
(s/def ::orders-typed (s/coll-of ::order-typed))
(s/valid? ::orders-typed [{::order-type ::order.type-b ::order-b "foo"}])
You've changed the problem ๐
I get the feeling that I didnโt understand it in the first place
๐
At the level of the "user" map, I want to select what keys are required in each map under :user/orders.
Without renaming my :user/orders key.
i see but those are different specs
Same schema, different selected keys.
the schema doesnโt know about select (just tried it)
i have to leave it at that (itโs late) but was fun so far. maybe someone actually knowledgeable can find a better way
Not sure what you mean exactly ๐ This is what I'd like.
(s/select ::user [:user/orders {:user/orders [:order/id
:order/type
;; if :order/type is :order.type/a then require :order/a
]}])
What I mean is that Iโm still a beginner with these things. I donโt really see a solution right now other than dispatching the select and conform/validate on the select spec.
Oh, I understand. Yes, I was 99% certain spec2 does not cover this. I am interested in thoughts on this particular problem and how spec2 might solve it.
i mean this sound pretty powerful (from the wiki): https://github.com/clojure/spec-alpha2/wiki/Differences-from-spec.alpha#creating-specs-programmatically
For sure! I'm confident something could be built to solve this (likely even in spec1). Curious if this use-case is in scope for spec2 though. It seems like a core problem.