This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-11-23
Channels
- # announcements (66)
- # babashka (41)
- # beginners (93)
- # calva (10)
- # cider (2)
- # clj-kondo (112)
- # cljs-dev (6)
- # cljsrn (1)
- # clojure (44)
- # clojure-dev (10)
- # clojure-europe (35)
- # clojure-italy (15)
- # clojure-nl (3)
- # clojure-uk (2)
- # clojurescript (38)
- # conjure (1)
- # datalevin (1)
- # datomic (16)
- # deps-new (4)
- # events (7)
- # figwheel-main (1)
- # fulcro (59)
- # graalvm (21)
- # integrant (3)
- # introduce-yourself (8)
- # jobs-discuss (2)
- # malli (23)
- # membrane (11)
- # membrane-term (2)
- # missionary (17)
- # off-topic (7)
- # pathom (23)
- # pedestal (6)
- # polylith (7)
- # portal (25)
- # releases (1)
- # remote-jobs (3)
- # reveal (5)
- # shadow-cljs (43)
- # spacemacs (7)
- # sql (18)
- # tools-deps (33)
- # vim (10)
- # xtdb (36)
Malli decoders are very cool. But as far as I understand, in order to use a schema that relies on decoders, clients have to decode data before validating it. It means that a schema that relies on decoders cannot be used as-is for validating data. Am I correct?
For now, that’s true. There was a discussion some time ago to add :parsed
schema element. That would just run m/-parse
in before validate, explain, transform etc. like s/conform
on spec. Could also be :decoded
, so that this would work:
(m/validate [:decoded {:decode :string} schema] "ip/127.0.0.1") ; => true
@ikitommi Here is my attempt to write a parser in user space:
(defn my-parse
[schema data]
(let [data' (decode schema data (transformer string-transformer default-value-transformer))]
(if (validate schema data')
(encode schema data' (transformer string-transformer default-value-transformer))
(humanize (explain schema data')))))
It does the job with asset ids but the problem is that it transform integer to strings.
(def schema
[:map
[:count :int]
[:asset-id [:multi {:dispatch first
:decode/string #(str/split % #"/")
:encode/string #(str/join "/" %)}
["domain" [:tuple [:= "domain"] domain]]
["ip" [:tuple {:error/message "Invalid IP"} [:= "ip"] ipv4]]]]])
(my-parse schema {:count 12
:asset-id "ip/127.0.0.1"})
;; {:count "12", :asset-id "ip/127.0.0.1"}
;; Oops "12" instead of 12
… or create a custom name for the parsing transformer, e.g. :parse
- it’s it a name you have defined, it doesn’t transform anything else.
(let [schema [:map
[:x :int]
[:y [:int {:decode/parse (partial + 10)
:encode/parse (partial * 2)}]]]
t (mt/transformer {:name :parse})]
(as-> (m/decode schema {:x 0, :y 0} t) $
(m/encode schema $ t)))
;; => {:x 0, :y 20}
I cannot return the original as I would like the default values to be added by the parser.
For instance, with a schema that assigns 42 as a default value to :count
(def schema
[:map
[:count [:int {:default 42}]]
[:asset-id [:multi {:dispatch first
:decode/string #(str/split % #"/")
:encode/string #(str/join "/" %)}
["domain" [:tuple [:= "domain"] domain]]
["ip" [:tuple {:error/message "Invalid IP"} [:= "ip"] ipv4]]]]])
(my-parse schema {:asset-id "ip/127.0.0.1"})
;; {:asset-id "ip/127.0.0.1", :count "42"}
However, I really like the idea of a custom name
We need that as our plan is to have a company wide schema repository to be consumed by all apps
Is there an option for MapSchemas to skip generating specific field/s?
here’s two:
;; a) a top-level property?
[:map {:gen/fields [:x :y]}
[:x :int]
[:y :int]
[:z :int]]
;; b) entry-level property?
[:map
[:x :int]
[:y :int]
[:z {:gen/gen nil} :int]]
i guess mu/select-keys could be used
I might have encountered a bug:
{:example/user [:map {:fully/entity? true
:fully.entity/id :user/id}
[:user/id :uuid]
[:user/username :string]
[:user/password :string]
[:user/email :string]]}
I have this map and i merge it with default-schemas and schemas to make my registry. Validate and generate work when I use them against
(m/schema type {:registry registry})
but the following returns just nil
(m/properties (m/schema type {:registry registry}))
It seems to work if i do deref before properties
Is this expected behaviour?
It's the current behavior and surprises me every time. References are also schemas, and usually without properties. Think like:
(def foo (with-meta {} {:a 1}))
(meta #'foo) ;=> .. no :a here
I guess when passed to malli functions like m/properties the different schema types should be dereffed if required. Like in nil punning where nil "can take the correct shape" depending on context
we would assume the references don't have properties, but they could. We could enforce them not to have, but not sure if that would be a good design decision :thinking_face:
It's the current behavior and surprises me every time. References are also schemas, and usually without properties. Think like:
(def foo (with-meta {} {:a 1}))
(meta #'foo) ;=> .. no :a here