malli

Casey 2025-02-26T09:34:07.469259Z

I'm trying to refer to schemas directly in my schema:

(m/explain
    [:map
     [:function-name :string]
     [:description :string]
     [:signature :schema]]              ; I've also tried m/schema?

    {:function-name "add"
     :description   "Adds two (and only two) numbers"
     :signature     (m/schema [:=> [:cat :int :int] :int])}) ; also tried without the m/schema wrapping
The value of :signature should be the function schema, not a function conforming to the schema. This results in a rather cryptic:
{:type clojure.lang.ExceptionInfo,
   :message ":malli.core/child-error",
   :data
   {:type :malli.core/child-error,
    :message :malli.core/child-error,
    :data
    {:type :schema, :properties nil, :children nil, :min 1, :max 1}},
   :at [malli.core$_exception invokeStatic "core.cljc" 157]}]
Interestingly using [:signature m/schema?] results in an invalid schema error for some reason.

opqdonut 2025-02-26T10:06:20.878229Z

yeah :schema gives you a child error because it's used as a wrapper for things like recursive schemas internally, so always in the form [:schema <something else>]

opqdonut 2025-02-26T10:07:30.982999Z

m/schema? is the right thing to check for, but it doesn't work because malli has an explicit whitelist of predicate schemas

opqdonut 2025-02-26T10:08:08.750439Z

[:fn m/schema?] should work, however

opqdonut 2025-02-26T10:11:49.152809Z

user=> (m/explain
    [:map
     [:function-name :string]
     [:description :string]
     [:signature [:fn m/schema?]]]

    {:function-name "add"
     :description   "Adds two (and only two) numbers"
     :signature     (m/schema [:=> [:cat :int :int] :int])})
nil
user=> (m/explain
    [:map
     [:function-name :string]
     [:description :string]
     [:signature [:fn m/schema?]]]

    {:function-name "add"
     :description   "Adds two (and only two) numbers"
     :signature     false})
{:schema [:map [:function-name :string] [:description :string] [:signature [:fn #object[malli.core$schema_QMARK_ 0x7757a37f "malli.core$schema_QMARK_@7757a37f"]]]], :value {:function-name "add", :description "Adds two (and only two) numbers", :signature false}, :errors ({:path [:signature], :in [:signature], :schema [:fn #object[malli.core$schema_QMARK_ 0x7757a37f "malli.core$schema_QMARK_@7757a37f"]], :value false})}

opqdonut 2025-02-26T10:12:42.836739Z

btw, here is the list of supported predicate schemas: https://github.com/metosin/malli?tab=readme-ov-file#mallicorepredicate-schemas

Casey 2025-02-26T13:29:45.400079Z

Oh interesting thank you. I assumed I could use any predicate function as a predicate (like spec I guess)

opqdonut 2025-02-26T13:31:23.344119Z

This restriction in Malli is because one of the points of Malli was to make schemas that can be persisted in a db

opqdonut 2025-02-26T13:31:56.227339Z

so can't allow for arbitrary code, or for references to functions that might change between serialising and deserialising the schema

opqdonut 2025-02-26T13:34:22.189969Z

recently there's been a move away from functions-as-schemas to named schemas: :int instead of int? etc

opqdonut 2025-02-26T13:34:36.615629Z

just to give some context to you

Casey 2025-02-26T14:02:24.926539Z

I'm surprised there isn't a builtin named schema for [:fn m/schema?]

Casey 2025-02-26T14:02:36.610009Z

It seems like something that would crop up more

opqdonut 2025-02-26T14:06:54.463009Z

yeah

valerauko 2025-02-26T11:56:18.192739Z

I'm thinking of using malli to generate mocks for database queries in testing. Is there any prior art out there I could use as reference?

MJ 2025-02-27T21:19:23.533489Z

I wouldn't directly mock the DB, but instead generate data and actually insert it in a rollback TX. I've been bitten by too many slight differences in behavior. I have used https://github.com/donut-party/datapotato for this and liked it overall, but it does have limitations & quirks

👀 1
2025-02-26T15:32:48.521659Z

using with-redefs or a test component, you can have the database query function return generated conforming values for your schemas

2025-02-26T15:33:13.717779Z

i'm on mobile or i'd write an example, but i think it's self explanatory