{{ reserveImport "context" }} {{ reserveImport "fmt" }} {{ reserveImport "io" }} {{ reserveImport "strconv" }} {{ reserveImport "time" }} {{ reserveImport "sync" }} {{ reserveImport "sync/atomic" }} {{ reserveImport "errors" }} {{ reserveImport "bytes" }} {{ reserveImport "embed" }} {{ reserveImport "github.com/vektah/gqlparser/v2" "gqlparser" }} {{ reserveImport "github.com/vektah/gqlparser/v2/ast" }} {{ reserveImport "github.com/99designs/gqlgen/graphql" }} {{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }} {{ if eq .Config.Exec.Layout "single-file" }} // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { return &executableSchema{ schema: cfg.Schema, resolvers: cfg.Resolvers, directives: cfg.Directives, complexity: cfg.Complexity, } } type Config struct { Schema *ast.Schema Resolvers ResolverRoot Directives DirectiveRoot Complexity ComplexityRoot } type ResolverRoot interface { {{- range $object := .Objects -}} {{ if $object.HasResolvers -}} {{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver {{ end }} {{- end }} {{- range $object := .Inputs -}} {{ if $object.HasResolvers -}} {{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver {{ end }} {{- end }} } type DirectiveRoot struct { {{ range $directive := .Directives }} {{- $directive.Declaration }} {{ end }} } type ComplexityRoot struct { {{- if not .Config.OmitComplexity }} {{ range $object := .Objects }} {{ if not $object.IsReserved -}} {{ ucFirst $object.Name }} struct { {{ range $_, $fields := $object.UniqueFields }} {{- $field := index $fields 0 -}} {{ if not $field.IsReserved -}} {{ $field.GoFieldName }} {{ $field.ComplexitySignature }} {{ end }} {{- end }} } {{- end }} {{ end }} {{- end }} } {{ end }} {{ range $object := .Objects -}} {{ if $object.HasResolvers }} type {{ucFirst $object.Name}}Resolver interface { {{ range $field := $object.Fields -}} {{- if $field.IsResolver }} {{- $field.GoFieldName}}{{ $field.ShortResolverDeclaration }} {{- end }} {{ end }} } {{- end }} {{- end }} {{ range $object := .Inputs -}} {{ if $object.HasResolvers }} type {{$object.Name}}Resolver interface { {{ range $field := $object.Fields -}} {{- if $field.IsResolver }} {{- $field.GoFieldName}}{{ $field.ShortResolverDeclaration }} {{- end }} {{ end }} } {{- end }} {{- end }} {{ if eq .Config.Exec.Layout "single-file" }} type executableSchema struct { schema *ast.Schema resolvers ResolverRoot directives DirectiveRoot complexity ComplexityRoot } func (e *executableSchema) Schema() *ast.Schema { if e.schema != nil { return e.schema } return parsedSchema } func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) { ec := executionContext{nil, e, 0, 0, nil} _ = ec {{ if not .Config.OmitComplexity -}} switch typeName + "." + field { {{ range $object := .Objects }} {{ if not $object.IsReserved }} {{ range $_, $fields := $object.UniqueFields }} {{- $len := len $fields }} {{- range $i, $field := $fields }} {{- $last := eq (add $i 1) $len }} {{- if not $field.IsReserved }} {{- if eq $i 0 }}case {{ end }}"{{$object.Name}}.{{$field.Name}}"{{ if not $last }},{{ else }}: if e.complexity.{{ucFirst $object.Name}}.{{$field.GoFieldName}} == nil { break } {{ if $field.Args }} args, err := ec.{{ $field.ArgsFunc }}(context.TODO(),rawArgs) if err != nil { return 0, false } {{ end }} return e.complexity.{{ucFirst $object.Name}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{ end }}), true {{ end }} {{- end }} {{- end }} {{ end }} {{ end }} {{ end }} } {{- end }} return 0, false } func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { rc := graphql.GetOperationContext(ctx) ec := executionContext{rc, e, 0, 0, make(chan graphql.DeferredResult)} inputUnmarshalMap := graphql.BuildUnmarshalerMap( {{- range $input := .Inputs -}} {{ if not $input.HasUnmarshal }} ec.unmarshalInput{{ $input.Name }}, {{- end }} {{- end }} ) first := true switch rc.Operation.Operation { {{- if .QueryRoot }} case ast.Query: return func(ctx context.Context) *graphql.Response { var response graphql.Response var data graphql.Marshaler if first { first = false ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) {{ if .Directives.LocationDirectives "QUERY" -}} data = ec._queryMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){ return ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet), nil }) {{- else -}} data = ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet) {{- end }} } else { if atomic.LoadInt32(&ec.pendingDeferred) > 0 { result := <-ec.deferredResults atomic.AddInt32(&ec.pendingDeferred, -1) data = result.Result response.Path = result.Path response.Label = result.Label response.Errors = result.Errors } else { return nil } } var buf bytes.Buffer data.MarshalGQL(&buf) response.Data = buf.Bytes() if atomic.LoadInt32(&ec.deferred) > 0 { hasNext := atomic.LoadInt32(&ec.pendingDeferred) > 0 response.HasNext = &hasNext } return &response } {{ end }} {{- if .MutationRoot }} case ast.Mutation: return func(ctx context.Context) *graphql.Response { if !first { return nil } first = false ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) {{ if .Directives.LocationDirectives "MUTATION" -}} data := ec._mutationMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){ return ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet), nil }) {{- else -}} data := ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet) {{- end }} var buf bytes.Buffer data.MarshalGQL(&buf) return &graphql.Response{ Data: buf.Bytes(), } } {{ end }} {{- if .SubscriptionRoot }} case ast.Subscription: {{ if .Directives.LocationDirectives "SUBSCRIPTION" -}} next := ec._subscriptionMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){ return ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet),nil }) {{- else -}} next := ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet) {{- end }} var buf bytes.Buffer return func(ctx context.Context) *graphql.Response { buf.Reset() data := next(ctx) if data == nil { return nil } data.MarshalGQL(&buf) return &graphql.Response{ Data: buf.Bytes(), } } {{ end }} default: return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) } } type executionContext struct { *graphql.OperationContext *executableSchema deferred int32 pendingDeferred int32 deferredResults chan graphql.DeferredResult } func (ec *executionContext) processDeferredGroup(dg graphql.DeferredGroup) { atomic.AddInt32(&ec.pendingDeferred, 1) go func () { ctx := graphql.WithFreshResponseContext(dg.Context) dg.FieldSet.Dispatch(ctx) ds := graphql.DeferredResult{ Path: dg.Path, Label: dg.Label, Result: dg.FieldSet, Errors: graphql.GetErrors(ctx), } // null fields should bubble up if dg.FieldSet.Invalids > 0 { ds.Result = graphql.Null } ec.deferredResults <- ds }() } func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { if ec.DisableIntrospection { return nil, errors.New("introspection disabled") } return introspection.WrapSchema(ec.Schema()), nil } func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { if ec.DisableIntrospection { return nil, errors.New("introspection disabled") } return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil } {{if .HasEmbeddableSources }} //go:embed{{- range $source := .AugmentedSources }}{{if $source.Embeddable}} {{$source.RelativePath|quote}}{{end}}{{- end }} var sourcesFS embed.FS func sourceData(filename string) string { data, err := sourcesFS.ReadFile(filename) if err != nil { panic(fmt.Sprintf("codegen problem: %s not available", filename)) } return string(data) } {{- end }} var sources = []*ast.Source{ {{- range $source := .AugmentedSources }} {Name: {{$source.RelativePath|quote}}, Input: {{if (not $source.Embeddable)}}{{$source.Source|rawQuote}}{{else}}sourceData({{$source.RelativePath|quote}}){{end}}, BuiltIn: {{$source.BuiltIn}}}, {{- end }} } var parsedSchema = gqlparser.MustLoadSchema(sources...) {{ end }}