Fork me on GitHub
#malli
<
2023-03-12
>
joshkh20:03:20

i’ve been reading the docs and can’t find an answer to this: can i validate one attribute of a map based on the value of another attribute in that map, e.g. :attr2 must be a hyphenated string of :attr1 which is a vector of strings? many thanks 😎

escherize19:03:26

yeah here’s an example:

joshkh21:03:56

a very late thank you, @U051GFP2V, this is exactly what i was looking for

😆 2
niwinz21:03:41

hello, I'm trying to use the malli.dot namespace and I found it a but buggy or at least the feeling is very strange when I use it with custom composite registry (default+ mutable)

user=> (v/schema :app.rpc.commands.files/file)
:app.rpc.commands.files/file
user=> (class (v/schema :app.rpc.commands.files/file))
malli.core$_schema_schema$reify$reify__10396
There you can look that the schema is correctly available on the registry (v/schema ...) is the same as (m/schema ... {:registry v/default-registry})... If I use it as is, I get an exception:
user=> (md/transform :app.rpc.commands.files/file {:registry v/default-registry})
Execution error (ExceptionInfo) at malli.core/-exception (core.cljc:138).
:malli.core/invalid-schema
If I use it wrapped in a schema I get an empty record node:
user=> (md/transform [:schema :app.rpc.commands.files/file] {:registry v/default-registry})
"digraph {\n  node [shape=\"record\", style=\"filled\", color=\"#000000\"]\n  edge [dir=\"back\", arrowtail=\"none\"]\n \n \n}\n"
On trying passing my composite registry as local registry on schema props, it fails:
user=> (md/transform [:schema {:registry v/default-registry} :app.rpc.commands.files/file])
Execution error (IllegalArgumentException) at malli.core/-property-registry (core.cljc:257).
Don't know how to create ISeq from: malli.registry$composite_registry$reify__8529
And it only works I pass a plain map to local registry (derefing the atom used for mutable registry):
user=> (md/transform [:schema {:registry @v/registry} :app.rpc.commands.files/file])
"digraph {\n  node [shape=\"record\", style=\"filled\", color=\"#000000\"]\n  edge [dir=\"back\", arrowtail=\"none\"]\n \n  \":app.common.validation/set-of-strings\" [label=\"{:app.common.validation/set-of-strings|:app.common.validation/set-of-strings\\l}\", [...] tail=\"odiamond\"]\n}\n"

niwinz21:03:35

Is this expected behavior, Do I need wrap always on [:schema when I want to use the md/transform? it is expected that I can't pass a registry instance to a local registry and it only accept a plain map type of registries? why I can't pass the registry as options to the md/transform instead of passing the local registry to the [:schema ?

niwinz21:03:48

the same happens with plantuml

niwinz21:03:17

my sensation is that the md/transform ignores the registry passed as options

niwinz21:03:04

Would be nice to be able to do this:

(md/transform [:schema {:registry {"File" :app.rpc.commands.files/file}} "File"] {:registry v/default-registry})
Execution error (ExceptionInfo) at malli.core/-exception (core.cljc:138).
:malli.core/invalid-schema
This will allow have better, human readable name for the type and not the fully qualified keyword on the dot output

niwinz10:03:09

After digging on it I think all is related to the pointer schema, I'm not clearly understand why it works this way:

niwinz10:03:57

I mean if I look up a schema with a keyword using a registry using m/schema it will return a pointer schema that will not show the form and will not walk, I need to explicit m/deref it, but I have no evident way for check if the schema is a pointer or real schema... I expect m/schema return ` real schema and not a pointer but maybe I'm missing something here that is not evident

ikitommi17:03:08

malli.dot is not complete (and platuml is built on top of it), should add that to docs. Any improvements / rewrite of it welcome.

ikitommi17:03:11

for pretty naming, something like a :title property could be used?

niwinz09:03:21

I have my own impl for openapi right now for penpot, and working on custom describe module I will show you the result when it is finished and we will see if it make sense to contribute it back to malli 😄 I have played with the dot and plantuml to understand how they works but I don't need them on the near future, maybe later

ikitommi09:03:33

own impl to openapi? Describe module? Sounds interesting. Reitit OpenAPI3.1 support just landed on master btw

niwinz09:03:11

oh, I wasn't aware of that

niwinz09:03:12

just a screenshot, I'm right now generating the full openapi.json for the penpot rpc api this is split in two modules: one that generates the schemas for the body from malli and one custom for generate the base openapi.json structure

niwinz09:03:16

I mean, I have started from swagger code from malli and adapted it to openapi with probably some customizations that I need my self, just a WIP right now, I will look on the openapi support that recently landed to the malli and look on if I can use it as-is

ikitommi10:03:52

👍 Reitit + OpenAPI was merged just few days ago, needs still testing before a release. If you have something that is missing/bad in the official impl, happy to pull them in. Also, the code is split between reitit & schema libs (malli, spec-tools, schema-tools) atm.

niwinz10:03:17

Ah, now I understand why I missed it, I;m not ussing reitit, I mean I use it but just for basic routing, behind that we have a classic RPC, this is why I use malli for define schemas for all metadata, and then generate openapi.json using the malli ability to walk the schemas (that is awesome)

niwinz10:03:22

Just a example:

👍 2
niwinz10:03:02

we started replacing spec with malli on the codebase, and malli is just awesome

👍 2
ikitommi10:03:32

I have an old example of doing reitit + malli + rpc, just a sec…

ikitommi10:03:57

really like the command/cqrs/rpc pattern, one can program in the business/domain terms, not with http/rest. a screenshot of an app with cqrs + fsm + malli (served via reitit).

niwinz13:03:56

yep, very similar, we also started with query/mutation pattern but on the end we normalized all to commands, the semantic difference is that queries start the name with get-

niwinz16:03:27

This is the candidate output for the describe module:

FileWithPermissions -> Object {
  id => UUID,
  features => FileFeatures -> Set[String],
  hasMediaTrimmed => boolean,
  commentThreadSeqn => integer,
  name => string,
  revn => integer,
  modifiedAt => Instant,
  isShared => boolean,
  projectId => UUID,
  createdAt => Instant,
  data? => anything,
  permissions => Permissions -> Object {
    type => keyword,
    isOwner => boolean,
    isAdmin => boolean,
    canEdit => boolean,
    canRead => boolean,
    isLogged => boolean
  }
}

niwinz16:03:25

that i'm working on right now, it will be used for display a human readable representation of the datatype that malli schema represents