diff --git a/graphql/schema/wrappers.go b/graphql/schema/wrappers.go index 45df7a20915..c15ed4356a9 100644 --- a/graphql/schema/wrappers.go +++ b/graphql/schema/wrappers.go @@ -629,6 +629,13 @@ func (f *field) ArgValue(name string) interface{} { if f.arguments == nil { // Compute and cache the map first time this function is called for a field. f.arguments = f.field.ArgumentMap(f.op.vars) + // use a deep-copy only if the request uses variables, as a variable could be shared by + // multiple queries in a single request and internally in our code we may overwrite field + // arguments which may result in the shared value being overwritten for all queries in a + // request. + if f.op.vars != nil { + f.arguments = x.DeepCopyJsonMap(f.arguments) + } } return f.arguments[name] } diff --git a/x/x.go b/x/x.go index 1edf76f6f90..be09c8f32a2 100644 --- a/x/x.go +++ b/x/x.go @@ -998,3 +998,47 @@ func StoreSync(db DB, closer *y.Closer) { } } } + +// DeepCopyJsonMap returns a deep copy of the input map `m`. +// `m` is supposed to be a map similar to the ones produced as a result of json unmarshalling. i.e., +// any value in `m` at any nested level should be of an inbuilt go type. +func DeepCopyJsonMap(m map[string]interface{}) map[string]interface{} { + if m == nil { + return nil + } + + mCopy := make(map[string]interface{}) + for k, v := range m { + switch val := v.(type) { + case map[string]interface{}: + mCopy[k] = DeepCopyJsonMap(val) + case []interface{}: + mCopy[k] = DeepCopyJsonArray(val) + default: + mCopy[k] = val + } + } + return mCopy +} + +// DeepCopyJsonArray returns a deep copy of the input array `a`. +// `a` is supposed to be an array similar to the ones produced as a result of json unmarshalling. +// i.e., any value in `a` at any nested level should be of an inbuilt go type. +func DeepCopyJsonArray(a []interface{}) []interface{} { + if a == nil { + return nil + } + + aCopy := make([]interface{}, 0, len(a)) + for _, v := range a { + switch val := v.(type) { + case map[string]interface{}: + aCopy = append(aCopy, DeepCopyJsonMap(val)) + case []interface{}: + aCopy = append(aCopy, DeepCopyJsonArray(val)) + default: + aCopy = append(aCopy, val) + } + } + return aCopy +}