Fork me on GitHub
#malli
<
2023-05-19
>
Shuai Lin06:05:09

hello channel đź‘‹ is there a way to specify a map that 1. must have a key :foo 2. and must have one (and only one) of :bar or :baz ? this shall work but looks awkward

[:and
   [:map
    [:foo :string]]
   [:or
    [:map [:bar :string]]
    [:map [:baz :string]]]]

tomc15:05:15

Hi All, Is there some shorthand for when an optional key is also allowed to be nil? For my purposes, if a key is absent that is the same as if it is present with the value nil . Right now I'm doing [:map [:k {:optional true} [:maybe string?]]] , but perhaps there is a better way?

p-himik21:05:44

Would also love to have something like that. But at the very least, since it's all data, you can easily create your own wrapper function that produces that vector.

escherize21:05:33

I would use [:map [:k {:optional true} [:maybe string?]]].

p-himik21:05:54

It's fine for a one-off (or "few-off"), but doesn't feel great when it's repeated tens of times.

escherize21:05:37

We have it in a few places. You can of course make code that returns [:k {:optional true} [:maybe string?]], but the current design is nice because optional is a property of the key, and maybe is a property of the value

tomc21:05:06

Thanks for the replies, all makes sense.

escherize21:05:47

Unrelated but in janet you cannot have nil as a value in a map for this reason!

escherize21:05:05

This way to “dissoc” a key, you can “assoc” the key with a nil value. 🎉

escherize21:05:48

(put  @{:a 4 :b 5}  :b nil)  
# => @{:a 4}

p-himik21:05:33

Not sure what you mean by "this reason", but it's rather practical to be able to distinguish between "there's no key" and "there's no value for this key". At the very least for easy communication with other entities that support nil-like things, e.g. relational databases.

escherize21:05:03

“this reason” => it is often not a useful distinction (:a {}) vs (:a {:a nil}).

escherize21:05:03

I meant it as a response to: > For my purposes, if a key is absent that is the same as if it is present with the value nil .

James Vickers21:05:03

Hi all! I was trying out the new https://github.com/metosin/malli#malliexperimentaltime feature and had a couple questions about using it for JSON schema đź§µ Thanks much for an awesome library!

James Vickers21:05:12

1. Is it intentional that https://github.com/metosin/malli/blob/master/src/malli/experimental/time/json_schema.cljc doesn’t have implementations for some of the specs like :time/instant? It seems like I’d need to implement malli.json-schema/accept for the missing specs to make them work properly for JSON schema. 2. I’m a bit surprised at the generated JSON schema for the new time specs; it uses references and is different than the corresponding predicate functions. I was hoping the new time keywords would generate a JSON schema similar to or the same as the corresponding predicate functions. I think this difference might be because of https://github.com/metosin/malli/blob/1a735fe5550b7dccf0832433f2f6d68ce9355edc/src/malli/core.cljc#L172 for these? Example:

(require '[malli.json-schema :as json-schema])

(json-schema/transform [:map [:t inst?]])
=> {:type "object", :properties {:t {:type "string", :format "date-time"}}, :required [:t]}

(json-schema/transform [:map [:t :time/instant]])
=> {:type "object", :properties {:t {:$ref "#/definitions/time~1instant"}}, :required [:t], :definitions #:time{:instant {}}}

Ben Sless21:05:44

I'm partially to blame for your troubles, because I authored this implementation - I only implemented what's in the json schema spec, so maybe you should use a offset-date-time instead of an instant?

James Vickers14:05:41

That wouldn’t have the same JSON representation or clojure/java type. We use java.time.Instant with ISO-8601 in JSON such as "2023-05-22T14:45:26.345322Z"

Ben Sless15:05:05

Isn't the Z representing zone offset?

James Vickers15:05:56

I think so, but with no offset since Instant is always UTC time zone? Using OffsetDateTime would be a different type than Instant which adds some inconvenience.

Ben Sless15:05:53

AFAIK instance has no zone, not a default zone,evident by it having no method to get an offset or zone from it, only adding them to it, getting a different time. To make things more annoying, there is no equivalent in Json schema, only offset date time.

👍 2
James Vickers15:05:15

Using inst? in a malli schema gives {:type "string", :format "date-time"} . I’m thinking :time/instant and inst? should preferably produce the same JSON schema.

Ben Sless15:05:49

https://datatracker.ietf.org/doc/html/rfc3339#section-5.6 full-time = partial-time time-offset date-time = full-date "T" full-time

James Vickers18:05:48

I’m confused what’s wrong specifically, can you clarify? The way inst? is serialized is wrong? The JSON schema that malli produces for inst? makes sense to me, since it’s an ISO-8601 string with an optional offset or just Z when there is no offset (e.g. UTC). The date-time format also matches how java.time.Instant is serialized to JSON by clojure and java libraries, as ISO-8601 strings. It also still seems to me like there’s a pain point and confusion if :time/instant and inst? generate different JSON schema representations even though they both are java.time.Instant and have the same JSON string representation.