Example #1
0
func newContext(
	schema typs.QLSchema,
	documentAST *lang.Document,
	rootValue interface{},
	rawVariableValues map[string]interface{},
	operationName string,
) *_Context {

	operations := make(map[string]*lang.OperationDefinition)
	fragments := make(map[string]*lang.FragmentDefinition)

	for _, statement := range documentAST.Definitions {
		switch statement := statement.(type) {
		case *lang.OperationDefinition:
			name := ""
			if statement.Name != nil {
				name = statement.Name.Value
			}
			operations[name] = statement
		case *lang.FragmentDefinition:
			fragments[statement.Name.Value] = statement
		default:
			panic(lang.NewQLError(
				fmt.Sprintf(`Cannot execute a request containing a %v.`, statement.Kind()),
				[]lang.INode{statement}))
		}
	}
	if operationName != "" && len(operations) != 1 {
		panic(lang.NewQLError(`Must provide operation name if query contains multiple operations.`, nil))
	}
	if operationName == "" {
		for name := range operations {
			operationName = name
		}
	}
	operation, ok := operations[operationName]
	if !ok {
		panic(lang.NewQLError(
			fmt.Sprintf(`Unknown operation named "%v".`, operationName), nil))
	}
	variableValues := GetVariableValues(schema, operation.VariableDefinitions, rawVariableValues)
	return &_Context{
		Schema:         schema,
		Fragments:      fragments,
		RootValue:      rootValue,
		Operation:      operation,
		VariableValues: variableValues,
		Errors:         nil,
	}
}
Example #2
0
func getOperationRootType(
	schema typs.QLSchema,
	operation *lang.OperationDefinition,
) *typs.QLObject {
	switch operation.Operation {
	case lang.OperationQuery:
		return schema.GetQueryType()
	case lang.OperationMutation:
		murationType := schema.GetMutationType()
		if murationType == nil {
			panic(lang.NewQLError(
				"Schema is not configured for mutations",
				[]lang.INode{operation}))
		}
		return murationType
	default:
		panic(lang.NewQLError(
			"Can only execute queries and mutation",
			[]lang.INode{operation}))
	}
}
Example #3
0
func (c *_Context) completeValue(
	returnType typs.QLType,
	fieldASTs []*lang.Field,
	info typs.QLResolveInfo,
	result interface{},
) interface{} {

	if returnType, ok := returnType.(*typs.QLNonNull); ok {
		completed := c.completeValue(returnType.OfType, fieldASTs, info, result)
		if completed == nil {
			nodes := make([]lang.INode, len(fieldASTs))
			for i, node := range fieldASTs {
				nodes[i] = node
			}
			panic(lang.NewQLError(
				fmt.Sprintf(
					`Cannot return null for non-nullable field %v.%v.`,
					info.ParentType, info.FieldName),
				nodes))
		}
		return completed
	}

	v := reflect.ValueOf(result)
	if result == nil {
		return nil
	}

	v = reflect.Indirect(v)
	t := v.Type()
	switch returnType := returnType.(type) {
	case *typs.QLList:
		if t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
			itemType := returnType.OfType
			list := make([]interface{}, t.NumField())
			for i, n := 0, t.NumField(); i < n; i++ {
				list[i] = c.completeValueCatchingError(itemType, fieldASTs, info, v.Field(i).Interface())
			}
			return list
		}
		panic("User Error: expected array of slice, but did not find one.")

	case *typs.QLScalar:
		if returnType.Serialize == nil {
			panic("Missing serialize method on type")
		}
		serializedResult := returnType.Serialize(result)
		if serializedResult == nil {
			return nil
		}
		return serializedResult

	case *typs.QLEnum:
		return returnType.Serialize(result)

	case *typs.QLObject:
		runtimeType := returnType
		subFieldASTs := map[string][]*lang.Field{}
		visitedFragmentNames := map[string]struct{}{}
		for _, fieldAST := range fieldASTs {
			selectionSet := fieldAST.SelectionSet
			if selectionSet != nil {
				subFieldASTs = c.collectFields(runtimeType, selectionSet, subFieldASTs, visitedFragmentNames)
			}
		}
		return c.executeFields(runtimeType, result, subFieldASTs)

	case typs.QLAbstractType:
		panic("not implemented")

	default:
		panic("unreachable")
	}
}