Example #1
0
/**
 * This method looks up the field on the given type defintion.
 * It has special casing for the two introspection fields, __schema
 * and __typename. __typename is special because it can always be
 * queried as a field, even in situations where no other fields
 * are allowed, like on a Union. __schema could get automatically
 * added to the query type, but that would require mutating type
 * definitions, which would cause issues.
 */
func getFieldDef(schema types.GraphQLSchema, parentType *types.GraphQLObjectType, fieldName string) *types.GraphQLFieldDefinition {

	if parentType == nil {
		return nil
	}

	if fieldName == types.SchemaMetaFieldDef.Name &&
		schema.GetQueryType() == parentType {
		return types.SchemaMetaFieldDef
	}
	if fieldName == types.TypeMetaFieldDef.Name &&
		schema.GetQueryType() == parentType {
		return types.TypeMetaFieldDef
	}
	if fieldName == types.TypeNameMetaFieldDef.Name {
		return types.TypeNameMetaFieldDef
	}
	return parentType.GetFields()[fieldName]
}
Example #2
0
func completeValue(eCtx *ExecutionContext, returnType types.GraphQLType, fieldASTs []*ast.Field, info types.GraphQLResolveInfo, result interface{}) interface{} {

	// TODO: explore resolving go-routines in completeValue

	resultVal := reflect.ValueOf(result)
	if resultVal.IsValid() && resultVal.Type().Kind() == reflect.Func {
		if propertyFn, ok := result.(func() interface{}); ok {
			return propertyFn()
		}
		err := graphqlerrors.NewGraphQLFormattedError("Error resolving func. Expected `func() interface{}` signature")
		panic(graphqlerrors.FormatError(err))
	}

	if returnType, ok := returnType.(*types.GraphQLNonNull); ok {
		completed := completeValue(eCtx, returnType.OfType, fieldASTs, info, result)
		if completed == nil {
			err := graphqlerrors.NewLocatedError(
				fmt.Sprintf("Cannot return null for non-nullable field %v.%v.", info.ParentType, info.FieldName),
				graphqlerrors.FieldASTsToNodeASTs(fieldASTs),
			)
			panic(graphqlerrors.FormatError(err))
		}
		return completed
	}

	if isNullish(result) {
		return nil
	}

	// If field type is List, complete each item in the list with the inner type
	if returnType, ok := returnType.(*types.GraphQLList); ok {

		resultVal := reflect.ValueOf(result)
		err := invariant(
			resultVal.IsValid() && resultVal.Type().Kind() == reflect.Slice,
			"User Error: expected iterable, but did not find one.",
		)
		if err != nil {
			panic(graphqlerrors.FormatError(err))
		}

		itemType := returnType.OfType
		completedResults := []interface{}{}
		for i := 0; i < resultVal.Len(); i++ {
			val := resultVal.Index(i).Interface()
			completedItem := completeValueCatchingError(eCtx, itemType, fieldASTs, info, val)
			completedResults = append(completedResults, completedItem)
		}
		return completedResults
	}

	// If field type is Scalar or Enum, serialize to a valid value, returning
	// null if serialization is not possible.
	if returnType, ok := returnType.(*types.GraphQLScalarType); ok {
		err := invariant(returnType.Serialize != nil, "Missing serialize method on type")
		if err != nil {
			panic(graphqlerrors.FormatError(err))
		}
		serializedResult := returnType.Serialize(result)
		if isNullish(serializedResult) {
			return nil
		}
		return serializedResult
	}
	if returnType, ok := returnType.(*types.GraphQLEnumType); ok {
		err := invariant(returnType.Serialize != nil, "Missing serialize method on type")
		if err != nil {
			panic(graphqlerrors.FormatError(err))
		}
		serializedResult := returnType.Serialize(result)
		if isNullish(serializedResult) {
			return nil
		}
		return serializedResult
	}

	// Field type must be Object, Interface or Union and expect sub-selections.
	var objectType *types.GraphQLObjectType
	switch returnType := returnType.(type) {
	case *types.GraphQLObjectType:
		objectType = returnType
	case types.GraphQLAbstractType:
		objectType = returnType.GetObjectType(result, info)
		if objectType != nil && !returnType.IsPossibleType(objectType) {
			panic(graphqlerrors.NewGraphQLFormattedError(
				fmt.Sprintf(`Runtime Object type "%v" is not a possible type `+
					`for "%v".`, objectType, returnType),
			))
		}
	}
	if objectType == nil {
		return nil
	}

	// If there is an isTypeOf predicate function, call it with the
	// current result. If isTypeOf returns false, then raise an error rather
	// than continuing execution.
	if objectType.IsTypeOf != nil && !objectType.IsTypeOf(result, info) {
		panic(graphqlerrors.NewGraphQLFormattedError(
			fmt.Sprintf(`Expected value of type "%v" but got: %T.`, objectType, result),
		))
	}

	// Collect sub-fields to execute to complete this value.
	subFieldASTs := map[string][]*ast.Field{}
	visitedFragmentNames := map[string]bool{}
	for _, fieldAST := range fieldASTs {
		if fieldAST == nil {
			continue
		}
		selectionSet := fieldAST.SelectionSet
		if selectionSet != nil {
			innerParams := CollectFieldsParams{
				ExeContext:           eCtx,
				OperationType:        objectType,
				SelectionSet:         selectionSet,
				Fields:               subFieldASTs,
				VisitedFragmentNames: visitedFragmentNames,
			}
			subFieldASTs = collectFields(innerParams)
		}
	}
	executeFieldsParams := ExecuteFieldsParams{
		ExecutionContext: eCtx,
		ParentType:       objectType,
		Source:           result,
		Fields:           subFieldASTs,
	}
	results := executeFields(executeFieldsParams)

	return results.Data

}