malli

2025-05-28T17:20:46.162849Z

Hi all, is this a good approach for recursively making map keys optional?

(defn recursive-optional-keys
  ([?schema] (recursive-optional-keys ?schema nil))
  ([?schema options]
   (m/walk
    ?schema
    (m/schema-walker
     (fn [schema]
       (case (m/type schema options)
         ::m/schema (recursive-optional-keys (m/deref schema) options)
         :ref (recursive-optional-keys (m/deref schema) options)
         :map (mu/optional-keys schema)
         schema)))
    options)))
Does it seem like I've missed anything that I need to handle in order to correctly descend into all the referenced/contained sub-schemas?

2025-05-28T18:52:59.715909Z

1. perhaps a check for -ref-schema? would be more general to handle all refs. or even let-bind (let [schema (m/deref-all schema)] ...). 2. I don't think think this works for recursive schemas. that might be tricky to handle.

2025-05-28T18:53:46.121169Z

Perhaps the most reliable approach would be to create your own ref schema.

2025-05-28T18:55:50.332479Z

e.g., [:optional [:schema {:registry {::foo [:or L R]} ::foo]] => m/deref => [:or [:optional L] [:optional R]]

2025-05-28T18:59:53.300299Z

otherwise, if you don't need support for recursive schemas, you'll just get a stackoverflow if you pass one to recursive-optional-keys and otherwise your approach looks fine.

2025-05-28T19:05:22.084979Z

Since my schemas aren't recursive right now I'll stick w/ what I have, but if my needs change I'll try the ref schema approach and post it here. Thanks!

👍 1
2025-05-28T19:08:31.417819Z

You might need to use my 1) suggestion to support :merge , or think through whether optionalizing :merge 's children is equivalent to optionalizing its expansion.

2025-05-28T19:10:52.589049Z

ditto for :select-keys and other malli.util ref schemas.