Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 55 additions & 7 deletions v2/pkg/engine/datasource/grpc_datasource/execution_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ type RPCMessage struct {
Name string
// Fields is a list of fields in the message
Fields RPCFields
// FieldSelectionSet are field selections based on inline fragments
FieldSelectionSet RPCFieldSelectionSet
// FragmentFields are field selections based on inline fragments
FragmentFields RPCFieldSelectionSet
// OneOfType indicates the type of the oneof field
OneOfType OneOfType
// MemberTypes provides the names of the types that are implemented by the Interface or Union
Expand Down Expand Up @@ -275,6 +275,15 @@ func (r RPCFields) Exists(name, alias string) bool {
return false
}

// Last returns the last element of r or nil if r has no elements.
func (r RPCFields) Last() *RPCField {
if len(r) == 0 {
return nil
}

return &r[len(r)-1]
}

func (r *RPCExecutionPlan) String() string {
var result strings.Builder

Expand Down Expand Up @@ -453,6 +462,45 @@ func (r *rpcPlanningContext) resolveRPCMethodMapping(operationType ast.Operation
return rpcConfig, nil
}

// enterNestedField handles descending into a nested response message
// when entering a selection set. inlineFragmentRef identifies the inline fragment
// that directly contains the field being descended into (ast.InvalidRef if none).
// Returns true if it descended into a nested message, false if there was nothing
// to descend into.
func (r *rpcPlanningContext) enterNestedField(info *planningInfo, enclosingTypeNode ast.Node, selectionSetRef, inlineFragmentRef int) bool {
lastField := r.lastResponseField(info.currentResponseMessage, inlineFragmentRef)
if lastField == nil {
return false
}

if lastField.Message == nil {
lastField.Message = r.newMessageFromSelectionSet(enclosingTypeNode, selectionSetRef)
}

info.responseMessageAncestors = append(info.responseMessageAncestors, info.currentResponseMessage)
info.currentResponseMessage = lastField.Message
return true
}

// lastResponseField returns a pointer to the last field (or fragment field) of the message,
// or nil if there are no fields.
func (r *rpcPlanningContext) lastResponseField(msg *RPCMessage, inlineFragmentRef int) *RPCField {
Comment thread
dkorittki marked this conversation as resolved.
if inlineFragmentRef == ast.InvalidRef {
return msg.Fields.Last()
}

inlineFragmentName := r.operation.InlineFragmentTypeConditionNameString(inlineFragmentRef)
return msg.FragmentFields[inlineFragmentName].Last()
}

// leaveNestedField pops the response message ancestors when leaving a selection set.
func (r *rpcPlanningContext) leaveNestedField(info *planningInfo) {
if len(info.responseMessageAncestors) > 0 {
info.currentResponseMessage = info.responseMessageAncestors[len(info.responseMessageAncestors)-1]
info.responseMessageAncestors = info.responseMessageAncestors[:len(info.responseMessageAncestors)-1]
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// newMessageFromSelectionSet creates a new message from the enclosing type node and the selection set reference.
func (r *rpcPlanningContext) newMessageFromSelectionSet(enclosingTypeNode ast.Node, selectSetRef int) *RPCMessage {
message := &RPCMessage{
Expand Down Expand Up @@ -769,11 +817,11 @@ func (r *rpcPlanningContext) buildFieldMessage(fieldTypeNode ast.Node, fieldRef
return nil, err
}

if message.FieldSelectionSet == nil {
message.FieldSelectionSet = make(RPCFieldSelectionSet)
if message.FragmentFields == nil {
message.FragmentFields = make(RPCFieldSelectionSet)
}

message.FieldSelectionSet.Add(typeName, fields...)
message.FragmentFields.Add(typeName, fields...)
}

for _, fieldRef := range fieldRefs {
Expand Down Expand Up @@ -1081,7 +1129,7 @@ func (r *rpcPlanningContext) buildFieldResolverTypeMessage(typeName string, reso

// If the resolved field returns a composite type we need to handle the selection set for the inline fragment.
if len(resolverField.fragmentSelections) > 0 {
message.FieldSelectionSet = make(RPCFieldSelectionSet, len(resolverField.fragmentSelections))
message.FragmentFields = make(RPCFieldSelectionSet, len(resolverField.fragmentSelections))

for _, fragmentSelection := range resolverField.fragmentSelections {
inlineFragmentTypeNode, found := r.definition.NodeByNameStr(fragmentSelection.typeName)
Expand All @@ -1094,7 +1142,7 @@ func (r *rpcPlanningContext) buildFieldResolverTypeMessage(typeName string, reso
return nil, err
}

message.FieldSelectionSet[fragmentSelection.typeName] = fields
message.FragmentFields[fragmentSelection.typeName] = fields
}
}

Expand Down
Loading