Fork me on GitHub
#malli
<
2023-03-24
>
hifumi12308:03:19

Is it possible to use malli to validate a JS object against a schema? Or do I always need to run js->clj beforehand?

juhoteperi11:03:56

There is no way to validate JS objects, but you could use decoding to coerce JS object to clj maps:

(defn to-map [^js o]
  (into {} (map (fn [[k v]]
                  [(keyword k) v])
                (js/Object.entries o))))

(js/console.log
  (pr-str
    (m/decode [:map
               {:decode/json to-map}
               [:a :string]
               [:b :string]
               [:c [:map {:decode/json to-map}
                    [:foo :string]]]]
              #js {:a "a"
                   :b "b"
                   :c #js {:foo "bar"}}
              (mt/json-transformer))))

👍 2
Yab Mas11:03:35

I'm seeing some really weird behaviour when trying to keywordize the result of my db-call (which is done with firestore-clj) The below structure is what I want, but it only keywordizes the top-level keys.

(let [board-link (get-board-link
                   {:platform "jira"
                    :board-id 10001})]
  (m/decode board-link-schema board-link (mt/key-transformer {:decode keyword})))
Now the weird thing. The below example does behave as expected and keywordizes all sub-maps. This is 100% a copy of the first example with only the board-link binding being substituted with the result of the function-call in the first example (copied from the repl). This doesn't make any sense to me. Is it possible that the db-call adds something to the result that confuses malli?
(let [board-link {"item-links" [{"jira-item-id" "EX-6", "monday-item-id" 4176528394}],
                  "jira" {"board-id" 10001},
                  "monday" {"board-id" 3990111892}}]
  (m/decode board-link-schema board-link (mt/key-transformer {:decode keyword})))

juhoteperi11:03:29

Yes, it is possible that the db is returning some objects that look like maps, but arent.

juhoteperi11:03:55

The code seems to refer to some DocumentSnapshot class for example

juhoteperi11:03:06

and there is ds->plain function

juhoteperi11:03:00

You could call class for one of the map-like items from the db call

Yab Mas11:03:34

Mja, the ->plain is for the real-time-data but. I'm doing a normal pull, about which the docs say it returns a normal map: You can use pull to fetch the results as a map.

Yab Mas11:03:05

Which is inline with what I see:

juhoteperi11:03:42

It was working with the top-level keys? What about objects inside item-links?

juhoteperi11:03:04

Or the values of jira and monday properties

juhoteperi11:03:38

But what is the class for those values

Yab Mas11:03:07

Ok I see, java.util.HashMap

Yab Mas11:03:44

Not sure what the best solution is, but should be able to figure it out from here. Thanks 🙏

juhoteperi11:03:03

You can add :decode/json (fn [v] (to-clj-map v)) to the map schemas where the value need to be convereted from HashMap to clj

juhoteperi11:03:29

(into {} v) or something might be enough

Yab Mas11:03:41

Ah, perfect. Will try.

juhoteperi11:03:18

Once it is clj map, Malli will handle key and value transformations inside the map like regular

Yab Mas13:03:07

Just confirming this is now solved. Still had to tinker a bit, but that was more because of me being relatively new with malli. Thanks again for the quick help 😉

souenzzo12:03:25

Hello. On this code:

(m/explain [:map {:closed true}]
  {:a 43})
=>
{:schema [:map {:closed true}],
 :value {:a 43},
 :errors ({:path [:a], :in [:a], :schema [:map {:closed true}], :value nil, :type :malli.core/extra-key})}
It reports :value nil. it is expected? I was expecting it to report :value 43

ikitommi13:03:41

it could retain the value. PR welcome

👍 2
souenzzo13:03:56

Actually it should be something with my custom schema registry.