Skip to content

Commit

Permalink
Support :error/path in humanized errors. Fix #105
Browse files Browse the repository at this point in the history
  • Loading branch information
ikitommi committed Nov 2, 2019
1 parent 1ce6e85 commit 87ce2f2
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 8 deletions.
31 changes: 31 additions & 0 deletions README.md
Expand Up @@ -201,6 +201,37 @@ Messages can be localized:
; :age "10, pitäisi olla > 18"}
```

Top-level humanized map-errors are under `:malli/error`:

```clj
(-> [:and [:map
[:password string?]
[:password2 string?]]
[:fn {:error/message "passwords don't match"}
'(fn [{:keys [password password2]}]
(= password password2))]]
(m/explain {:password "secret"
:password2 "faarao"})
(me/humanize {:wrap :message}))
; {:malli/error "passwords don't match"}
```

Errors can be targetted using `:error/path` property:

```clj
(-> [:and [:map
[:password string?]
[:password2 string?]]
[:fn {:error/message "passwords don't match"
:error/path [:password2]}
'(fn [{:keys [password password2]}]
(= password password2))]]
(m/explain {:password "secret"
:password2 "faarao"})
(me/humanize {:wrap :message}))
; {:password2 "passwords don't match"}
```

## Value Transformation

Schema-driven value transformations with `m/transform`:
Expand Down
15 changes: 14 additions & 1 deletion src/malli/error.cljc
Expand Up @@ -78,10 +78,23 @@
acc acc
:else error))

(defn- -path [{:keys [schema]}
{:keys [locale default-locale]
:or {default-locale :en}}]
(let [properties (m/properties schema)]
(or (-maybe-localized (:error/path properties) locale)
(-maybe-localized (:error/path properties) default-locale))))

;;
;; public api
;;

(defn error-path
([error]
(error-path error nil))
([error opts]
(into (:in error) (-path error opts))))

(defn error-message
([error]
(error-message error nil))
Expand Down Expand Up @@ -118,6 +131,6 @@
(if (coll? value)
(reduce
(fn [acc error]
(-assoc-in acc value (:in error) (f (with-error-message error opts))))
(-assoc-in acc value (error-path error opts) (f (with-error-message error opts))))
nil errors)
(f (with-error-message (first errors) opts))))))
30 changes: 23 additions & 7 deletions test/malli/error_test.cljc
Expand Up @@ -107,16 +107,32 @@
(deftest composing-with-and-test

(testing "top-level map-schemas are written in :malli/error"
(let [map-schema [:and [:map [:x int?]
[:y int?]
[:z int?]]
[:fn {:error/message "(> x y)"}
'(fn [{:keys [x y]}] (> x y))]]]
(let [schema [:and [:map
[:x int?]
[:y int?]
[:z int?]]
[:fn {:error/message "(> x y)"}
'(fn [{:keys [x y]}] (> x y))]]]

(is (= {:z "should be int", :malli/error "(> x y)"}
(-> map-schema
(-> schema
(m/explain {:x 1 :y 2, :z "1"})
(me/humanize {:wrap :message}))))))
(me/humanize {:wrap :message})))))

(testing ":error/path contributes to path"
(let [schema [:and [:map
[:password string?]
[:password2 string?]]
[:fn {:error/message "passwords don't match"
:error/path [:password2]}
'(fn [{:keys [password password2]}]
(= password password2))]]]

(is (= {:password2 "passwords don't match"}
(-> schema
(m/explain {:password "secret"
:password2 "faarao"})
(me/humanize {:wrap :message})))))))

(testing "on collections, first error wins"
(let [schema [:and
Expand Down

0 comments on commit 87ce2f2

Please sign in to comment.