summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable
diff options
context:
space:
mode:
authorWim <wim@42.be>2022-04-01 00:23:19 +0200
committerGitHub <noreply@github.com>2022-04-01 00:23:19 +0200
commitc6716e030c02f316b887c1d3ee4b443aa3ab6afd (patch)
tree470461fe2d29662e7a69834ed21fce30beed65ab /vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable
parent4ab72acec656dafd304f88359b509b1f27c06604 (diff)
downloadmatterbridge-msglm-c6716e030c02f316b887c1d3ee4b443aa3ab6afd.tar.gz
matterbridge-msglm-c6716e030c02f316b887c1d3ee4b443aa3ab6afd.tar.bz2
matterbridge-msglm-c6716e030c02f316b887c1d3ee4b443aa3ab6afd.zip
Update dependencies (#1784)
Diffstat (limited to 'vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable')
-rw-r--r--vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/meta.go70
-rw-r--r--vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/resolvable.go453
2 files changed, 523 insertions, 0 deletions
diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/meta.go b/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/meta.go
new file mode 100644
index 00000000..02d5e262
--- /dev/null
+++ b/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/meta.go
@@ -0,0 +1,70 @@
+package resolvable
+
+import (
+ "reflect"
+
+ "github.com/graph-gophers/graphql-go/introspection"
+ "github.com/graph-gophers/graphql-go/types"
+)
+
+// Meta defines the details of the metadata schema for introspection.
+type Meta struct {
+ FieldSchema Field
+ FieldType Field
+ FieldTypename Field
+ Schema *Object
+ Type *Object
+}
+
+func newMeta(s *types.Schema) *Meta {
+ var err error
+ b := newBuilder(s)
+
+ metaSchema := s.Types["__Schema"].(*types.ObjectTypeDefinition)
+ so, err := b.makeObjectExec(metaSchema.Name, metaSchema.Fields, nil, false, reflect.TypeOf(&introspection.Schema{}))
+ if err != nil {
+ panic(err)
+ }
+
+ metaType := s.Types["__Type"].(*types.ObjectTypeDefinition)
+ t, err := b.makeObjectExec(metaType.Name, metaType.Fields, nil, false, reflect.TypeOf(&introspection.Type{}))
+ if err != nil {
+ panic(err)
+ }
+
+ if err := b.finish(); err != nil {
+ panic(err)
+ }
+
+ fieldTypename := Field{
+ FieldDefinition: types.FieldDefinition{
+ Name: "__typename",
+ Type: &types.NonNull{OfType: s.Types["String"]},
+ },
+ TraceLabel: "GraphQL field: __typename",
+ }
+
+ fieldSchema := Field{
+ FieldDefinition: types.FieldDefinition{
+ Name: "__schema",
+ Type: s.Types["__Schema"],
+ },
+ TraceLabel: "GraphQL field: __schema",
+ }
+
+ fieldType := Field{
+ FieldDefinition: types.FieldDefinition{
+ Name: "__type",
+ Type: s.Types["__Type"],
+ },
+ TraceLabel: "GraphQL field: __type",
+ }
+
+ return &Meta{
+ FieldSchema: fieldSchema,
+ FieldTypename: fieldTypename,
+ FieldType: fieldType,
+ Schema: so,
+ Type: t,
+ }
+}
diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/resolvable.go b/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/resolvable.go
new file mode 100644
index 00000000..3410f557
--- /dev/null
+++ b/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/resolvable.go
@@ -0,0 +1,453 @@
+package resolvable
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/graph-gophers/graphql-go/decode"
+ "github.com/graph-gophers/graphql-go/internal/exec/packer"
+ "github.com/graph-gophers/graphql-go/types"
+)
+
+type Schema struct {
+ *Meta
+ types.Schema
+ Query Resolvable
+ Mutation Resolvable
+ Subscription Resolvable
+ Resolver reflect.Value
+}
+
+type Resolvable interface {
+ isResolvable()
+}
+
+type Object struct {
+ Name string
+ Fields map[string]*Field
+ TypeAssertions map[string]*TypeAssertion
+}
+
+type Field struct {
+ types.FieldDefinition
+ TypeName string
+ MethodIndex int
+ FieldIndex []int
+ HasContext bool
+ HasError bool
+ ArgsPacker *packer.StructPacker
+ ValueExec Resolvable
+ TraceLabel string
+}
+
+func (f *Field) UseMethodResolver() bool {
+ return len(f.FieldIndex) == 0
+}
+
+type TypeAssertion struct {
+ MethodIndex int
+ TypeExec Resolvable
+}
+
+type List struct {
+ Elem Resolvable
+}
+
+type Scalar struct{}
+
+func (*Object) isResolvable() {}
+func (*List) isResolvable() {}
+func (*Scalar) isResolvable() {}
+
+func ApplyResolver(s *types.Schema, resolver interface{}) (*Schema, error) {
+ if resolver == nil {
+ return &Schema{Meta: newMeta(s), Schema: *s}, nil
+ }
+
+ b := newBuilder(s)
+
+ var query, mutation, subscription Resolvable
+
+ if t, ok := s.EntryPoints["query"]; ok {
+ if err := b.assignExec(&query, t, reflect.TypeOf(resolver)); err != nil {
+ return nil, err
+ }
+ }
+
+ if t, ok := s.EntryPoints["mutation"]; ok {
+ if err := b.assignExec(&mutation, t, reflect.TypeOf(resolver)); err != nil {
+ return nil, err
+ }
+ }
+
+ if t, ok := s.EntryPoints["subscription"]; ok {
+ if err := b.assignExec(&subscription, t, reflect.TypeOf(resolver)); err != nil {
+ return nil, err
+ }
+ }
+
+ if err := b.finish(); err != nil {
+ return nil, err
+ }
+
+ return &Schema{
+ Meta: newMeta(s),
+ Schema: *s,
+ Resolver: reflect.ValueOf(resolver),
+ Query: query,
+ Mutation: mutation,
+ Subscription: subscription,
+ }, nil
+}
+
+type execBuilder struct {
+ schema *types.Schema
+ resMap map[typePair]*resMapEntry
+ packerBuilder *packer.Builder
+}
+
+type typePair struct {
+ graphQLType types.Type
+ resolverType reflect.Type
+}
+
+type resMapEntry struct {
+ exec Resolvable
+ targets []*Resolvable
+}
+
+func newBuilder(s *types.Schema) *execBuilder {
+ return &execBuilder{
+ schema: s,
+ resMap: make(map[typePair]*resMapEntry),
+ packerBuilder: packer.NewBuilder(),
+ }
+}
+
+func (b *execBuilder) finish() error {
+ for _, entry := range b.resMap {
+ for _, target := range entry.targets {
+ *target = entry.exec
+ }
+ }
+
+ return b.packerBuilder.Finish()
+}
+
+func (b *execBuilder) assignExec(target *Resolvable, t types.Type, resolverType reflect.Type) error {
+ k := typePair{t, resolverType}
+ ref, ok := b.resMap[k]
+ if !ok {
+ ref = &resMapEntry{}
+ b.resMap[k] = ref
+ var err error
+ ref.exec, err = b.makeExec(t, resolverType)
+ if err != nil {
+ return err
+ }
+ }
+ ref.targets = append(ref.targets, target)
+ return nil
+}
+
+func (b *execBuilder) makeExec(t types.Type, resolverType reflect.Type) (Resolvable, error) {
+ var nonNull bool
+ t, nonNull = unwrapNonNull(t)
+
+ switch t := t.(type) {
+ case *types.ObjectTypeDefinition:
+ return b.makeObjectExec(t.Name, t.Fields, nil, nonNull, resolverType)
+
+ case *types.InterfaceTypeDefinition:
+ return b.makeObjectExec(t.Name, t.Fields, t.PossibleTypes, nonNull, resolverType)
+
+ case *types.Union:
+ return b.makeObjectExec(t.Name, nil, t.UnionMemberTypes, nonNull, resolverType)
+ }
+
+ if !nonNull {
+ if resolverType.Kind() != reflect.Ptr {
+ return nil, fmt.Errorf("%s is not a pointer", resolverType)
+ }
+ resolverType = resolverType.Elem()
+ }
+
+ switch t := t.(type) {
+ case *types.ScalarTypeDefinition:
+ return makeScalarExec(t, resolverType)
+
+ case *types.EnumTypeDefinition:
+ return &Scalar{}, nil
+
+ case *types.List:
+ if resolverType.Kind() != reflect.Slice {
+ return nil, fmt.Errorf("%s is not a slice", resolverType)
+ }
+ e := &List{}
+ if err := b.assignExec(&e.Elem, t.OfType, resolverType.Elem()); err != nil {
+ return nil, err
+ }
+ return e, nil
+
+ default:
+ panic("invalid type: " + t.String())
+ }
+}
+
+func makeScalarExec(t *types.ScalarTypeDefinition, resolverType reflect.Type) (Resolvable, error) {
+ implementsType := false
+ switch r := reflect.New(resolverType).Interface().(type) {
+ case *int32:
+ implementsType = t.Name == "Int"
+ case *float64:
+ implementsType = t.Name == "Float"
+ case *string:
+ implementsType = t.Name == "String"
+ case *bool:
+ implementsType = t.Name == "Boolean"
+ case decode.Unmarshaler:
+ implementsType = r.ImplementsGraphQLType(t.Name)
+ }
+
+ if !implementsType {
+ return nil, fmt.Errorf("can not use %s as %s", resolverType, t.Name)
+ }
+ return &Scalar{}, nil
+}
+
+func (b *execBuilder) makeObjectExec(typeName string, fields types.FieldsDefinition, possibleTypes []*types.ObjectTypeDefinition,
+ nonNull bool, resolverType reflect.Type) (*Object, error) {
+ if !nonNull {
+ if resolverType.Kind() != reflect.Ptr && resolverType.Kind() != reflect.Interface {
+ return nil, fmt.Errorf("%s is not a pointer or interface", resolverType)
+ }
+ }
+
+ methodHasReceiver := resolverType.Kind() != reflect.Interface
+
+ Fields := make(map[string]*Field)
+ rt := unwrapPtr(resolverType)
+ fieldsCount := fieldCount(rt, map[string]int{})
+ for _, f := range fields {
+ var fieldIndex []int
+ methodIndex := findMethod(resolverType, f.Name)
+ if b.schema.UseFieldResolvers && methodIndex == -1 {
+ if fieldsCount[strings.ToLower(stripUnderscore(f.Name))] > 1 {
+ return nil, fmt.Errorf("%s does not resolve %q: ambiguous field %q", resolverType, typeName, f.Name)
+ }
+ fieldIndex = findField(rt, f.Name, []int{})
+ }
+ if methodIndex == -1 && len(fieldIndex) == 0 {
+ hint := ""
+ if findMethod(reflect.PtrTo(resolverType), f.Name) != -1 {
+ hint = " (hint: the method exists on the pointer type)"
+ }
+ return nil, fmt.Errorf("%s does not resolve %q: missing method for field %q%s", resolverType, typeName, f.Name, hint)
+ }
+
+ var m reflect.Method
+ var sf reflect.StructField
+ if methodIndex != -1 {
+ m = resolverType.Method(methodIndex)
+ } else {
+ sf = rt.FieldByIndex(fieldIndex)
+ }
+ fe, err := b.makeFieldExec(typeName, f, m, sf, methodIndex, fieldIndex, methodHasReceiver)
+ if err != nil {
+ var resolverName string
+ if methodIndex != -1 {
+ resolverName = m.Name
+ } else {
+ resolverName = sf.Name
+ }
+ return nil, fmt.Errorf("%s\n\tused by (%s).%s", err, resolverType, resolverName)
+ }
+ Fields[f.Name] = fe
+ }
+
+ // Check type assertions when
+ // 1) using method resolvers
+ // 2) Or resolver is not an interface type
+ typeAssertions := make(map[string]*TypeAssertion)
+ if !b.schema.UseFieldResolvers || resolverType.Kind() != reflect.Interface {
+ for _, impl := range possibleTypes {
+ methodIndex := findMethod(resolverType, "To"+impl.Name)
+ if methodIndex == -1 {
+ return nil, fmt.Errorf("%s does not resolve %q: missing method %q to convert to %q", resolverType, typeName, "To"+impl.Name, impl.Name)
+ }
+ if resolverType.Method(methodIndex).Type.NumOut() != 2 {
+ return nil, fmt.Errorf("%s does not resolve %q: method %q should return a value and a bool indicating success", resolverType, typeName, "To"+impl.Name)
+ }
+ a := &TypeAssertion{
+ MethodIndex: methodIndex,
+ }
+ if err := b.assignExec(&a.TypeExec, impl, resolverType.Method(methodIndex).Type.Out(0)); err != nil {
+ return nil, err
+ }
+ typeAssertions[impl.Name] = a
+ }
+ }
+
+ return &Object{
+ Name: typeName,
+ Fields: Fields,
+ TypeAssertions: typeAssertions,
+ }, nil
+}
+
+var contextType = reflect.TypeOf((*context.Context)(nil)).Elem()
+var errorType = reflect.TypeOf((*error)(nil)).Elem()
+
+func (b *execBuilder) makeFieldExec(typeName string, f *types.FieldDefinition, m reflect.Method, sf reflect.StructField,
+ methodIndex int, fieldIndex []int, methodHasReceiver bool) (*Field, error) {
+
+ var argsPacker *packer.StructPacker
+ var hasError bool
+ var hasContext bool
+
+ // Validate resolver method only when there is one
+ if methodIndex != -1 {
+ in := make([]reflect.Type, m.Type.NumIn())
+ for i := range in {
+ in[i] = m.Type.In(i)
+ }
+ if methodHasReceiver {
+ in = in[1:] // first parameter is receiver
+ }
+
+ hasContext = len(in) > 0 && in[0] == contextType
+ if hasContext {
+ in = in[1:]
+ }
+
+ if len(f.Arguments) > 0 {
+ if len(in) == 0 {
+ return nil, fmt.Errorf("must have parameter for field arguments")
+ }
+ var err error
+ argsPacker, err = b.packerBuilder.MakeStructPacker(f.Arguments, in[0])
+ if err != nil {
+ return nil, err
+ }
+ in = in[1:]
+ }
+
+ if len(in) > 0 {
+ return nil, fmt.Errorf("too many parameters")
+ }
+
+ maxNumOfReturns := 2
+ if m.Type.NumOut() < maxNumOfReturns-1 {
+ return nil, fmt.Errorf("too few return values")
+ }
+
+ if m.Type.NumOut() > maxNumOfReturns {
+ return nil, fmt.Errorf("too many return values")
+ }
+
+ hasError = m.Type.NumOut() == maxNumOfReturns
+ if hasError {
+ if m.Type.Out(maxNumOfReturns-1) != errorType {
+ return nil, fmt.Errorf(`must have "error" as its last return value`)
+ }
+ }
+ }
+
+ fe := &Field{
+ FieldDefinition: *f,
+ TypeName: typeName,
+ MethodIndex: methodIndex,
+ FieldIndex: fieldIndex,
+ HasContext: hasContext,
+ ArgsPacker: argsPacker,
+ HasError: hasError,
+ TraceLabel: fmt.Sprintf("GraphQL field: %s.%s", typeName, f.Name),
+ }
+
+ var out reflect.Type
+ if methodIndex != -1 {
+ out = m.Type.Out(0)
+ sub, ok := b.schema.EntryPoints["subscription"]
+ if ok && typeName == sub.TypeName() && out.Kind() == reflect.Chan {
+ out = m.Type.Out(0).Elem()
+ }
+ } else {
+ out = sf.Type
+ }
+ if err := b.assignExec(&fe.ValueExec, f.Type, out); err != nil {
+ return nil, err
+ }
+
+ return fe, nil
+}
+
+func findMethod(t reflect.Type, name string) int {
+ for i := 0; i < t.NumMethod(); i++ {
+ if strings.EqualFold(stripUnderscore(name), stripUnderscore(t.Method(i).Name)) {
+ return i
+ }
+ }
+ return -1
+}
+
+func findField(t reflect.Type, name string, index []int) []int {
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+
+ if field.Type.Kind() == reflect.Struct && field.Anonymous {
+ newIndex := findField(field.Type, name, []int{i})
+ if len(newIndex) > 1 {
+ return append(index, newIndex...)
+ }
+ }
+
+ if strings.EqualFold(stripUnderscore(name), stripUnderscore(field.Name)) {
+ return append(index, i)
+ }
+ }
+
+ return index
+}
+
+// fieldCount helps resolve ambiguity when more than one embedded struct contains fields with the same name.
+func fieldCount(t reflect.Type, count map[string]int) map[string]int {
+ if t.Kind() != reflect.Struct {
+ return nil
+ }
+
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+ fieldName := strings.ToLower(stripUnderscore(field.Name))
+
+ if field.Type.Kind() == reflect.Struct && field.Anonymous {
+ count = fieldCount(field.Type, count)
+ } else {
+ if _, ok := count[fieldName]; !ok {
+ count[fieldName] = 0
+ }
+ count[fieldName]++
+ }
+ }
+
+ return count
+}
+
+func unwrapNonNull(t types.Type) (types.Type, bool) {
+ if nn, ok := t.(*types.NonNull); ok {
+ return nn.OfType, true
+ }
+ return t, false
+}
+
+func stripUnderscore(s string) string {
+ return strings.Replace(s, "_", "", -1)
+}
+
+func unwrapPtr(t reflect.Type) reflect.Type {
+ if t.Kind() == reflect.Ptr {
+ return t.Elem()
+ }
+ return t
+}