Repository: jensneuse/graphql-go-tools
Pull request #129 (2019-12-02 14:58:55)

add extra arguments to execution context
This PR will ensure that extra arguments get added to the execution context as context arguments so that they are available during execution.


Patch:
diff --git a/pkg/execution/execution.go b/pkg/execution/execution.go
index 43d4f112..1dc334f7 100644
--- a/pkg/execution/execution.go
+++ b/pkg/execution/execution.go
@@ -218,6 +218,8 @@ func (e *Executor) resolveNode(node Node, data []byte, path string, prefetch *sy
 
 func (e *Executor) ResolveArgs(args []Argument, data []byte) ResolvedArgs {
 
+	args = append(args, e.context.ExtraArguments...)
+
 	resolved := make(ResolvedArgs, len(args))
 	for i := 0; i < len(args); i++ {
 		switch arg := args[i].(type) {
@@ -232,8 +234,8 @@ func (e *Executor) ResolveArgs(args []Argument, data []byte) ResolvedArgs {
 			resolved[i].Value = e.context.Variables[xxhash.Sum64(arg.VariableName)]
 		case *ListArgument:
 			resolved[i].Key = arg.Name
-			listArgs := e.ResolveArgs(arg.Arguments,data)
-			listValues := make(map[string]string,len(listArgs))
+			listArgs := e.ResolveArgs(arg.Arguments, data)
+			listValues := make(map[string]string, len(listArgs))
 			for j := range listArgs {
 				listValues[string(listArgs[j].Key)] = string(listArgs[j].Value)
 			}
@@ -242,7 +244,7 @@ func (e *Executor) ResolveArgs(args []Argument, data []byte) ResolvedArgs {
 	}
 
 	for i := range resolved {
-		if !bytes.Contains(resolved[i].Value,literal.DOUBLE_LBRACE){
+		if !bytes.Contains(resolved[i].Value, literal.DOUBLE_LBRACE) {
 			continue
 		}
 		t, err := fasttemplate.NewTemplate(string(resolved[i].Value), literal.DOUBLE_LBRACE_STR, literal.DOUBLE_RBRACE_STR)
@@ -253,27 +255,27 @@ func (e *Executor) ResolveArgs(args []Argument, data []byte) ResolvedArgs {
 			tag = strings.TrimFunc(tag, func(r rune) bool {
 				return r == runes.SPACE || r == runes.TAB || r == runes.LINETERMINATOR
 			})
-			if strings.Count(tag,".") == 1 {
-				tag = strings.TrimPrefix(tag,".")
+			if strings.Count(tag, ".") == 1 {
+				tag = strings.TrimPrefix(tag, ".")
 				tagBytes := []byte(tag)
 				for j := range resolved {
-					if bytes.Equal(resolved[j].Key,tagBytes){
+					if bytes.Equal(resolved[j].Key, tagBytes) {
 						return w.Write(resolved[j].Value)
 					}
 				}
 			}
 			for j := range resolved {
 				key := string(resolved[j].Key)
-				if !strings.HasPrefix(tag,key){
+				if !strings.HasPrefix(tag, key) {
 					continue
 				}
-				key = strings.TrimPrefix(tag,key)
+				key = strings.TrimPrefix(tag, key)
 				if key == "" {
 					return w.Write(resolved[j].Value)
 				}
-				key = strings.TrimPrefix(key,".")
-				keys := strings.Split(key,".")
-				value,_,_,_ := jsonparser.Get(resolved[j].Value,keys...)
+				key = strings.TrimPrefix(key, ".")
+				keys := strings.Split(key, ".")
+				value, _, _, _ := jsonparser.Get(resolved[j].Value, keys...)
 				return w.Write(value)
 			}
 			return w.Write([]byte("{{ " + tag + " }}"))
@@ -282,7 +284,7 @@ func (e *Executor) ResolveArgs(args []Argument, data []byte) ResolvedArgs {
 	}
 
 	resolved.Filter(func(i int) (keep bool) {
-		return !bytes.HasPrefix(resolved[i].Key,literal.DOT)
+		return !bytes.HasPrefix(resolved[i].Key, literal.DOT)
 	})
 
 	return resolved
@@ -309,7 +311,8 @@ type RootNode interface {
 
 type Context struct {
 	context.Context
-	Variables Variables
+	Variables      Variables
+	ExtraArguments []Argument
 }
 
 type Variables map[uint64][]byte
@@ -325,10 +328,10 @@ type ResolvedArgument struct {
 
 type ResolvedArgs []ResolvedArgument
 
-func (r *ResolvedArgs) Filter (condition func(i int) (keep bool)){
+func (r *ResolvedArgs) Filter(condition func(i int) (keep bool)) {
 	n := 0
 	for i := range *r {
-		if condition(i){
+		if condition(i) {
 			(*r)[n] = (*r)[i]
 			n++
 		}
@@ -394,7 +397,7 @@ func (s *StaticVariableArgument) ArgName() []byte {
 }
 
 type ListArgument struct {
-	Name []byte
+	Name      []byte
 	Arguments []Argument
 }
 
diff --git a/pkg/execution/handler.go b/pkg/execution/handler.go
index a1a4fb49..02983083 100644
--- a/pkg/execution/handler.go
+++ b/pkg/execution/handler.go
@@ -85,7 +85,7 @@ func (h *Handler) Handle(requestData, extraVariables []byte) (executor *Executor
 		return
 	}
 
-	variables := h.VariablesFromJson(graphqlRequest.Variables, extraVariables)
+	variables, extraArguments := h.VariablesFromJson(graphqlRequest.Variables, extraVariables)
 
 	planner := NewPlanner(h.resolverDefinitions(&report))
 	if report.HasErrors() {
@@ -124,20 +124,27 @@ func (h *Handler) Handle(requestData, extraVariables []byte) (executor *Executor
 	executor = NewExecutor()
 	ctx = Context{
 		Variables: variables,
+		ExtraArguments: extraArguments,
 	}
 
 	return executor, plan, ctx, err
 }
 
-func (h *Handler) VariablesFromJson(inputJson ...[]byte) Variables {
-	variables := map[uint64][]byte{}
-	for i := range inputJson {
-		_ = jsonparser.ObjectEach(inputJson[i], func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
-			variables[xxhash.Sum64(key)] = value
-			return nil
+func (h *Handler) VariablesFromJson(requestVariables, extraVariables []byte) (variables Variables, extraArguments []Argument) {
+	variables = map[uint64][]byte{}
+	_ = jsonparser.ObjectEach(requestVariables, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
+		variables[xxhash.Sum64(key)] = value
+		return nil
+	})
+	_ = jsonparser.ObjectEach(extraVariables, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
+		variables[xxhash.Sum64(key)] = value
+		extraArguments = append(extraArguments, &ContextVariableArgument{
+			Name:         key,
+			VariableName: key,
 		})
-	}
-	return variables
+		return nil
+	})
+	return
 }
 
 func (h *Handler) resolverDefinitions(report *operationreport.Report) ResolverDefinitions {


Test patch:
diff --git a/pkg/execution/handler_test.go b/pkg/execution/handler_test.go
index 4c2bd378..41cade7a 100644
--- a/pkg/execution/handler_test.go
+++ b/pkg/execution/handler_test.go
@@ -55,7 +55,7 @@ func TestHandler_VariablesFromRequest(t *testing.T) {
 
 	extra := []byte(`{"request":{"headers":{"Authorization":"Bearer foo123"}}}`)
 
-	variables := handler.VariablesFromJson(request.Variables,extra)
+	variables,extraArguments := handler.VariablesFromJson(request.Variables,extra)
 
 	for key,value := range map[string]string{
 		"foo": "bar",
@@ -67,4 +67,15 @@ func TestHandler_VariablesFromRequest(t *testing.T) {
 			t.Errorf("want {{ %s }}, got: {{ %s }}'",want,got)
 		}
 	}
+
+	if len(extraArguments) != 1 {
+		t.Fatalf("want 1")
+	}
+
+	if !bytes.Equal(extraArguments[0].(*ContextVariableArgument).Name,[]byte("request")){
+		t.Fatalf("unexpected")
+	}
+	if !bytes.Equal(extraArguments[0].(*ContextVariableArgument).VariableName,[]byte("request")){
+		t.Fatalf("unexpected")
+	}
 }
\ No newline at end of file