Fork me on GitHub
#schema
<
2018-05-18
>
nha11:05:52

Hello @ikitommi finally following on our conversation from https://clojurians-log-staging.clojureverse.org/schema/2017-10-16.html I gave your fn a try - it is not exactly the behaviour I am after. I would like to know if there is something that would help in schema-tools?

(require '[schema-tools.core :as st]
         '[schema.coerce]
         '[schema.core :as s])

(defn coercer [schema matcher {:keys [open?]}]
  (let [f (if open? st/open-schema identity)]
    (schema.coerce/coercer (f schema) matcher)))

(def schema {:a Long, :b [(s/maybe {:a Long, s/Keyword s/Keyword})]})

(def schema-coercer (coercer schema (constantly nil) {:open? true}))

(deftest coerce-data

  (testing "coerces values correctly"
    ;; OK
    (is (= {:a 1, :b [{:a 1, "kikka" "kukka"}], "kukka" "kakka"}
           (schema-coercer {:a 1, :b [{:a 1, "kikka" "kukka"}], "kukka" "kakka"}))))

  (testing "returns coerced data even if missing keys/errors"
    ;; KO
    (is (= {:a 1}
           (schema-coercer {:a 1}))))

  (testing "leaves extra keys"
    ;; KO
    (is (= {:a 1 :z "extra"}
           (schema-coercer {:a 1
                            :z "extra"}))))

  (testing "coerces nested data"
    ;; OK
    (is (= {:a 1, :b [{:a 1, "kikka" "kukka"}], "kukka" "kakka"}
           (schema-coercer {:a 1, :b [{:a 1, "kikka" "kukka"}], "kukka" "kakka"}))))

  (testing "leaves extra nested data"
    ;; OK
    (is (= {:a 1, :b [{:a 1, "kikka" "kukka"
                       :nested "keep-me-please"}], "kukka" "kakka"}
           (schema-coercer {:a 1, :b [{:a 1, "kikka" "kukka"
                                       :nested "keep-me-please"}], "kukka" "kakka"}))))

  (testing "leave data"
    ;; KO
    (is (= {:a 1, :b [{:a 1, "kikka" "kukka"}
                      {:b "keep-me-too"}], "kukka" "kakka"}
           (schema-coercer {:a 1, :b [{:a 1, "kikka" "kukka"}
                                      {:b "keep-me-too"}], "kukka" "kakka"}))))
  )
Basically I am after a coerce that always returns the data, and coerces as much as possible of it. Validation is a secondary, although what I currently do is return {:data {...} :errors {}} (and just log the errors). However my code currently doesn’t handle nested data (was fine since it was only used on data from an SQL database, which was flat). I would like to know if there is something that would help build the above in schema-tools?

nha19:05:04

It turns out schema.tools/get-in is really useful for my use case 😄

nha20:05:35

Something bugs my though - why does the following returns nil in the second case?

(st/get-in  {:a s/Int} [:a]) ;; ok
  (st/get-in  (s/maybe {:a s/Int}) [:a]) ;; why nil?

justinlee22:05:31

@nha I think because st/get-in works on associative schemas and the result of s/maybe isn’t associative. this works, for example: (st/get-in {:a (s/maybe s/Int)} [:a])

🙂 1