Skip to content

Commit

Permalink
feat: add named type info to field and usage info (#649)
Browse files Browse the repository at this point in the history
  • Loading branch information
StarpTech authored Oct 30, 2023
1 parent 46f4fe2 commit ddb7fff
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
Info: &resolve.FieldInfo{
Name: "user",
ParentTypeNames: []string{"Query"},
NamedType: "User",
Source: resolve.TypeFieldSource{
IDs: []string{"user.service"},
},
Expand All @@ -531,6 +532,7 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
Name: []byte("account"),
Info: &resolve.FieldInfo{
Name: "account",
NamedType: "Account",
ParentTypeNames: []string{"User"},
Source: resolve.TypeFieldSource{
IDs: []string{"user.service"},
Expand All @@ -544,6 +546,7 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
Name: []byte("name"),
Info: &resolve.FieldInfo{
Name: "name",
NamedType: "String",
ParentTypeNames: []string{"Account"},
Source: resolve.TypeFieldSource{
IDs: []string{"account.service"},
Expand All @@ -557,6 +560,7 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
Name: []byte("shippingInfo"),
Info: &resolve.FieldInfo{
Name: "shippingInfo",
NamedType: "ShippingInfo",
ParentTypeNames: []string{"Account"},
Source: resolve.TypeFieldSource{
IDs: []string{"account.service"},
Expand All @@ -570,6 +574,7 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
Name: []byte("zip"),
Info: &resolve.FieldInfo{
Name: "zip",
NamedType: "String",
ParentTypeNames: []string{"ShippingInfo"},
Source: resolve.TypeFieldSource{
IDs: []string{"account.service"},
Expand Down
2 changes: 2 additions & 0 deletions v2/pkg/engine/plan/schemausageinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type SchemaUsageInfo struct {

type TypeFieldUsageInfo struct {
FieldName string
NamedType string
TypeNames []string
Path []string
Source TypeFieldSource
Expand Down Expand Up @@ -54,6 +55,7 @@ func (p *planVisitor) visitNode(node resolve.Node, path []string) {
p.usage.TypeFields = append(p.usage.TypeFields, TypeFieldUsageInfo{
FieldName: field.Info.Name,
TypeNames: field.Info.ParentTypeNames,
NamedType: field.Info.NamedType,
Path: newPath,
Source: TypeFieldSource{
IDs: field.Info.Source.IDs,
Expand Down
40 changes: 29 additions & 11 deletions v2/pkg/engine/plan/schemausageinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestGetSchemaUsageInfo(t *testing.T) {
Name: []byte("searchResults"),
Info: &resolve.FieldInfo{
Name: "searchResults",
NamedType: "SearchResults",
ParentTypeNames: []string{"Query"},
Source: source,
},
Expand All @@ -41,6 +42,7 @@ func TestGetSchemaUsageInfo(t *testing.T) {
},
Info: &resolve.FieldInfo{
Name: "__typename",
NamedType: "String",
ParentTypeNames: []string{"Human", "Droid"},
Source: source,
},
Expand All @@ -54,6 +56,7 @@ func TestGetSchemaUsageInfo(t *testing.T) {
OnTypeNames: [][]byte{[]byte("Human"), []byte("Droid")},
Info: &resolve.FieldInfo{
Name: "name",
NamedType: "String",
ParentTypeNames: []string{"Human", "Droid"},
Source: source,
},
Expand All @@ -67,6 +70,7 @@ func TestGetSchemaUsageInfo(t *testing.T) {
OnTypeNames: [][]byte{[]byte("Starship")},
Info: &resolve.FieldInfo{
Name: "length",
NamedType: "String",
ParentTypeNames: []string{"Starship"},
Source: source,
},
Expand All @@ -75,7 +79,8 @@ func TestGetSchemaUsageInfo(t *testing.T) {
Name: []byte("user"),
Info: &resolve.FieldInfo{
Name: "user",
ParentTypeNames: []string{"searchResults"},
NamedType: "User",
ParentTypeNames: []string{"SearchResults"},
Source: source,
},
Value: &resolve.Object{
Expand All @@ -86,7 +91,8 @@ func TestGetSchemaUsageInfo(t *testing.T) {
Name: []byte("account"),
Info: &resolve.FieldInfo{
Name: "account",
ParentTypeNames: []string{"user"},
NamedType: "Account",
ParentTypeNames: []string{"User"},
Source: source,
},
Value: &resolve.Object{
Expand All @@ -97,7 +103,8 @@ func TestGetSchemaUsageInfo(t *testing.T) {
Name: []byte("name"),
Info: &resolve.FieldInfo{
Name: "name",
ParentTypeNames: []string{"account"},
NamedType: "String",
ParentTypeNames: []string{"Account"},
Source: source,
},
Value: &resolve.String{
Expand All @@ -108,18 +115,20 @@ func TestGetSchemaUsageInfo(t *testing.T) {
Name: []byte("shippingInfo"),
Info: &resolve.FieldInfo{
Name: "shippingInfo",
ParentTypeNames: []string{"account"},
NamedType: "ShippingInfo",
ParentTypeNames: []string{"Account"},
Source: source,
},
Value: &resolve.Object{
Path: []string{"shippingInfo"},
Path: []string{"ShippingInfo"},
Nullable: true,
Fields: []*resolve.Field{
{
Name: []byte("zip"),
Info: &resolve.FieldInfo{
Name: "zip",
ParentTypeNames: []string{"shippingInfo"},
NamedType: "String",
ParentTypeNames: []string{"ShippingInfo"},
Source: source,
},
Value: &resolve.String{
Expand Down Expand Up @@ -157,6 +166,7 @@ func TestGetSchemaUsageInfo(t *testing.T) {
FieldName: "searchResults",
TypeNames: []string{"Query"},
Path: []string{"searchResults"},
NamedType: "SearchResults",
Source: TypeFieldSource{
IDs: []string{"https://swapi.dev/api"},
},
Expand All @@ -165,6 +175,7 @@ func TestGetSchemaUsageInfo(t *testing.T) {
Path: []string{"searchResults", "__typename"},
TypeNames: []string{"Human", "Droid"},
FieldName: "__typename",
NamedType: "String",
Source: TypeFieldSource{
IDs: []string{"https://swapi.dev/api"},
},
Expand All @@ -173,53 +184,60 @@ func TestGetSchemaUsageInfo(t *testing.T) {
Path: []string{"searchResults", "name"},
TypeNames: []string{"Human", "Droid"},
FieldName: "name",
NamedType: "String",
Source: TypeFieldSource{
IDs: []string{"https://swapi.dev/api"},
},
},
{
Path: []string{"searchResults", "length"},
TypeNames: []string{"Starship"},
NamedType: "String",
FieldName: "length",
Source: TypeFieldSource{
IDs: []string{"https://swapi.dev/api"},
},
},
{
Path: []string{"searchResults", "user"},
TypeNames: []string{"searchResults"},
NamedType: "User",
TypeNames: []string{"SearchResults"},
FieldName: "user",
Source: TypeFieldSource{
IDs: []string{"https://swapi.dev/api"},
},
},
{
Path: []string{"searchResults", "user", "account"},
TypeNames: []string{"user"},
TypeNames: []string{"User"},
NamedType: "Account",
FieldName: "account",
Source: TypeFieldSource{
IDs: []string{"https://swapi.dev/api"},
},
},
{
Path: []string{"searchResults", "user", "account", "name"},
TypeNames: []string{"account"},
TypeNames: []string{"Account"},
NamedType: "String",
FieldName: "name",
Source: TypeFieldSource{
IDs: []string{"https://swapi.dev/api"},
},
},
{
Path: []string{"searchResults", "user", "account", "shippingInfo"},
TypeNames: []string{"account"},
NamedType: "ShippingInfo",
TypeNames: []string{"Account"},
FieldName: "shippingInfo",
Source: TypeFieldSource{
IDs: []string{"https://swapi.dev/api"},
},
},
{
Path: []string{"searchResults", "user", "account", "shippingInfo", "zip"},
TypeNames: []string{"shippingInfo"},
TypeNames: []string{"ShippingInfo"},
NamedType: "String",
FieldName: "zip",
Source: TypeFieldSource{
IDs: []string{"https://swapi.dev/api"},
Expand Down
38 changes: 25 additions & 13 deletions v2/pkg/engine/plan/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,15 @@ func (v *Visitor) EnterField(ref int) {

fieldName := v.Operation.FieldNameBytes(ref)
fieldAliasOrName := v.Operation.FieldAliasOrNameBytes(ref)

fieldDefinition, ok := v.Walker.FieldDefinition(ref)
if !ok {
return
}

path := v.resolveFieldPath(ref)
fieldDefinitionType := v.Definition.FieldDefinitionType(fieldDefinition)

if bytes.Equal(fieldName, literal.TYPENAME) {
v.currentField = &resolve.Field{
Name: fieldAliasOrName,
Expand All @@ -274,20 +283,12 @@ func (v *Visitor) EnterField(ref int) {
SkipVariableName: skipVariableName,
IncludeDirectiveDefined: include,
IncludeVariableName: includeVariableName,
Info: v.resolveFieldInfo(ref),
Info: v.resolveFieldInfo(ref, fieldDefinitionType),
}
*v.currentFields[len(v.currentFields)-1].fields = append(*v.currentFields[len(v.currentFields)-1].fields, v.currentField)
return
}

fieldDefinition, ok := v.Walker.FieldDefinition(ref)
if !ok {
return
}

path := v.resolveFieldPath(ref)
fieldDefinitionType := v.Definition.FieldDefinitionType(fieldDefinition)

v.currentField = &resolve.Field{
Name: fieldAliasOrName,
Value: v.resolveFieldValue(ref, fieldDefinitionType, true, path),
Expand All @@ -297,9 +298,9 @@ func (v *Visitor) EnterField(ref int) {
SkipVariableName: skipVariableName,
IncludeDirectiveDefined: include,
IncludeVariableName: includeVariableName,
Info: v.resolveFieldInfo(ref),
}

// to avoid running v.resolveOnTypeNames() again, we set the field info here
v.currentField.Info = v.resolveFieldInfo(ref, fieldDefinitionType)
*v.currentFields[len(v.currentFields)-1].fields = append(*v.currentFields[len(v.currentFields)-1].fields, v.currentField)

typeName := v.Walker.EnclosingTypeDefinition.NameString(v.Definition)
Expand All @@ -311,13 +312,22 @@ func (v *Visitor) EnterField(ref int) {
v.fieldConfigs[ref] = fieldConfig
}

func (v *Visitor) resolveFieldInfo(ref int) *resolve.FieldInfo {
func (v *Visitor) resolveFieldInfo(ref, typeRef int) *resolve.FieldInfo {
if !v.Config.IncludeInfo {
return nil
}
onTypeNames := v.resolveOnTypeNames()

onTypeNames := v.currentField.OnTypeNames
enclosingTypeName := v.Walker.EnclosingTypeDefinition.NameString(v.Definition)
fieldName := v.Operation.FieldNameString(ref)
underlyingType := v.Definition.ResolveUnderlyingType(typeRef)
typeName := v.Definition.ResolveTypeNameString(typeRef)

// if the value is not a named type, try to resolve the underlying type
if underlyingType != -1 {
typeName = v.Definition.ResolveTypeNameString(underlyingType)
}

parentTypeNames := []string{enclosingTypeName}
for i := range onTypeNames {
onTypeName := string(onTypeNames[i])
Expand All @@ -327,6 +337,7 @@ func (v *Visitor) resolveFieldInfo(ref int) *resolve.FieldInfo {
}
parentTypeNames = append(parentTypeNames, onTypeName)
}

sourceIDs := make([]string, 0, 1)
for i := range v.planners {
for j := range v.planners[i].paths {
Expand All @@ -337,6 +348,7 @@ func (v *Visitor) resolveFieldInfo(ref int) *resolve.FieldInfo {
}
return &resolve.FieldInfo{
Name: fieldName,
NamedType: typeName,
ParentTypeNames: parentTypeNames,
Source: resolve.TypeFieldSource{
IDs: sourceIDs,
Expand Down
9 changes: 7 additions & 2 deletions v2/pkg/engine/resolve/node_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,14 @@ type FieldInfo struct {
// E.g. for a root field, this will be Query, Mutation, Subscription.
// For a field on an object type, this will be the name of that object type.
// For a field on an interface type, this will be the name of that interface type and all of its possible implementations.
// For a field on a union type, this will be the name of that union type and all of its possible members.
ParentTypeNames []string
Source TypeFieldSource
// NamedType is the underlying node type of the field.
// E.g. for a field of type Hobby! this will be Hobby.
// For a field of type [Hobby] this will be Hobby.
// For a field of type [Hobby!]! this will be Hobby.
// For scalar fields, this will return string, int, float, boolean, ID.
NamedType string
Source TypeFieldSource
}

type TypeFieldSource struct {
Expand Down

0 comments on commit ddb7fff

Please sign in to comment.