Fork me on GitHub
#malli
<
2021-03-23
>
robert-stuttaford06:03:25

thanks all, i'll report back on how it goes!

ikitommi08:03:01

@raymcdermott I can look your thing today/tomorrow.

3
ikitommi11:03:56

@d.ian.b no inbuilt mapping for fn?. But, you can:

(m/validate [:fn fn?] (partial +))
; => true

ikitommi11:03:07

also:

(m/explain
  [:=> [:cat [:* [:int {:gen/min -1000, :gen/max 1000}]]] :int] 
  (partial +)
  {::m/function-checker mg/function-checker})
; => nil

Ian Fernandez11:03:18

I've made it right now haha

👍 3
ikitommi11:03:49

(m/explain
  [:=> [:cat [:* [:int {:gen/min -1000, :gen/max 1000}]]] [:int {:min 1}]]
  (partial +)
  {::m/function-checker mg/function-checker})
;{:schema [:=> [:cat [:* [:int #:gen{:min -1000, :max 1000}]]] [:int {:min 1}]],
; :value #object[clojure.core$_PLUS_ 0x6edca2b1 "clojure.core$_PLUS_@6edca2b1"],
; :errors (#Error{:path [],
;                 :in [],
;                 :schema [:=> [:cat [:* [:int #:gen{:min -1000, :max 1000}]]] [:int {:min 1}]],
;                 :value #object[clojure.core$_PLUS_ 0x6edca2b1 "clojure.core$_PLUS_@6edca2b1"],
;                 :check {:total-nodes-visited 0,
;                         :depth 0,
;                         :pass? false,
;                         :result false,
;                         :result-data nil,
;                         :time-shrinking-ms 0,
;                         :smallest [()],
;                         :malli.generator/explain-output {:schema [:int {:min 1}],
;                                                          :value 0,
;                                                          :errors (#Error{:path [],
;                                                                          :in [],
;                                                                          :schema [:int {:min 1}],
;                                                                          :value 0})}}})}

clojure-spin 6
Ian Fernandez11:03:22

How I can use a register of the (m/function-schemas) registry, onto m/validate?

Ian Fernandez16:03:41

(get-in (m/function-schemas) [(quote *ns*) 'foo :schema])

ikitommi16:03:40

@d.ian.b good question, atm, no easy way. Idea with the function registry is that there will be a instrument kinda thing, that will wrap a) some b) all registered function schmaas like Orchestra - running input & output validation. Could be also used to emit generated data based only on the function definitions. Ideas and PRs welcome on that.

ikitommi16:03:59

also, did a spike on infferring schemas from normal vars. you get useful guesses pretty easily, better with tools.analyzer & clj-kondo and I guess. really good with core.typed.

ikitommi16:03:00

the new kw-varargs thing would work nicely with global registry, my guess is that the core team will plug into that with spec. e.g. given a function:

(defn doit [& {:domain.user/keys [id name]}] [id name])
… running (m/collect #'doit) would infer a [:map :domain.user/id :domain.user/name] out of it, register it as a malli function schma, after (m/instrument my-registry) saying:
(doit :domain.user/id 1, :domain.user/name "kikka")
would cause it to run validation.

clojure-spin 3
ikitommi16:03:04

given there is few hours extra time, I would write a sample code so that I could prove a point that it’s doable and awesome.

sheepy 3
genRaiy16:03:39

I don't seem to be able to merge maps with [:and] constraints

genRaiy16:03:33

(def x [:and [:map
              [:start int?]
              [:end int?]]
        [:fn (fn [{:keys [start end]}]
               (< start end))]])
=> #'user/x
(def y [:map
        [:here int?]
        [:there int?]])
=> #'user/y
(require '[malli.util :as mu])
=> nil
(mu/merge y x)
=> [:and [:map [:start int?] [:end int?]] [:fn #object[user$fn__4910 0x40fa91ef "user$fn__4910@40fa91ef"]]]
(mu/merge x y)
=> [:map [:here int?] [:there int?]]

genRaiy16:03:43

is this expected?

borkdude16:03:15

and should merge combine the predicate in another predicate which ands those if both maps have predicates?

genRaiy16:03:34

it should invoke both functions ... maybe the order would not be predictable but I'll take that

borkdude16:03:45

probably the order of merge args

borkdude16:03:45

this could lead to funny problems, like what if you merge in a closed map in an open map, probably the resulting map should be open?

borkdude16:03:19

or should merge consider predicates and other properties like metadata, which is ignored in merge args?

borkdude17:03:18

(with-properties-of (merge x y) y)

genRaiy17:03:01

merge takes the last as the 'winner' so I think that would be the most idiomatic

genRaiy17:03:37

but I agree that merging things that are not maps is tricky

ikitommi19:03:15

Plumatic dropped s/both in favour of s/constrained just because the first is not a good idea: “apple and fruit and a car” please. Currently :and already kinda means “the first thing constrained with the rest” as we pick the generator from first and then constraint with the rest using gen/such-that. Given that, we could make :and mergable, would merge with the first and keep the rest as extra leaves of :and? e.g.

[:map ::x]
[:map ::y] 
; => [:map ::x ::y]

[:map ::x]
[:and [:map ::y] map?] 
; => [:and [:map ::x ::y] map?]

[:and [:map ::x] map?]
[:map ::y] 
; => [:and [:map ::x ::y] map?]

[:and [:map ::x] map?]
[:and [:map ::y] map?] 
; => [:and [:map ::x ::y] map? map?]

[:and [:map ::x]]
map? 
; => map?
would that be … more correct?

ikitommi19:03:03

having [:and [:map …] [:fn …]] is quite common, having it non-mergable is a bummer.

😬 3
genRaiy21:03:07

if both maps have [:and [:map ..][fn...] it could be rejected. If one has an [:and ...] and the other doesn't can't you still merge the maps? I am probably under thinking it 🙂

Panel22:03:22

Anyway to have a dynamic default ? Like if I want a default timestamp to be generated when runing decode with default-value-transformer ?

Panel23:03:39

(malli/decode
 [:map {:registry
        {:inst (m/-simple-schema
                {:type :inst
                 :pred inst?})}}
  [:time :inst]
  [:id1 :uuid]
  [:id2 :uuid]]
 {}
 (mt/default-value-transformer
  {:defaults {:inst (constantly (rand-int 100))
              :uuid (constantly (char (rand-int 100)))}}))
Found something that works for me, but the default are generated once per type so for example if you need two different uuid it won't work.

Panel23:03:22

(mu/optional-keys
 [:map {:registry
        {:inst (m/-simple-schema
                {:type :inst
                 :pred inst?})}}
  [:time :inst]
  [:id :uuid]])
This throw a java.lang.StackOverflowError

Panel01:03:09

It does work if the registry is passed in the options map

(mu/optional-keys
 [:map
  [:time :inst]
  [:id :uuid]]
 {:registry
  (mr/composite-registry
   m/default-registry
   {:inst (m/-simple-schema
           {:type :inst
            :pred inst?})})})