-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for constraint schemas: This, that, or both keys in map #474
Comments
Current solution: (def Schema
[:and
[:map
[:x boolean?]
[:y {:optional true} int?]
[:z {:optional true} string?]]
[:fn {:error/message "y & z are mutually exclusive"
:error/path [:y]}
(fn [{:keys [z y]}]
(not (and z y)))]])
(-> Schema
(m/explain {:x true :y 1 :z "hi"})
(me/humanize))
; => {:y ["y & z are mutually exclusive"]} Future: a declarative way to do this, something like https://github.com/bsless/malli-keys-relations |
actually, this is duplicate of #438. As this has more info, will close the other one. |
What do you think about a datalog-like syntax for describing the constraints? Something like a simplified |
I was thinking of using meander. I think both could be tested "on paper" for few sample cases to get more insight on how they would/not work. Code syntax samples into this thread? |
Sure, I'll whip up a few examples |
I considered two notations, one as property and one as a standalone schema: [:map
{:where
'[[?e :x ?x]
[?e :y ?y]
[(< ?x ?y)]]}
[:x int?]
[:y int?]]
[:and
[:map
[:x int?]
[:y int?]]
[:where
'[[?e :x ?x]
[?e :y ?y]
[(< ?x ?y)]]]] I'll with the property notation for brevity. [:map
{:in '?e
:where
'[[?e :x ?x]
[?e :y ?y]
[(< ?x ?y)]]}
[:x int?]
[:y int?]] Binding intermediate values: [:map
{:in '?e
:where
'[[?e :x ?x]
[?e :y ?y]
[(count ?x) ?n]
[(< ?n ?y)]]}
[:x [:vector int?]]
[:y int?]] Nested maps: [:map
{:in 'e?
:where
'[[?e :x ?x]
[?x :z ?z]
[?e :y ?y]
[(== ?z ?y)]]}
[:x [:map [:z int?]]]
[:y int?]] "every" syntax: [:map
{:in '?e
:where
'[[?e :x [?x :as ?xs]]
[?x :z ?z]
[?e :y ?y]
[(count ?xs) ?n]
[(< ?x ?n)]
[(== ?z ?y)]]}
[:x [:vector [:map [:z int?]]]]
[:y int?]] Implicit unification: [:map
{:in '?e
:where
'[[?e :x [?x :as ?xs]]
[?x :z ?y]
[?e :y ?y]
[(count ?xs) ?n]
[(< ?x ?n)]]}
[:x [:vector [:map [:z int?]]]]
[:y int?]] Mutual exclusion (can't have a situation where both 2 and 3 succeed), this is also a "contains" syntax. [:map
{:in '?e
:where
'[[?e :x ?x] ;1
(not
[?e :y] ;2
[?e :z])]} ;3
[:x int?]
[:y int?]
[:z int?]] I tried to introduce as few innovations as possible with this syntax. What do you think? |
Thanks for your thoughts @bsless! I think the separate But, not ready on committing to an official malli relations-mapping solution yet, so if you would like to implement that, it could start as an add-on lib. Will try to resolve the global registry so that it's easy to plug-in custom schema types from 3rd party libraries. cheers. |
Sounds good. One issue I'd appreciate directions on is how to compile it to be performant. A naive approach would be building up a map of all the bindings, but where's the fun in that? Can it be done with functions? Do I need some CPS magic? |
not an datalog perf expert, there is #datalog chan in clojurians, maybe people there can share insights. I believe Asami has a fast imp (https://github.com/threatgrid/asami) |
I figured I can use malli to parse the query :) |
First not so successful attempt at translating the datalog spec directly to malli |
Update: the parser works. Data patterns are a bit too general so I'm considering adding specialized EA and EAV patterns but they're slightly ugly. |
I also ran into this problem, and we discussed it on slack. I tried something like
but that didn't work out. I also tried a lot of stuff with
This seems to say: a map with property :x, and a map with property :y, a map with property :z or a map with property :y and property :z.
The top level map suggests that everything here happens in the context of a single map.
This kind of syntax would honor the principle of least astonishment (dear to my heart) for me, but Tommi pointed out that te problem with this is that Malli can in this case not distinguish :or & :and from properties in the map. I guess a combination of :or and :map is used for that. so, for completeness:
To me this kind of syntax feels most familiar, it is what I would expect to have to write. |
I also hope something like @ebunders suggested works one day as the syntax is more explicit and easier to maintain than the current :fn workaround |
I'm just getting started with Malli, and I really like it!
There is something I can't figure out.
Consider this schema:
Now imagine I want to require
:y
,:z
, or both such that:Attempt 1
Attempt 2
That's not good!
Attempt 3
This seems to work, but there's a bit of repetition.
The errors are pretty good, but perhaps they could be better if I did this the right way:
What's the best way to do this?
The text was updated successfully, but these errors were encountered: