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?It turns out schema.tools/get-in
is really useful for my use case 😄
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?
@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])