agent_patch
runs/2026-02-28__13-38-10__gpt-5-4/flux-pr-1230/flux-pr-1230.1-of-1.2026-02-28__13-38-10__gpt-5-4/agent-logs/agent.patch
23864 bytes
diff --git a/tmp/agent-patch-flux-pr-1230.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/astprinter/astprinter.go b/app/v2/pkg/astprinter/astprinter.go
index dad5337..36fc8f6 100644
--- a/tmp/agent-patch-flux-pr-1230.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/astprinter/astprinter.go
+++ b/app/v2/pkg/astprinter/astprinter.go
@@ -3,6 +3,7 @@ package astprinter
import (
"bytes"
+ "fmt"
"io"
"strconv"
@@ -95,7 +96,10 @@ func (p *Printer) Print(document *ast.Document, out io.Writer) error {
if !p.registered {
p.walker.SetVisitor(&p.visitor)
}
- return p.walker.Walk(p.visitor.document, nil)
+ if err := p.walker.Walk(p.visitor.document, nil); err != nil {
+ return err
+ }
+ return p.visitor.err
}
type printVisitor struct {
@@ -313,6 +317,11 @@ func (p *printVisitor) LeaveOperationDefinition(ref int) {
}
func (p *printVisitor) EnterSelectionSet(ref int) {
+ if p.document.SelectionSetIsEmpty(ref) {
+ p.err = fmt.Errorf("astprinter: empty selection set at ref %d", ref)
+ return
+ }
+
if p.debug {
p.writeIndented(literal.LINETERMINATOR)
p.writeIndented([]byte("# SelectionSet ref:"))
diff --git a/tmp/agent-patch-flux-pr-1230.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/astprinter/astprinter_test.go b/app/v2/pkg/astprinter/astprinter_test.go
index 8dbd5d7..178ae38 100644
--- a/tmp/agent-patch-flux-pr-1230.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/astprinter/astprinter_test.go
+++ b/app/v2/pkg/astprinter/astprinter_test.go
@@ -726,6 +726,16 @@ func TestPrintOperationDefinition(t *testing.T) {
}
}
+func TestPrintRejectsEmptySelectionSet(t *testing.T) {
+ doc := unsafeparser.ParseGraphqlDocumentString(`query { user { id } }`)
+ doc.EmptySelectionSet(doc.OperationDefinitions[0].SelectionSet)
+
+ buff := bytes.Buffer{}
+ err := Print(&doc, &buff)
+ require.Error(t, err)
+ assert.EqualError(t, err, "astprinter: empty selection set at ref 1")
+}
+
func BenchmarkPrint(b *testing.B) {
must := func(err error) {
diff --git a/tmp/agent-patch-flux-pr-1230.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/datasource_filter_visitor.go b/app/v2/pkg/engine/plan/datasource_filter_visitor.go
index c0a9987..4f16fe4 100644
--- a/tmp/agent-patch-flux-pr-1230.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/datasource_filter_visitor.go
+++ b/app/v2/pkg/engine/plan/datasource_filter_visitor.go
@@ -217,10 +217,8 @@ const (
ReasonProvidesProvidedByPlanner = "@provides"
)
-// selectUniqueNodes - selects nodes (e.g. fields) which are unique to a single datasource
-// In addition we select:
-// - parent of such node if the node is a leaf and not nested under the fragment
-// - siblings nodes
+// selectUniqueNodes selects nodes (e.g. fields) which are unique to a single datasource.
+// In addition we select the parent chain of such nodes on the same datasource up to a root node.
func (f *DataSourceFilter) selectUniqueNodes() {
for i := range f.nodes.items {
@@ -236,26 +234,8 @@ func (f *DataSourceFilter) selectUniqueNodes() {
// unique nodes always have priority
f.nodes.items[i].selectWithReason(ReasonStage1Unique, f.enableSelectionReasons)
- if !f.nodes.items[i].onFragment { // on a first stage do not select parent of nodes on fragments
- // if node parents of the unique node is on the same source, prioritize it too
- f.selectUniqNodeParentsUpToRootNode(i)
- }
-
- // if node has leaf children on the same source, prioritize them too
- children := f.nodes.childNodesOnSameSource(i)
- for _, child := range children {
- if f.nodes.isLeaf(child) && f.nodes.isNodeUnique(child) {
- f.nodes.items[child].selectWithReason(ReasonStage1SameSourceLeafChild, f.enableSelectionReasons)
- }
- }
-
- // prioritize leaf siblings of the node on the same source
- siblings := f.nodes.siblingNodesOnSameSource(i)
- for _, sibling := range siblings {
- if f.nodes.isLeaf(sibling) && f.nodes.isNodeUnique(sibling) {
- f.nodes.items[sibling].selectWithReason(ReasonStage1SameSourceLeafSibling, f.enableSelectionReasons)
- }
- }
+ // if node parents of the unique node are on the same source, prioritize them too
+ f.selectUniqNodeParentsUpToRootNode(i)
}
}
@@ -529,36 +509,9 @@ func (f *DataSourceFilter) selectDuplicateNodes(secondPass bool) {
continue
}
- // 2. Lookup for the first parent root node with enabled entity resolver
- // when we haven't found a possible duplicate
- // we need to find parent node which is a root node and has enabled entity resolver, e.g. the point in the query from where we could jump
- // it is a parent entity jump case
+ // stages 2,3,4 - are stages when choices are equal, and we should select the simplest available node first
- if f.checkNodes(itemIDs,
- func(i int) bool {
- if f.nodes.items[i].IsExternal && !f.nodes.items[i].IsProvided {
- return false
- }
-
- parents := f.findPossibleParents(i)
- if len(parents) > 0 {
- if f.selectWithExternalCheck(i, ReasonStage3SelectNodeUnderFirstParentRootNode) {
- for _, parent := range parents {
- f.nodes.items[parent].selectWithReason(ReasonStage3SelectParentRootNodeWithEnabledEntityResolver, f.enableSelectionReasons)
- }
-
- return true
- }
- }
- return false
- },
- nil) {
- continue
- }
-
- // stages 3,4,5 - are stages when choices are equal, and we should select first available node
-
- // 3. we choose first available leaf node
+ // 2. we choose first available leaf node
if f.checkNodes(itemIDs,
func(i int) bool {
return f.selectWithExternalCheck(i, ReasonStage3SelectAvailableLeafNode)
@@ -582,7 +535,7 @@ func (f *DataSourceFilter) selectDuplicateNodes(secondPass bool) {
continue
}
- // 4. if node is not a leaf we select a node which could provide more selections on the same source
+ // 3. if node is not a leaf we select a node which could provide more selections on the same source
currentChildNodeCount := -1
currentItemIDx := -1
@@ -605,7 +558,7 @@ func (f *DataSourceFilter) selectDuplicateNodes(secondPass bool) {
continue
}
- // 5. We check here not leaf nodes which could provide keys to the child nodes
+ // 4. We check here not leaf nodes which could provide keys to the child nodes
// this rule one of the rules responsible for the shareable nodes
if f.checkNodes(itemIDs,
func(i int) bool {
@@ -630,6 +583,34 @@ func (f *DataSourceFilter) selectDuplicateNodes(secondPass bool) {
}) {
continue
}
+
+ // 5. Lookup for the first parent root node with enabled entity resolver
+ // when we haven't found a simpler duplicate, we can still resolve the field by
+ // selecting a parent root node with an enabled entity resolver and jumping from there.
+ if f.checkNodes(itemIDs,
+ func(i int) bool {
+ if f.nodes.items[i].IsExternal && !f.nodes.items[i].IsProvided {
+ return false
+ }
+
+ parents := f.findPossibleParents(i)
+ if len(parents) == 0 {
+ return false
+ }
+
+ if !f.selectWithExternalCheck(i, ReasonStage3SelectNodeUnderFirstParentRootNode) {
+ return false
+ }
+
+ for _, parent := range parents {
+ f.nodes.items[parent].selectWithReason(ReasonStage3SelectParentRootNodeWithEnabledEntityResolver, f.enableSelectionReasons)
+ }
+
+ return true
+ },
+ nil) {
+ continue
+ }
}
}
diff --git a/tmp/agent-patch-flux-pr-1230.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/datasource_filter_visitor_test.go b/app/v2/pkg/engine/plan/datasource_filter_visitor_test.go
index f4ef39f..824e3cf 100644
--- a/tmp/agent-patch-flux-pr-1230.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/datasource_filter_visitor_test.go
+++ b/app/v2/pkg/engine/plan/datasource_filter_visitor_test.go
@@ -8,6 +8,7 @@ import (
"github.com/kylelemons/godebug/pretty"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"github.com/wundergraph/graphql-go-tools/v2/pkg/astvalidation"
"github.com/wundergraph/graphql-go-tools/v2/pkg/internal/unsafeparser"
@@ -291,7 +292,7 @@ func TestFindBestDataSourceSet(t *testing.T) {
{TypeName: "Query", FieldName: "user", DataSourceHash: 11, Path: "query.user", ParentPath: "query", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "User", FieldName: "id", DataSourceHash: 11, Path: "query.user.id", ParentPath: "query.user", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage2: node on the same source as selected parent"}},
{TypeName: "User", FieldName: "name", DataSourceHash: 22, Path: "query.user.name", ParentPath: "query.user", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
- {TypeName: "User", FieldName: "surname", DataSourceHash: 22, Path: "query.user.surname", ParentPath: "query.user", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: same source leaf sibling of unique node"}},
+ {TypeName: "User", FieldName: "surname", DataSourceHash: 22, Path: "query.user.surname", ParentPath: "query.user", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
}),
},
{
@@ -560,8 +561,8 @@ func TestFindBestDataSourceSet(t *testing.T) {
{TypeName: "Lines", FieldName: "id", DataSourceHash: 22, Path: "query.user.details.address.lines.id", ParentPath: "query.user.details.address.lines", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage2: node on the same source as selected parent"}},
{TypeName: "Lines", FieldName: "line1", DataSourceHash: 44, Path: "query.user.details.address.lines.line1", ParentPath: "query.user.details.address.lines", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage2: node on the same source as selected sibling"}},
{TypeName: "Lines", FieldName: "line2", DataSourceHash: 44, Path: "query.user.details.address.lines.line2", ParentPath: "query.user.details.address.lines", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
- {TypeName: "Address", FieldName: "name", DataSourceHash: 22, Path: "query.user.details.address.name", ParentPath: "query.user.details.address", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: same source leaf child of unique node"}},
- {TypeName: "Details", FieldName: "age", DataSourceHash: 22, Path: "query.user.details.age", ParentPath: "query.user.details", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: same source leaf child of unique node"}},
+ {TypeName: "Address", FieldName: "name", DataSourceHash: 22, Path: "query.user.details.address.name", ParentPath: "query.user.details.address", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
+ {TypeName: "Details", FieldName: "age", DataSourceHash: 22, Path: "query.user.details.age", ParentPath: "query.user.details", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "User", FieldName: "name", DataSourceHash: 22, Path: "query.user.name", ParentPath: "query.user", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage2: node on the same source as selected parent"}},
}),
},
@@ -820,7 +821,7 @@ func TestFindBestDataSourceSet(t *testing.T) {
{TypeName: "Query", FieldName: "me", DataSourceHash: 11, Path: "query.me", ParentPath: "query", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "User", FieldName: "details", DataSourceHash: 33, Path: "query.me.details", ParentPath: "query.me", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: same source parent of unique node"}},
{TypeName: "Details", FieldName: "pets", DataSourceHash: 33, Path: "query.me.details.pets", ParentPath: "query.me.details", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
- {TypeName: "Pet", FieldName: "name", DataSourceHash: 33, Path: "query.me.details.pets.name", ParentPath: "query.me.details.pets", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: same source leaf child of unique node"}},
+ {TypeName: "Pet", FieldName: "name", DataSourceHash: 33, Path: "query.me.details.pets.name", ParentPath: "query.me.details.pets", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
}),
},
{
@@ -829,7 +830,7 @@ func TestFindBestDataSourceSet(t *testing.T) {
{TypeName: "Query", FieldName: "me", DataSourceHash: 11, Path: "query.me", ParentPath: "query", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "User", FieldName: "details", DataSourceHash: 33, Path: "query.me.details", ParentPath: "query.me", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: same source parent of unique node"}},
{TypeName: "Details", FieldName: "pets", DataSourceHash: 33, Path: "query.me.details.pets", ParentPath: "query.me.details", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
- {TypeName: "Pet", FieldName: "name", DataSourceHash: 33, Path: "query.me.details.pets.name", ParentPath: "query.me.details.pets", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: same source leaf child of unique node"}},
+ {TypeName: "Pet", FieldName: "name", DataSourceHash: 33, Path: "query.me.details.pets.name", ParentPath: "query.me.details.pets", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
}),
},
},
@@ -938,7 +939,7 @@ func TestFindBestDataSourceSet(t *testing.T) {
{TypeName: "NestedOne", FieldName: "uniqueOne", DataSourceHash: 11, Path: "query.user.nested.uniqueOne", ParentPath: "query.user.nested", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "NestedOne", FieldName: "uniqueTwo", DataSourceHash: 22, Path: "query.user.nested.uniqueTwo", ParentPath: "query.user.nested", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "User", FieldName: "object", DataSourceHash: 11, Path: "query.user.object", ParentPath: "query.user", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
- {TypeName: "Object", FieldName: "name", DataSourceHash: 11, Path: "query.user.object.name", ParentPath: "query.user.object", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: same source leaf child of unique node"}},
+ {TypeName: "Object", FieldName: "name", DataSourceHash: 11, Path: "query.user.object.name", ParentPath: "query.user.object", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
}),
},
{
@@ -956,7 +957,7 @@ func TestFindBestDataSourceSet(t *testing.T) {
{TypeName: "NestedOne", FieldName: "uniqueOne", DataSourceHash: 11, Path: "query.user.nested.uniqueOne", ParentPath: "query.user.nested", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "NestedOne", FieldName: "uniqueTwo", DataSourceHash: 22, Path: "query.user.nested.uniqueTwo", ParentPath: "query.user.nested", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "User", FieldName: "object", DataSourceHash: 11, Path: "query.user.object", ParentPath: "query.user", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
- {TypeName: "Object", FieldName: "name", DataSourceHash: 11, Path: "query.user.object.name", ParentPath: "query.user.object", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: same source leaf child of unique node"}},
+ {TypeName: "Object", FieldName: "name", DataSourceHash: 11, Path: "query.user.object.name", ParentPath: "query.user.object", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage1: unique"}},
}),
},
},
@@ -992,10 +993,10 @@ func TestFindBestDataSourceSet(t *testing.T) {
{TypeName: "PaginatedUser", FieldName: "edges", DataSourceHash: 11, Path: "query.users.edges", ParentPath: "query.users", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage2: node on the same source as selected parent"}},
{TypeName: "UserToEdge", FieldName: "node", DataSourceHash: 11, Path: "query.users.edges.node", ParentPath: "query.users.edges", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage2: node on the same source as selected parent"}},
{TypeName: "User", FieldName: "address", DataSourceHash: 22, Path: "query.users.edges.node.address", ParentPath: "query.users.edges.node", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
- {TypeName: "Address", FieldName: "street", DataSourceHash: 22, Path: "query.users.edges.node.address.street", ParentPath: "query.users.edges.node.address", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: same source leaf child of unique node"}},
+ {TypeName: "Address", FieldName: "street", DataSourceHash: 22, Path: "query.users.edges.node.address.street", ParentPath: "query.users.edges.node.address", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "User", FieldName: "firstName", DataSourceHash: 11, Path: "query.users.edges.node.firstName", ParentPath: "query.users.edges.node", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "User", FieldName: "id", DataSourceHash: 11, Path: "query.users.edges.node.id", ParentPath: "query.users.edges.node", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage2: node on the same source as selected parent"}},
- {TypeName: "User", FieldName: "lastName", DataSourceHash: 11, Path: "query.users.edges.node.lastName", ParentPath: "query.users.edges.node", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: same source leaf sibling of unique node"}},
+ {TypeName: "User", FieldName: "lastName", DataSourceHash: 11, Path: "query.users.edges.node.lastName", ParentPath: "query.users.edges.node", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
}),
},
{
@@ -1005,10 +1006,10 @@ func TestFindBestDataSourceSet(t *testing.T) {
{TypeName: "PaginatedUser", FieldName: "edges", DataSourceHash: 11, Path: "query.users.edges", ParentPath: "query.users", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage2: node on the same source as selected parent"}},
{TypeName: "UserToEdge", FieldName: "node", DataSourceHash: 11, Path: "query.users.edges.node", ParentPath: "query.users.edges", IsRootNode: false, Selected: true, SelectionReasons: []string{"stage2: node on the same source as selected parent"}},
{TypeName: "User", FieldName: "address", DataSourceHash: 22, Path: "query.users.edges.node.address", ParentPath: "query.users.edges.node", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
- {TypeName: "Address", FieldName: "street", DataSourceHash: 22, Path: "query.users.edges.node.address.street", ParentPath: "query.users.edges.node.address", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: same source leaf child of unique node"}},
+ {TypeName: "Address", FieldName: "street", DataSourceHash: 22, Path: "query.users.edges.node.address.street", ParentPath: "query.users.edges.node.address", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "User", FieldName: "firstName", DataSourceHash: 11, Path: "query.users.edges.node.firstName", ParentPath: "query.users.edges.node", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
{TypeName: "User", FieldName: "id", DataSourceHash: 11, Path: "query.users.edges.node.id", ParentPath: "query.users.edges.node", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage2: node on the same source as selected parent"}},
- {TypeName: "User", FieldName: "lastName", DataSourceHash: 11, Path: "query.users.edges.node.lastName", ParentPath: "query.users.edges.node", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: same source leaf sibling of unique node"}},
+ {TypeName: "User", FieldName: "lastName", DataSourceHash: 11, Path: "query.users.edges.node.lastName", ParentPath: "query.users.edges.node", IsRootNode: true, Selected: true, SelectionReasons: []string{"stage1: unique"}},
}),
},
},
@@ -1097,6 +1098,134 @@ func TestFindBestDataSourceSet(t *testing.T) {
}
}
+func TestSelectUniqueNodeOnFragmentSelectsParentChain(t *testing.T) {
+ definition := `
+ type Query {
+ provider: AccountProvider!
+ }
+
+ union Account = User
+
+ type AccountProvider {
+ accounts: [Account!]!
+ }
+
+ type User {
+ id: ID!
+ details: Details!
+ }
+
+ type Details {
+ name: String!
+ }
+ `
+
+ query := `
+ query {
+ provider {
+ accounts {
+ ... on User {
+ details {
+ name
+ }
+ }
+ }
+ }
+ }
+ `
+
+ dataSources := []DataSource{
+ dsb().Hash(11).Schema(`
+ type Query {
+ provider: AccountProvider!
+ }
+
+ union Account = User
+
+ type AccountProvider {
+ accounts: [Account!]!
+ }
+
+ type User @key(fields: "id") {
+ id: ID!
+ details: Details!
+ }
+
+ type Details {
+ id: ID!
+ }
+ `).RootNode("Query", "provider").
+ ChildNode("AccountProvider", "accounts").
+ RootNode("User", "id", "details").
+ ChildNode("Details", "id").
+ DS(),
+ dsb().Hash(22).Schema(`
+ union Account = User
+
+ type AccountProvider {
+ accounts: [Account!]!
+ }
+
+ type User @key(fields: "id") {
+ id: ID!
+ details: Details!
+ }
+
+ type Details {
+ name: String!
+ }
+ `).ChildNode("AccountProvider", "accounts").
+ RootNode("User", "id", "details").
+ ChildNode("Details", "name").
+ DS(),
+ }
+
+ selected := collectSelectedSuggestionsForTest(t, definition, query, dataSources)
+
+ byPath := make(map[string]*NodeSuggestion, len(selected))
+ for _, item := range selected {
+ byPath[item.Path] = item
+ }
+
+ assert.Equal(t, DSHash(22), byPath["query.provider.accounts.$0User.details.name"].DataSourceHash)
+ assert.Equal(t, []string{"stage1: unique"}, byPath["query.provider.accounts.$0User.details.name"].SelectionReasons)
+ assert.Equal(t, DSHash(22), byPath["query.provider.accounts.$0User.details"].DataSourceHash)
+ assert.Equal(t, []string{"stage1: same source parent of unique node"}, byPath["query.provider.accounts.$0User.details"].SelectionReasons)
+}
+
+func collectSelectedSuggestionsForTest(t *testing.T, definition, query string, dataSources []DataSource) []*NodeSuggestion {
+ t.Helper()
+
+ def := unsafeparser.ParseGraphqlDocumentStringWithBaseSchema(definition)
+ operation := unsafeparser.ParseGraphqlDocumentString(query)
+ report := operationreport.Report{}
+
+ astvalidation.DefaultOperationValidator().Validate(&operation, &def, &report)
+ require.False(t, report.HasErrors(), report.Error())
+
+ dsFilter := NewDataSourceFilter(&operation, &def, &report)
+ require.False(t, report.HasErrors(), report.Error())
+
+ dsFilter.EnableSelectionReasons()
+ dsFilter.dataSources = dataSources
+
+ planned, _ := dsFilter.findBestDataSourceSet(nil, nil)
+ require.False(t, report.HasErrors(), report.Error())
+
+ selected := make([]*NodeSuggestion, 0, len(planned.items))
+ for _, item := range planned.items {
+ if item.Selected {
+ selected = append(selected, item)
+ }
+ }
+
+ slices.SortFunc(selected, func(a, b *NodeSuggestion) int {
+ return strings.Compare(a.Path, b.Path)
+ })
+
+ return selected
+}
+
const shareableDefinition = `
type User {
id: ID!