Closed mindbound closed 3 weeks ago
The design of either is that it will match the first schema that validates the object. Dictionary is also a bit softer now and doesn't complain about unknown entries by default. So strictly speaking, this behaviour is correct, but I agree that it's counterintuitive at best and undesirable at worst.
Just at work at the moment but I'll have a play around so see what solution might work best, though I'd very much appreciate your input.
My first thought is a mutual exclusivity parameter on either, but I think I might need to add per-schema z-ctx
management to change dictionary too. I'll post some proofs of concept later, if you can let me know which one "feels" best.
Sure, I'll comment on your proposed proofs of concept, this seems like a logical extension to the either
behaviour.
Right so having untangled the bug a bit, here's what was happening:
Either accepts the first schema that validates the object as being the correct one, and it does so by asking if its validation step returned anything (or, not none
). Dictionaries are kind of special in that they return an empty dictionary even when they fail because it makes things a bit easier on the end programmer. Specifically, they return either an empty dictionary, or the input dictionary. A step in a dictionary validation is insert child fields, which come from the validation step of those children (themselves sometimes returning none
if validation fails). It means you got failed validations that returned non-empty dictionaries.
Phew.
This lead to a few big changes, which I'll outline below:
strict
context parameter (defaulting to false) to check in all fields in given dictionary are present in the schema and vis versa (previously, it only checked if all the schema entries were present in the given dictionary)either
schema generator function now takes a parameter strict
(defaulting to true) to set the strict
context parameter on its children. This is a breaking change that fixes the bug you've brought upnone
. This is quite a big breaking change the package previously guaranteed that fields defined in schema would have keys defined in validated objects (even if that value was none
). I think doing it this way is better, but its still a big change so I won't merge until everyone has a good chance to test it out first.Changes are made available on this development branch: https://github.com/typst-community/valkyrie/tree/27-mutually-exclusive-choices-in-either
For reference, this is how your code would look:
#let schema = z.either(
strict: true,
z.dictionary((
seed: z.integer(),
)),
z.dictionary((
dynamic: z.boolean(),
)),
)
LGTM! I'll test this and let you know if anything unexpected comes up.
I could also see a distinct z.object()
or something, referring to a strict dictionary
Everything seems to be working fine for me.
Is it possible to set
either
to have mutually exclusive choices, e.g. where only one ofcan be the case but not both?
I might be doing something wrong but this schema seems to pass even when there's a dictionary with both fields present.