// Extracts the root type of the operation from the schema. func getOperationRootType(schema types.GraphQLSchema, operation ast.Definition, r chan *types.GraphQLResult) (objType *types.GraphQLObjectType) { if operation == nil { var result types.GraphQLResult err := graphqlerrors.NewGraphQLFormattedError("Can only execute queries and mutations") result.Errors = append(result.Errors, err) r <- &result return objType } switch operation.GetOperation() { case "query": return schema.GetQueryType() case "mutation": mutationType := schema.GetMutationType() if mutationType.Name == "" { var result types.GraphQLResult err := graphqlerrors.NewGraphQLFormattedError("Schema is not configured for mutations") result.Errors = append(result.Errors, err) r <- &result return objType } return mutationType default: var result types.GraphQLResult err := graphqlerrors.NewGraphQLFormattedError("Can only execute queries and mutations") result.Errors = append(result.Errors, err) r <- &result return objType } }
func Execute(p ExecuteParams, resultChan chan *types.GraphQLResult) { var errors []graphqlerrors.GraphQLFormattedError var result types.GraphQLResult params := BuildExecutionCtxParams{ Schema: p.Schema, Root: p.Root, AST: p.AST, OperationName: p.OperationName, Args: p.Args, Errors: errors, Result: &result, ResultChan: resultChan, } exeContext := buildExecutionContext(params) if result.HasErrors() { return } defer func() { if r := recover(); r != nil { var err error if r, ok := r.(error); ok { err = graphqlerrors.FormatError(r) } exeContext.Errors = append(exeContext.Errors, graphqlerrors.FormatError(err)) result.Errors = exeContext.Errors resultChan <- &result } }() eOperationParams := ExecuteOperationParams{ ExecutionContext: exeContext, Root: p.Root, Operation: exeContext.Operation, } executeOperation(eOperationParams, resultChan) }
func buildExecutionContext(p BuildExecutionCtxParams) (eCtx ExecutionContext) { operations := make(map[string]ast.Definition) fragments := make(map[string]ast.Definition) for _, statement := range p.AST.Definitions { switch stm := statement.(type) { case *ast.OperationDefinition: log.Println("kinds.OperationDefinition") key := "" if stm.GetName().Value != "" { key = stm.GetName().Value } operations[key] = stm break case *ast.FragmentDefinition: log.Println("kinds.FragmentDefinition") fragments[stm.GetName().Value] = stm break default: log.Println("default") } } log.Printf("debug - operations: %v", operations) if (p.OperationName == "") && (len(operations) != 1) { err := graphqlerrors.NewGraphQLFormattedError("Must provide operation name if query contains multiple operations") p.Result.Errors = append(p.Result.Errors, err) p.ResultChan <- p.Result return eCtx } var opName string if p.OperationName == "" { for k, _ := range operations { opName = k break } } operation, found := operations[opName] if !found { var result types.GraphQLResult err := graphqlerrors.NewGraphQLFormattedError(fmt.Sprintf("Unknown operation name: %s", opName)) result.Errors = append(result.Errors, err) return eCtx } variables := GetVariableValues(p.Schema, operation.GetVariableDefinitions(), p.Args) eCtx.Schema = p.Schema eCtx.Fragments = fragments eCtx.Root = p.Root eCtx.Operation = operation eCtx.Variables = variables eCtx.Errors = p.Errors return eCtx }
// Implements the "Evaluating selection sets" section of the spec for "write" mode. func executeFieldsSerially(p ExecuteFieldsParams, resultChan chan *types.GraphQLResult) { if p.Source == nil { p.Source = map[string]interface{}{} } if p.Fields == nil { p.Fields = map[string][]*ast.Field{} } var result types.GraphQLResult finalResults := map[string]interface{}{} for responseName, fieldASTs := range p.Fields { resolved, state := resolveField(p.ExecutionContext, p.ParentType, p.Source, fieldASTs) if state.hasNoFieldDefs { continue } finalResults[responseName] = resolved } result.Errors = p.ExecutionContext.Errors result.Data = finalResults resultChan <- &result }
func executeOperation(p ExecuteOperationParams, resultChan chan *types.GraphQLResult) { var results types.GraphQLResult operationType := getOperationRootType(p.ExecutionContext.Schema, p.Operation, resultChan) collectFieldsParams := CollectFieldsParams{ ExeContext: p.ExecutionContext, OperationType: operationType, SelectionSet: p.Operation.GetSelectionSet(), } fields := collectFields(collectFieldsParams) executeFieldsParams := ExecuteFieldsParams{ ExecutionContext: p.ExecutionContext, ParentType: operationType, Source: p.Root, Fields: fields, } if p.Operation.GetOperation() == "mutation" { executeFieldsSerially(executeFieldsParams, resultChan) return } results = executeFields(executeFieldsParams) results.Errors = p.ExecutionContext.Errors resultChan <- &results }