Skip to content

Commit 11836f4

Browse files
authored
Merge branch 'master' into master
2 parents ac6c6f5 + 77807ed commit 11836f4

12 files changed

+192
-79
lines changed

examples/crud/Readme.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
# Go GraphQL CRUD example
22

3-
Implementation create, read, update and delete on Go
3+
Implement create, read, update and delete on Go.
44

5-
To run the program, go to the directory
6-
`cd examples/crud`
5+
To run the program:
76

8-
Run the example
9-
`go run main.go`
7+
1. go to the directory: `cd examples/crud`
8+
2. Run the example: `go run main.go`
109

1110
## Create
11+
1212
`http://localhost:8080/product?query=mutation+_{create(name:"Inca Kola",info:"Inca Kola is a soft drink that was created in Peru in 1935 by British immigrant Joseph Robinson Lindley using lemon verbena (wiki)",price:1.99){id,name,info,price}}`
1313

1414
## Read
15-
Get single product by id
16-
`http://localhost:8080/product?query={product(id:1){name,info,price}}`
1715

18-
Get product list
19-
`http://localhost:8080/product?query={list{id,name,info,price}}`
16+
* Get single product by id: `http://localhost:8080/product?query={product(id:1){name,info,price}}`
17+
* Get product list: `http://localhost:8080/product?query={list{id,name,info,price}}`
2018

2119
## Update
20+
2221
`http://localhost:8080/product?query=mutation+_{update(id:1,price:3.95){id,name,info,price}}`
2322

2423
## Delete
24+
2525
`http://localhost:8080/product?query=mutation+_{delete(id:1){id,name,info,price}}`

examples/crud/main.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,34 @@ import (
1010
"github.com/graphql-go/graphql"
1111
)
1212

13+
// Product contains information about one product
1314
type Product struct {
1415
ID int64 `json:"id"`
1516
Name string `json:"name"`
1617
Info string `json:"info,omitempty"`
1718
Price float64 `json:"price"`
1819
}
1920

20-
var products []Product
21+
var products = []Product{
22+
{
23+
ID: 1,
24+
Name: "Chicha Morada",
25+
Info: "Chicha morada is a beverage originated in the Andean regions of Perú but is actually consumed at a national level (wiki)",
26+
Price: 7.99,
27+
},
28+
{
29+
ID: 2,
30+
Name: "Chicha de jora",
31+
Info: "Chicha de jora is a corn beer chicha prepared by germinating maize, extracting the malt sugars, boiling the wort, and fermenting it in large vessels (traditionally huge earthenware vats) for several days (wiki)",
32+
Price: 5.95,
33+
},
34+
{
35+
ID: 3,
36+
Name: "Pisco",
37+
Info: "Pisco is a colorless or yellowish-to-amber colored brandy produced in winemaking regions of Peru and Chile (wiki)",
38+
Price: 9.95,
39+
},
40+
}
2141

2242
var productType = graphql.NewObject(
2343
graphql.ObjectConfig{
@@ -204,17 +224,7 @@ func executeQuery(query string, schema graphql.Schema) *graphql.Result {
204224
return result
205225
}
206226

207-
func initProductsData(p *[]Product) {
208-
product1 := Product{ID: 1, Name: "Chicha Morada", Info: "Chicha morada is a beverage originated in the Andean regions of Perú but is actually consumed at a national level (wiki)", Price: 7.99}
209-
product2 := Product{ID: 2, Name: "Chicha de jora", Info: "Chicha de jora is a corn beer chicha prepared by germinating maize, extracting the malt sugars, boiling the wort, and fermenting it in large vessels (traditionally huge earthenware vats) for several days (wiki)", Price: 5.95}
210-
product3 := Product{ID: 3, Name: "Pisco", Info: "Pisco is a colorless or yellowish-to-amber colored brandy produced in winemaking regions of Peru and Chile (wiki)", Price: 9.95}
211-
*p = append(*p, product1, product2, product3)
212-
}
213-
214227
func main() {
215-
// Primary data initialization
216-
initProductsData(&products)
217-
218228
http.HandleFunc("/product", func(w http.ResponseWriter, r *http.Request) {
219229
result := executeQuery(r.URL.Query().Get("query"), schema)
220230
json.NewEncoder(w).Encode(result)

executor.go

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
"reflect"
8+
"sort"
89
"strings"
910

1011
"github.com/graphql-go/graphql/gqlerrors"
@@ -254,7 +255,9 @@ func executeFieldsSerially(p executeFieldsParams) *Result {
254255
}
255256

256257
finalResults := make(map[string]interface{}, len(p.Fields))
257-
for responseName, fieldASTs := range p.Fields {
258+
for _, orderedField := range orderedFields(p.Fields) {
259+
responseName := orderedField.responseName
260+
fieldASTs := orderedField.fieldASTs
258261
fieldPath := p.Path.WithKey(responseName)
259262
resolved, state := resolveField(p.ExecutionContext, p.ParentType, p.Source, fieldASTs, fieldPath)
260263
if state.hasNoFieldDefs {
@@ -650,15 +653,15 @@ func resolveField(eCtx *executionContext, parentType *Object, source interface{}
650653
Context: eCtx.Context,
651654
})
652655

653-
if resolveFnError != nil {
654-
panic(resolveFnError)
655-
}
656-
657656
extErrs = resolveFieldFinishFn(result, resolveFnError)
658657
if len(extErrs) != 0 {
659658
eCtx.Errors = append(eCtx.Errors, extErrs...)
660659
}
661660

661+
if resolveFnError != nil {
662+
panic(resolveFnError)
663+
}
664+
662665
completed := completeValueCatchingError(eCtx, returnType, fieldASTs, info, path, result)
663666
return completed, resultState
664667
}
@@ -1038,3 +1041,39 @@ func getFieldDef(schema Schema, parentType *Object, fieldName string) *FieldDefi
10381041
}
10391042
return parentType.Fields()[fieldName]
10401043
}
1044+
1045+
// contains field information that will be placed in an ordered slice
1046+
type orderedField struct {
1047+
responseName string
1048+
fieldASTs []*ast.Field
1049+
}
1050+
1051+
// orders fields from a fields map by location in the source
1052+
func orderedFields(fields map[string][]*ast.Field) []*orderedField {
1053+
orderedFields := []*orderedField{}
1054+
fieldMap := map[int]*orderedField{}
1055+
startLocs := []int{}
1056+
1057+
for responseName, fieldASTs := range fields {
1058+
// find the lowest location in the current fieldASTs
1059+
lowest := -1
1060+
for _, fieldAST := range fieldASTs {
1061+
loc := fieldAST.GetLoc().Start
1062+
if lowest == -1 || loc < lowest {
1063+
lowest = loc
1064+
}
1065+
}
1066+
startLocs = append(startLocs, lowest)
1067+
fieldMap[lowest] = &orderedField{
1068+
responseName: responseName,
1069+
fieldASTs: fieldASTs,
1070+
}
1071+
}
1072+
1073+
sort.Ints(startLocs)
1074+
for _, startLoc := range startLocs {
1075+
orderedFields = append(orderedFields, fieldMap[startLoc])
1076+
}
1077+
1078+
return orderedFields
1079+
}

extensions_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ func tinit(t *testing.T) graphql.Schema {
2323
return "foo", nil
2424
},
2525
},
26+
"erred": &graphql.Field{
27+
Type: graphql.String,
28+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
29+
return "", errors.New("ooops")
30+
},
31+
},
2632
},
2733
}),
2834
})
@@ -306,6 +312,35 @@ func TestExtensionResolveFieldFinishFuncPanic(t *testing.T) {
306312
}
307313
}
308314

315+
func TestExtensionResolveFieldFinishFuncAfterError(t *testing.T) {
316+
var fnErrs int
317+
ext := newtestExt("testExt")
318+
ext.resolveFieldDidStartFn = func(ctx context.Context, i *graphql.ResolveInfo) (context.Context, graphql.ResolveFieldFinishFunc) {
319+
return ctx, func(v interface{}, err error) {
320+
if err != nil {
321+
fnErrs++
322+
}
323+
}
324+
}
325+
326+
schema := tinit(t)
327+
query := `query Example { erred }`
328+
schema.AddExtensions(ext)
329+
330+
result := graphql.Do(graphql.Params{
331+
Schema: schema,
332+
RequestString: query,
333+
})
334+
335+
if resErrs := len(result.Errors); resErrs != 1 {
336+
t.Errorf("Incorrect number of returned result errors: %d", resErrs)
337+
}
338+
339+
if fnErrs != 1 {
340+
t.Errorf("Incorrect number of errors captured: %d", fnErrs)
341+
}
342+
}
343+
309344
func TestExtensionGetResultPanic(t *testing.T) {
310345
ext := newtestExt("testExt")
311346
ext.getResultFn = func(context.Context) interface{} {

introspection.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,14 @@ func init() {
312312
},
313313
"deprecationReason": &Field{
314314
Type: String,
315+
Resolve: func(p ResolveParams) (interface{}, error) {
316+
if field, ok := p.Source.(*FieldDefinition); ok {
317+
if field.DeprecationReason != "" {
318+
return field.DeprecationReason, nil
319+
}
320+
}
321+
return nil, nil
322+
},
315323
},
316324
},
317325
})
@@ -497,6 +505,14 @@ func init() {
497505
},
498506
"deprecationReason": &Field{
499507
Type: String,
508+
Resolve: func(p ResolveParams) (interface{}, error) {
509+
if field, ok := p.Source.(*EnumValueDefinition); ok {
510+
if field.DeprecationReason != "" {
511+
return field.DeprecationReason, nil
512+
}
513+
}
514+
return nil, nil
515+
},
500516
},
501517
},
502518
})

0 commit comments

Comments
 (0)