Skip to content

Recursive Schemas Impl #209

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

Merged
merged 26 commits into from
Jun 30, 2020
Merged

Recursive Schemas Impl #209

merged 26 commits into from
Jun 30, 2020

Conversation

ikitommi
Copy link
Member

@ikitommi ikitommi commented Jun 22, 2020

Displaces impl from #117, which will remain a place to discuss & history. FIxs #20 .

  • new m/Schema method -children to get child schemas instances too
  • :multi implements m/MapSchma
  • new m/RefSchma protocol with the following impls:
    • :ref - a lazy reference, enabling recursion
    • :schema, like m/schema (entity) but in data, eager
    • malli.core/schema, eager schema (value) ref, used internally. if no properties and child is a qualified keyword, derived form from the child
  • support for local :registry in any element
  • validators, explainers etc are moved from schema creation to actual m/Schema methods, to support laziness
  • m/-distance and m/-lookup helpers
  • m/from-map-syntax works with non-map child's (enums, refs)
  • updated README (local registry, recursive schemas)

TODO

  • :schema for non-lazy references (retains original information)
  • local recursion using :id
  • local mutual recursion using :registy
  • new element to ensure local registries as data
  • ambiguity rules
  • ensure it's done right

Current syntax:

(testing "recursion limiting"
  (are [schema]
    (is (every? (partial m/validate schema) (mg/sample schema {:size 1000})))

    ;; maybe
    [:schema {:registry {::rec [:maybe [:ref ::rec]]}}
     ::rec]

    ;; maps
    [:schema {:registry {::rec [:map [:rec {:optional true} [:ref ::rec]]]}}
     ::rec]

    ;; or
    [:schema {:registry {::tuple [:tuple boolean? [:ref ::or]]
                         ::or [:or int? ::tuple]}}
     ::or]

    ;; multi
    [:schema {:registry {::multi
                         [:multi {:dispatch :type}
                          [:int [:map [:type [:= :int]] [:int int?]]]
                          [:multi [:map [:type [:= :multi]] [:multi [:ref ::multi]]]]]}}
     [:ref ::multi]]))

Initial Syntax:

(support for local recursion removed)

malli-rec

@ikitommi ikitommi mentioned this pull request Jun 23, 2020
@ikitommi
Copy link
Member Author

Recursive schema resolution is too eager now:

(m/form
  [:and
   {:registry {::ping ::pong2
               ::pong2 ::pong
               ::pong [:and pos-int?]}}
   ::ping])
;[:and {:registry {:user/ping [:and pos-int?]
;                  :user/pong2 [:and pos-int?]
;                  :user/pong [:and pos-int?]}} 
; [:and pos-int?]]

, should retain the pointer information.

@ikitommi ikitommi marked this pull request as ready for review June 30, 2020 09:15
@ikitommi ikitommi merged commit f9f24af into master Jun 30, 2020
Copy link
Contributor

@rschmukler rschmukler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Left a super nitpicky comment that really doesn't warrant any changes. Code looks really nice, as always.

(defn -map-gen [schema options]
(let [entries (m/map-entries schema)
value-gen (fn [k s] (gen/fmap (fn [v] [k v]) (generator s options)))
options' (-recursion-options schema options)
Copy link
Contributor

@rschmukler rschmukler Jun 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this is better filed as a bug with them, but just worth noting that the "prime" convention isn't well supported in some editors' understanding of the clojure grammar. Emacs will attempt to convert options' into options ' causing the expression to rebind options to the quoted expression '(-recursion-options schema options).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants