mutual recursion, current status:
(mg/generate
::ping
{:registry (mr/composite-registry
(m/default-schemas)
{::ping [:maybe [:tuple [:= "ping"] [:ref ::pong]]]
::pong [:maybe [:tuple [:= "pong"] [:ref ::ping]]]})
:size 7, :seed 86})
; => ["ping" ["pong" ["ping" ["pong" ["ping" nil]]]]]
tested also a fail-fast on ambiguity with refs, so instead of:
(mg/generate
::ping
{:registry (mr/composite-registry
(m/default-schemas)
{::ping [:maybe {:id ::pong} [:tuple [:= "ping"] [:ref ::pong]]]
::pong [:maybe [:tuple [:= "pong"] [:ref ::ping]]]})
:size 7, :seed 86})
; => ["ping" ["ping" ["ping" ["ping" ["ping" nil]]]]]
the default code will throw instead:
Execution error (ExceptionInfo) at malli.core/fail! (core.cljc:80).
:malli.core/ambiguous-ref {:type :ref, :ref :user/pong}
the code is in a new PR: https://github.com/metosin/malli/pull/209
@ikitommi [suggestion] if you can embed registries locally, then maybe you don't need to have support for a custom global registry - just ask the users to include their registry as a part of their models.
The custom Schema
elements can’t be embedded as data, if they are code. It’s good have a mechanism to add those to the schema registry. All user/project-defined that are just data COULD be used via embedded registries, a decision done in user space.
I woudn’t register any project-spesific (data) schemas into global registry, as they can be references mosty as Vars.
The recursive schemas could also be allowed to be introduces using Vars, but not sure if that’s a good idea.
Something like:
(declare Pong)
(def Ping [:maybe [:tuple [:= "ping"] [:ref #'Pong]]])
(def Pong [:maybe [:tuple [:= "pong"] [:ref #'Ping]]])
Imaginary example with not much boilerplate with schematized fns using custom schema element :db/ref
registered into the global registry:
(m/defn my-fn [x :- int?, y :- [:maybe [:db/ref uuid?]]
(println x y))
About the Var refs - how would that be serialized? It could be done by having an asymmetric m/form
for that component, which might be a bad idea:
(m/form [:maybe [:tuple [:= "ping"] [:ref #'Pong]])
;[:registry
; {:registry {::ping [:maybe {:id ::pong} [:tuple [:= "ping"] [:ref ::pong]]]
; ::pong [:maybe [:tuple [:= "pong"] [:ref ::ping]]]}}
; [:ref ::ping]]
or is it?
this works now too:
(mg/generate
[:registry
{:registry {::ping [:maybe [:tuple [:= "ping"] [:ref ::pong]]]
::pong [:maybe [:tuple [:= "pong"] [:ref ::ping]]]}}
[:ref ::ping]]
{:size 7, :seed 86})
; => ["ping" ["pong" ["ping" ["pong" ["ping" nil]]]]]