Skip to content

Commit

Permalink
execute mutations serially
Browse files Browse the repository at this point in the history
  • Loading branch information
neelance committed Oct 26, 2016
1 parent 1faf666 commit 3c15e17
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 28 deletions.
58 changes: 58 additions & 0 deletions graphql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ func (r *helloWorldResolver2) Hello(ctx context.Context) (string, error) {
return "Hello world!", nil
}

type theNumberResolver struct {
number int32
}

func (r *theNumberResolver) TheNumber() int32 {
return r.number
}

func (r *theNumberResolver) ChangeTheNumber(args *struct{ NewNumber int32 }) *theNumberResolver {
r.number = args.NewNumber
return r
}

var tests = []struct {
name string
schema string
Expand Down Expand Up @@ -1012,6 +1025,51 @@ var tests = []struct {
}
`,
},

{
name: "MutationOrder",
schema: `
schema {
query: Query
mutation: Mutation
}
type Query {
theNumber: Int!
}
type Mutation {
changeTheNumber(newNumber: Int!): Query
}
`,
resolver: &theNumberResolver{},
query: `
mutation {
first: changeTheNumber(newNumber: 1) {
theNumber
}
second: changeTheNumber(newNumber: 3) {
theNumber
}
third: changeTheNumber(newNumber: 2) {
theNumber
}
}
`,
result: `
{
"first": {
"theNumber": 1
},
"second": {
"theNumber": 3
},
"third": {
"theNumber": 2
}
}
`,
},
}

func TestAll(t *testing.T) {
Expand Down
61 changes: 35 additions & 26 deletions internal/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,19 +391,19 @@ func (e *Exec) Exec(ctx context.Context, document *query.Document, variables map

data := func() interface{} {
defer r.handlePanic()
return opExec.exec(r, op.SelSet, e.resolver)
return opExec.exec(r, op.SelSet, e.resolver, op.Type == query.Mutation)
}()

return data, r.errs
}

type iExec interface {
exec(r *request, selSet *query.SelectionSet, resolver reflect.Value) interface{}
exec(r *request, selSet *query.SelectionSet, resolver reflect.Value, serially bool) interface{}
}

type scalarExec struct{}

func (e *scalarExec) exec(r *request, selSet *query.SelectionSet, resolver reflect.Value) interface{} {
func (e *scalarExec) exec(r *request, selSet *query.SelectionSet, resolver reflect.Value, serially bool) interface{} {
return resolver.Interface()
}

Expand All @@ -412,7 +412,7 @@ type listExec struct {
nonNull bool
}

func (e *listExec) exec(r *request, selSet *query.SelectionSet, resolver reflect.Value) interface{} {
func (e *listExec) exec(r *request, selSet *query.SelectionSet, resolver reflect.Value, serially bool) interface{} {
if !e.nonNull {
if resolver.IsNil() {
return nil
Expand All @@ -426,7 +426,7 @@ func (e *listExec) exec(r *request, selSet *query.SelectionSet, resolver reflect
go func(i int) {
defer wg.Done()
defer r.handlePanic()
l[i] = e.elem.exec(r, selSet, resolver.Index(i))
l[i] = e.elem.exec(r, selSet, resolver.Index(i), false)
}(i)
}
wg.Wait()
Expand All @@ -442,7 +442,7 @@ type objectExec struct {

type addResultFn func(key string, value interface{})

func (e *objectExec) exec(r *request, selSet *query.SelectionSet, resolver reflect.Value) interface{} {
func (e *objectExec) exec(r *request, selSet *query.SelectionSet, resolver reflect.Value, serially bool) interface{} {
if resolver.IsNil() {
if e.nonNull {
r.addError(errors.Errorf("got nil for non-null %q", e.name))
Expand All @@ -456,20 +456,33 @@ func (e *objectExec) exec(r *request, selSet *query.SelectionSet, resolver refle
results[key] = value
mu.Unlock()
}
e.execSelectionSet(r, selSet, resolver, addResult)
e.execSelectionSet(r, selSet, resolver, addResult, serially)
return results
}

func (e *objectExec) execSelectionSet(r *request, selSet *query.SelectionSet, resolver reflect.Value, addResult addResultFn) {
func (e *objectExec) execSelectionSet(r *request, selSet *query.SelectionSet, resolver reflect.Value, addResult addResultFn, serially bool) {
var wg sync.WaitGroup
for _, sel := range selSet.Selections {
execSel := func(f func()) {
if serially {
defer r.handlePanic()
f()
return
}

wg.Add(1)
go func() {
defer wg.Done()
defer r.handlePanic()
f()
}()
}

switch sel := sel.(type) {
case *query.Field:
if !skipByDirective(r, sel.Directives) {
wg.Add(1)
go func(f *query.Field) {
defer wg.Done()
defer r.handlePanic()
f := sel
execSel(func() {
switch f.Name {
case "__typename":
for name, a := range e.typeAssertions {
Expand All @@ -493,31 +506,27 @@ func (e *objectExec) execSelectionSet(r *request, selSet *query.SelectionSet, re
}
fe.execField(r, f, resolver, addResult)
}
}(sel)
})
}

case *query.FragmentSpread:
if !skipByDirective(r, sel.Directives) {
wg.Add(1)
go func(fs *query.FragmentSpread) {
defer wg.Done()
defer r.handlePanic()
fs := sel
execSel(func() {
frag, ok := r.doc.Fragments[fs.Name]
if !ok {
panic(fmt.Errorf("fragment %q not found", fs.Name)) // TODO proper error handling
}
e.execFragment(r, &frag.Fragment, resolver, addResult)
}(sel)
})
}

case *query.InlineFragment:
if !skipByDirective(r, sel.Directives) {
wg.Add(1)
go func(frag *query.InlineFragment) {
defer wg.Done()
defer r.handlePanic()
frag := sel
execSel(func() {
e.execFragment(r, &frag.Fragment, resolver, addResult)
}(sel)
})
}

default:
Expand All @@ -537,10 +546,10 @@ func (e *objectExec) execFragment(r *request, frag *query.Fragment, resolver ref
if !out[1].Bool() {
return
}
a.typeExec.(*objectExec).execSelectionSet(r, frag.SelSet, out[0], addResult)
a.typeExec.(*objectExec).execSelectionSet(r, frag.SelSet, out[0], addResult, false)
return
}
e.execSelectionSet(r, frag.SelSet, resolver, addResult)
e.execSelectionSet(r, frag.SelSet, resolver, addResult, false)
}

type fieldExec struct {
Expand Down Expand Up @@ -575,7 +584,7 @@ func (e *fieldExec) execField(r *request, f *query.Field, resolver reflect.Value
addResult(f.Alias, nil) // TODO handle non-nil
return
}
addResult(f.Alias, e.valueExec.exec(r, f.SelSet, out[0]))
addResult(f.Alias, e.valueExec.exec(r, f.SelSet, out[0], false))
}

type typeAssertExec struct {
Expand Down
4 changes: 2 additions & 2 deletions internal/exec/introspection.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ func init() {
}

func introspectSchema(r *request, selSet *query.SelectionSet) interface{} {
return schemaExec.exec(r, selSet, reflect.ValueOf(&schemaResolver{r.schema}))
return schemaExec.exec(r, selSet, reflect.ValueOf(&schemaResolver{r.schema}), false)
}

func introspectType(r *request, name string, selSet *query.SelectionSet) interface{} {
t, ok := r.schema.Types[name]
if !ok {
return nil
}
return typeExec.exec(r, selSet, reflect.ValueOf(&typeResolver{t}))
return typeExec.exec(r, selSet, reflect.ValueOf(&typeResolver{t}), false)
}

var metaSchemaSrc = `
Expand Down

0 comments on commit 3c15e17

Please sign in to comment.