Fork me on GitHub
#malli
<
2022-10-21
>
Thomas Moerman12:10:54

I'm currently implementing a custom schema (for reference types). My question: Is it idiomatic to call (m/validate ?schema ?subject {:registry ?my-local-reg}) within the body of a content-dependent schema like in:

(let [;; self-checking keyword spec is necessary to make `[:my/ref :asset/id] work
      local-registry
                 (merge
                   ;; self-validating schemas
                   {:asset/id   (m/schema [:fn #(= :asset/id %)])
                    :grommet/id (m/schema [:fn #(= :grommet/id %)])}
                   
                   ;; for ID values
                   {:or     (m/-or-schema)
                    :int    (m/-int-schema)
                    :string (m/-string-schema)
                    :uuid   (m/-uuid-schema)
                    :id     [:or :int :string :uuid]})
      
      ;; content-dependent schema
      Ref        (m/-simple-schema (fn [props children]
                                     (log/spy :info children)
                                     {:type :my/ref
                                      :pred (fn [x]
                                              (let [attr-schema (first children)
                                                    [id-attr id-val] (first x)]
                                                (and (map? x)
                                                     (= 1 (count x))
                                                     ;; ============== ;;
                                                     ;; Q: is this ok? ;;
                                                     ;; ============== ;;
                                                     (m/validate :id id-val {:registry local-registry})
                                                     (m/validate attr-schema id-attr {:registry local-registry}))))
                                      ;; Don't forget the children count constraints!
                                      :min  1
                                      :max  1}))

      custom-reg {:my/ref Ref}

      registry   (mr/composite-registry
                   m/default-registry
                   local-registry
                   custom-reg)]

  [(m/validate [:my/ref :asset/id] {:asset/id 123} {:registry registry})
   (m/validate [:my/ref :asset/id] {:grommet/id 123} {:registry registry})
   (m/validate [:my/ref [:or :asset/id :grommet/id]] {:asset/id 123} {:registry registry})
   (m/validate [:my/ref [:or :asset/id :grommet/id]] {:other/id 123} {:registry registry})
   ])
Is there perhaps another approach preferable? Thanks 🙏

Thomas Moerman12:10:39

I guess a better version would look somethat like -maybe-schema instead of using simple-schema

ikitommi07:10:58

Have stumbled few times on writing custom reference schemas, not trivial. No best practices, but we have been adding new configuration options to schemas, (e.g. just added :pred to m/-map-schema), so if there is an existing schema type which is almost what you need and would be exactly what you need with adding an configuration option - I’m open to hearing & maybe adding that.

ikitommi07:10:03

but, prefer using a cached m/validator instead of m/validate if possible, it’s much faster.

Thomas Moerman14:10:25

Yeah you're right, it's not trivial. I'm trying to get my head around the essence of what makes it so difficult, there is some kind of circularity in the problem, it seems.