Fork me on GitHub
#malli
<
2024-03-20
>
mkvlr08:03:22

is there a way to specify what keys a map has to contain, without saying what that key is?

(malli.core/validate [:map [:my/uuid uuid?]] {:my/uuid (random-uuid)}) ;; works
(malli.core/validate [:map {:registry {:my/uuid uuid?}} :my/uuid] {:my/uuid (random-uuid)}) ;; also works
(malli.core/validate [:map :my/uuid] {:my/uuid (random-uuid)}) ;; throws :malli.core/invalid-schema

escherize15:03:11

you mean like [:map [:my/uuid :any]] ?

escherize15:03:41

[:map :my/uuid] is not a valid schema, there

mkvlr16:03:13

that’s sort of my question

mkvlr16:03:31

can I not specify that the key is needed, without saying what is in the key?

escherize16:03:17

you can, and that is how

mkvlr16:03:50

then I do say that the value is any?

escherize16:03:42

I must not understand your question

mkvlr16:03:22

as I understand it, clojure.spec made the intentional choice to separate what keys are in a map, from what the contents of these keys are, see https://clojure.org/about/spec#_map_specs_should_be_of_keysets_only and https://clojuredocs.org/clojure.spec.alpha/keys. I was wondering if there’s a similar construct in malli.

mkvlr16:03:51

I can’t find a way to specify a key being required without a spec.

escherize16:03:33

what use case does putting :any not cover for that? an example will help

mkvlr16:03:33

it doesn’t reflect what I actually want to say, which is I may or may not specify this spec elsewhere, but it probably won’t be any?

mkvlr16:03:04

(I haven’t tried yet how [:map [:my/uuid any?]] would interact with the global registry)

ambrosebs18:03:19

I don't think malli checks namespaced keys that aren't declared in the :map though.

ambrosebs18:03:09

i.e., I don't think it has this feature of keys:

In addition, the values of *all* namespace-qualified keys will be validated
(and possibly destructured) by any registered specs.

mkvlr18:03:52

yes, the qualified keys in a map example with the local registry is my second example but it fails without a registry argument

ambrosebs18:03:18

Yes sorry didn't fully understand your example at first.

ambrosebs18:03:03

Looking at the implementation of :map I don't think this is supported by :map. Could do this:

user=> (m/validate [:and [:map] [:fn `#(contains? % :my/key)]] {})
false
user=> (m/validate [:and [:map] [:fn `#(contains? % :my/key)]] {:my/key true})
true

ambrosebs18:03:32

The generator would need tweaking though.

mkvlr20:03:08

@U055XFK8V is :map a generator? Do you think supporting (malli.core/validate [:map :my/uuid] {:my/uuid (random-uuid)}) could be a sensible addition to the syntax?

ambrosebs20:03:32

I mean that trying to generate values will fail:

user=> (mg/generate [:and [:map] [:fn `#(contains? % :my/key)]])
Execution error (ExceptionInfo) at clojure.test.check.generators/fn (generators.cljc:435).
Couldn't satisfy such-that predicate after 100 tries.
Will need a property like :gen/fmap to fix it:
user=> (mg/generate [:and [:map {:gen/fmap `#(assoc % :my/key :whatever)} ] [:fn `#(contains? % :my/key)]])
#:my{:key :whatever}
Could probably make a case for at least supporting a property for the behavior you want, like say [:map {:unregistered-qualified-kw true} ...] .

mkvlr20:03:40

ah right, thanks for the explanation!

👍 1
mkvlr09:03:15

also noticed when running the example from https://github.com/metosin/malli/blob/master/docs/function-schemas.md#development-instrumentation that I needed to add a call to (mi/instrument!) for the example to throw. Is that expected? This was with malli 0.11, trying 0.14… Same there.