malli

escherize 2025-06-10T16:49:20.609509Z

Is it worth making malli.util/keys work with schemas that are close to maps?

(mut/keys [:map [:a int?]])
;; => (:a)
(mut/keys [:maybe [:map [:a int?]]])
;; => nil (could be (:a))
I think a general solution for this is impossible, for e.g. [:or [:map [:a int?]] [:map [:b :string]]], keys of this doesn't make sense. But maybe keys should traverse through :maybe, or :ands with 1 map schema in them. Is that behavior desirable?

escherize 2025-06-10T16:50:27.222769Z

It's easy enough to walk the schema form and compile keys from all maps, thats what I would reccomend doing now, but it seems like malli.util/keys could do a little more work here

2025-06-10T17:21:30.847659Z

I think it could be generalized to work with unions and return a list of lists. perhaps a keyword option or under a different name.

(mut/keys-groups [:map [:a int?]])
;; => ((:a))
(mut/keys-groups [:maybe [:map [:a int?]]])
;; => (() (:a))
Then more specific custom tools could be built on top of that.
(defn known-keys [s] (apply concat (mut/keys-groups s)))

2025-06-10T17:22:38.690839Z

I think that might require a transformation to disjunctive normal form (OR of ANDs).

2025-06-10T17:24:02.308159Z

if could be made extensible if we provide an extension to convert a schema to DNF.

2025-06-10T17:24:41.367449Z

[:maybe [:map [:a int?]]] => [:or [:= nil nil] [:map [:a int?]]]

2025-06-10T17:29:31.776059Z

I guess keys-groups is trivial if converted to DNF, so the real work is DNF. I don't think I've specifically tried this, but I have applied De Morgan laws to schemas which would have a similar shape https://github.com/frenchy64/malli/pull/4/files#diff-9f5ce127b24a172f70188161d9c355f41891bfa64fa107800d6fb7389e2b23cb

2025-06-10T18:08:37.094169Z

even mut/keys could be defined in terms of this:

(defn keys [s] (some seq (keys-groups s)))

escherize 2025-06-10T18:08:52.371039Z

I see how Operations like keys-groups become trivial because you can analyze each disjunct separately

👍 1
Samuel Ludwig 2025-06-10T18:42:32.788309Z

Got a strange exception/interaction with malli dev-mode (experienced with the last two versions of the lib, unconfirmed on others); I think it might have something to do with the experimental.time interface. Flowstorm doesn't seem to give me readouts of whats happening, but it seems like its happening when calling of one of my instrumented functions (specifically when checking the schema of the return value if I had to guess). When I run the function outside of dev-mode, there are no exceptions, with dev-mode, I get a java.lang.UnsupportedOperationException, on what seems to be a conversion of some value to an Instant. I'm writing this now before I do any kind of deep-dive(/learn how to do proper git-bisecting), so I only have rudimentary info and a stack-trace (which I will append in-thread).

2025-06-26T12:08:03.415729Z

It does look like a bug in fipp. I updated the fipp issue you linked but basically it's trying to call .toInstant on a java.sql.Date which according to the docs always throws an UnsupportedOperationException: https://devdocs.io/openjdk~21/java.sql/java/sql/date#toInstant()

Samuel Ludwig 2025-06-26T14:41:20.321459Z

Ahhh, ok I just now finally realized it does occur in the above example if I use (java.sql.Date.) instead of (java.util.Date.)~ weird though, I am pulling dates from a mysql DB but they always materialize as an #inst for me normally... just not sure what the source of this is still, I definitely don't have any calls to java.sql.Date in my codebase by itself, unless its involved in some kind of transformation-dance for malli. I do use the experimental.time namespace where I assume this is ultimately coming from, but I'm not seeing any explicit reference to java.sql itself in there?

2025-06-26T14:50:18.224809Z

Yeah, it can be confusing b/c an #inst isn't actually a type:

clojure
user=> (clojure.instant/read-instant-date "2025-06-26")
#inst "2025-06-26T00:00:00.000-00:00"
user=> (type (clojure.instant/read-instant-date "2025-06-26"))
java.util.Date
user=> (clojure.instant/read-instant-timestamp "2025-06-26")
#inst "2025-06-26T00:00:00.000000000-00:00"
user=> (type (clojure.instant/read-instant-timestamp "2025-06-26"))
java.sql.Timestamp

Samuel Ludwig 2025-06-26T14:50:59.033169Z

AHHHHHHH oh wow that makes sense let me confirm

Samuel Ludwig 2025-06-26T14:52:51.368569Z

Indeed!!!

Samuel Ludwig 2025-06-26T15:41:31.287689Z

ok well, i suppose then i'll need to coerce that inst to a different type until that bug is resolved (though, that repo doesn't seem particularly active...)

Samuel Ludwig 2025-06-26T15:53:57.753689Z

I'll also make an issue in the malli repo itself, for documentation's sake at least edit: done https://github.com/metosin/malli/issues/1214

Samuel Ludwig 2025-06-26T15:54:24.224629Z

very much appreciate the help @batoms, this ghost has been in my brain for so long now

2025-06-26T16:59:08.361249Z

You're very welcome

1
Samuel Ludwig 2025-06-25T22:02:04.550549Z

OK i have been really trying to get a minimally reproducible example for about two weeks now, not exactly with much success, but I suspect the error is related to this https://github.com/brandonbloom/fipp/issues/85

Samuel Ludwig 2025-06-25T22:04:42.699399Z

The error does only happen in the function signature where I use an inst? schema (but also seems to happen if I use a time/instant schema as well), but the stacktrace is pretty much identical to the one from the fipp issue

Samuel Ludwig 2025-06-25T22:05:24.163779Z

(just to make clear, I am indeed on the newest version of malli still)

Samuel Ludwig 2025-06-25T22:09:44.046179Z

Feeling slightly insane because the error doesn't happen when I try to use a simpler example like so

(def MySpec
  (m/schema
    [:map
     [:some-time [:map [:my-time inst?]]]
     [:one-thing :string]
     [:another :string]]))

(m/=> my-test-fn [:-> MySpec MySpec])
(defn my-test-fn [m]
  m)

(my-test-fn {:some-time {:my-time (java.util.Date. (System/currentTimeMillis))}
             :one-thing 22
             :another "okay"})
trying to determine what the critical factor is still...

Samuel Ludwig 2025-06-10T18:45:53.652119Z

Samuel Ludwig 2025-06-10T18:49:06.993919Z

I will note that I haven't altered the specs being instrumented in quite some time, and only began experiencing this a few days ago, after an (non-trivially-traceable) series of tangential logic changes.

Samuel Ludwig 2025-06-10T19:10:08.280649Z

In addition: of the two schemas in the instrumented fn (both the only argument, and the return value), they both validate without error when done separately.