This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-01-15
Channels
- # aleph (1)
- # announcements (7)
- # beginners (6)
- # calva (24)
- # cider (18)
- # clj-otel (1)
- # clojars (8)
- # clojure (22)
- # clojure-dev (11)
- # clojure-europe (52)
- # clojure-finland (12)
- # clojure-nl (1)
- # clojure-norway (28)
- # clojure-uk (7)
- # clojured (1)
- # cursive (6)
- # datomic (1)
- # events (1)
- # humbleui (41)
- # hyperfiddle (75)
- # lsp (46)
- # malli (34)
- # matrix (1)
- # off-topic (16)
- # releases (1)
- # shadow-cljs (12)
- # squint (11)
- # timbre (1)
- # tools-deps (24)
Hello everyone, I'm trying to learn Malli and I was wondering. There are logical operators for the schema syntax such as [:or
[:and
[:=>
Are there any detailed documentation available as to how they operate?
I'm trying to write a schema for a messy data where i have a map such as
{:notification1 "stringValue"
;; several fixed keys from 1 to 24
:notification24 "stringValue"
;; Following key is user defined in an external source.
:<user-input> {;;homogenuous map of nodes
node-1-<user-input> {...}
node-2-<user-input> {...}}
}
Unfortunately I cannot modify the data structure at the source, only within my own application. Hence me trying to use Malli to transform it into a better format for my use. However I haven't been able to write a schema that successfully validates the random user input and the notification keys accurately.
Does anyone have pointers where I could look to learn how to write that schema successfully on http://malli.io for example?Hi, something like this?
(require '[malli.generator :as mg])
(mg/sample
[:map
[:notification :string]
[:notification24 :string]
[::m/default [:map-of {:gen/max 2} :string [:map-of {:gen/max 4} :string :map]]]])
;({:notification "", :notification24 ""}
; {:notification "", :notification24 "2"}
; {:notification "8", :notification24 "5y", "" {}}
; {:notification "Q", :notification24 "DD", "" {"S8K" {}}}
; {:notification "5O38", :notification24 ""}
; {:notification "v4W2",
; :notification24 "T",
; "9J" {"8" {}, "4rLwM" {}, "" {}, "KoQZ" {}},
; "0" {"kOro" {}, "Z" {}, "" {}}}
; {:notification "q6", :notification24 "", "2hxIz" {"e" {}}}
; {:notification "", :notification24 "", "0WVu" {}}
; {:notification "", :notification24 "egwdu"}
; {:notification "FBee", :notification24 "6UVm", "MjQ" {"M1Ig3" {}, "3O" {}, "a1t50QoD" {}}})
This was precisely what I was looking for. I did manage to validate the incomind data using a modified version of your example. I'm a bit embarrased that I managed to miss / not understand how the m/default and map-of syntax worked from the readme.md. Thank you kindly for the answer
Hello This is my first post in this channel I am just starting out with Malli (in my first clojure project at work), and run into a simple problem I can not solve. I want to validate a map that kan have either one key or the other. I try to do it like this, but it does not seem to work:
(def registry (merge (m/default-schemas) (mu/schemas)))
(m/schema
"data"
{:registry (merge registry {"dependency" [:map
[:data map?]
[:dependencies {:optional true} [:set [:ref "dependency"]]]
[:type string?]
[:update-path [:vector string?]]]
"data" [:union
[:or
[:map [:data map?]]
[:map [:dependencies {:optional true} [:set [:ref "dependency"]]]]]
[:map [:type {:optional true} string?]]]})})
So either :data or :dependencies should be there.
I would expect something like:
[:map [:or [:foo string?] [:bar string?]]]
But that does not work either.
The whole semantics of :union, :or & :merge are a bit unclear to me. Can someone give me a pointer?so this works:
(m/schema
[:and
[:map
[:foo {:optional true} number?]
[:bar {:optional true} number?]]
[:fn
{:error/message "either use :foo or :bar"}
(fn [m] (or (some? (get m :foo)) (some? (get m :bar))))]]
{:registry registry})
but I doubt this is the idiomatic way to do this...currently, there isn’t more idiomatic way to do that. See https://github.com/metosin/malli/issues/474
if someone can cook a good and simple syntax for defining the key requirements/dependencies, I'm all ears
thanks for the reply. With my limited understanding so far, you can use :or either on the :map level
[:or
[:map [:foo number?]
[:map [:bar number?]]
or on the value level
[:map [:foo [:or number? string?]]
but not on the property level:
[:map
[:or
[:map [:foo number?]
[:map [:bar number?]]
[:baz number?]
That would seem pretty straightforward, but as I mentioned, I'm not sure I fully understand :or yetThe entry-parser doesn't understand the :or
currently. How would you differentiate it from expected map key :or
?
I see your point. from that perspective it would perhaps have been nice to namespace all Malli keywords... What makes me wonder, in your last example
[:map
[::m/or [:map [:x :int]]]
Why the second :map?
I would think that if you :or on this level, it would express nested maps, which is not what's happening and so a little surprising.
What I would expect is semantics like this: suppose we have an address that can either be a zip code and a house number, or an city, a street name and a house number, I would not be surprised to see it expressed like this:
[:map
[:house-number number?]
[::m/or
[:zip-code string?]
[::m/and
[:city string?]
[:street-name string?]]]]
Exactly. Didn’t notice that my schema had a bug in it. Correct pair would be:
[:map
[:or [:map [:tuple :int]]]
vs.
[:map
[::m/or [:map [:tuple :int]]]
, with would mean (despite being silly):
"a map with EITHER a key :map key with :tuple of one :int OR nothing, e.g {:map [1]}"
, so exactly what you described in:
[:map
[:house-number number?]
[::m/or
[:zip-code string?]
[::m/and
[:city string?]
[:street-name string?]]]]
implementation of this would require a change in the map parser + internal data structure, so some amount of work.
Hi all, happy monday
I have been enjoying using malli.experimental
for instrumenting expected input / output shape.
I have a question about syntax. I have a lot of functions which look like this
(mx/defn my-function
[{:keys [file-type] :as env} :- [:map [:file-type :string]]]
...)
I would like to avoid having to duplicate the name of the key when writing the expected schema, and instead write something like
(mx/defn my-function
[{:keys [file-type :- :string] :as env}]
(+ 1 2 3))
however this doesn’t work, because clojure reads :-
and :string
as binding variables.
My questions are
• is this currently possible (i.e. labelling expected schema of a variable inside a destructuring expression)?
• if not, is this planned / is there a github issue I can track?
hope this makes sense, thanksHear you, just needs to implemented. Not sure if that would be even a big thing to do, but things like precedence should be thought.
Here are the schematized parse tests: https://github.com/metosin/malli/blob/master/test/malli/destructure_test.cljc#L171-L287 Would you be interested in writing a minimalistic but complete expectation and attach that into an new issue of this?
revisited te parser code, kinda dense, but there is not much of it as it's using malli for parsing 😉 https://github.com/metosin/malli/blob/master/src/malli/destructure.cljc
Hi all, good evening!
I'm having trouble with the strip-extra-keys-transformer
in conjunction with :and
schemas:
(m/decode
[:and [:map [:y :int]] [:map [:x :int]]]
{:x 1 :y 2 :z 3}
(mt/strip-extra-keys-transformer))
strips all keys, instead of stripping only :z
and keeping :x
and :y
.
I think this is a known issue, but the regular workaround of using :merge
doesn't really work for my use case: I'm relying on :and
to compose :map
schemas together, which works great for documentation as I can have options
on the composed schemas and use refs
(and a registry) for the components (e.g. [:and {:title "composed schema"} ::component1 [:map {:title "component 2"} [:a :int]]]
).
:merge
's options
are overridden by the last component, and I also lose refs
when it's converted to json-schema
.
Another issue is that I want to use strip-extra-keys-transformer
to implement select
(a la clojure.spec
), and for the same reason, m/coerce
also fails if I use it with strip-extra-keys-transformer
.
I tried extending strip-extra-keys-transformer
with a special case for :and
, and I was able to generate the complete keyset, but when the transformer descends into the children, it eventually drops all the keys (as long as all the children have a disjunct set of keys, which they almost always do in my case).
Could someone please help me with implementing a transformer that strips extra keys correctly for [:and [:map ..] [:map ..]]
schemas?Hmm. Interesting use case for :and
! It works if as long as you don't close the maps.
Can't recall the code, but what happens if you set the maps explicitly open with :closed false
property. Would that work?
The issue with :closed false
is that I would like to use the strip-extra-keys-transformer
to implement select-schema
(like metosin.schema-tools/select-schema
), and that wouldn't work if I leave the maps open.
By "options on the composed schema" I mean documentation keys like :title
, :description
:json-schema/format
etc. I'll write a better example in a bit. Update: I realize I've been using the wrong term options
while I actually meant properties
. Sorry for the confusion.
To repeat, the two issues are:
1. When using mallo.json-schema/transofrm
, :merge
also merges the options properties of the schemas that are being merged and doesn't retain the options properties for the root (e.g. with [:merge props a b c d]
, only the options properties of d
will remain).
2. ref
s also get resolved in the process
But even if both of these behaviours would be changed in :merge
, I would still want to keep using :and
, because in some cases it describes the intention and the purpose of the schema more accurately than :merge
.