diff --git a/src/com/walmartlabs/lacinia/internal_utils.clj b/src/com/walmartlabs/lacinia/internal_utils.clj index fbe9e15a..7f0c3a53 100644 --- a/src/com/walmartlabs/lacinia/internal_utils.clj +++ b/src/com/walmartlabs/lacinia/internal_utils.clj @@ -409,7 +409,8 @@ (defn- null? [v] - (= v :com.walmartlabs.lacinia.schema/null)) + (or (nil? v) + (= v :com.walmartlabs.lacinia.schema/null))) (defn deep-merge "Merges two maps together. Later map override earlier. diff --git a/test/com/walmartlabs/lacinia/executor_test.clj b/test/com/walmartlabs/lacinia/executor_test.clj index 9afdd15e..ae30a846 100644 --- a/test/com/walmartlabs/lacinia/executor_test.clj +++ b/test/com/walmartlabs/lacinia/executor_test.clj @@ -20,7 +20,7 @@ [com.walmartlabs.test-utils :refer [execute]] [com.walmartlabs.lacinia.schema :as schema])) -(deftest deep-merge-on-error +(def compiled-schema (let [test-schema {:interfaces {:Node {:fields {:id {:type '(non-null String)}}}} @@ -28,13 +28,16 @@ :objects {:Post {:implements [:Node] - :fields {:id {:type '(non-null String)} - :author {:type '(non-null :Author) - :resolve (fn [_ _ _] - {:id "2000"})} - :title {:type 'String - :resolve (fn [_ _ _] - "Hello, World!")}}} + :fields {:id {:type '(non-null String)} + :author {:type '(non-null :Author) + :resolve (fn [_ _ _] + {:id "2000"})} + :title {:type 'String + :resolve (fn [_ _ _] + "Hello, World!")} + :comments {:type '(list :Comment) + :resolve (fn [_ _ _] + [{:id "3000"}])}}} :Author {:implements [:Node] @@ -47,20 +50,24 @@ nil)} :alwaysFail {:type '(non-null String) :resolve (fn [_ _ _] - (resolve-as nil {:message "This field can't be resolved."}))}}}} + (resolve-as nil {:message "This field can't be resolved."}))}}} + + :Comment + {:implements [:Node] + :fields {:id {:type '(non-null String)}}}} :queries {:node {:type '(non-null :Node) :args {:id {:type '(non-null String)}} :resolve (fn [ctx args v] (let [{:keys [episode]} args] - (schema/tag-with-type {:id "1000"} :Post)))}}} - ] - (def compiled-schema (schema/compile test-schema)) + (schema/tag-with-type {:id "1000"} :Post)))}}}] + (schema/compile test-schema))) - (is (= {:data nil, - :errors [{:message "This field can't be resolved.", :locations [{:line 4, :column 5}], :path [:node :author :alwaysFail]}]} - (execute compiled-schema " +(deftest deep-merge-on-error + (is (= {:data nil, + :errors [{:message "This field can't be resolved.", :locations [{:line 4, :column 5}], :path [:node :author :alwaysFail]}]} + (execute compiled-schema " fragment PostFragment on Post { author { alwaysFail @@ -78,9 +85,9 @@ query MyQuery { } }"))) - (is (= {:data nil, - :errors [{:message "This field can't be resolved.", :locations [{:line 4, :column 5}], :path [:node :author :alwaysFail]}]} - (execute compiled-schema " + (is (= {:data nil, + :errors [{:message "This field can't be resolved.", :locations [{:line 4, :column 5}], :path [:node :author :alwaysFail]}]} + (execute compiled-schema " fragment PostFragment on Post { author { alwaysFail @@ -98,12 +105,12 @@ query MyQuery { } }"))) - (testing "when non-null field is resolved to nil, deep-merge should return nil" - (is (= {:data nil, - :errors [{:message "This field can't be resolved.", - :locations [{:line 13, :column 5}], - :path [:node :author :alwaysFail]}]} - (execute compiled-schema " + (testing "when non-null field is resolved to nil, deep-merge should return nil" + (is (= {:data nil, + :errors [{:message "This field can't be resolved.", + :locations [{:line 13, :column 5}], + :path [:node :author :alwaysFail]}]} + (execute compiled-schema " query MyQuery { node(id: \"1000\") { ... on Post { @@ -127,11 +134,11 @@ fragment PostFragment2 on Post { } "))) - (is (= {:data nil, - :errors [{:message "This field can't be resolved.", - :locations [{:line 14, :column 5}], - :path [:node :author :alwaysFail]}]} - (execute compiled-schema " + (is (= {:data nil, + :errors [{:message "This field can't be resolved.", + :locations [{:line 14, :column 5}], + :path [:node :author :alwaysFail]}]} + (execute compiled-schema " query MyQuery { node(id: \"1000\") { ... on Post { @@ -153,6 +160,4 @@ fragment PostFragment2 on Post { name } } -")))) - - )) +"))))) diff --git a/test/com/walmartlabs/lacinia/internal_utils_tests.clj b/test/com/walmartlabs/lacinia/internal_utils_tests.clj index 68f47eae..37e27c9a 100644 --- a/test/com/walmartlabs/lacinia/internal_utils_tests.clj +++ b/test/com/walmartlabs/lacinia/internal_utils_tests.clj @@ -14,8 +14,8 @@ (ns com.walmartlabs.lacinia.internal-utils-tests (:require - [clojure.test :refer [deftest is]] - [com.walmartlabs.lacinia.internal-utils :refer [assoc-in! update-in!]] + [clojure.test :refer [deftest testing is]] + [com.walmartlabs.lacinia.internal-utils :refer [assoc-in! update-in! deep-merge]] [clojure.string :as str]) (:import (clojure.lang ExceptionInfo))) @@ -63,3 +63,56 @@ :map {:name {:type String}} :more-keys (:description)} (ex-data e))))) + +(deftest test-deep-merge + (testing "Basic map merge" + (is (= (deep-merge {:a 1} {:b 2}) + {:a 1, :b 2})) + (is (= (deep-merge {:a 1} {:a 2}) + {:a 2}))) + + (testing "Nested map merge" + (is (= (deep-merge {:a {:b 1}} {:a {:c 2}}) + {:a {:b 1, :c 2}})) + (is (= (deep-merge {:a {:b 1}} {:a {:b 2}}) + {:a {:b 2}}))) + + (testing "Mixed map and sequential" + (is (thrown-with-msg? ExceptionInfo #"unable to deep merge" + (deep-merge {:a 1} [1 2 3]))) + (is (thrown-with-msg? ExceptionInfo #"unable to deep merge" + (deep-merge [1 2 3] {:a 1})))) + + #_(testing "Merge with nil values" + (is (thrown-with-msg? ExceptionInfo #"unable to deep merge" (deep-merge {:a 1} nil) + {:a 1})) + (is (thrown-with-msg? ExceptionInfo #"unable to deep merge" (deep-merge nil {:a 1}) + {:a 1}))) + + (testing "Merging with :com.walmartlabs.lacinia.schema/null values" + (is (= (deep-merge {:a 1} :com.walmartlabs.lacinia.schema/null) + :com.walmartlabs.lacinia.schema/null)) + (is (= (deep-merge :com.walmartlabs.lacinia.schema/null {:a 1}) + :com.walmartlabs.lacinia.schema/null)) + (is (= (deep-merge :com.walmartlabs.lacinia.schema/null :com.walmartlabs.lacinia.schema/null) + :com.walmartlabs.lacinia.schema/null))) + + (testing "Merging with empty maps" + (is (= (deep-merge {} {:a 1}) + {:a 1})) + (is (= (deep-merge {:a 1} {}) + {:a 1}))) + + (testing "Complex nested structures" + (is (= (deep-merge {:a {:b [1 2]}} {:a {:b [3 4]}}) + {:a {:b [3 4]}})) + (is (= (deep-merge {:a [{:b 1} {:c 2}]} {:a [{:d 3} {:e 4}]}) + {:a [{:b 1, :d 3} {:c 2, :e 4}]}))) + + (testing "Nested :com.walmartlabs.lacinia.schema/null values" + (is (= (deep-merge {:a {:b :com.walmartlabs.lacinia.schema/null}} {:a {:b 1}}) + {:a {:b :com.walmartlabs.lacinia.schema/null}})) + (is (= (deep-merge {:a {:b 1}} {:a {:b :com.walmartlabs.lacinia.schema/null}}) + {:a {:b :com.walmartlabs.lacinia.schema/null}})) + (is (= (deep-merge {:a {:b :com.walmartlabs.lacinia.schema/null, :c 2}} {:a {:b 1, :c :com.walmartlabs.lacinia.schema/null}}) + {:a {:b :com.walmartlabs.lacinia.schema/null, :c :com.walmartlabs.lacinia.schema/null}}))))