Fork me on GitHub
#malli
<
2024-05-16
>
Karol Wójcik04:05:53

Q: How can we create a schema for Tuples (see https://docs.datomic.com/schema/schema-reference.html#composite-tuples) taking into account :db/valueType set to :db.type/tuple should imply either Composite Tuple, Heterogeneous tuple or Homogeneus tuple. Is there a syntax in malli to support this kind of linkage?

Karol Wójcik04:05:18

Hope the answer is not multi schema with hand written enumeration of every combination 😂

ambrosebs04:05:44

;; implications of keys is not very well supported. can hack it together with :and+:map+:map-of.
[:multi {:dispatch :db/valueType}
 [:db.type/tuple [:map [:db/tupleType {:optional true} ...]
                       [:db/tupleAttrs {:optional true} ...]
                       [:db/tupleTypes {:optional true} ...]]]]
This is directly supported in https://github.com/metosin/malli/pull/1025:
[:multi {:dispatch :db/valueType}
 [:db.type/tuple [:map {:xor [:db/tupleType :db/tupleAttrs :db/tupleTypes]}
                  [:db/tupleType {:optional true} ...]
                  [:db/tupleAttrs {:optional true} ...]
                  [:db/tupleTypes {:optional true} ...]]]]

ambrosebs04:05:04

;; this is kind of hack I'm alluding to
[:multi {:dispatch :db/valueType}
 [:db.type/tuple [:and
                  [:map [:db/tupleType {:optional true} ...]
                        [:db/tupleAttrs {:optional true} ...]
                        [:db/tupleTypes {:optional true} ...]]
                  [:fn #(= 1 (count (filter #{:db/tupleType :db/tupleAttrs :db/tupleTypes} (keys %))))]]

ambrosebs05:05:53

I wonder if I can directly add :dispatch as a keyset constraint like:

[:map {:dispatch [:db/valueType
                  [:db.type/tuple [:xor :db/tupleType :db/tupleAttrs :db/tupleTypes]]]
                  [:db.type/string ...]
                  [:db.type/ref ...]}
 [:db/tupleType {:optional true} ...]
 [:db/tupleAttrs {:optional true} ...]
 [:db/tupleTypes {:optional true} ...]]

Karol Wójcik08:05:13

Hm, what about chaining many :fn in :and? I think it might work really well to add schema contraints? What is your opinion?

ambrosebs15:05:19

IMO it only works well for validation. it might make generators fail, and you need to add custom error messages. but it's your only choice atm (e.g., the "hack" schema I posted 3 messages ago).

Karol Wójcik15:05:04

Thank you @U055XFK8V! I will patiently wait till this use case is more widely supported upstream!

Ben Wadsworth14:05:45

Is there/I can't find a way to apply a custom generator to a whole schema... ie. I have property A which I want to generator with wither a 1 or a 2 and then have property B generate with an X or a Y based on that generated A property.

(defn custom-generator
  []
  (gen/let [prop-a (gen/elements [1 2])]
    {:A prop-a
     :B (if (= 1 prop-a) "X" "Y")}))

(def my-schema
  [:map
   {:gen custom-generator}
   [:A [:enum 1 2]]
   [:B [:enum "X" "Y"]]])

(mg/generate my-schema)
This doesn't work, I will get something like {:A 1 :B "Y"}

ambrosebs15:05:27

{:gen/gen (custom-generator)}

Ben Wadsworth15:05:32

facepalm just had to use it as a function huh.. Thanks! I got what I needed