...

Source file src/github.com/99designs/gqlgen/plugin/federation/entity.go

Documentation: github.com/99designs/gqlgen/plugin/federation

     1  package federation
     2  
     3  import (
     4  	"go/types"
     5  
     6  	"github.com/vektah/gqlparser/v2/ast"
     7  
     8  	"github.com/99designs/gqlgen/codegen/config"
     9  	"github.com/99designs/gqlgen/codegen/templates"
    10  	"github.com/99designs/gqlgen/plugin/federation/fieldset"
    11  )
    12  
    13  // Entity represents a federated type
    14  // that was declared in the GQL schema.
    15  type Entity struct {
    16  	Name      string // The same name as the type declaration
    17  	Def       *ast.Definition
    18  	Resolvers []*EntityResolver
    19  	Requires  []*Requires
    20  	Multi     bool
    21  	Type      types.Type
    22  }
    23  
    24  type EntityResolver struct {
    25  	ResolverName  string      // The resolver name, such as FindUserByID
    26  	KeyFields     []*KeyField // The fields declared in @key.
    27  	InputType     types.Type  // The Go generated input type for multi entity resolvers
    28  	InputTypeName string
    29  }
    30  
    31  func (e *EntityResolver) LookupInputType() string {
    32  	return templates.CurrentImports.LookupType(e.InputType)
    33  }
    34  
    35  type KeyField struct {
    36  	Definition *ast.FieldDefinition
    37  	Field      fieldset.Field        // len > 1 for nested fields
    38  	Type       *config.TypeReference // The Go representation of that field type
    39  }
    40  
    41  // Requires represents an @requires clause
    42  type Requires struct {
    43  	Name  string                // the name of the field
    44  	Field fieldset.Field        // source Field, len > 1 for nested fields
    45  	Type  *config.TypeReference // The Go representation of that field type
    46  }
    47  
    48  func (e *Entity) allFieldsAreExternal(federationVersion int) bool {
    49  	for _, field := range e.Def.Fields {
    50  		if !e.isFieldImplicitlyExternal(field, federationVersion) && field.Directives.ForName("external") == nil {
    51  			return false
    52  		}
    53  	}
    54  	return true
    55  }
    56  
    57  // In federation v2, key fields are implicitly external.
    58  func (e *Entity) isFieldImplicitlyExternal(field *ast.FieldDefinition, federationVersion int) bool {
    59  	// Key fields are only implicitly external in Federation 2
    60  	if federationVersion != 2 {
    61  		return false
    62  	}
    63  	// TODO: From the spec, it seems like if an entity is not resolvable then it should not only not have a resolver, but should not appear in the _Entitiy union.
    64  	// The current implementation is a less drastic departure from the previous behavior, but should probably be reviewed.
    65  	// See https://www.apollographql.com/docs/federation/subgraph-spec/
    66  	if e.isResolvable() {
    67  		return false
    68  	}
    69  	// If the field is a key field, it is implicitly external
    70  	if e.isKeyField(field) {
    71  		return true
    72  	}
    73  
    74  	return false
    75  }
    76  
    77  // Determine if the entity is resolvable.
    78  func (e *Entity) isResolvable() bool {
    79  	key := e.Def.Directives.ForName("key")
    80  	if key == nil {
    81  		// If there is no key directive, the entity is resolvable.
    82  		return true
    83  	}
    84  	resolvable := key.Arguments.ForName("resolvable")
    85  	if resolvable == nil {
    86  		// If there is no resolvable argument, the entity is resolvable.
    87  		return true
    88  	}
    89  	// only if resolvable: false has been set on the @key directive do we consider the entity non-resolvable.
    90  	return resolvable.Value.Raw != "false"
    91  }
    92  
    93  // Determine if a field is part of the entities key.
    94  func (e *Entity) isKeyField(field *ast.FieldDefinition) bool {
    95  	for _, keyField := range e.keyFields() {
    96  		if keyField == field.Name {
    97  			return true
    98  		}
    99  	}
   100  	return false
   101  }
   102  
   103  // Get the key fields for this entity.
   104  func (e *Entity) keyFields() []string {
   105  	key := e.Def.Directives.ForName("key")
   106  	if key == nil {
   107  		return []string{}
   108  	}
   109  	fields := key.Arguments.ForName("fields")
   110  	if fields == nil {
   111  		return []string{}
   112  	}
   113  	fieldSet := fieldset.New(fields.Value.Raw, nil)
   114  	keyFields := make([]string, len(fieldSet))
   115  	for i, field := range fieldSet {
   116  		keyFields[i] = field[0]
   117  	}
   118  	return keyFields
   119  }
   120  
   121  // GetTypeInfo - get the imported package & type name combo.  package.TypeName
   122  func (e Entity) GetTypeInfo() string {
   123  	return templates.CurrentImports.LookupType(e.Type)
   124  }
   125  

View as plain text