From fc595e34ac3b7453af8e96e8b8c743323c2bc0b8 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Thu, 8 Aug 2024 13:29:30 -0500 Subject: [PATCH 01/18] prototype --- src/malli/core.cljc | 16 ++++++++++++++++ src/malli/util.cljc | 2 ++ test/malli/util_test.cljc | 12 +++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/malli/core.cljc b/src/malli/core.cljc index f8818b8bb..d01950664 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -92,12 +92,16 @@ (-function-info [this]) (-instrument-f [schema props f options])) +(defprotocol DistributiveSchema + (-distribute-to-children [this f options])) + (defn -ref-schema? [x] (#?(:clj instance?, :cljs implements?) malli.core.RefSchema x)) (defn -entry-parser? [x] (#?(:clj instance?, :cljs implements?) malli.core.EntryParser x)) (defn -entry-schema? [x] (#?(:clj instance?, :cljs implements?) malli.core.EntrySchema x)) (defn -cached? [x] (#?(:clj instance?, :cljs implements?) malli.core.Cached x)) (defn -ast? [x] (#?(:clj instance?, :cljs implements?) malli.core.AST x)) (defn -transformer? [x] (#?(:clj instance?, :cljs implements?) malli.core.Transformer x)) +(defn -distributive? [x] (#?(:clj instance?, :cljs implements?) malli.core.DistributiveSchema x)) (extend-type #?(:clj Object, :cljs default) FunctionSchema @@ -1613,6 +1617,18 @@ (reify AST (-to-ast [this _] (-entry-ast this (-entry-keyset entry-parser))) + DistributiveSchema + (-distribute-to-children [this f options'] + (prn "-distribute-to-children") + (-into-schema parent + properties + (mapv (fn [c] + (when-not (and (vector? c) + (= 2 (count c))) + (throw (ex-info "TODO" {}))) + (update c 1 f options)) + children) + options)) Schema (-validator [_] (let [find (finder (reduce-kv (fn [acc k s] (assoc acc k (-validator s))) {} @dispatch-map))] diff --git a/src/malli/util.cljc b/src/malli/util.cljc index 79f8d7e66..7ae519bfa 100644 --- a/src/malli/util.cljc +++ b/src/malli/util.cljc @@ -80,6 +80,8 @@ (cond (nil? s1) s2 (nil? s2) s1 + (m/-distributive? s1) (m/-distribute-to-children s1 (fn [s _options] (merge s s2 options)) options) + (m/-distributive? s2) (m/-distribute-to-children s2 (fn [s _options] (merge s1 s options)) options) (not (and (-> t1 #{:map :and}) (-> t2 #{:map :and}))) (merge-default s1 s2 options) (not (and (-> t1 (= :map)) (-> t2 (= :map)))) (join (tear t1 s1) (tear t2 s2)) :else (let [p (bear (m/-properties s1) (m/-properties s2)) diff --git a/test/malli/util_test.cljc b/test/malli/util_test.cljc index e0a8c7522..f0448dbb8 100644 --- a/test/malli/util_test.cljc +++ b/test/malli/util_test.cljc @@ -813,7 +813,17 @@ [:z {:optional true} :boolean]] (m/form (m/deref s)))) (is (= true (m/validate s {:x "x", :y 1, :z true}))) (is (= false (m/validate s {:x "x", :y "y"}))) - (is (= {:x [:str "x"], :y 1, :z true} (m/parse s {:x "x", :y 1, :z true}))))) + (is (= {:x [:str "x"], :y 1, :z true} (m/parse s {:x "x", :y 1, :z true}))) + (is (= (m/form + (m/deref + (->> [:merge + [:map [:x :int]] + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]]]))) + [:multi {:dispatch :y} + [1 [:map [:x :int] [:y [:= 1]]]] + [2 [:map [:x :int] [:y [:= 2]]]]])))) (testing "union" (let [s (->> [:union From 7c676d6714e238bc06ffc3fbb55373f05b4a743a Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Thu, 8 Aug 2024 15:09:42 -0500 Subject: [PATCH 02/18] orn or --- src/malli/core.cljc | 15 +++++- test/malli/distributive_test.cljc | 80 +++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 test/malli/distributive_test.cljc diff --git a/src/malli/core.cljc b/src/malli/core.cljc index d01950664..2b7bd8362 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -799,6 +799,9 @@ #(reduce (fn [_ parser] (miu/-map-valid reduced (parser %))) ::invalid parsers)))] ^{:type ::schema} (reify + DistributiveSchema + (-distribute-to-children [this f options'] + (-into-schema parent properties (mapv #(f % options) children) options)) Schema (-validator [_] (let [validators (-vmap -validator children)] (miu/-some-pred validators))) @@ -844,6 +847,17 @@ cache (-create-cache options)] ^{:type ::schema} (reify + DistributiveSchema + (-distribute-to-children [this f options'] + (-into-schema parent + properties + (mapv (fn [c] + (when-not (and (vector? c) + (= 2 (count c))) + (throw (ex-info "TODO" {}))) + (update c 1 f options)) + children) + options)) AST (-to-ast [this _] (-entry-ast this (-entry-keyset entry-parser))) Schema @@ -1619,7 +1633,6 @@ (-to-ast [this _] (-entry-ast this (-entry-keyset entry-parser))) DistributiveSchema (-distribute-to-children [this f options'] - (prn "-distribute-to-children") (-into-schema parent properties (mapv (fn [c] diff --git a/test/malli/distributive_test.cljc b/test/malli/distributive_test.cljc new file mode 100644 index 000000000..908fc98b3 --- /dev/null +++ b/test/malli/distributive_test.cljc @@ -0,0 +1,80 @@ +(ns malli.distributive-test + (:require [clojure.test :refer [are deftest is testing]] + [malli.core :as m] + [malli.impl.util :as miu] + [malli.registry :as mr] + [malli.transform :as mt] + [malli.util :as mu])) + +(def options {:registry (merge (mu/schemas) (m/default-schemas))}) + +(deftest distributive-test + (is (= (m/form + (m/deref + [:merge + [:map [:x :int]] + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]]] + options)) + [:multi {:dispatch :y} + [1 [:map [:x :int] [:y [:= 1]]]] + [2 [:map [:x :int] [:y [:= 2]]]]])) + (is (= (m/form + (m/deref + [:merge + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:map [:x :int]]] + options)) + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]] [:x :int]]] + [2 [:map [:y [:= 2]] [:x :int]]]])) + + (is (= (m/form + (m/deref + [:merge + [:map [:x :int]] + [:orn + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]]] + options)) + [:orn + [1 [:map [:x :int] [:y [:= 1]]]] + [2 [:map [:x :int] [:y [:= 2]]]]])) + (is (= (m/form + (m/deref + [:merge + [:orn + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:map [:x :int]]] + options)) + [:orn + [1 [:map [:y [:= 1]] [:x :int]]] + [2 [:map [:y [:= 2]] [:x :int]]]])) + + (is (= (m/form + (m/deref + [:merge + [:map [:x :int]] + [:or + [:map [:y [:= 1]]] + [:map [:y [:= 2]]]]] + options)) + [:or + [:map [:x :int] [:y [:= 1]]] + [:map [:x :int] [:y [:= 2]]]])) + (is (= (m/form + (m/deref + [:merge + [:or + [:map [:y [:= 1]]] + [:map [:y [:= 2]]]] + [:map [:x :int]]] + options)) + [:or + [:map [:y [:= 1]] [:x :int]] + [:map [:y [:= 2]] [:x :int]]])) + ) From 445f90deca99a1f91c7d7c4c356cce51ae2b282b Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Thu, 8 Aug 2024 15:11:59 -0500 Subject: [PATCH 03/18] and --- src/malli/core.cljc | 3 +++ test/malli/distributive_test.cljc | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/malli/core.cljc b/src/malli/core.cljc index 2b7bd8362..0a4a7cdcd 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -760,6 +760,9 @@ #(reduce (fn [x parser] (miu/-map-invalid reduced (parser x))) % parsers)))] ^{:type ::schema} (reify + DistributiveSchema + (-distribute-to-children [this f options'] + (-into-schema parent properties (mapv #(f % options) children) options)) Schema (-validator [_] (let [validators (-vmap -validator children)] (miu/-every-pred validators))) diff --git a/test/malli/distributive_test.cljc b/test/malli/distributive_test.cljc index 908fc98b3..514669556 100644 --- a/test/malli/distributive_test.cljc +++ b/test/malli/distributive_test.cljc @@ -77,4 +77,26 @@ [:or [:map [:y [:= 1]] [:x :int]] [:map [:y [:= 2]] [:x :int]]])) + (is (= (m/form + (m/deref + [:merge + [:map [:x :int]] + [:and + [:map [:y [:= 1]]] + [:map [:y [:= 2]]]]] + options)) + [:and + [:map [:x :int] [:y [:= 1]]] + [:map [:x :int] [:y [:= 2]]]])) + (is (= (m/form + (m/deref + [:merge + [:and + [:map [:y [:= 1]]] + [:map [:y [:= 2]]]] + [:map [:x :int]]] + options)) + [:and + [:map [:y [:= 1]] [:x :int]] + [:map [:y [:= 2]] [:x :int]]])) ) From 215ab135d1ce3276554b273701e0030feefa2027 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Thu, 8 Aug 2024 15:33:42 -0500 Subject: [PATCH 04/18] -and --- src/malli/core.cljc | 3 --- test/malli/distributive_test.cljc | 25 +------------------------ test/malli/util_test.cljc | 17 +++++------------ 3 files changed, 6 insertions(+), 39 deletions(-) diff --git a/src/malli/core.cljc b/src/malli/core.cljc index 0a4a7cdcd..2b7bd8362 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -760,9 +760,6 @@ #(reduce (fn [x parser] (miu/-map-invalid reduced (parser x))) % parsers)))] ^{:type ::schema} (reify - DistributiveSchema - (-distribute-to-children [this f options'] - (-into-schema parent properties (mapv #(f % options) children) options)) Schema (-validator [_] (let [validators (-vmap -validator children)] (miu/-every-pred validators))) diff --git a/test/malli/distributive_test.cljc b/test/malli/distributive_test.cljc index 514669556..edff83c76 100644 --- a/test/malli/distributive_test.cljc +++ b/test/malli/distributive_test.cljc @@ -76,27 +76,4 @@ options)) [:or [:map [:y [:= 1]] [:x :int]] - [:map [:y [:= 2]] [:x :int]]])) - (is (= (m/form - (m/deref - [:merge - [:map [:x :int]] - [:and - [:map [:y [:= 1]]] - [:map [:y [:= 2]]]]] - options)) - [:and - [:map [:x :int] [:y [:= 1]]] - [:map [:x :int] [:y [:= 2]]]])) - (is (= (m/form - (m/deref - [:merge - [:and - [:map [:y [:= 1]]] - [:map [:y [:= 2]]]] - [:map [:x :int]]] - options)) - [:and - [:map [:y [:= 1]] [:x :int]] - [:map [:y [:= 2]] [:x :int]]])) - ) + [:map [:y [:= 2]] [:x :int]]]))) diff --git a/test/malli/util_test.cljc b/test/malli/util_test.cljc index f0448dbb8..42a480919 100644 --- a/test/malli/util_test.cljc +++ b/test/malli/util_test.cljc @@ -37,7 +37,10 @@ (deftest merge-test (are [?s1 ?s2 expected] - (= true (mu/equals expected (mu/merge ?s1 ?s2))) + (do (is (= true (mu/equals expected (mu/merge ?s1 ?s2))) + (with-out-str (clojure.pprint/pprint {:actual (m/form (mu/merge ?s1 ?s2)) + :expected (m/form expected)}))) + true) int? int? int? int? pos-int? pos-int? @@ -813,17 +816,7 @@ [:z {:optional true} :boolean]] (m/form (m/deref s)))) (is (= true (m/validate s {:x "x", :y 1, :z true}))) (is (= false (m/validate s {:x "x", :y "y"}))) - (is (= {:x [:str "x"], :y 1, :z true} (m/parse s {:x "x", :y 1, :z true}))) - (is (= (m/form - (m/deref - (->> [:merge - [:map [:x :int]] - [:multi {:dispatch :y} - [1 [:map [:y [:= 1]]]] - [2 [:map [:y [:= 2]]]]]]))) - [:multi {:dispatch :y} - [1 [:map [:x :int] [:y [:= 1]]]] - [2 [:map [:x :int] [:y [:= 2]]]]])))) + (is (= {:x [:str "x"], :y 1, :z true} (m/parse s {:x "x", :y 1, :z true}))))) (testing "union" (let [s (->> [:union From 9825891e8f211825717c3f7929396dfad8b21837 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Thu, 8 Aug 2024 15:56:50 -0500 Subject: [PATCH 05/18] wip --- src/malli/util.cljc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/malli/util.cljc b/src/malli/util.cljc index 7ae519bfa..4ef0f7c86 100644 --- a/src/malli/util.cljc +++ b/src/malli/util.cljc @@ -70,6 +70,8 @@ s2 (when ?schema2 (m/deref-all (m/schema ?schema2 options))) t1 (when s1 (m/type s1)) t2 (when s2 (m/type s2)) + distributive-allowed? (and (not (contains? options :merge-default)) + (not (contains? options :merge-required))) {:keys [merge-default merge-required] :or {merge-default (fn [_ s2 _] s2) merge-required (fn [_ r2] r2)}} options @@ -80,8 +82,8 @@ (cond (nil? s1) s2 (nil? s2) s1 - (m/-distributive? s1) (m/-distribute-to-children s1 (fn [s _options] (merge s s2 options)) options) - (m/-distributive? s2) (m/-distribute-to-children s2 (fn [s _options] (merge s1 s options)) options) + (and distributive-allowed? (m/-distributive? s1)) (m/-distribute-to-children s1 (fn [s _options] (merge s s2 options)) options) + (and distributive-allowed? (m/-distributive? s2)) (m/-distribute-to-children s2 (fn [s _options] (merge s1 s options)) options) (not (and (-> t1 #{:map :and}) (-> t2 #{:map :and}))) (merge-default s1 s2 options) (not (and (-> t1 (= :map)) (-> t2 (= :map)))) (join (tear t1 s1) (tear t2 s2)) :else (let [p (bear (m/-properties s1) (m/-properties s2)) From 4c748b1a07a47b30c4427b6c027eb7372eb512b8 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Thu, 8 Aug 2024 15:57:47 -0500 Subject: [PATCH 06/18] wip --- test/malli/util_test.cljc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/malli/util_test.cljc b/test/malli/util_test.cljc index 42a480919..e0a8c7522 100644 --- a/test/malli/util_test.cljc +++ b/test/malli/util_test.cljc @@ -37,10 +37,7 @@ (deftest merge-test (are [?s1 ?s2 expected] - (do (is (= true (mu/equals expected (mu/merge ?s1 ?s2))) - (with-out-str (clojure.pprint/pprint {:actual (m/form (mu/merge ?s1 ?s2)) - :expected (m/form expected)}))) - true) + (= true (mu/equals expected (mu/merge ?s1 ?s2))) int? int? int? int? pos-int? pos-int? From d5d0ffac2cd30c1333852796bd3c18448afdb20a Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Thu, 8 Aug 2024 16:06:05 -0500 Subject: [PATCH 07/18] doc --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 0f44477ef..358a32695 100644 --- a/README.md +++ b/README.md @@ -1767,6 +1767,32 @@ is equivalent to `[:map [:x [:or :string :int]]]`. ; => true ``` +`:merge` also distributes over `:or`, `orn`, and `:multi` in the following manner: + +```clojure +(m/deref + [:merge + [:map [:x :int]] + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]]] + {:registry registry}) +; => [:multi {:dispatch :y} +; [1 [:map [:x :int] [:y [:= 1]]]] +; [2 [:map [:x :int] [:y [:= 2]]]]] + +(m/deref + [:merge + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:map [:x :int]]] + {:registry registry}) +; => [:multi {:dispatch :y} +; [1 [:map [:y [:= 1]] [:x :int]]] +; [2 [:map [:y [:= 2]] [:x :int]]]] +``` + ## Persisting schemas From 81c15db6aa03c969d6298bea7702021d894682aa Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 9 Aug 2024 11:37:58 -0500 Subject: [PATCH 08/18] installer --- bin/install | 2 ++ pom.xml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100755 bin/install diff --git a/bin/install b/bin/install new file mode 100755 index 000000000..0e6535605 --- /dev/null +++ b/bin/install @@ -0,0 +1,2 @@ +#!/bin/bash +clojure -M:jar && clojure -M:install diff --git a/pom.xml b/pom.xml index c3c4acd0b..d8c992f81 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 metosin malli - 0.16.3 + 0.16.4-SNAPSHOT malli From c8f8f4591d9bda202af161adaf5961ece6aed465 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 9 Aug 2024 15:08:51 -0500 Subject: [PATCH 09/18] proxy support --- src/malli/core.cljc | 14 ++++- src/malli/util.cljc | 8 +-- test/malli/distributive_test.cljc | 88 ++++++++++++++----------------- 3 files changed, 56 insertions(+), 54 deletions(-) diff --git a/src/malli/core.cljc b/src/malli/core.cljc index 2b7bd8362..886b8c0aa 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -93,6 +93,7 @@ (-instrument-f [schema props f options])) (defprotocol DistributiveSchema + (-distributive-schema? [this]) (-distribute-to-children [this f options])) (defn -ref-schema? [x] (#?(:clj instance?, :cljs implements?) malli.core.RefSchema x)) @@ -110,6 +111,9 @@ (-function-schema-arities [_]) (-instrument-f [_ _ _ _]) + DistributiveSchema + (-distributive-schema? [_] false) + RegexSchema (-regex-op? [_] false) @@ -800,6 +804,7 @@ ^{:type ::schema} (reify DistributiveSchema + (-distributive-schema? [_] true) (-distribute-to-children [this f options'] (-into-schema parent properties (mapv #(f % options) children) options)) Schema @@ -848,7 +853,8 @@ ^{:type ::schema} (reify DistributiveSchema - (-distribute-to-children [this f options'] + (-distributive-schema? [_] true) + (-distribute-to-children [_ f options'] (-into-schema parent properties (mapv (fn [c] @@ -1813,6 +1819,9 @@ RefSchema (-ref [_] id) (-deref [_] child) + DistributiveSchema + (-distributive? [_] (-distributive? child)) + (-distribute-to-children [_ f options] (-distribute-to-children child f options)) RegexSchema (-regex-op? [_] (if internal @@ -2045,6 +2054,9 @@ (-keep [_]) (-get [_ key default] (if (= ::in key) schema (get children key default))) (-set [_ key value] (into-schema type properties (assoc children key value))) + DistributiveSchema + (-distributive? [_] (-distributive? schema)) + (-distribute-to-children [_ f options] (-distribute-to-children schema f options)) FunctionSchema (-function-schema? [_] (-function-schema? schema)) (-function-info [_] (-function-info schema)) diff --git a/src/malli/util.cljc b/src/malli/util.cljc index 4ef0f7c86..eddb887de 100644 --- a/src/malli/util.cljc +++ b/src/malli/util.cljc @@ -70,8 +70,8 @@ s2 (when ?schema2 (m/deref-all (m/schema ?schema2 options))) t1 (when s1 (m/type s1)) t2 (when s2 (m/type s2)) - distributive-allowed? (and (not (contains? options :merge-default)) - (not (contains? options :merge-required))) + can-distribute? (and (not (contains? options :merge-default)) + (not (contains? options :merge-required))) {:keys [merge-default merge-required] :or {merge-default (fn [_ s2 _] s2) merge-required (fn [_ r2] r2)}} options @@ -82,8 +82,8 @@ (cond (nil? s1) s2 (nil? s2) s1 - (and distributive-allowed? (m/-distributive? s1)) (m/-distribute-to-children s1 (fn [s _options] (merge s s2 options)) options) - (and distributive-allowed? (m/-distributive? s2)) (m/-distribute-to-children s2 (fn [s _options] (merge s1 s options)) options) + (and can-distribute? (m/-distributive? s1)) (m/-distribute-to-children s1 (fn [s _options] (merge s s2 options)) options) + (and can-distribute? (m/-distributive? s2)) (m/-distribute-to-children s2 (fn [s _options] (merge s1 s options)) options) (not (and (-> t1 #{:map :and}) (-> t2 #{:map :and}))) (merge-default s1 s2 options) (not (and (-> t1 (= :map)) (-> t2 (= :map)))) (join (tear t1 s1) (tear t2 s2)) :else (let [p (bear (m/-properties s1) (m/-properties s2)) diff --git a/test/malli/distributive_test.cljc b/test/malli/distributive_test.cljc index edff83c76..25ffc3569 100644 --- a/test/malli/distributive_test.cljc +++ b/test/malli/distributive_test.cljc @@ -8,72 +8,62 @@ (def options {:registry (merge (mu/schemas) (m/default-schemas))}) +(defn dist [s] + (m/form (m/deref s options))) + (deftest distributive-test - (is (= (m/form - (m/deref - [:merge - [:map [:x :int]] - [:multi {:dispatch :y} - [1 [:map [:y [:= 1]]]] - [2 [:map [:y [:= 2]]]]]] - options)) + (is (= (dist + [:merge + [:map [:x :int]] + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]]]) [:multi {:dispatch :y} [1 [:map [:x :int] [:y [:= 1]]]] [2 [:map [:x :int] [:y [:= 2]]]]])) - (is (= (m/form - (m/deref - [:merge - [:multi {:dispatch :y} - [1 [:map [:y [:= 1]]]] - [2 [:map [:y [:= 2]]]]] - [:map [:x :int]]] - options)) + (is (= (dist + [:merge + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:map [:x :int]]]) [:multi {:dispatch :y} [1 [:map [:y [:= 1]] [:x :int]]] [2 [:map [:y [:= 2]] [:x :int]]]])) - (is (= (m/form - (m/deref - [:merge - [:map [:x :int]] - [:orn - [1 [:map [:y [:= 1]]]] - [2 [:map [:y [:= 2]]]]]] - options)) + (is (= (dist + [:merge + [:map [:x :int]] + [:orn + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]]]) [:orn [1 [:map [:x :int] [:y [:= 1]]]] [2 [:map [:x :int] [:y [:= 2]]]]])) - (is (= (m/form - (m/deref - [:merge - [:orn - [1 [:map [:y [:= 1]]]] - [2 [:map [:y [:= 2]]]]] - [:map [:x :int]]] - options)) + (is (= (dist + [:merge + [:orn + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:map [:x :int]]]) [:orn [1 [:map [:y [:= 1]] [:x :int]]] [2 [:map [:y [:= 2]] [:x :int]]]])) - - (is (= (m/form - (m/deref - [:merge - [:map [:x :int]] - [:or - [:map [:y [:= 1]]] - [:map [:y [:= 2]]]]] - options)) + (is (= (dist + [:merge + [:map [:x :int]] + [:or + [:map [:y [:= 1]]] + [:map [:y [:= 2]]]]]) [:or [:map [:x :int] [:y [:= 1]]] [:map [:x :int] [:y [:= 2]]]])) - (is (= (m/form - (m/deref - [:merge - [:or - [:map [:y [:= 1]]] - [:map [:y [:= 2]]]] - [:map [:x :int]]] - options)) + (is (= (dist + [:merge + [:or + [:map [:y [:= 1]]] + [:map [:y [:= 2]]]] + [:map [:x :int]]]) [:or [:map [:y [:= 1]] [:x :int]] [:map [:y [:= 2]] [:x :int]]]))) From dd45607a763acf49e018f07a4e8b368116e9b396 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 9 Aug 2024 15:42:16 -0500 Subject: [PATCH 10/18] simplify to just multi, add problematic registry test --- src/malli/core.cljc | 25 ++--------- src/malli/util.cljc | 4 +- test/malli/distributive_test.cljc | 75 ++++++++++++++++++------------- 3 files changed, 50 insertions(+), 54 deletions(-) diff --git a/src/malli/core.cljc b/src/malli/core.cljc index 886b8c0aa..235fd3f4d 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -102,7 +102,6 @@ (defn -cached? [x] (#?(:clj instance?, :cljs implements?) malli.core.Cached x)) (defn -ast? [x] (#?(:clj instance?, :cljs implements?) malli.core.AST x)) (defn -transformer? [x] (#?(:clj instance?, :cljs implements?) malli.core.Transformer x)) -(defn -distributive? [x] (#?(:clj instance?, :cljs implements?) malli.core.DistributiveSchema x)) (extend-type #?(:clj Object, :cljs default) FunctionSchema @@ -113,6 +112,8 @@ DistributiveSchema (-distributive-schema? [_] false) + (-distribute-to-children [this f options'] + (throw (ex-info "Not distributive" {:schema this}))) RegexSchema (-regex-op? [_] false) @@ -803,10 +804,6 @@ #(reduce (fn [_ parser] (miu/-map-valid reduced (parser %))) ::invalid parsers)))] ^{:type ::schema} (reify - DistributiveSchema - (-distributive-schema? [_] true) - (-distribute-to-children [this f options'] - (-into-schema parent properties (mapv #(f % options) children) options)) Schema (-validator [_] (let [validators (-vmap -validator children)] (miu/-some-pred validators))) @@ -852,18 +849,6 @@ cache (-create-cache options)] ^{:type ::schema} (reify - DistributiveSchema - (-distributive-schema? [_] true) - (-distribute-to-children [_ f options'] - (-into-schema parent - properties - (mapv (fn [c] - (when-not (and (vector? c) - (= 2 (count c))) - (throw (ex-info "TODO" {}))) - (update c 1 f options)) - children) - options)) AST (-to-ast [this _] (-entry-ast this (-entry-keyset entry-parser))) Schema @@ -1638,6 +1623,7 @@ AST (-to-ast [this _] (-entry-ast this (-entry-keyset entry-parser))) DistributiveSchema + (-distributive-schema? [_] true) (-distribute-to-children [this f options'] (-into-schema parent properties @@ -1819,9 +1805,6 @@ RefSchema (-ref [_] id) (-deref [_] child) - DistributiveSchema - (-distributive? [_] (-distributive? child)) - (-distribute-to-children [_ f options] (-distribute-to-children child f options)) RegexSchema (-regex-op? [_] (if internal @@ -2055,7 +2038,7 @@ (-get [_ key default] (if (= ::in key) schema (get children key default))) (-set [_ key value] (into-schema type properties (assoc children key value))) DistributiveSchema - (-distributive? [_] (-distributive? schema)) + (-distributive-schema? [_] (-distributive-schema? schema)) (-distribute-to-children [_ f options] (-distribute-to-children schema f options)) FunctionSchema (-function-schema? [_] (-function-schema? schema)) diff --git a/src/malli/util.cljc b/src/malli/util.cljc index eddb887de..a61042e12 100644 --- a/src/malli/util.cljc +++ b/src/malli/util.cljc @@ -82,8 +82,8 @@ (cond (nil? s1) s2 (nil? s2) s1 - (and can-distribute? (m/-distributive? s1)) (m/-distribute-to-children s1 (fn [s _options] (merge s s2 options)) options) - (and can-distribute? (m/-distributive? s2)) (m/-distribute-to-children s2 (fn [s _options] (merge s1 s options)) options) + (and can-distribute? (m/-distributive-schema? s1)) (m/-distribute-to-children s1 (fn [s _options] (merge s s2 options)) options) + (and can-distribute? (m/-distributive-schema? s2)) (m/-distribute-to-children s2 (fn [s _options] (merge s1 s options)) options) (not (and (-> t1 #{:map :and}) (-> t2 #{:map :and}))) (merge-default s1 s2 options) (not (and (-> t1 (= :map)) (-> t2 (= :map)))) (join (tear t1 s1) (tear t2 s2)) :else (let [p (bear (m/-properties s1) (m/-properties s2)) diff --git a/test/malli/distributive_test.cljc b/test/malli/distributive_test.cljc index 25ffc3569..39e825077 100644 --- a/test/malli/distributive_test.cljc +++ b/test/malli/distributive_test.cljc @@ -5,13 +5,19 @@ [malli.registry :as mr] [malli.transform :as mt] [malli.util :as mu])) +(comment + (m/type + [:schema + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]]])) (def options {:registry (merge (mu/schemas) (m/default-schemas))}) (defn dist [s] (m/form (m/deref s options))) -(deftest distributive-test +(deftest distributive-multi-test (is (= (dist [:merge [:map [:x :int]] @@ -21,49 +27,56 @@ [:multi {:dispatch :y} [1 [:map [:x :int] [:y [:= 1]]]] [2 [:map [:x :int] [:y [:= 2]]]]])) - (is (= (dist - [:merge - [:multi {:dispatch :y} - [1 [:map [:y [:= 1]]]] - [2 [:map [:y [:= 2]]]]] - [:map [:x :int]]]) - [:multi {:dispatch :y} - [1 [:map [:y [:= 1]] [:x :int]]] - [2 [:map [:y [:= 2]] [:x :int]]]])) - (is (= (dist [:merge [:map [:x :int]] - [:orn - [1 [:map [:y [:= 1]]]] - [2 [:map [:y [:= 2]]]]]]) - [:orn + [:schema + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]]]]) + [:multi {:dispatch :y} [1 [:map [:x :int] [:y [:= 1]]]] [2 [:map [:x :int] [:y [:= 2]]]]])) (is (= (dist [:merge - [:orn + [:multi {:dispatch :y} [1 [:map [:y [:= 1]]]] [2 [:map [:y [:= 2]]]]] [:map [:x :int]]]) - [:orn + [:multi {:dispatch :y} [1 [:map [:y [:= 1]] [:x :int]]] [2 [:map [:y [:= 2]] [:x :int]]]])) (is (= (dist [:merge - [:map [:x :int]] - [:or - [:map [:y [:= 1]]] - [:map [:y [:= 2]]]]]) - [:or - [:map [:x :int] [:y [:= 1]]] - [:map [:x :int] [:y [:= 2]]]])) + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:multi {:dispatch :y} + [3 [:map [:y [:= 3]]]] + [4 [:map [:y [:= 4]]]]]]) + [:multi {:dispatch :y} + [1 [:multi {:dispatch :y} + [3 [:map [:y [:= 3]]]] + [4 [:map [:y [:= 4]]]]]] + [2 [:multi {:dispatch :y} + [3 [:map [:y [:= 3]]]] + [4 [:map [:y [:= 4]]]]]]]))) + +;;FIXME +(deftest distribute-registry-test (is (= (dist [:merge - [:or - [:map [:y [:= 1]]] - [:map [:y [:= 2]]]] - [:map [:x :int]]]) - [:or - [:map [:y [:= 1]] [:x :int]] - [:map [:y [:= 2]] [:x :int]]]))) + [:map {:registry {::y boolean?}} + [:y :int]] + [:multi {:dispatch :z + :registry {::y :int}} + [1 [:map [:z :int]]] + [2 [:map [:z :int]]]]]) + [:multi {:dispatch :z + ;;problem!! shadowed by maps + :registry {::y :int}} + [1 [:map {:registry {::y 'boolean?}} + [:y :int] + [:z :int]]] + [2 [:map {:registry {::y 'boolean?}} + [:y :int] [:z :int]]]]))) From f95197c6d886cdcbbedf81d7de1a419ceaf45de3 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Thu, 15 Aug 2024 20:17:38 -0500 Subject: [PATCH 11/18] wip --- README.md | 41 ++++++++++- src/malli/util.cljc | 2 + test/malli/distributive_test.cljc | 117 +++++++++++++++++++++++++----- 3 files changed, 141 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 358a32695..69b30fea8 100644 --- a/README.md +++ b/README.md @@ -1767,9 +1767,44 @@ is equivalent to `[:map [:x [:or :string :int]]]`. ; => true ``` -`:merge` also distributes over `:or`, `orn`, and `:multi` in the following manner: +### Distributive property + +`:merge` also distributes over `:multi` in a [similar way](https://en.wikipedia.org/wiki/Distributive_property) to how multiplication +distributes over addition in arithmetic. There are two transformation rules, applied in the following order: + +```clojure +;; right-distributive +[:merge [:multi M1 M2 ...] M3] +=> +[:multi [:merge M1 M3] [:merge M2 M3] ...] + +;; left-distributive +[:merge M1 [:multi M2 M3 ...]] +=> +[:multi [:merge M1 M2] [:merge M1 M3] ...] +``` + +For `:merge` with more than two arguments, the rules are applied iteratively left-to-right +as if the following transformation was applied: + +```clojure +[:merge M1 M2 M3 M4 ...] +=> +[:merge + [:merge + [:merge M1 M2] + M3] + M4] +... +``` + +The distributive property of `:multi` is useful combined with `:merge` +if you want all clauses of a `:multi` to share extra entries. + +Here are concrete examples of applying the rules: ```clojure +;; left-distributive (m/deref [:merge [:map [:x :int]] @@ -1781,6 +1816,7 @@ is equivalent to `[:map [:x [:or :string :int]]]`. ; [1 [:map [:x :int] [:y [:= 1]]]] ; [2 [:map [:x :int] [:y [:= 2]]]]] +;; right-distributive (m/deref [:merge [:multi {:dispatch :y} @@ -1793,6 +1829,9 @@ is equivalent to `[:map [:x [:or :string :int]]]`. ; [2 [:map [:y [:= 2]] [:x :int]]]] ``` +It is not recommended to use local registries in schemas that are transformed. +Also be aware that merging non-maps via the distributive property inherits +the same semantics as `:merge`, which is based on [meta-merge](https://github.com/weavejester/meta-merge). ## Persisting schemas diff --git a/src/malli/util.cljc b/src/malli/util.cljc index a61042e12..335fc3150 100644 --- a/src/malli/util.cljc +++ b/src/malli/util.cljc @@ -82,7 +82,9 @@ (cond (nil? s1) s2 (nil? s2) s1 + ;; right-distributive: [:merge [:multi M1 M2 ...] M3] => [:multi [:merge M1 M3] [:merge M2 M3] ...] (and can-distribute? (m/-distributive-schema? s1)) (m/-distribute-to-children s1 (fn [s _options] (merge s s2 options)) options) + ;; left-distributive: [:merge M1 [:multi M2 M3 ...]] => [:multi [:merge M1 M2] [:merge M1 M3] ...] (and can-distribute? (m/-distributive-schema? s2)) (m/-distribute-to-children s2 (fn [s _options] (merge s1 s options)) options) (not (and (-> t1 #{:map :and}) (-> t2 #{:map :and}))) (merge-default s1 s2 options) (not (and (-> t1 (= :map)) (-> t2 (= :map)))) (join (tear t1 s1) (tear t2 s2)) diff --git a/test/malli/distributive_test.cljc b/test/malli/distributive_test.cljc index 39e825077..f53573169 100644 --- a/test/malli/distributive_test.cljc +++ b/test/malli/distributive_test.cljc @@ -5,18 +5,13 @@ [malli.registry :as mr] [malli.transform :as mt] [malli.util :as mu])) -(comment - (m/type - [:schema - [:multi {:dispatch :y} - [1 [:map [:y [:= 1]]]] - [2 [:map [:y [:= 2]]]]]])) - (def options {:registry (merge (mu/schemas) (m/default-schemas))}) (defn dist [s] (m/form (m/deref s options))) +(defn valid? [?schema value] (m/validate ?schema value options)) + (deftest distributive-multi-test (is (= (dist [:merge @@ -46,6 +41,70 @@ [:multi {:dispatch :y} [1 [:map [:y [:= 1]] [:x :int]]] [2 [:map [:y [:= 2]] [:x :int]]]])) + (is (= (dist + [:merge + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:map [:x :int]] + [:map [:z :int]]]) + (dist + [:merge + [:merge + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:map [:x :int]]] + [:map [:z :int]]]) + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]] [:x :int] [:z :int]]] + [2 [:map [:y [:= 2]] [:x :int] [:z :int]]]])) + (is (= (dist + [:merge + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:map [:x :int]] + [:map [:z :int]] + [:multi {:dispatch :y} + [3 [:map [:y [:= 3]]]] + [4 [:map [:y [:= 4]]]]]]) + (dist + [:merge + [:merge + [:merge + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:map [:x :int]]] + [:map [:z :int]]] + [:multi {:dispatch :y} + [3 [:map [:y [:= 3]]]] + [4 [:map [:y [:= 4]]]]]]) + [:multi {:dispatch :y} + [1 [:multi {:dispatch :y} + [3 [:map [:y [:= 3]] [:x :int] [:z :int]]] + [4 [:map [:y [:= 4]] [:x :int] [:z :int]]]]] + [2 [:multi {:dispatch :y} + [3 [:map [:y [:= 3]] [:x :int] [:z :int]]] + [4 [:map [:y [:= 4]] [:x :int] [:z :int]]]]]])) + (is (= (dist + [:merge + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:map [:x :int]] + [:map [:z :int]] + [:multi {:dispatch :a} + [3 [:map [:a [:= 3]]]] + [4 [:map [:a [:= 4]]]]]]) + [:multi {:dispatch :y} + [1 [:multi {:dispatch :a} + [3 [:map [:y [:= 1]] [:x :int] [:z :int] [:a [:= 3]]]] + [4 [:map [:y [:= 1]] [:x :int] [:z :int] [:a [:= 4]]]]]] + [2 [:multi {:dispatch :a} + [3 [:map [:y [:= 2]] [:x :int] [:z :int] [:a [:= 3]]]] + [4 [:map [:y [:= 2]] [:x :int] [:z :int] [:a [:= 4]]]]]]])) (is (= (dist [:merge [:multi {:dispatch :y} @@ -60,20 +119,42 @@ [4 [:map [:y [:= 4]]]]]] [2 [:multi {:dispatch :y} [3 [:map [:y [:= 3]]]] - [4 [:map [:y [:= 4]]]]]]]))) - -;;FIXME -(deftest distribute-registry-test + [4 [:map [:y [:= 4]]]]]]])) (is (= (dist [:merge - [:map {:registry {::y boolean?}} - [:y :int]] - [:multi {:dispatch :z - :registry {::y :int}} - [1 [:map [:z :int]]] - [2 [:map [:z :int]]]]]) + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:multi {:dispatch :z} + [3 [:map [:z [:= 3]]]] + [4 [:map [:z [:= 4]]]]]]) + [:multi {:dispatch :y} + [1 [:multi {:dispatch :z} + [3 [:map [:y [:= 1]] [:z [:= 3]]]] + [4 [:map [:y [:= 1]] [:z [:= 4]]]]]] + [2 [:multi {:dispatch :z} + [3 [:map [:y [:= 2]] [:z [:= 3]]]] + [4 [:map [:y [:= 2]] [:z [:= 4]]]]]]]))) + +(def dreg + [:merge + [:map + {::y boolean?} + [:y ::y]] + [:multi {:dispatch :z + :registry {::y :int}} + [1 [:map [:z ::y]]] + [2 [:map [:z ::y]]]]]) + +;; distributing schemas with registries in them works in memory, but +;; does not serialize cleanly. https://github.com/metosin/malli/issues/1088 +(deftest distribute-registry-test + (is (not (valid? dreg {:y 1 :z 1}))) + (is (valid? dreg {:y true :z 1})) + (is (-> dreg dist (valid? {:y true :z 1}))) + (is (-> dreg dist (valid? {:y 1 :z 1}))) + (is (= (dist dreg) [:multi {:dispatch :z - ;;problem!! shadowed by maps :registry {::y :int}} [1 [:map {:registry {::y 'boolean?}} [:y :int] From c3e79ed14127cd1d3176e061b80d84166ba73f1b Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 16 Aug 2024 12:31:30 -0500 Subject: [PATCH 12/18] tests --- test/malli/distributive_test.cljc | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/test/malli/distributive_test.cljc b/test/malli/distributive_test.cljc index f53573169..8e85aff17 100644 --- a/test/malli/distributive_test.cljc +++ b/test/malli/distributive_test.cljc @@ -5,6 +5,7 @@ [malli.registry :as mr] [malli.transform :as mt] [malli.util :as mu])) + (def options {:registry (merge (mu/schemas) (m/default-schemas))}) (defn dist [s] @@ -135,29 +136,3 @@ [2 [:multi {:dispatch :z} [3 [:map [:y [:= 2]] [:z [:= 3]]]] [4 [:map [:y [:= 2]] [:z [:= 4]]]]]]]))) - -(def dreg - [:merge - [:map - {::y boolean?} - [:y ::y]] - [:multi {:dispatch :z - :registry {::y :int}} - [1 [:map [:z ::y]]] - [2 [:map [:z ::y]]]]]) - -;; distributing schemas with registries in them works in memory, but -;; does not serialize cleanly. https://github.com/metosin/malli/issues/1088 -(deftest distribute-registry-test - (is (not (valid? dreg {:y 1 :z 1}))) - (is (valid? dreg {:y true :z 1})) - (is (-> dreg dist (valid? {:y true :z 1}))) - (is (-> dreg dist (valid? {:y 1 :z 1}))) - (is (= (dist dreg) - [:multi {:dispatch :z - :registry {::y :int}} - [1 [:map {:registry {::y 'boolean?}} - [:y :int] - [:z :int]]] - [2 [:map {:registry {::y 'boolean?}} - [:y :int] [:z :int]]]]))) From 0c928f0f9d35294bf3f905f59d645d7c221bbf1e Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 16 Aug 2024 12:35:20 -0500 Subject: [PATCH 13/18] doc --- CHANGELOG.md | 6 +++++- bin/install | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dd625427..d1f2fde20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,10 +14,14 @@ We use [Break Versioning][breakver]. The version numbers follow a `.` added to default registry, see [documentation](https://github.com/metosin/malli/blob/master/docs/function-schemas.md#flat-arrow-function-schemas). -* New `:sequable` and `:every` schemas [#1041](https://github.com/metosin/malli/pull/1041), see [docs](https://github.com/metosin/malli#seqable-schemas) +* New `:seqable` and `:every` schemas [#1041](https://github.com/metosin/malli/pull/1041), see [docs](https://github.com/metosin/malli#seqable-schemas) * Fix OOM error with infinitely expanding schema [#1069](https://github.com/metosin/malli/pull/1069) * Correctly form prop-less schemas that have map/nil as first child [#1071](https://github.com/metosin/malli/pull/1071) * Support min/max on uncountables like eductions [#1075](https://github.com/metosin/malli/pull/1075) diff --git a/bin/install b/bin/install index 0e6535605..0ab02bb43 100755 --- a/bin/install +++ b/bin/install @@ -1,2 +1,5 @@ #!/bin/bash + +set -xe + clojure -M:jar && clojure -M:install From 2e752c09591cd398afedebaeff5c812d3a8a0de9 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 16 Aug 2024 12:39:35 -0500 Subject: [PATCH 14/18] doc --- CHANGELOG.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1f2fde20..74b475067 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ Malli is in well matured [alpha](README.md#alpha). ## NEXT -* Distribute `:merge` over `:multi` [#1086](https://github.com/metosin/malli/pull/1086), see [documentation](README.md#distributive-property) +* Distribute `:merge` over `:multi` [#1086](https://github.com/metosin/malli/pull/1086), see [documentation](README.md#distributive-schemas) ## 0.16.3 (2024-08-05) diff --git a/README.md b/README.md index 69b30fea8..75e05aaf4 100644 --- a/README.md +++ b/README.md @@ -1767,7 +1767,7 @@ is equivalent to `[:map [:x [:or :string :int]]]`. ; => true ``` -### Distributive property +### Distributive schemas `:merge` also distributes over `:multi` in a [similar way](https://en.wikipedia.org/wiki/Distributive_property) to how multiplication distributes over addition in arithmetic. There are two transformation rules, applied in the following order: From 04c36088a48302945a0a6ac5aabf56227611c0e3 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 16 Aug 2024 18:42:57 -0500 Subject: [PATCH 15/18] parse test --- test/malli/distributive_test.cljc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/malli/distributive_test.cljc b/test/malli/distributive_test.cljc index 8e85aff17..f3ea179b5 100644 --- a/test/malli/distributive_test.cljc +++ b/test/malli/distributive_test.cljc @@ -136,3 +136,16 @@ [2 [:multi {:dispatch :z} [3 [:map [:y [:= 2]] [:z [:= 3]]]] [4 [:map [:y [:= 2]] [:z [:= 4]]]]]]]))) + +(deftest parse-distributive-multi-test + (is (= [1 [3 {:y 1, :z 3}]] + (m/parse + [:merge + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:multi {:dispatch :z} + [3 [:map [:z [:= 3]]]] + [4 [:map [:z [:= 4]]]]]] + {:y 1 :z 3} + options)))) From 9a264808f4c100b2c75a2faac667c65db5ad35fb Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 16 Aug 2024 18:45:12 -0500 Subject: [PATCH 16/18] gen --- test/malli/distributive_test.cljc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/malli/distributive_test.cljc b/test/malli/distributive_test.cljc index f3ea179b5..df84339c0 100644 --- a/test/malli/distributive_test.cljc +++ b/test/malli/distributive_test.cljc @@ -2,6 +2,7 @@ (:require [clojure.test :refer [are deftest is testing]] [malli.core :as m] [malli.impl.util :as miu] + [malli.generator :as mg] [malli.registry :as mr] [malli.transform :as mt] [malli.util :as mu])) @@ -149,3 +150,16 @@ [4 [:map [:z [:= 4]]]]]] {:y 1 :z 3} options)))) + +(deftest gen-distributive-multi-test + (is (= [{:y 1, :z 3} {:y 2, :z 4} {:y 2, :z 3} {:y 2, :z 3} {:y 1, :z 4} + {:y 1, :z 3} {:y 1, :z 3} {:y 1, :z 3} {:y 1, :z 3} {:y 2, :z 4}] + (mg/sample + [:merge + [:multi {:dispatch :y} + [1 [:map [:y [:= 1]]]] + [2 [:map [:y [:= 2]]]]] + [:multi {:dispatch :z} + [3 [:map [:z [:= 3]]]] + [4 [:map [:z [:= 4]]]]]] + (assoc options :seed 0))))) From 6f7c7236406eb63986414a5cc0cc8e0dc85e4768 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Tue, 27 Aug 2024 14:42:08 +0300 Subject: [PATCH 17/18] style --- src/malli/core.cljc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/malli/core.cljc b/src/malli/core.cljc index 6a26bb07c..264736d20 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -112,7 +112,7 @@ DistributiveSchema (-distributive-schema? [_] false) - (-distribute-to-children [this f options'] + (-distribute-to-children [this _ _] (throw (ex-info "Not distributive" {:schema this}))) RegexSchema @@ -1306,7 +1306,7 @@ :else (let [size (when (and bounded (not (-safely-countable? x))) bounded)] (loop [acc acc, i 0, [x & xs :as ne] (seq x)] - (if (and ne (or (not size) (< i #?(:cljs ^number size + (if (and ne (or (not size) (< i #?(:cljs ^number size :default size)))) (cond-> (or (explainer x (conj in (fin i x)) acc) acc) xs (recur (inc i) xs)) acc))))))) @@ -1625,7 +1625,7 @@ (-to-ast [this _] (-entry-ast this (-entry-keyset entry-parser))) DistributiveSchema (-distributive-schema? [_] true) - (-distribute-to-children [this f options'] + (-distribute-to-children [_ f _] (-into-schema parent properties (mapv (fn [c] From be2c2be1663027ae9bc1bfa7c29fbf9aa2431fe9 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Tue, 27 Aug 2024 14:43:22 +0300 Subject: [PATCH 18/18] -children returns always vector of 3 --- src/malli/core.cljc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/malli/core.cljc b/src/malli/core.cljc index 264736d20..1355eaddc 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -1625,15 +1625,10 @@ (-to-ast [this _] (-entry-ast this (-entry-keyset entry-parser))) DistributiveSchema (-distributive-schema? [_] true) - (-distribute-to-children [_ f _] + (-distribute-to-children [this f _] (-into-schema parent properties - (mapv (fn [c] - (when-not (and (vector? c) - (= 2 (count c))) - (throw (ex-info "TODO" {}))) - (update c 1 f options)) - children) + (mapv (fn [c] (update c 2 f options)) (-children this)) options)) Schema (-validator [_]