Fork me on GitHub
#malli
<
2024-05-19
>
Eugen09:05:01

hi, should this be an error?

(plantuml/transform [:schema {:registry r} "Network"])

; Execution error (IllegalArgumentException) at malli.core/-property-registry (core.cljc:258).
; Don't know how to create ISeq from: malli.registry$composite_registry$reify__10480

ambrosebs15:05:54

I think the rule of thumb is everything inside a schema needs to be serializable. so no IntoSchema definitions, composite schemas etc., (they should all go in options). related https://github.com/metosin/malli/issues/1048

Eugen09:05:50

I am trying to visualize a schema that also has :time/instant so I build a custom registry with defaults, time + my schema . Also, I expected this to work but it does not

(plantuml/transform "Network" {:registry r}) 
; Execution error (ExceptionInfo) at malli.core/-exception (core.cljc:136).
; :malli.core/invalid-schema
while I can do
(mg/generate "Network" {:registry r})

Eugen09:05:21

seems like I can

(plantuml/transform :int {:registry r})
so I guess the issue is with my schema + plantuml

Eugen10:05:40

I made a reproducer for the issue I am getting with malli 0.16.1

(ns user 
  (:require [malli.experimental.time.generator]
            [malli.experimental.time :as mt]
            [malli.core :as m]
            [malli.registry :as mr]
            [malli.generator :as mg]
            [malli.plantuml :as plantuml]
            [malli.dot :as md]))

(def snm-schema {"Curve" [:enum :curve25519 :p256]})

(def r
  (mr/composite-registry
   m/default-registry
   (mr/registry (mt/schemas))
   (mr/registry snm-schema)))

(comment
  (mg/generate "Curve" {:registry r})
  ;; => :p256

  (plantuml/transform ["Curve"] {:registry r})
  ;; => Execution error (ExceptionInfo) at malli.core/-exception (core.cljc:136).
  ;;    :malli.core/invalid-schema

  (md/transform ["Curve"] {:registry r})
  ;; => Execution error (ExceptionInfo) at malli.core/-exception (core.cljc:136).
  ;;    :malli.core/invalid-schema
  
  )

ambrosebs16:05:39

Apparently the registry needs to be embedded in the schema atm.

(println (plantuml/transform [:schema {:registry {"Curve" [:enum :curve25519 :p256]}} "Curve"]))
@startuml
entity Curve {
 [:enum :curve25519 :p256]
}
@enduml

Eugen16:05:02

I guess this is a bug ?

Eugen16:05:10

should I create an issue ?

ambrosebs16:05:35

yeah probably

ambrosebs16:05:18

maybe ref handling needs an overhaul here. recursive schemas also don't work.

Eugen16:05:47

@ambrosebs: can you help me figure out how to build a schema from vars? I have a bunch of and don't know how to build a schema from them . It worked with a map {"Curve" [:enum ... }

(def Curve [:enum :curve25519 :p256])

ambrosebs16:05:57

Like this?

[:schema {:registry {"Curve" Curve}} "Curve"]

Eugen16:05:11

will this work if I have references?

(def KeyPair [:map {:title "Key pair"}
              [:curve [:ref {:min 1 :max 1} #'Curve]]
and want to add KeyPair as well?

Eugen16:05:48

it's a bit confusing honestly 🙂

ambrosebs17:05:46

So there's this separate feature for using vars as schemas, but I'm going to assume you want the simplest thing.

(def Curve [:enum :curve25519 :p256])
(def KeyPair [:map {:title "Key pair"}
              [:curve [:ref {:min 1 :max 1} "Curve"]]])
[:schema {:registry {"Curve" Curve, "KeyPair" KeyPair}} ...]

Eugen17:05:09

yes, I would like to get this working - but was also curios to understand why / how it works and there are nota lot of docs

ambrosebs17:05:28

It's a bit more advanced than you need, but the second example shows that whenever schema sees a registry reference, it eagerly replaces it with the schema it's pointing to.

ambrosebs17:05:36

you can see a bit of how it works by using m/deref, which replaces a ref with its mapped schema.

(take 3 (iterate m/deref (m/schema [:schema {:registry {"Curve" [:enum :curve25519 :p256]}} "Curve"])))
([:schema {:registry {"Curve" [:enum :curve25519 :p256]}} "Curve"]
 "Curve"
 [:enum :curve25519 :p256])

ambrosebs17:05:06

a dereferenced schema remembers the registry it was defined with

(-> [:schema {:registry {"Curve" [:enum :curve25519 :p256]}} "Curve"]
    m/deref-all
    m/options
    :registry
    mr/-schemas
    (select-keys ["Curve"]))
{"Curve" [:enum :curve25519 :p256]}

ambrosebs17:05:52

this is how you can have interdependent registries.

ambrosebs17:05:40

registries also use dynamic scope which is a bit tricky to think about but they work similar to dynamic vars in clojure. the most recently seen registry mapping wins when resolving a ref.