This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-09-13
Channels
- # announcements (1)
- # babashka (12)
- # beginners (10)
- # biff (9)
- # calva (2)
- # cherry (21)
- # cider (14)
- # clj-commons (76)
- # clj-kondo (8)
- # clj-on-windows (34)
- # cljs-dev (5)
- # clojure (48)
- # clojure-austin (7)
- # clojure-europe (97)
- # clojure-nl (1)
- # clojure-norway (14)
- # clojure-uk (22)
- # clojurescript (137)
- # conjure (33)
- # cursive (4)
- # datalevin (1)
- # deps-new (4)
- # devcards (2)
- # duct (3)
- # events (1)
- # fulcro (12)
- # graphql (9)
- # hyperfiddle (16)
- # jobs (8)
- # kaocha (1)
- # leiningen (6)
- # lsp (39)
- # malli (38)
- # membrane (20)
- # nbb (68)
- # observability (7)
- # off-topic (49)
- # pathom (11)
- # polylith (8)
- # portal (22)
- # re-frame (6)
- # releases (1)
- # remote-jobs (2)
- # shadow-cljs (24)
- # spacemacs (2)
- # squint (6)
- # xtdb (7)
Is there a decoder for malli schema itself from JSON?
For instance if I have this schema:
[:map [:key {:optional true} :string]]
Can I parse it from this JSON?
["map",
["key", { "optional": true }, "string"]
]
[:map ["key" {:optional true} :string]]
is also a valid schema, so one can’t guess from the JSON example that the "key"
should be handled as a keyword.
but, if someone would write schemas of all malli schema syntaxes, one could do everything else (but not guess the string->kw things)
Ok. That means that a dumbed-down version would work :thinking_face:
yes. If you want all maps to have keyword keys, you can:
1. read in from json
2. clojure-walk all vectors to have first arg as keyword
3. m/schema
4. m/walk and convert all map keys into keyword
5. profit
There is also a difference between keyword
and symbol
.
And that's also significant because :inst?
,`inst?` and "inst?"
are different :thinking_face:
maybe Tagged JSON? https://github.com/metosin/jsonista#tagged-json
I was thinking about dumbing down the schema and making everything a keyword or a number :thinking_face: I don't need all power.
If you know all your map keys are going to be keywords, you could use walker and transform to change map keys to keywords from strings, in the read schema.
Or you if just write limited Malli schema for the Malli schemas you need to support, you can use :keyword
there to read the JSON strings as keys for the map keys.
I was thinking about making a subset of malli by doing something similar to a custom parser.
And then use :inst
instead of inst?
and :number
instead of number?
to make it all very uniform for the reader and parser. And after parsing I would do clojure.walk/postwalk
or something similar to replace into the functions that malli understands.
So I should probably implement parsing for all basic types, :map
, :set
and some basic options like :optional
. I think I don't need seq regex matching in this specific use as this will only be used to define a data structure and sequences, maybe lists with order too but there shouldn't be tuples.
Hey! Just discovered malli, and it looks like it does a lot of the things I need it for 😃 Could be I’ve missed something in the README, but one thing that isn’t immediately apparent to me, is if/how I can do validation of values that reference other attributes? So say that I have a map like:
{
"min": 10,
"max": 20
}
and I want to ensure that the min
value is never greater than the value for max
, etcThe malli playground is a great place to discover malli features. Maybe https://malli.io/?value=%7B%3Ax%201%2C%20%3Ay%202%7D&schema=%5B%3Aand%0A%20%5B%3Amap%20%5B%3Ax%20int%3F%5D%20%5B%3Ay%20int%3F%5D%5D%0A%20%5B%3Afn%0A%20%20%7B%3Aerror%2Fmessage%20%22x%20should%20be%20greater%20than%20y%22%7D%0A%20%20(fn%20%5B%7B%3Akeys%20%5Bx%20y%5D%7D%5D%20(%3E%20x%20y))%5D%5D will give you inspiration?
Ooohh, that's very nice! Thanks very much 😃
For sure! For whatever reason, I hadn't registered that was a thing before. Much appreciated 👍
Back again 😅 While the custom validator function works for validation, I’ve found it breaks the default value transformer. My code looks something like this:
(def Conf
[:map
[:polling
[:and
[:map {:default {}}
[:min-delay-seconds [int? {:default 60}]]
[:max-delay-seconds [int? {:default 120}]]]
[:fn
{:error/message "max polling delay must be >= min polling delay"}
(fn [{:keys [min-delay-seconds max-delay-seconds]}]
(> min-delay-seconds max-delay-seconds))]]]])
Without the :and
+ :fn
:
(m/decode Conf {} mt/default-value-transformer)
=> {:polling {:min-delay-seconds 60, :max-delay-seconds 120}}
And once that’s been added, the map comes back empty:
(m/decode Conf {} mt/default-value-transformer)
=> {}
I assume I’m doing something wrong, but I struggle with understanding what 🙂Doesn’t make a difference I’m afraid… I’ve tried a large number of combinations, but apparently not the right one 😅
I don’t want to to think I know malli well at all, so there might be other ways.
Moving the :default {}
up seems to work:
(require '[malli.core :as m]
'[malli.transform :as mt])
(def Conf
[:map
[:polling {:default {}}
[:and
[:map
[:min-delay-seconds [int? {:default 60}]]
[:max-delay-seconds [int? {:default 120}]]]
[:fn
{:error/message "max polling delay must be >= min polling delay"}
(fn [{:keys [min-delay-seconds max-delay-seconds]}]
(> min-delay-seconds max-delay-seconds))]]]])
(m/decode Conf {} mt/default-value-transformer)
;; => {:polling {:min-delay-seconds 60, :max-delay-seconds 120}}
(m/decode Conf {:polling {:min-delay-seconds 1231}} mt/default-value-transformer)
;; => {:polling {:min-delay-seconds 1231, :max-delay-seconds 120}}
Wow, it does! I must have tried pretty much any combination but that one Thanks again, Lee! ⭐️
My pleasure, more experienced mallites might chime in, but the above looks ok to me.
Hey, I have some code that have dependencies on spec, something that I cannot address in the near term, so I still need to duplicate malli and spec schemas everywhere. I'm just wondering if there is a lib that allows some sort of translation of malli schemas into spec schemas, in a way that we can make other spec dependent code thinks that a malli schema is a spec schema. Does anyone knows about some think like this?
I'm aware of: https://github.com/dvingo/malli-code-gen/blob/main/thoughts.md#clojurespecalpha https://github.com/dvingo/malli-code-gen/blob/main/src/main/space/matterandvoid/malli_gen/clojure_alpha_specs.cljc I remember reading the docs, but have no idea how complete the actual implementation is.
I also remember this presentation showing how to generate domain models from malli (similar to the above repo thoughts). It's not directly related to clojure.spec, but perhaps you may gleam some insights if you go down the road of actually implementing this kind of generator. https://www.youtube.com/watch?v=ww9yR_rbgQs
I think both of these things came about before malli introduced https://github.com/metosin/malli#qualified-keys-in-a-map - perhaps with some clever use of macros and custom malli registries, you can get 80% there without much effort?
Lets see, there is a lot of duplication going on so I need to solve it through some clever strategy
Yea, I paused working on that, but the good news is that since then malli added malli.core/ast
which makes it a lot easier to parse and walk schemas.
I have a transform for taking malli schemas describing a hashmap and producing pathom output vectors that is working:
https://gist.github.com/dvingo/213633acfdd520bddcdc91fc1c7b9e44
you should be able to do something similar to output clojure specs. The Kondo output has a more complete set of schema types:
https://github.com/metosin/malli/blob/master/src/malli/clj_kondo.cljc
I think @U0A5V8ZR6 continued working on something similar https://github.com/Blasterai/malli-datomic/blob/master/src/blasterai/malli_datomic/spec_utils.cljc
I want to use malli for the clj-kondo type-mismatch stuff on a large clojure project. But I’d rather not add it as a dependency. Is there a way to make malli.core/=> annotate functions in other namespaces? Then I can put all my m/=>
’s into an un-committed namespace and still get the benefits of (
. I looked at the code, and adding the feature doesn’t seem too tough. But I may be missing another approach
yea that should be possible with a little custom code. Underneath =>
just calls -register-function-schema
https://github.com/metosin/malli/blob/bf92680ad76e57697261dd45c52dd31ffa9a8e1e/src/malli/instrument.clj#L41
which takes an ns symbol, a name symbol, a schema and a metadata map
would not be a big change I guess: https://github.com/metosin/malli/blob/master/src/malli/core.cljc#L2440-L2442
How do I make a schema for a vector that has 3 items: int, nil, string? e.g. [1 nil "a"]
I can make a vector that is homogenous, or I can make a list using sequence schema. But I can’t figure this one out
Exactly right! In hindsight I could have also:
(mp/provide
[[1 nil "x"]
[2 nil "y"]
[1 nil "z"]]
{:malli.provider/tuple-threshold 3})
Back again 😅 While the custom validator function works for validation, I’ve found it breaks the default value transformer. My code looks something like this:
(def Conf
[:map
[:polling
[:and
[:map {:default {}}
[:min-delay-seconds [int? {:default 60}]]
[:max-delay-seconds [int? {:default 120}]]]
[:fn
{:error/message "max polling delay must be >= min polling delay"}
(fn [{:keys [min-delay-seconds max-delay-seconds]}]
(> min-delay-seconds max-delay-seconds))]]]])
Without the :and
+ :fn
:
(m/decode Conf {} mt/default-value-transformer)
=> {:polling {:min-delay-seconds 60, :max-delay-seconds 120}}
And once that’s been added, the map comes back empty:
(m/decode Conf {} mt/default-value-transformer)
=> {}
I assume I’m doing something wrong, but I struggle with understanding what 🙂