func TestPrinter_CorrectlyPrintsNonQueryOperationsWithoutName(t *testing.T) { // Test #1 queryAstShorthanded := `query { id, name }` expected := `{ id name } ` astDoc := parse(t, queryAstShorthanded) results := printer.Print(astDoc) if !reflect.DeepEqual(expected, results) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(results, expected)) } // Test #2 mutationAst := `mutation { id, name }` expected = `mutation { id name } ` astDoc = parse(t, mutationAst) results = printer.Print(astDoc) if !reflect.DeepEqual(expected, results) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(results, expected)) } // Test #3 queryAstWithArtifacts := `query ($foo: TestType) @testDirective { id, name }` expected = `query ($foo: TestType) @testDirective { id name } ` astDoc = parse(t, queryAstWithArtifacts) results = printer.Print(astDoc) if !reflect.DeepEqual(expected, results) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(results, expected)) } // Test #4 mutationAstWithArtifacts := `mutation ($foo: TestType) @testDirective { id, name }` expected = `mutation ($foo: TestType) @testDirective { id name } ` astDoc = parse(t, mutationAstWithArtifacts) results = printer.Print(astDoc) if !reflect.DeepEqual(expected, results) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(results, expected)) } }
// Given a variable definition, and any value of input, return a value which // adheres to the variable definition, or throw an error. func getVariableValue(schema Schema, definitionAST *ast.VariableDefinition, input interface{}) (interface{}, error) { ttype, err := typeFromAST(schema, definitionAST.Type) if err != nil { return nil, err } variable := definitionAST.Variable if ttype == nil || !IsInputType(ttype) { return "", gqlerrors.NewError( fmt.Sprintf(`Variable "$%v" expected value of type `+ `"%v" which cannot be used as an input type.`, variable.Name.Value, printer.Print(definitionAST.Type)), []ast.Node{definitionAST}, "", nil, []int{}, ) } if isValidInputValue(input, ttype) { if isNullish(input) { defaultValue := definitionAST.DefaultValue if defaultValue != nil { variables := map[string]interface{}{} val := valueFromAST(defaultValue, ttype, variables) return val, nil } } return coerceValue(ttype, input), nil } if isNullish(input) { return "", gqlerrors.NewError( fmt.Sprintf(`Variable "$%v" of required type `+ `"%v" was not provided.`, variable.Name.Value, printer.Print(definitionAST.Type)), []ast.Node{definitionAST}, "", nil, []int{}, ) } inputStr := "" b, err := json.Marshal(input) if err == nil { inputStr = string(b) } return "", gqlerrors.NewError( fmt.Sprintf(`Variable "$%v" expected value of type `+ `"%v" but got: %v.`, variable.Name.Value, printer.Print(definitionAST.Type), inputStr), []ast.Node{definitionAST}, "", nil, []int{}, ) }
func TestSchemaPrinter_PrintsKitchenSink(t *testing.T) { b, err := ioutil.ReadFile("../../schema-kitchen-sink.graphql") if err != nil { t.Fatalf("unable to load schema-kitchen-sink.graphql") } query := string(b) astDoc := parse(t, query) expected := `schema { query: QueryType mutation: MutationType } type Foo implements Bar { one: Type two(argument: InputType!): Type three(argument: InputType, other: String): Int four(argument: String = "string"): String five(argument: [String] = ["string", "string"]): String six(argument: InputType = {key: "value"}): Type } interface Bar { one: Type four(argument: String = "string"): String } union Feed = Story | Article | Advert scalar CustomScalar enum Site { DESKTOP MOBILE } input InputType { key: String! answer: Int = 42 } extend type Foo { seven(argument: [String]): Type } directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT ` results := printer.Print(astDoc) if !reflect.DeepEqual(expected, results) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(results, expected)) } }
func TestSchemaPrinter_PrintsMinimalAST(t *testing.T) { astDoc := ast.NewScalarDefinition(&ast.ScalarDefinition{ Name: ast.NewName(&ast.Name{ Value: "foo", }), }) results := printer.Print(astDoc) expected := "scalar foo" if !reflect.DeepEqual(results, expected) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, results)) } }
func TestPrinter_PrintsMinimalAST(t *testing.T) { astDoc := ast.NewField(&ast.Field{ Name: ast.NewName(&ast.Name{ Value: "foo", }), }) results := printer.Print(astDoc) expected := "foo" if !reflect.DeepEqual(results, expected) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, results)) } }
func TestPrinter_PrintsKitchenSink(t *testing.T) { b, err := ioutil.ReadFile("../../kitchen-sink.graphql") if err != nil { t.Fatalf("unable to load kitchen-sink.graphql") } query := string(b) astDoc := parse(t, query) expected := `query namedQuery($foo: ComplexFooType, $bar: Bar = DefaultBarValue) { customUser: user(id: [987, 654]) { id ... on User @defer { field2 { id alias: field1(first: 10, after: $foo) @include(if: $foo) { id ...frag } } } } } mutation favPost { fav(post: 123) @defer { post { id } } } fragment frag on Follower { foo(size: $size, bar: $b, obj: {key: "value"}) } { unnamed(truthyVal: true, falseyVal: false) query } ` results := printer.Print(astDoc) if !reflect.DeepEqual(expected, results) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(results, expected)) } }
func TestSchemaPrinter_DoesNotAlterAST(t *testing.T) { b, err := ioutil.ReadFile("../../schema-kitchen-sink.graphql") if err != nil { t.Fatalf("unable to load schema-kitchen-sink.graphql") } query := string(b) astDoc := parse(t, query) astDocBefore := testutil.ASTToJSON(t, astDoc) _ = printer.Print(astDoc) astDocAfter := testutil.ASTToJSON(t, astDoc) _ = testutil.ASTToJSON(t, astDoc) if !reflect.DeepEqual(astDocAfter, astDocBefore) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(astDocAfter, astDocBefore)) } }
func init() { __TypeKind = NewEnum(EnumConfig{ Name: "__TypeKind", Description: "An enum describing what kind of type a given __Type is", Values: EnumValueConfigMap{ "SCALAR": &EnumValueConfig{ Value: TypeKindScalar, Description: "Indicates this type is a scalar.", }, "OBJECT": &EnumValueConfig{ Value: TypeKindObject, Description: "Indicates this type is an object. " + "`fields` and `interfaces` are valid fields.", }, "INTERFACE": &EnumValueConfig{ Value: TypeKindInterface, Description: "Indicates this type is an interface. " + "`fields` and `possibleTypes` are valid fields.", }, "UNION": &EnumValueConfig{ Value: TypeKindUnion, Description: "Indicates this type is a union. " + "`possibleTypes` is a valid field.", }, "ENUM": &EnumValueConfig{ Value: TypeKindEnum, Description: "Indicates this type is an enum. " + "`enumValues` is a valid field.", }, "INPUT_OBJECT": &EnumValueConfig{ Value: TypeKindInputObject, Description: "Indicates this type is an input object. " + "`inputFields` is a valid field.", }, "LIST": &EnumValueConfig{ Value: TypeKindList, Description: "Indicates this type is a list. " + "`ofType` is a valid field.", }, "NON_NULL": &EnumValueConfig{ Value: TypeKindNonNull, Description: "Indicates this type is a non-null. " + "`ofType` is a valid field.", }, }, }) // Note: some fields (for e.g "fields", "interfaces") are defined later due to cyclic reference __Type = NewObject(ObjectConfig{ Name: "__Type", Fields: FieldConfigMap{ "kind": &FieldConfig{ Type: NewNonNull(__TypeKind), Resolve: func(p GQLFRParams) interface{} { switch p.Source.(type) { case *Scalar: return TypeKindScalar case *Object: return TypeKindObject case *Interface: return TypeKindInterface case *Union: return TypeKindUnion case *Enum: return TypeKindEnum case *InputObject: return TypeKindInputObject case *List: return TypeKindList case *NonNull: return TypeKindNonNull } panic(fmt.Sprintf("Unknown kind of type: %v", p.Source)) }, }, "name": &FieldConfig{ Type: String, }, "description": &FieldConfig{ Type: String, }, "fields": &FieldConfig{}, "interfaces": &FieldConfig{}, "possibleTypes": &FieldConfig{}, "enumValues": &FieldConfig{}, "inputFields": &FieldConfig{}, "ofType": &FieldConfig{}, }, }) __InputValue = NewObject(ObjectConfig{ Name: "__InputValue", Fields: FieldConfigMap{ "name": &FieldConfig{ Type: NewNonNull(String), }, "description": &FieldConfig{ Type: String, }, "type": &FieldConfig{ Type: NewNonNull(__Type), }, "defaultValue": &FieldConfig{ Type: String, Resolve: func(p GQLFRParams) interface{} { if inputVal, ok := p.Source.(*Argument); ok { if inputVal.DefaultValue == nil { return nil } astVal := astFromValue(inputVal.DefaultValue, inputVal) return printer.Print(astVal) } if inputVal, ok := p.Source.(*InputObjectField); ok { if inputVal.DefaultValue == nil { return nil } astVal := astFromValue(inputVal.DefaultValue, inputVal) return printer.Print(astVal) } return nil }, }, }, }) __Field = NewObject(ObjectConfig{ Name: "__Field", Fields: FieldConfigMap{ "name": &FieldConfig{ Type: NewNonNull(String), }, "description": &FieldConfig{ Type: String, }, "args": &FieldConfig{ Type: NewNonNull(NewList(NewNonNull(__InputValue))), Resolve: func(p GQLFRParams) interface{} { if field, ok := p.Source.(*FieldDefinition); ok { return field.Args } return []interface{}{} }, }, "type": &FieldConfig{ Type: NewNonNull(__Type), }, "isDeprecated": &FieldConfig{ Type: NewNonNull(Boolean), Resolve: func(p GQLFRParams) interface{} { if field, ok := p.Source.(*FieldDefinition); ok { return (field.DeprecationReason != "") } return false }, }, "deprecationReason": &FieldConfig{ Type: String, }, }, }) __Directive = NewObject(ObjectConfig{ Name: "__Directive", Fields: FieldConfigMap{ "name": &FieldConfig{ Type: NewNonNull(String), }, "description": &FieldConfig{ Type: String, }, "args": &FieldConfig{ Type: NewNonNull(NewList( NewNonNull(__InputValue), )), }, "onOperation": &FieldConfig{ Type: NewNonNull(Boolean), }, "onFragment": &FieldConfig{ Type: NewNonNull(Boolean), }, "onField": &FieldConfig{ Type: NewNonNull(Boolean), }, }, }) __Schema = NewObject(ObjectConfig{ Name: "__Schema", Description: `A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query and mutation operations.`, Fields: FieldConfigMap{ "types": &FieldConfig{ Description: "A list of all types supported by this server.", Type: NewNonNull(NewList( NewNonNull(__Type), )), Resolve: func(p GQLFRParams) interface{} { if schema, ok := p.Source.(Schema); ok { results := []Type{} for _, ttype := range schema.GetTypeMap() { results = append(results, ttype) } return results } return []Type{} }, }, "queryType": &FieldConfig{ Description: "The type that query operations will be rooted at.", Type: NewNonNull(__Type), Resolve: func(p GQLFRParams) interface{} { if schema, ok := p.Source.(Schema); ok { return schema.GetQueryType() } return nil }, }, "mutationType": &FieldConfig{ Description: `If this server supports mutation, the type that ` + `mutation operations will be rooted at.`, Type: __Type, Resolve: func(p GQLFRParams) interface{} { if schema, ok := p.Source.(Schema); ok { if schema.GetMutationType() != nil { return schema.GetMutationType() } } return nil }, }, "directives": &FieldConfig{ Description: `A list of all directives supported by this server.`, Type: NewNonNull(NewList( NewNonNull(__Directive), )), Resolve: func(p GQLFRParams) interface{} { if schema, ok := p.Source.(Schema); ok { return schema.GetDirectives() } return nil }, }, }, }) __EnumValue = NewObject(ObjectConfig{ Name: "__EnumValue", Fields: FieldConfigMap{ "name": &FieldConfig{ Type: NewNonNull(String), }, "description": &FieldConfig{ Type: String, }, "isDeprecated": &FieldConfig{ Type: NewNonNull(Boolean), Resolve: func(p GQLFRParams) interface{} { if field, ok := p.Source.(*EnumValueDefinition); ok { return (field.DeprecationReason != "") } return false }, }, "deprecationReason": &FieldConfig{ Type: String, }, }, }) // Again, adding field configs to __Type that have cyclic reference here // because golang don't like them too much during init/compile-time __Type.AddFieldConfig("fields", &FieldConfig{ Type: NewList(NewNonNull(__Field)), Args: FieldConfigArgument{ "includeDeprecated": &ArgumentConfig{ Type: Boolean, DefaultValue: false, }, }, Resolve: func(p GQLFRParams) interface{} { includeDeprecated, _ := p.Args["includeDeprecated"].(bool) switch ttype := p.Source.(type) { case *Object: if ttype == nil { return nil } fields := []*FieldDefinition{} for _, field := range ttype.GetFields() { if !includeDeprecated && field.DeprecationReason != "" { continue } fields = append(fields, field) } return fields case *Interface: if ttype == nil { return nil } fields := []*FieldDefinition{} for _, field := range ttype.GetFields() { if !includeDeprecated && field.DeprecationReason != "" { continue } fields = append(fields, field) } return fields } return nil }, }) __Type.AddFieldConfig("interfaces", &FieldConfig{ Type: NewList(NewNonNull(__Type)), Resolve: func(p GQLFRParams) interface{} { switch ttype := p.Source.(type) { case *Object: return ttype.GetInterfaces() } return nil }, }) __Type.AddFieldConfig("possibleTypes", &FieldConfig{ Type: NewList(NewNonNull(__Type)), Resolve: func(p GQLFRParams) interface{} { switch ttype := p.Source.(type) { case *Interface: return ttype.GetPossibleTypes() case *Union: return ttype.GetPossibleTypes() } return nil }, }) __Type.AddFieldConfig("enumValues", &FieldConfig{ Type: NewList(NewNonNull(__EnumValue)), Args: FieldConfigArgument{ "includeDeprecated": &ArgumentConfig{ Type: Boolean, DefaultValue: false, }, }, Resolve: func(p GQLFRParams) interface{} { includeDeprecated, _ := p.Args["includeDeprecated"].(bool) switch ttype := p.Source.(type) { case *Enum: if includeDeprecated { return ttype.GetValues() } values := []*EnumValueDefinition{} for _, value := range ttype.GetValues() { if value.DeprecationReason != "" { continue } values = append(values, value) } return values } return nil }, }) __Type.AddFieldConfig("inputFields", &FieldConfig{ Type: NewList(NewNonNull(__InputValue)), Resolve: func(p GQLFRParams) interface{} { switch ttype := p.Source.(type) { case *InputObject: fields := []*InputObjectField{} for _, field := range ttype.GetFields() { fields = append(fields, field) } return fields } return nil }, }) __Type.AddFieldConfig("ofType", &FieldConfig{ Type: __Type, }) /** * Note that these are FieldDefinition and not FieldConfig, * so the format for args is different. */ SchemaMetaFieldDef = &FieldDefinition{ Name: "__schema", Type: NewNonNull(__Schema), Description: "Access the current type schema of this server.", Args: []*Argument{}, Resolve: func(p GQLFRParams) interface{} { return p.Info.Schema }, } TypeMetaFieldDef = &FieldDefinition{ Name: "__type", Type: __Type, Description: "Request the type information of a single type.", Args: []*Argument{ &Argument{ Name: "name", Type: NewNonNull(String), }, }, Resolve: func(p GQLFRParams) interface{} { name, ok := p.Args["name"].(string) if !ok { return nil } return p.Info.Schema.GetType(name) }, } TypeNameMetaFieldDef = &FieldDefinition{ Name: "__typename", Type: NewNonNull(String), Description: "The name of the current Object type at runtime.", Args: []*Argument{}, Resolve: func(p GQLFRParams) interface{} { return p.Info.ParentType.GetName() }, } }
func init() { typeKindEnum = NewEnum(EnumConfig{ Name: "__TypeKind", Description: "An enum describing what kind of type a given `__Type` is", Values: EnumValueConfigMap{ "SCALAR": &EnumValueConfig{ Value: TypeKindScalar, Description: "Indicates this type is a scalar.", }, "OBJECT": &EnumValueConfig{ Value: TypeKindObject, Description: "Indicates this type is an object. " + "`fields` and `interfaces` are valid fields.", }, "INTERFACE": &EnumValueConfig{ Value: TypeKindInterface, Description: "Indicates this type is an interface. " + "`fields` and `possibleTypes` are valid fields.", }, "UNION": &EnumValueConfig{ Value: TypeKindUnion, Description: "Indicates this type is a union. " + "`possibleTypes` is a valid field.", }, "ENUM": &EnumValueConfig{ Value: TypeKindEnum, Description: "Indicates this type is an enum. " + "`enumValues` is a valid field.", }, "INPUT_OBJECT": &EnumValueConfig{ Value: TypeKindInputObject, Description: "Indicates this type is an input object. " + "`inputFields` is a valid field.", }, "LIST": &EnumValueConfig{ Value: TypeKindList, Description: "Indicates this type is a list. " + "`ofType` is a valid field.", }, "NON_NULL": &EnumValueConfig{ Value: TypeKindNonNull, Description: "Indicates this type is a non-null. " + "`ofType` is a valid field.", }, }, }) directiveLocationEnum = NewEnum(EnumConfig{ Name: "__DirectiveLocation", Description: "A Directive can be adjacent to many parts of the GraphQL language, a " + "__DirectiveLocation describes one such possible adjacencies.", Values: EnumValueConfigMap{ "QUERY": &EnumValueConfig{ Value: DirectiveLocationQuery, Description: "Location adjacent to a query operation.", }, "MUTATION": &EnumValueConfig{ Value: DirectiveLocationMutation, Description: "Location adjacent to a mutation operation.", }, "SUBSCRIPTION": &EnumValueConfig{ Value: DirectiveLocationSubscription, Description: "Location adjacent to a subscription operation.", }, "FIELD": &EnumValueConfig{ Value: DirectiveLocationField, Description: "Location adjacent to a field.", }, "FRAGMENT_DEFINITION": &EnumValueConfig{ Value: DirectiveLocationFragmentDefinition, Description: "Location adjacent to a fragment definition.", }, "FRAGMENT_SPREAD": &EnumValueConfig{ Value: DirectiveLocationFragmentSpread, Description: "Location adjacent to a fragment spread.", }, "INLINE_FRAGMENT": &EnumValueConfig{ Value: DirectiveLocationInlineFragment, Description: "Location adjacent to an inline fragment.", }, }, }) // Note: some fields (for e.g "fields", "interfaces") are defined later due to cyclic reference typeType = NewObject(ObjectConfig{ Name: "__Type", Description: "The fundamental unit of any GraphQL Schema is the type. There are " + "many kinds of types in GraphQL as represented by the `__TypeKind` enum." + "\n\nDepending on the kind of a type, certain fields describe " + "information about that type. Scalar types provide no information " + "beyond a name and description, while Enum types provide their values. " + "Object and Interface types provide the fields they describe. Abstract " + "types, Union and Interface, provide the Object types possible " + "at runtime. List and NonNull types compose other types.", Fields: Fields{ "kind": &Field{ Type: NewNonNull(typeKindEnum), Resolve: func(p ResolveParams) (interface{}, error) { switch p.Source.(type) { case *Scalar: return TypeKindScalar, nil case *Object: return TypeKindObject, nil case *Interface: return TypeKindInterface, nil case *Union: return TypeKindUnion, nil case *Enum: return TypeKindEnum, nil case *InputObject: return TypeKindInputObject, nil case *List: return TypeKindList, nil case *NonNull: return TypeKindNonNull, nil } return nil, fmt.Errorf("Unknown kind of type: %v", p.Source) }, }, "name": &Field{ Type: String, }, "description": &Field{ Type: String, }, "fields": &Field{}, "interfaces": &Field{}, "possibleTypes": &Field{}, "enumValues": &Field{}, "inputFields": &Field{}, "ofType": &Field{}, }, }) inputValueType = NewObject(ObjectConfig{ Name: "__InputValue", Description: "Arguments provided to Fields or Directives and the input fields of an " + "InputObject are represented as Input Values which describe their type " + "and optionally a default value.", Fields: Fields{ "name": &Field{ Type: NewNonNull(String), }, "description": &Field{ Type: String, }, "type": &Field{ Type: NewNonNull(typeType), }, "defaultValue": &Field{ Type: String, Description: "A GraphQL-formatted string representing the default value for this " + "input value.", Resolve: func(p ResolveParams) (interface{}, error) { if inputVal, ok := p.Source.(*Argument); ok { if inputVal.DefaultValue == nil { return nil, nil } if isNullish(inputVal.DefaultValue) { return nil, nil } astVal := astFromValue(inputVal.DefaultValue, inputVal) return printer.Print(astVal), nil } if inputVal, ok := p.Source.(*InputObjectField); ok { if inputVal.DefaultValue == nil { return nil, nil } astVal := astFromValue(inputVal.DefaultValue, inputVal) return printer.Print(astVal), nil } return nil, nil }, }, }, }) fieldType = NewObject(ObjectConfig{ Name: "__Field", Description: "Object and Interface types are described by a list of Fields, each of " + "which has a name, potentially a list of arguments, and a return type.", Fields: Fields{ "name": &Field{ Type: NewNonNull(String), }, "description": &Field{ Type: String, }, "args": &Field{ Type: NewNonNull(NewList(NewNonNull(inputValueType))), Resolve: func(p ResolveParams) (interface{}, error) { if field, ok := p.Source.(*FieldDefinition); ok { return field.Args, nil } return []interface{}{}, nil }, }, "type": &Field{ Type: NewNonNull(typeType), }, "isDeprecated": &Field{ Type: NewNonNull(Boolean), Resolve: func(p ResolveParams) (interface{}, error) { if field, ok := p.Source.(*FieldDefinition); ok { return (field.DeprecationReason != ""), nil } return false, nil }, }, "deprecationReason": &Field{ Type: String, }, }, }) directiveType = NewObject(ObjectConfig{ Name: "__Directive", Description: "A Directive provides a way to describe alternate runtime execution and " + "type validation behavior in a GraphQL document. " + "\n\nIn some cases, you need to provide options to alter GraphQL's " + "execution behavior in ways field arguments will not suffice, such as " + "conditionally including or skipping a field. Directives provide this by " + "describing additional information to the executor.", Fields: Fields{ "name": &Field{ Type: NewNonNull(String), }, "description": &Field{ Type: String, }, "locations": &Field{ Type: NewNonNull(NewList( NewNonNull(directiveLocationEnum), )), }, "args": &Field{ Type: NewNonNull(NewList( NewNonNull(inputValueType), )), }, // NOTE: the following three fields are deprecated and are no longer part // of the GraphQL specification. "onOperation": &Field{ DeprecationReason: "Use `locations`.", Type: NewNonNull(Boolean), Resolve: func(p ResolveParams) (interface{}, error) { if dir, ok := p.Source.(*Directive); ok { res := false for _, loc := range dir.Locations { if loc == DirectiveLocationQuery || loc == DirectiveLocationMutation || loc == DirectiveLocationSubscription { res = true break } } return res, nil } return false, nil }, }, "onFragment": &Field{ DeprecationReason: "Use `locations`.", Type: NewNonNull(Boolean), Resolve: func(p ResolveParams) (interface{}, error) { if dir, ok := p.Source.(*Directive); ok { res := false for _, loc := range dir.Locations { if loc == DirectiveLocationFragmentSpread || loc == DirectiveLocationInlineFragment || loc == DirectiveLocationFragmentDefinition { res = true break } } return res, nil } return false, nil }, }, "onField": &Field{ DeprecationReason: "Use `locations`.", Type: NewNonNull(Boolean), Resolve: func(p ResolveParams) (interface{}, error) { if dir, ok := p.Source.(*Directive); ok { res := false for _, loc := range dir.Locations { if loc == DirectiveLocationField { res = true break } } return res, nil } return false, nil }, }, }, }) schemaType = NewObject(ObjectConfig{ Name: "__Schema", Description: `A GraphQL Schema defines the capabilities of a GraphQL server. ` + `It exposes all available types and directives on the server, as well as ` + `the entry points for query, mutation, and subscription operations.`, Fields: Fields{ "types": &Field{ Description: "A list of all types supported by this server.", Type: NewNonNull(NewList( NewNonNull(typeType), )), Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { results := []Type{} for _, ttype := range schema.TypeMap() { results = append(results, ttype) } return results, nil } return []Type{}, nil }, }, "queryType": &Field{ Description: "The type that query operations will be rooted at.", Type: NewNonNull(typeType), Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { return schema.QueryType(), nil } return nil, nil }, }, "mutationType": &Field{ Description: `If this server supports mutation, the type that ` + `mutation operations will be rooted at.`, Type: typeType, Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { if schema.MutationType() != nil { return schema.MutationType(), nil } } return nil, nil }, }, "subscriptionType": &Field{ Description: `If this server supports subscription, the type that ` + `subscription operations will be rooted at.`, Type: typeType, Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { if schema.SubscriptionType() != nil { return schema.SubscriptionType(), nil } } return nil, nil }, }, "directives": &Field{ Description: `A list of all directives supported by this server.`, Type: NewNonNull(NewList( NewNonNull(directiveType), )), Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { return schema.Directives(), nil } return nil, nil }, }, }, }) enumValueType = NewObject(ObjectConfig{ Name: "__EnumValue", Description: "One possible value for a given Enum. Enum values are unique values, not " + "a placeholder for a string or numeric value. However an Enum value is " + "returned in a JSON response as a string.", Fields: Fields{ "name": &Field{ Type: NewNonNull(String), }, "description": &Field{ Type: String, }, "isDeprecated": &Field{ Type: NewNonNull(Boolean), Resolve: func(p ResolveParams) (interface{}, error) { if field, ok := p.Source.(*EnumValueDefinition); ok { return (field.DeprecationReason != ""), nil } return false, nil }, }, "deprecationReason": &Field{ Type: String, }, }, }) // Again, adding field configs to __Type that have cyclic reference here // because golang don't like them too much during init/compile-time typeType.AddFieldConfig("fields", &Field{ Type: NewList(NewNonNull(fieldType)), Args: FieldConfigArgument{ "includeDeprecated": &ArgumentConfig{ Type: Boolean, DefaultValue: false, }, }, Resolve: func(p ResolveParams) (interface{}, error) { includeDeprecated, _ := p.Args["includeDeprecated"].(bool) switch ttype := p.Source.(type) { case *Object: if ttype == nil { return nil, nil } fields := []*FieldDefinition{} for _, field := range ttype.Fields() { if !includeDeprecated && field.DeprecationReason != "" { continue } fields = append(fields, field) } return fields, nil case *Interface: if ttype == nil { return nil, nil } fields := []*FieldDefinition{} for _, field := range ttype.Fields() { if !includeDeprecated && field.DeprecationReason != "" { continue } fields = append(fields, field) } return fields, nil } return nil, nil }, }) typeType.AddFieldConfig("interfaces", &Field{ Type: NewList(NewNonNull(typeType)), Resolve: func(p ResolveParams) (interface{}, error) { switch ttype := p.Source.(type) { case *Object: return ttype.Interfaces(), nil } return nil, nil }, }) typeType.AddFieldConfig("possibleTypes", &Field{ Type: NewList(NewNonNull(typeType)), Resolve: func(p ResolveParams) (interface{}, error) { switch ttype := p.Source.(type) { case *Interface: return p.Info.Schema.PossibleTypes(ttype), nil case *Union: return p.Info.Schema.PossibleTypes(ttype), nil } return nil, nil }, }) typeType.AddFieldConfig("enumValues", &Field{ Type: NewList(NewNonNull(enumValueType)), Args: FieldConfigArgument{ "includeDeprecated": &ArgumentConfig{ Type: Boolean, DefaultValue: false, }, }, Resolve: func(p ResolveParams) (interface{}, error) { includeDeprecated, _ := p.Args["includeDeprecated"].(bool) switch ttype := p.Source.(type) { case *Enum: if includeDeprecated { return ttype.Values(), nil } values := []*EnumValueDefinition{} for _, value := range ttype.Values() { if value.DeprecationReason != "" { continue } values = append(values, value) } return values, nil } return nil, nil }, }) typeType.AddFieldConfig("inputFields", &Field{ Type: NewList(NewNonNull(inputValueType)), Resolve: func(p ResolveParams) (interface{}, error) { switch ttype := p.Source.(type) { case *InputObject: fields := []*InputObjectField{} for _, field := range ttype.Fields() { fields = append(fields, field) } return fields, nil } return nil, nil }, }) typeType.AddFieldConfig("ofType", &Field{ Type: typeType, }) // Note that these are FieldDefinition and not FieldConfig, // so the format for args is different. d SchemaMetaFieldDef = &FieldDefinition{ Name: "__schema", Type: NewNonNull(schemaType), Description: "Access the current type schema of this server.", Args: []*Argument{}, Resolve: func(p ResolveParams) (interface{}, error) { return p.Info.Schema, nil }, } TypeMetaFieldDef = &FieldDefinition{ Name: "__type", Type: typeType, Description: "Request the type information of a single type.", Args: []*Argument{ { PrivateName: "name", Type: NewNonNull(String), }, }, Resolve: func(p ResolveParams) (interface{}, error) { name, ok := p.Args["name"].(string) if !ok { return nil, nil } return p.Info.Schema.Type(name), nil }, } TypeNameMetaFieldDef = &FieldDefinition{ Name: "__typename", Type: NewNonNull(String), Description: "The name of the current Object type at runtime.", Args: []*Argument{}, Resolve: func(p ResolveParams) (interface{}, error) { return p.Info.ParentType.Name(), nil }, } }
func TestParsesMultiByteCharacters_UnicodeText(t *testing.T) { doc := ` # This comment has a фы世界 multi-byte character. { field(arg: "Has a фы世界 multi-byte character.") } ` astDoc := parse(t, doc) expectedASTDoc := ast.NewDocument(&ast.Document{ Loc: ast.NewLocation(&ast.Location{ Start: 67, End: 121, }), Definitions: []ast.Node{ ast.NewOperationDefinition(&ast.OperationDefinition{ Loc: ast.NewLocation(&ast.Location{ Start: 67, End: 119, }), Operation: "query", SelectionSet: ast.NewSelectionSet(&ast.SelectionSet{ Loc: ast.NewLocation(&ast.Location{ Start: 67, End: 119, }), Selections: []ast.Selection{ ast.NewField(&ast.Field{ Loc: ast.NewLocation(&ast.Location{ Start: 67, End: 117, }), Name: ast.NewName(&ast.Name{ Loc: ast.NewLocation(&ast.Location{ Start: 69, End: 74, }), Value: "field", }), Arguments: []*ast.Argument{ ast.NewArgument(&ast.Argument{ Loc: ast.NewLocation(&ast.Location{ Start: 75, End: 116, }), Name: ast.NewName(&ast.Name{ Loc: ast.NewLocation(&ast.Location{ Start: 75, End: 78, }), Value: "arg", }), Value: ast.NewStringValue(&ast.StringValue{ Loc: ast.NewLocation(&ast.Location{ Start: 80, End: 116, }), Value: "Has a фы世界 multi-byte character.", }), }), }, }), }, }), }), }, }) astDocQuery := printer.Print(astDoc) expectedASTDocQuery := printer.Print(expectedASTDoc) if !reflect.DeepEqual(astDocQuery, expectedASTDocQuery) { t.Fatalf("unexpected document, expected: %v, got: %v", astDocQuery, expectedASTDocQuery) } }