Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query complexity calculation and limits #315

Merged
merged 11 commits into from
Aug 31, 2018
4 changes: 2 additions & 2 deletions codegen/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ type TypeMapEntry struct {
}

type TypeMapField struct {
Resolver bool `yaml:"resolver"`
FieldName string `yaml:"fieldName"`
Resolver bool `yaml:"resolver"`
FieldName string `yaml:"fieldName"`
}

func (c *PackageConfig) normalize() error {
Expand Down
26 changes: 24 additions & 2 deletions codegen/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ func (f *Field) IsResolver() bool {
return f.GoFieldName == ""
}

func (f *Field) IsSystem() bool {
return strings.HasPrefix(f.GQLName, "__")
}

func (f *Field) IsMethod() bool {
return f.GoFieldType == GoFieldMethod
}
Expand Down Expand Up @@ -165,6 +169,24 @@ func (f *Field) ResolverDeclaration() string {
return res
}

func (f *Field) ComplexitySignature() string {
res := fmt.Sprintf("func(childComplexity int")
for _, arg := range f.Args {
res += fmt.Sprintf(", %s %s", arg.GoVarName, arg.Signature())
}
res += ") int"
return res
}

func (f *Field) ComplexityArgs() string {
var args []string
for _, arg := range f.Args {
args = append(args, "args["+strconv.Quote(arg.GQLName)+"].("+arg.Signature()+")")
}

return strings.Join(args, ", ")
}

func (f *Field) CallArgs() string {
var args []string

Expand Down Expand Up @@ -198,7 +220,7 @@ func (f *Field) doWriteJson(val string, remainingMods []string, astType *ast.Typ
ec.Errorf(ctx, "must not be null")
}
{{- end }}
return graphql.Null
return graphql.Null
}
{{.next }}`, map[string]interface{}{
"val": val,
Expand Down Expand Up @@ -227,7 +249,7 @@ func (f *Field) doWriteJson(val string, remainingMods []string, astType *ast.Typ
ctx := graphql.WithResolverContext(ctx, rctx)
{{- end}}
{{.arr}} = append({{.arr}}, func() graphql.Marshaler {
{{ .next }}
{{ .next }}
}())
}
return {{.arr}}`, map[string]interface{}{
Expand Down
2 changes: 1 addition & 1 deletion codegen/templates/data.go

Large diffs are not rendered by default.

46 changes: 45 additions & 1 deletion codegen/templates/generated.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
}
}

type Config struct {
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
}

type ResolverRoot interface {
Expand All @@ -35,7 +37,19 @@ type DirectiveRoot struct {
{{ end }}
}

{{- range $object := .Objects -}}
type ComplexityRoot struct {
{{ range $object := .Objects }}
{{ $object.GQLType|toCamel }} struct {
{{ range $field := $object.Fields -}}
{{ if $field.IsSystem }}{{ else -}}
{{ $field.GQLName|toCamel }} {{ $field.ComplexitySignature }}
{{ end }}
{{- end }}
}
{{ end }}
}

{{ range $object := .Objects -}}
{{ if $object.HasResolvers }}
type {{$object.GQLType}}Resolver interface {
{{ range $field := $object.Fields -}}
Expand All @@ -48,12 +62,42 @@ type DirectiveRoot struct {
type executableSchema struct {
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}

func (e *executableSchema) Schema() *ast.Schema {
return parsedSchema
}

func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
switch typeName + "." + field {
{{ range $object := .Objects }}
{{ range $field := $object.Fields }}
{{ if $field.IsSystem }}{{ else }}
case "{{$object.GQLType}}.{{$field.GQLName}}":
if e.complexity.{{$object.GQLType|toCamel}}.{{$field.GQLName|toCamel}} == nil {
break
}
{{ if $field.Args }}args := map[string]interface{}{} {{end}}
{{ range $i, $arg := $field.Args }}
var arg{{$i}} {{$arg.Signature }}
if tmp, ok := rawArgs[{{$arg.GQLName|quote}}]; ok {
var err error
{{$arg.Unmarshal (print "arg" $i) "tmp" }}
if err != nil {
return 0, false
}
}
args[{{$arg.GQLName|quote}}] = arg{{$i}}
{{ end }}
return e.complexity.{{$object.GQLType|toCamel}}.{{$field.GQLName|toCamel}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{end}}), true
{{ end }}
{{ end }}
{{ end }}
}
return 0, false
}

func (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
{{- if .QueryRoot }}
ec := executionContext{graphql.GetRequestContext(ctx), e}
Expand Down
Loading