From bec2dee441ea3d949ac59e674cb497bf9b28c260 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Tue, 21 Nov 2023 14:25:18 -0500 Subject: [PATCH 1/4] document :or vs :union vs :merge --- README.md | 57 +++++++++++++++++++++++++++++++++++++++ test/malli/util_test.cljc | 26 ++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/README.md b/README.md index 4c5d430b6..4ab3e9cb0 100644 --- a/README.md +++ b/README.md @@ -1486,6 +1486,63 @@ Merged ; => true ``` +`:union` is similar to `:or`, except map schemas in different disjuncts are merged +together with `:or`. +For example, `UnionMaps` is equivalent to `[:map [:x [:or :int :string]] [:y [:or :int :string]]]`. + +```clojure +(def OrMaps + (m/schema + [:merge + [:map [:x :int] [:x :string]] + [:map [:x :string] [:x :int]]] + {:registry registry})) + +(def UnionMaps + (m/schema + [:merge + [:map [:x :int] [:x :string]] + [:map [:x :string] [:x :int]]] + {:registry registry})) + +(m/validate OrMaps {:x "kikka" :y "kikka"}) +; => false + +(m/validate UnionMaps {:x "kikka" :y "kikka"}) +; => true +``` + +`:merge` and `:union` differ on schemas with common keys: right-most +map schemas win with `:merge`, and schemas are joined with `:or` with `:union`. +For example, `MergedCommon` is equivalent to `[:map [:x :int]]`, and UnionCommon +is equivalent to `[:map [:x [:or :string :int]]]`. + +```clojure +(def MergedCommon + (m/schema + [:merge + [:map [:x :string]] + [:map [:x :int]]] + {:registry registry})) + +(def UnionCommon + (m/schema + [:merge + [:map [:x :string]] + [:map [:x :int]]] + {:registry registry})) + +(m/validate MergedCommon {:x "kikka"}) +; => true +(m/validate MergedCommon {:x 1}) +; => false +(m/validate UnionCommon {:x "kikka"}) +; => true +(m/validate UnionCommon {:x 1}) +; => true +``` + + ## Persisting schemas Writing and Reading schemas as [EDN](https://github.com/edn-format/edn), no `eval` needed. diff --git a/test/malli/util_test.cljc b/test/malli/util_test.cljc index e5fe993c9..1f3652726 100644 --- a/test/malli/util_test.cljc +++ b/test/malli/util_test.cljc @@ -822,6 +822,32 @@ (is (= {:x [:str "x"]} (m/parse s {:x "x"}))) (is (= {:x 1} (m/parse s {:x 1}))))) + (testing "merge vs union" + (let [->s #(->> [% + [:map [:x :string]] + [:map [:x :int]]]) + u (->s :union) + m (->s :merge)] + (is (m/validate u {:x 1})) + (is (m/validate u {:x "a"})) + (is (m/validate m {:x 1})) + (is (m/explain m {:x "a"})))) + + (testing "union vs or" + (let [->s #(->> [% + [:map [:x :string] [:y :int]] + [:map [:x :int] [:y :string]]]) + u (->s :union) + o (->s :or)] + (is (m/validate u {:x 1 :y 1})) + (is (m/validate u {:x 1 :y "a"})) + (is (m/validate u {:x "a" :y 1})) + (is (m/validate u {:x "a" :y "a"})) + (is (m/explain o {:x 1 :y 1})) + (is (m/validate o {:x 1 :y "a"})) + (is (m/validate o {:x "a" :y 1})) + (is (m/explain o {:x "a" :y "a"})))) + (testing "select-keys" (let [s (->> [:select-keys [:schema From fc301062ac6f2cda2bcae244e3c701e39b8d1ca6 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Tue, 21 Nov 2023 14:33:18 -0500 Subject: [PATCH 2/4] fmt --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ab3e9cb0..fd0d5a00a 100644 --- a/README.md +++ b/README.md @@ -1514,7 +1514,7 @@ For example, `UnionMaps` is equivalent to `[:map [:x [:or :int :string]] [:y [:o `:merge` and `:union` differ on schemas with common keys: right-most map schemas win with `:merge`, and schemas are joined with `:or` with `:union`. -For example, `MergedCommon` is equivalent to `[:map [:x :int]]`, and UnionCommon +For example, `MergedCommon` is equivalent to `[:map [:x :int]]`, and `UnionCommon` is equivalent to `[:map [:x [:or :string :int]]]`. ```clojure From 6ca4877b789550eed5cef1b9316fce3984d4bce3 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Tue, 21 Nov 2023 14:36:17 -0500 Subject: [PATCH 3/4] feedback --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fd0d5a00a..dc2c80205 100644 --- a/README.md +++ b/README.md @@ -1493,14 +1493,14 @@ For example, `UnionMaps` is equivalent to `[:map [:x [:or :int :string]] [:y [:o ```clojure (def OrMaps (m/schema - [:merge + [:or [:map [:x :int] [:x :string]] [:map [:x :string] [:x :int]]] {:registry registry})) (def UnionMaps (m/schema - [:merge + [:union [:map [:x :int] [:x :string]] [:map [:x :string] [:x :int]]] {:registry registry})) @@ -1527,7 +1527,7 @@ is equivalent to `[:map [:x [:or :string :int]]]`. (def UnionCommon (m/schema - [:merge + [:union [:map [:x :string]] [:map [:x :int]]] {:registry registry})) From d63ce568c1fbbde3d542043736e41b666bf1ee88 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Tue, 21 Nov 2023 14:44:37 -0500 Subject: [PATCH 4/4] reword --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index dc2c80205..497388b85 100644 --- a/README.md +++ b/README.md @@ -1486,8 +1486,7 @@ Merged ; => true ``` -`:union` is similar to `:or`, except map schemas in different disjuncts are merged -together with `:or`. +`:union` is similar to `:or`, except `:union` combines map schemas in different disjuncts with `:or`. For example, `UnionMaps` is equivalent to `[:map [:x [:or :int :string]] [:y [:or :int :string]]]`. ```clojure @@ -1512,8 +1511,8 @@ For example, `UnionMaps` is equivalent to `[:map [:x [:or :int :string]] [:y [:o ; => true ``` -`:merge` and `:union` differ on schemas with common keys: right-most -map schemas win with `:merge`, and schemas are joined with `:or` with `:union`. +`:merge` and `:union` differ on schemas with common keys. `:merge` chooses the right-most +schema of common keys, and `:union` combines them with `:or`. For example, `MergedCommon` is equivalent to `[:map [:x :int]]`, and `UnionCommon` is equivalent to `[:map [:x [:or :string :int]]]`.