malli

https://github.com/metosin/malli :malli:
ikitommi 2020-10-19T06:09:39.242900Z

πŸŽ‰

πŸŽ‰ 3
dharrigan 2020-10-19T07:17:06.243300Z

Fantastic! Going to try these out now!

ikitommi 2020-10-19T07:48:46.243900Z

https://malli.io/?value=%7B%3Atype%20%22Cat%22%2C%20%3Aname%20%22Viivi%22%2C%20%3AhuntingSkill%20%3Aadventurous%7D&schema=%5B%3Aschema%20%7B%3Aregistry%20%7B%22Pet%22%20%5B%3Amap%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%3Atype%20keyword%3F%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%3Aname%20string%3F%5D%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Cat%22%20%5B%3Amerge%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Pet%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%3Amap%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%3Atype%20%5B%3A%3D%20%22Cat%22%5D%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%3AhuntingSkill%20%5B%3Aenum%20%7B%3Adescription%20%22The%20measured%20skill%20for%20hunting%22%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Aclueless%2C%20%3Alazy%2C%20%3Aadventurous%2C%20%3Aaggressive%5D%5D%5D%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Dog%22%20%5B%3Amerge%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Pet%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%3Amap%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%3Atype%20%5B%3A%3D%20%22Dog%22%5D%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%3ApackSize%20%5B%3Aint%20%7B%3Amin%200%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Adefault%200%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Adescription%20%22the%20size%20of%20the%20pack%20the%20dog%20is%20from%22%7D%5D%5D%5D%5D%7D%7D%0A%20%5B%3Amulti%20%7B%3Adispatch%20%3Atype%7D%20%22Cat%22%20%22Dog%22%5D%5D

ikitommi 2020-10-19T13:32:50.245700Z

what a brilliant/horrible idea: add optional :object schema, which allows maps to be described using clojure maps. Kinda like data-specs but for malli:

[:object
 {"name" [:required :string]
  "age" [:required :number :positive :integer]
  "email" [:string :email]
  "website" [:string :url]
  "createdOn" [[:date {:default "2020-18-10"}]]
  "address" [:object
             {"street" [[:string {:min 1}]]
              "zip" [:int]}]}]

ikitommi 2020-10-19T13:35:28.246500Z

or:

[:object
 {"name" [:and :required :string]
  "age" [:and :required :number :positive :integer]
  "email" [:and :string :email]
  "website" [:and :string :url]
  "createdOn" [:date {:default "2020-18-10"}]
  "address" {:street [:string {:min 1}]
             :zip :int}}]

borkdude 2020-10-19T14:17:49.246800Z

a bit like Schema, but more EDN-like

ikitommi 2020-10-19T14:37:33.254700Z

☝️. simple formats like Schema and data-spec are kinda easy, but not simple: the core utilties (`select-keys`, assoc etc.) almost work, unless you have a wrapper for keys like ds/opt or s/optional-key in case they don’t. Also, value wrappers are needed to add visible properties/meta-data to schemas. And there is no order for keys. But, super nice for many things like defining inlined route parameters:

["/plus"
 {:get {:summary "plus with spec query parameters"
        :parameters {:query {:x int?, :y int?}}
        :responses {200 {:body {:total int?}}}
        :handler handle-plus}]

ikitommi 2020-10-19T14:40:27.256700Z

if there was a litemalli coercion in reitit, one could swap the data-spec apps almost 1:1 to it.

pithyless 2020-10-19T14:47:29.258900Z

I prefer #1 to #2; the latter is making nested map notation implicit and special for :object and I don't know if it's worth it.

pithyless 2020-10-19T14:51:52.261100Z

That reitit example could just as easily be solved by a utility function that takes the concise nested map notation and converts it to a tree of :object

πŸ‘ 1
borkdude 2020-10-19T14:52:13.261600Z

someone should write malli-tools ;)

ikitommi 2020-10-19T14:52:43.262Z

:grinning_face_with_one_large_and_one_small_eye:

pithyless 2020-10-19T14:58:11.265700Z

Does :object offer different semantics or tradeoffs than :map? Or would it deref/merge down to a :map schema? Or would we have two things that are the same but different? :]

pithyless 2020-10-19T14:59:56.267400Z

To be clear, I prefer writing the map notation and was always confused why :map used vectors; but that ship has sailed... or has it?

borkdude 2020-10-19T15:01:14.268400Z

we're in a dynlang, we can do everything we want ;)

pithyless 2020-10-19T15:03:43.271Z

I'm thinking :object could be just a nice alternative syntax that would "compile down" to a :map. But maybe I'm just missing the point. :)

ikitommi 2020-10-19T15:04:56.271800Z

https://github.com/metosin/malli/issues/286

borkdude 2020-10-19T15:06:21.273300Z

why it is called object though?

borkdude 2020-10-19T15:06:44.274100Z

like JavaScript object?

borkdude 2020-10-19T15:08:23.276900Z

I was thinking like: wow, is this a schema to describe Java objects like bean-stuff?

borkdude 2020-10-19T15:08:36.277500Z

anyone not working on front-ends might think the same

☝️ 1
ikitommi 2020-10-19T15:09:31.278700Z

vector syntax for :map allows simple way to define properties for it and retains the order of keys. But yes, we can add more schemas to build things in different ways. Could have also optional :`json-schema` that allows any JSON Schema in it etc.

ikitommi 2020-10-19T15:13:31.282600Z

the name could be anything, just flushing stuff from my brain (after a vacation).

pithyless 2020-10-19T15:19:56.288800Z

IMO, it would be confusing to see both :map and :object somewhere in my system output and they were semantically the same thing (a representation of known key-value mapping); so the way I see it: 1. if we want an alternative writing notation, why not just make it a utility function? (instead of introducing a new kind of schema) 2. if we want an alternative notation that is a data-literal (utility functions need runtime support), then we could introduce an alternative name (like :object ); but it could just as easily be :kv or :map2 ; or even why not extend existing :map to support both kinds of notations (vectors or maps) 3. if this is something similar to :map but offers possibly different semantics, than currently those semantics aren't clear to me; otherwise it'd be great if we didn't have two things that represent essentially the same thing (this would make merging, etc. more complicated to deal with later on)

pithyless 2020-10-19T15:21:45.290300Z

(This is also why I like having :map and :map-of , because they represent different semantics; even though they are using the same internal datastructure)

ikitommi 2020-10-19T15:38:33.292600Z

Related to 2, I think they should be kept separate (if implemented). If :map supported both syntax, there would be ambiguity issues:

[:map
 {:id :int
  :title :string}]
is that empty map with props? or map with no props but with keys?

ikitommi 2020-10-19T15:43:28.297100Z

If I would implement that today, it would be a separate ns, malli.object etc, with a Schema impl, a helper and a extra registry snipplet so one can merge the schemas into a registry easily:

(require '[malli.core :as m])
(require '[malli.object :as mo])

(def registry (merge (m/default-schemas) (mo/schemas)))

(m/schema
  [:object 
   {:id int?
    :address [:object {:street string?}]}]
  {:registry registry})