Skip to content

Commit 4fad7c8

Browse files
authored
Merge branch 'master' into patch-1
2 parents 15f000b + 105a6c2 commit 4fad7c8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+703
-1691
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
.DS_Store
2+
.idea

abstract_test.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,147 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) {
158158
}
159159
}
160160

161+
162+
func TestAppendTypeUsedToAddRuntimeCustomScalarTypeForInterface(t *testing.T) {
163+
164+
petType := graphql.NewInterface(graphql.InterfaceConfig{
165+
Name: "Pet",
166+
Fields: graphql.Fields{
167+
"name": &graphql.Field{
168+
Type: graphql.String,
169+
},
170+
},
171+
})
172+
173+
// ie declare that Dog belongs to Pet interface
174+
dogType := graphql.NewObject(graphql.ObjectConfig{
175+
Name: "Dog",
176+
Interfaces: []*graphql.Interface{
177+
petType,
178+
},
179+
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
180+
_, ok := p.Value.(*testDog)
181+
return ok
182+
},
183+
Fields: graphql.Fields{
184+
"name": &graphql.Field{
185+
Type: graphql.String,
186+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
187+
if dog, ok := p.Source.(*testDog); ok {
188+
return dog.Name, nil
189+
}
190+
return nil, nil
191+
},
192+
},
193+
"woofs": &graphql.Field{
194+
Type: graphql.Boolean,
195+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
196+
if dog, ok := p.Source.(*testDog); ok {
197+
return dog.Woofs, nil
198+
}
199+
return nil, nil
200+
},
201+
},
202+
},
203+
})
204+
// ie declare that Cat belongs to Pet interface
205+
catType := graphql.NewObject(graphql.ObjectConfig{
206+
Name: "Cat",
207+
Interfaces: []*graphql.Interface{
208+
petType,
209+
},
210+
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
211+
_, ok := p.Value.(*testCat)
212+
return ok
213+
},
214+
Fields: graphql.Fields{
215+
"name": &graphql.Field{
216+
Type: graphql.String,
217+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
218+
if cat, ok := p.Source.(*testCat); ok {
219+
return cat.Name, nil
220+
}
221+
return nil, nil
222+
},
223+
},
224+
"meows": &graphql.Field{
225+
Type: graphql.Boolean,
226+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
227+
if cat, ok := p.Source.(*testCat); ok {
228+
return cat.Meows, nil
229+
}
230+
return nil, nil
231+
},
232+
},
233+
},
234+
})
235+
schema, err := graphql.NewSchema(graphql.SchemaConfig{
236+
Query: graphql.NewObject(graphql.ObjectConfig{
237+
Name: "Query",
238+
Fields: graphql.Fields{
239+
"pets": &graphql.Field{
240+
Type: graphql.NewList(petType),
241+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
242+
return []interface{}{
243+
&testDog{"Odie", true},
244+
&testCat{"Garfield", false},
245+
}, nil
246+
},
247+
},
248+
},
249+
}),
250+
251+
})
252+
if err != nil {
253+
t.Fatalf("Error in schema %v", err.Error())
254+
}
255+
256+
//Now add types catType and dogType at runtime.
257+
schema.AppendType(catType)
258+
schema.AppendType(dogType)
259+
260+
query := `{
261+
pets {
262+
name
263+
... on Dog {
264+
woofs
265+
}
266+
... on Cat {
267+
meows
268+
}
269+
}
270+
}`
271+
272+
expected := &graphql.Result{
273+
Data: map[string]interface{}{
274+
"pets": []interface{}{
275+
map[string]interface{}{
276+
"name": "Odie",
277+
"woofs": bool(true),
278+
},
279+
map[string]interface{}{
280+
"name": "Garfield",
281+
"meows": bool(false),
282+
},
283+
},
284+
},
285+
Errors: nil,
286+
}
287+
288+
result := graphql.Do(graphql.Params{
289+
Schema: schema,
290+
RequestString: query,
291+
})
292+
if len(result.Errors) != 0 {
293+
t.Fatalf("wrong result, unexpected errors: %v", result.Errors)
294+
}
295+
if !reflect.DeepEqual(expected, result) {
296+
t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result))
297+
}
298+
}
299+
300+
301+
161302
func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) {
162303

163304
dogType := graphql.NewObject(graphql.ObjectConfig{

definition.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package graphql
22

33
import (
4+
"context"
45
"fmt"
56
"reflect"
67
"regexp"
78

89
"github.com/graphql-go/graphql/language/ast"
9-
"golang.org/x/net/context"
1010
)
1111

1212
// Type interface for all of the possible kinds of GraphQL types
@@ -398,6 +398,7 @@ type ObjectConfig struct {
398398
IsTypeOf IsTypeOfFn `json:"isTypeOf"`
399399
Description string `json:"description"`
400400
}
401+
401402
type FieldsThunk func() Fields
402403

403404
func NewObject(config ObjectConfig) *Object {
@@ -506,19 +507,26 @@ func defineInterfaces(ttype *Object, interfaces []*Interface) ([]*Interface, err
506507
return ifaces, nil
507508
}
508509

509-
func defineFieldMap(ttype Named, fields Fields) (FieldDefinitionMap, error) {
510+
func defineFieldMap(ttype Named, fields interface{}) (FieldDefinitionMap, error) {
511+
var fieldMap Fields
512+
switch fields.(type) {
513+
case Fields:
514+
fieldMap = fields.(Fields)
515+
case FieldsThunk:
516+
fieldMap = fields.(FieldsThunk)()
517+
}
510518

511519
resultFieldMap := FieldDefinitionMap{}
512520

513521
err := invariant(
514-
len(fields) > 0,
522+
len(fieldMap) > 0,
515523
fmt.Sprintf(`%v fields must be an object with field names as keys or a function which return such an object.`, ttype),
516524
)
517525
if err != nil {
518526
return resultFieldMap, err
519527
}
520528

521-
for fieldName, field := range fields {
529+
for fieldName, field := range fieldMap {
522530
if field == nil {
523531
continue
524532
}
@@ -988,17 +996,27 @@ func (gt *Enum) Values() []*EnumValueDefinition {
988996
return gt.values
989997
}
990998
func (gt *Enum) Serialize(value interface{}) interface{} {
991-
if enumValue, ok := gt.getValueLookup()[value]; ok {
999+
v := value
1000+
if reflect.ValueOf(v).Kind() == reflect.Ptr {
1001+
v = reflect.Indirect(reflect.ValueOf(v)).Interface()
1002+
}
1003+
if enumValue, ok := gt.getValueLookup()[v]; ok {
9921004
return enumValue.Name
9931005
}
9941006
return nil
9951007
}
9961008
func (gt *Enum) ParseValue(value interface{}) interface{} {
997-
valueStr, ok := value.(string)
998-
if !ok {
1009+
var v string
1010+
1011+
switch value := value.(type) {
1012+
case string:
1013+
v = value
1014+
case *string:
1015+
v = *value
1016+
default:
9991017
return nil
10001018
}
1001-
if enumValue, ok := gt.getNameLookup()[valueStr]; ok {
1019+
if enumValue, ok := gt.getNameLookup()[v]; ok {
10021020
return enumValue.Value
10031021
}
10041022
return nil
@@ -1070,8 +1088,8 @@ type InputObject struct {
10701088

10711089
typeConfig InputObjectConfig
10721090
fields InputObjectFieldMap
1073-
1074-
err error
1091+
init bool
1092+
err error
10751093
}
10761094
type InputObjectFieldConfig struct {
10771095
Type Input `json:"type"`
@@ -1119,7 +1137,7 @@ func NewInputObject(config InputObjectConfig) *InputObject {
11191137
gt.PrivateName = config.Name
11201138
gt.PrivateDescription = config.Description
11211139
gt.typeConfig = config
1122-
gt.fields = gt.defineFieldMap()
1140+
//gt.fields = gt.defineFieldMap()
11231141
return gt
11241142
}
11251143

@@ -1165,9 +1183,14 @@ func (gt *InputObject) defineFieldMap() InputObjectFieldMap {
11651183
field.DefaultValue = fieldConfig.DefaultValue
11661184
resultFieldMap[fieldName] = field
11671185
}
1186+
gt.init = true
11681187
return resultFieldMap
11691188
}
1189+
11701190
func (gt *InputObject) Fields() InputObjectFieldMap {
1191+
if !gt.init {
1192+
gt.fields = gt.defineFieldMap()
1193+
}
11711194
return gt.fields
11721195
}
11731196
func (gt *InputObject) Name() string {
@@ -1252,8 +1275,7 @@ func (gl *List) Error() error {
12521275
//
12531276
// Note: the enforcement of non-nullability occurs within the executor.
12541277
type NonNull struct {
1255-
PrivateName string `json:"name"` // added to conform with introspection for NonNull.Name = nil
1256-
OfType Type `json:"ofType"`
1278+
OfType Type `json:"ofType"`
12571279

12581280
err error
12591281
}

definition_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,3 +619,25 @@ func TestTypeSystem_DefinitionExample_IncludesFieldsThunk(t *testing.T) {
619619
t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(fieldMap["s"].Type, someObject))
620620
}
621621
}
622+
623+
func TestTypeSystem_DefinitionExampe_AllowsCyclicFieldTypes(t *testing.T) {
624+
personType := graphql.NewObject(graphql.ObjectConfig{
625+
Name: "Person",
626+
Fields: (graphql.FieldsThunk)(func() graphql.Fields {
627+
return graphql.Fields{
628+
"name": &graphql.Field{
629+
Type: graphql.String,
630+
},
631+
"bestFriend": &graphql.Field{
632+
Type: personType,
633+
},
634+
}
635+
}),
636+
})
637+
638+
fieldMap := personType.Fields()
639+
if !reflect.DeepEqual(fieldMap["name"].Type, graphql.String) {
640+
t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(fieldMap["bestFriend"].Type, personType))
641+
}
642+
643+
}

enum_type_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,47 @@ func TestTypeSystem_EnumValues_EnumValueMayBeNullable(t *testing.T) {
377377
t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result))
378378
}
379379
}
380+
381+
func TestTypeSystem_EnumValues_EnumValueMayBePointer(t *testing.T) {
382+
var enumTypeTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{
383+
Query: graphql.NewObject(graphql.ObjectConfig{
384+
Name: "Query",
385+
Fields: graphql.Fields{
386+
"query": &graphql.Field{
387+
Type: graphql.NewObject(graphql.ObjectConfig{
388+
Name: "query",
389+
Fields: graphql.Fields{
390+
"color": &graphql.Field{
391+
Type: enumTypeTestColorType,
392+
},
393+
"foo": &graphql.Field{
394+
Description: "foo field",
395+
Type: graphql.Int,
396+
},
397+
},
398+
}),
399+
Resolve: func(_ graphql.ResolveParams) (interface{}, error) {
400+
one := 1
401+
return struct {
402+
Color *int `graphql:"color"`
403+
Foo *int `graphql:"foo"`
404+
}{&one, &one}, nil
405+
},
406+
},
407+
},
408+
}),
409+
})
410+
query := "{ query { color foo } }"
411+
expected := &graphql.Result{
412+
Data: map[string]interface{}{
413+
"query": map[string]interface{}{
414+
"color": "GREEN",
415+
"foo": 1}}}
416+
result := g(t, graphql.Params{
417+
Schema: enumTypeTestSchema,
418+
RequestString: query,
419+
})
420+
if !reflect.DeepEqual(expected, result) {
421+
t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result))
422+
}
423+
}

examples/context/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package main
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
67
"log"
78
"net/http"
89

910
"github.com/graphql-go/graphql"
10-
"golang.org/x/net/context"
1111
)
1212

1313
var Schema graphql.Schema
@@ -46,7 +46,7 @@ func graphqlHandler(w http.ResponseWriter, r *http.Request) {
4646
}{1, "cool user"}
4747
result := graphql.Do(graphql.Params{
4848
Schema: Schema,
49-
RequestString: r.URL.Query()["query"][0],
49+
RequestString: r.URL.Query().Get("query"),
5050
Context: context.WithValue(context.Background(), "currentUser", user),
5151
})
5252
if len(result.Errors) > 0 {

examples/http/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func main() {
8888
_ = importJSONDataFromFile("data.json", &data)
8989

9090
http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
91-
result := executeQuery(r.URL.Query()["query"][0], schema)
91+
result := executeQuery(r.URL.Query().Get("query"), schema)
9292
json.NewEncoder(w).Encode(result)
9393
})
9494

examples/httpdynamic/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func main() {
127127
}
128128

129129
http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
130-
result := executeQuery(r.URL.Query()["query"][0], schema)
130+
result := executeQuery(r.URL.Query().Get("query"), schema)
131131
json.NewEncoder(w).Encode(result)
132132
})
133133

0 commit comments

Comments
 (0)