diff --git a/juniper/src/types/base.rs b/juniper/src/types/base.rs index 014af5de..911b561a 100644 --- a/juniper/src/types/base.rs +++ b/juniper/src/types/base.rs @@ -617,5 +617,41 @@ where /// Merges `response_name`/`value` pair into `result` pub(crate) fn merge_key_into(result: &mut Object, response_name: &str, value: Value) { + if let Some(v) = result.get_mut_field_value(response_name) { + match v { + Value::Object(dest_obj) => { + if let Value::Object(src_obj) = value { + merge_maps(dest_obj, src_obj); + } + } + Value::List(dest_list) => { + if let Value::List(src_list) = value { + dest_list + .iter_mut() + .zip(src_list.into_iter()) + .for_each(|(d, s)| { + if let Value::Object(d_obj) = d { + if let Value::Object(s_obj) = s { + merge_maps(d_obj, s_obj); + } + } + }); + } + } + _ => {} + } + return; + } result.add_field(response_name, value); } + +/// Merges `src` object's fields into `dest` +fn merge_maps(dest: &mut Object, src: Object) { + for (key, value) in src { + if dest.contains_field(&key) { + merge_key_into(dest, &key, value); + } else { + dest.add_field(key, value); + } + } +} diff --git a/juniper/src/value/object.rs b/juniper/src/value/object.rs index d4a6713a..92071b5b 100644 --- a/juniper/src/value/object.rs +++ b/juniper/src/value/object.rs @@ -1,22 +1,14 @@ -use std::iter::FromIterator; +use std::{iter::FromIterator, mem}; use super::Value; use indexmap::map::{IndexMap, IntoIter}; /// A Object value -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Object { key_value_list: IndexMap>, } -impl PartialEq for Object { - fn eq(&self, _: &Object) -> bool { - match self { - Object { key_value_list } => self.key_value_list == *key_value_list, - } - } -} - impl Object { /// Create a new Object value with a fixed number of /// preallocated slots for field-value pairs @@ -35,28 +27,18 @@ impl Object { /// returned. pub fn add_field(&mut self, k: K, value: Value) -> Option> where - K: Into, - for<'a> &'a str: PartialEq, + K: AsRef + Into, { - let key: String = k.into(); - match (value, self.key_value_list.get_mut(&key)) { - (Value::::Object(obj_val), Some(Value::::Object(existing_obj))) => { - for (key, val) in obj_val.into_iter() { - existing_obj.add_field::(key, val); - } - None - } - (non_obj_val, _) => self.key_value_list.insert(key, non_obj_val), + if let Some(v) = self.key_value_list.get_mut(k.as_ref()) { + Some(mem::replace(v, value)) + } else { + self.key_value_list.insert(k.into(), value) } } /// Check if the object already contains a field with the given name - pub fn contains_field(&self, f: K) -> bool - where - K: Into, - for<'a> &'a str: PartialEq, - { - self.key_value_list.contains_key(&f.into()) + pub fn contains_field>(&self, k: K) -> bool { + self.key_value_list.contains_key(k.as_ref()) } /// Get a iterator over all field value pairs @@ -75,12 +57,13 @@ impl Object { } /// Get the value for a given field - pub fn get_field_value(&self, key: K) -> Option<&Value> - where - K: Into, - for<'a> &'a str: PartialEq, - { - self.key_value_list.get(&key.into()) + pub fn get_field_value>(&self, key: K) -> Option<&Value> { + self.key_value_list.get(key.as_ref()) + } + + /// Get the mutable value for a given field + pub fn get_mut_field_value>(&mut self, key: K) -> Option<&mut Value> { + self.key_value_list.get_mut(key.as_ref()) } } @@ -101,8 +84,7 @@ impl From> for Value { impl FromIterator<(K, Value)> for Object where - K: Into, - for<'a> &'a str: PartialEq, + K: AsRef + Into, { fn from_iter(iter: I) -> Self where