Repository: graphql-rust/juniper (language: rust)

Issue:
Multiple fragments on sub types override each other
**Describe the bug**
If a query has multiple fragments selecting the same sub type, the selected fields override each other

**To Reproduce**
Steps to reproduce the behavior: Run a query like
```graphql
query Me {
  loggedInUser {
    id
    ...PicOne
    ...PicTwo
  }
}

fragment PicOne on User {
  profilePicture {
    id
    width
    height
  }
}

fragment PicTwo on User {
  profilePicture {
    id
    url
  }
}
```

Returns only the fields of the later fragment.


**Expected behavior**
It should merge the selected sub fields and return both values.



Discussion / hints:

Fix patch:
diff --git a/juniper/src/value/object.rs b/juniper/src/value/object.rs
index 64299b8ad..d4a6713ac 100644
--- a/juniper/src/value/object.rs
+++ b/juniper/src/value/object.rs
@@ -28,14 +28,26 @@ impl<S> Object<S> {
 
     /// Add a new field with a value
     ///
-    /// If there is already a field with the same name the old value
-    /// is returned
+    /// If there is already a field for the given key
+    /// any both values are objects, they are merged.
+    ///
+    /// Otherwise the existing value is replaced and
+    /// returned.
     pub fn add_field<K>(&mut self, k: K, value: Value<S>) -> Option<Value<S>>
     where
         K: Into<String>,
         for<'a> &'a str: PartialEq<K>,
     {
-        self.key_value_list.insert(k.into(), value)
+        let key: String = k.into();
+        match (value, self.key_value_list.get_mut(&key)) {
+            (Value::<S>::Object(obj_val), Some(Value::<S>::Object(existing_obj))) => {
+                for (key, val) in obj_val.into_iter() {
+                    existing_obj.add_field::<String>(key, val);
+                }
+                None
+            }
+            (non_obj_val, _) => self.key_value_list.insert(key, non_obj_val),
+        }
     }
 
     /// Check if the object already contains a field with the given name


Test patch:
diff --git a/integration_tests/juniper_tests/src/issue_914.rs b/integration_tests/juniper_tests/src/issue_914.rs
new file mode 100644
index 000000000..be15514fb
--- /dev/null
+++ b/integration_tests/juniper_tests/src/issue_914.rs
@@ -0,0 +1,119 @@
+use juniper::*;
+
+struct Query;
+
+#[derive(GraphQLObject)]
+struct Foo {
+    bar: Bar,
+}
+
+#[derive(GraphQLObject)]
+struct Bar {
+    a: i32,
+    b: i32,
+    baz: Baz,
+}
+
+#[derive(GraphQLObject)]
+struct Baz {
+    c: i32,
+    d: i32,
+}
+
+#[graphql_object]
+impl Query {
+    fn foo() -> Foo {
+        let baz = Baz { c: 1, d: 2 };
+        let bar = Bar { a: 1, b: 2, baz };
+        Foo { bar }
+    }
+}
+
+type Schema = juniper::RootNode<'static, Query, EmptyMutation, EmptySubscription>;
+
+#[tokio::test]
+async fn test_fragments_with_nested_objects_dont_override_previous_selections() {
+    let query = r#"
+        query Query {
+            foo {
+                ...BarA
+                ...BarB
+                ...BazC
+                ...BazD
+            }
+        }
+
+        fragment BarA on Foo {
+            bar {
+                a
+            }
+        }
+
+        fragment BarB on Foo {
+            bar {
+                b
+            }
+        }
+
+        fragment BazC on Foo {
+            bar {
+                baz {
+                    c
+                }
+            }
+        }
+
+        fragment BazD on Foo {
+            bar {
+                baz {
+                    d
+                }
+            }
+        }
+    "#;
+
+    let (async_value, errors) = juniper::execute(
+        query,
+        None,
+        &Schema::new(Query, EmptyMutation::new(), EmptySubscription::new()),
+        &Variables::new(),
+        &(),
+    )
+    .await
+    .unwrap();
+    assert_eq!(errors.len(), 0);
+
+    let (sync_value, errors) = juniper::execute_sync(
+        query,
+        None,
+        &Schema::new(Query, EmptyMutation::new(), EmptySubscription::new()),
+        &Variables::new(),
+        &(),
+    )
+    .unwrap();
+    assert_eq!(errors.len(), 0);
+
+    assert_eq!(async_value, sync_value);
+
+    let bar = async_value
+        .as_object_value()
+        .unwrap()
+        .get_field_value("foo")
+        .unwrap()
+        .as_object_value()
+        .unwrap()
+        .get_field_value("bar")
+        .unwrap()
+        .as_object_value()
+        .unwrap();
+    assert!(bar.contains_field("a"), "Field a should be selected");
+    assert!(bar.contains_field("b"), "Field b should be selected");
+
+    let baz = bar
+        .get_field_value("baz")
+        .unwrap()
+        .as_object_value()
+        .unwrap();
+    assert!(baz.contains_field("c"), "Field c should be selected");
+    assert!(baz.contains_field("d"), "Field d should be selected");
+}
diff --git a/integration_tests/juniper_tests/src/lib.rs b/integration_tests/juniper_tests/src/lib.rs
index f6bfb6837..ce6123d32 100644
--- a/integration_tests/juniper_tests/src/lib.rs
+++ b/integration_tests/juniper_tests/src/lib.rs
@@ -19,4 +19,6 @@ mod issue_407;
 #[cfg(test)]
 mod issue_500;
 #[cfg(test)]
+mod issue_914;
+#[cfg(test)]
 mod pre_parse;