Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify content-dependent schema creation #866

Merged
merged 6 commits into from
Mar 13, 2023
Merged

Conversation

ikitommi
Copy link
Member

@ikitommi ikitommi commented Mar 10, 2023

Both m/-simple-schema and m/-collection-schema support "content-dependent schema creation", which mean you can use schema properties and children to create the actual Schema instance. Old mechanism to do this was using a arity2 callback function children properties -> props instead of actual property map. This is a bad because:

  • there was no way to define props for the IntoSchema instance. e.g.
(-> (m/default-schemas) :> (m/-type))
; => null
  • the code was hard to reason about as there was atom and type-casting of the ?props
  • options was not passed on to the callback

This MR introduces a :compile options, which is a arity3 function children properties options -> props. Original properties (without the :compile) are merged to the result of the :compile function, so one can define static properties ahead of time an this works now:

(-> (m/default-schemas) :> (m/-type))
; => :>

It's a breaking change for the extender API, marked as m/-deprecated so it's easy to migrate to using this.

Bump into this while working on #264.

Usage example:

(def Between
  (m/-simple-schema
   {:type `Between
    :compile (fn [_properties [min max] _options]
               (when-not (and (int? min) (int? max))
                 (m/-fail! ::invalid-children {:min min, :max max}))
               {:pred #(and (int? %) (>= min % max))
                :min 2 ;; at least 1 child
                :max 2 ;; at most 1 child
                :type-properties {:error/fn (fn [error _] (str "should be betweeb " min " and " max ", was " (:value error)))
                                  :decode/string mt/-string->long
                                  :json-schema {:type "integer"
                                                :format "int64"
                                                :minimum min
                                                :maximum max}
                                  :gen/gen (gen/large-integer* {:min (inc min), :max max})}})}))

(m/form [Between 10 20])
; => [user/Between 10 20]

(-> [Between 10 20]
    (m/explain 8)
    (me/humanize))
; => ["should be betweeb 10 and 20, was 8"]

(mg/sample [Between -10 10])
; => (-1 0 -2 -4 -4 0 -2 7 1 0)

@bsless
Copy link
Contributor

bsless commented Mar 12, 2023

Is it possible to not make the change breaking at the moment, but accept both and emit a warning?

@ikitommi
Copy link
Member Author

thanks @bsless, it is. Changed so that the old syntax works too, just with extra DEPRECATED printing on the console.

@ikitommi ikitommi merged commit e62bc8b into master Mar 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants