This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-09-11
Channels
- # babashka (66)
- # beginners (6)
- # calva (4)
- # clerk (25)
- # cljdoc (2)
- # clojars (2)
- # clojure (22)
- # clojure-europe (20)
- # clojure-nl (1)
- # clojure-norway (19)
- # clojure-uk (2)
- # conjure (1)
- # cursive (2)
- # data-science (8)
- # datomic (14)
- # helix (1)
- # hyperfiddle (15)
- # kaocha (1)
- # lsp (4)
- # malli (12)
- # polylith (36)
- # releases (2)
- # shadow-cljs (3)
- # spacemacs (2)
- # sql (7)
- # xtdb (2)
- # yaml (2)
how should I write a m/=>
function schema for a fn that takes in an open-ended option-map (where I need to ensure types if certain keys are provided)? for example:
(def Entity
(m/schema
[:map
[:id uuid?]
[:attributes map?]]))
(m/=> create-new [:=> [:cat ___?] Entity])
(defn create-new [& {:as kvs}]
(merge
{:id (random-uuid)
:attributes {}}
kvs))
which might be called as
(create-new
:attributes {:one 2 :three [4 5]}
:six 7)
not seeing any examples in the docs afaict (but I may have missed them)I'm not sure of a way to describe that either, but maybe a small addition to malli.core/-instrument
can help:
In my fork I added the ability to do this:
(def Entity (m/schema [:map [:id uuid?] [:attributes map?]]))
(def Args (m/schema [:map
[:id {:optional true} uuid?]
[:other {:optional true} :string]
[:attributes {:optional true} map?]]))
(defn create-new
{:malli/schema [:=> [:cat Args] Entity]
:malli/xform-args (fn [& x] [(apply hash-map x)])}
[& {:as kvs}]
(merge
{:id (random-uuid)
:attributes {}}
kvs))
;; call with
(d/pre (pr-str (create-new :id "(random-uuid)")
https://github.com/dvingo/malli/blob/5e1ce89dbfa9a6fa55724e72a8aeffcf0479cbca/src/malli/core.cljc#L2564
which gives this error in cljs:This was needed to get integration with the helix library where the function will receive a js object but by using a macro it appears to be a hashmap. So I needed a way to transform the arguments so malli would validate it correctly
not sure if this would be accepted upstream, but you can copy dev/start! to use this version of instrument in your project
maybe =>
can be updated to accept optional data
as well so that version would support this transform
two things in this thread:
1. there is no inbuilt schema to support kw-args, but you can describe them with :alt
, example below. Issue welcome if you want a :kwargs
utility schema for this
2. xform-args - looks interesting, is this just for validating or also as a “transform args behind the scenes” thing?
malli.desctructure
has examples on how to describe the kwargs: https://github.com/metosin/malli/blob/master/test/malli/destructure_test.cljc#L123-L147
so, here it would be:
[:altn
[:map [:map
[:id uuid?]
[:attributes map?]]]
[:args [:*
[:alt
[:cat [:= :id] uuid?]
[:cat [:= :attributes] map?]]]]]
or just:
[:alt
[:map
[:id uuid?]
[:attributes map?]]
[:*
[:alt
[:cat [:= :id] uuid?]
[:cat [:= :attributes] map?]]]]
but, there could be something like:
[:sequential-map
[:id uuid?]
[:attributes map?]]
… that would behave like it.and because it’s all data, this should work too:
(defn kwargs [m]
[:altn
["map" (m/form m)]
["args" [:* (into [:alt] (reduce (fn [acc [k _ v]] (conj acc [:cat [:= k] v])) [] (m/children m)))]]])
(kwargs
[:map
[:id uuid?]
[:attributes map?]])
;[:altn
; ["map"
; [:map
; [:id uuid?]
; [:attributes map?]]]
; ["args"
; [:*
; [:alt
; [:cat [:= :id] uuid?]
; [:cat [:= :attributes] map?]]]]]
thanks for the pointers Tommi! good to know about :alt
and :altn
For the xform-args - it's intended to only be used for validations, the function will get the original args unprocessed
It came from a use-case where helix, the react library, emits a function for you via a macro that will transform a JS object to hashmap, but I wanted to add instrumentation to by describing the args with a :map
schema. This xform-args was one solution to get it working without needing to add more macro layers.
But it seems like it could be useful in other cases where a transformation can simplify the arguments schema validation
and because it’s all data, this should work too:
(defn kwargs [m]
[:altn
["map" (m/form m)]
["args" [:* (into [:alt] (reduce (fn [acc [k _ v]] (conj acc [:cat [:= k] v])) [] (m/children m)))]]])
(kwargs
[:map
[:id uuid?]
[:attributes map?]])
;[:altn
; ["map"
; [:map
; [:id uuid?]
; [:attributes map?]]]
; ["args"
; [:*
; [:alt
; [:cat [:= :id] uuid?]
; [:cat [:= :attributes] map?]]]]]