Skip to content

fix: improve query planning time#1326

Merged
devsergiy merged 25 commits intomasterfrom
sergiy/eng-8285-improve-query-planning-time
Oct 29, 2025
Merged

fix: improve query planning time#1326
devsergiy merged 25 commits intomasterfrom
sergiy/eng-8285-improve-query-planning-time

Conversation

@devsergiy
Copy link
Copy Markdown
Member

@devsergiy devsergiy commented Oct 20, 2025

Summary by CodeRabbit

  • Performance Improvements

    • Interface implementations are now precomputed after parsing to reduce redundant work.
    • Per-data-source collection and BFS traversal improve plan building and make resolution paths explicit.
  • Bug Fixes & Improvements

    • Improved error propagation during key collection and per-source filtering.
    • Better tracking of newly discovered fields to ensure consistent planning and revisit handling.
    • Walkers now carry identifiers to aid debugging/tracing (no behavior change).
  • Tests

    • Test fixtures updated to use explicit resolution paths and reflect API adjustments.

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 20, 2025

Walkthrough

Adds interface→object caching and a parser precalc step; introduces walker IDs via NewWalkerWithID and updates callers; refactors datasource node collection into per-data-source visitors with a nodesCollector and newFieldRefs propagation; multiple visitors, builders, and tests updated to the new APIs and flows.

Changes

Cohort / File(s) Summary
Interface implementation caching
v2/pkg/ast/ast_interface_type_definition.go, v2/pkg/astparser/parser.go
Added ImplementedByObjectDefinitions []int on InterfaceTypeDefinition, Document.PopulateInterfaceTypeDefinitionImplementedByObjects(), and a parser precalculate() step invoked after successful parse to populate interface→object refs.
Walker struct & constructors
v2/pkg/astvisitor/visitor.go
Added walkerID string to Walker; new constructors NewWalkerWithID(ancestorSize int, id string) and NewDefaultWalkerWithID(id string); NewWalker internals adjusted (Path capacity) and pprof-label comment added.
Propagate walker IDs across visitors
v2/pkg/astnormalization/..., v2/pkg/astvalidation/..., v2/pkg/asttransform/..., v2/pkg/variablesvalidation/..., v2/pkg/engine/plan/...
Replaced many NewWalker(...) / NewDefaultWalker() calls with NewWalkerWithID(..., "<Name>") or NewDefaultWalkerWithID("<Name>") across normalization, validation, transform, variables mapping, and multiple plan visitors.
Parser post-parse precalculation
v2/pkg/astparser/parser.go
Parse and ParseWithLimits now call precalculate() after parse; precalculate() guards on parse errors and calls the document population for implemented-by refs.
Datasource collection → per-DS visitors
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go, v2/pkg/engine/plan/datasource_filter_node_suggestions.go
Refactored node collection into per-data-source visitors (collectNodesDSVisitor) with per-DS reports and parallelized visits; added TreeNodeFieldRef, nodeVisitTask, and BFS traversal helper; propagated fieldInfo.enclosingTypeDefinition; changed collection semantics and reporting shapes.
Datasource filter API & state
v2/pkg/engine/plan/datasource_filter_visitor.go, v2/pkg/engine/plan/datasource_filter_visitor_test.go
DataSourceFilter now holds dataSources []DataSource, newFieldRefs map[int]struct{}, and nodesCollector *nodesCollector; NewDataSourceFilter signature extended to accept dataSources and newFieldRefs; FilterDataSources, findBestDataSourceSet, and collectNodes signatures changed to use internal state; tests updated.
Key fields visitor changes
v2/pkg/engine/plan/key_fields_visitor.go, v2/pkg/engine/plan/key_fields_visitor_test.go
Renamed collectNodesVisitorcollectNodesDSVisitor; collectKeysForPath now returns error and callers/tests updated to assert no error; walker created with NewWalkerWithID.
Node selection & newFieldRefs tracking
v2/pkg/engine/plan/node_selection_builder.go, v2/pkg/engine/plan/node_selection_visitor.go
Added newFieldRefs map[int]struct{} tracking in node selection visitor; propagate newFieldRefs into NewDataSourceFilter; added helpers to accumulate skip/new refs and updated flows so newly discovered fields are tracked and may trigger reruns.
Plan visitor path resolution tweak
v2/pkg/engine/plan/visitor.go
EnterField now sets non-typename field path to single-element Operation.FieldAliasOrNameString(ref) instead of resolveFieldPath(ref) (alias-override logic disabled, TODO added).
BFS helper & minor plan helpers
v2/pkg/engine/plan/datasource_filter_node_suggestions.go, v2/pkg/engine/plan/...
Added TraverseBFS helper for tree traversal; other small helpers and fieldInfo propagation updates across plan components.
Tests and plan config comment
v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go, v2/pkg/engine/plan/configuration.go
Tests: removed some DisableDefaultMapping usage and added explicit Path entries in expected plan literals; added a comment on FieldConfiguration.DisableDefaultMapping.
Federation metadata entity tracking
v2/pkg/engine/plan/datasource_configuration.go, v2/pkg/engine/plan/federation_metadata.go
Added entityTypeNames map[string]struct{} to FederationMetaData; InitKeys populates it and HasEntity now checks the map directly.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(200,230,255,0.35)
    participant Parser
    participant P as parser.precalculate
    participant Doc as Document
    participant IF as InterfaceTypeDefinition
    end

    Parser->>P: after Parse()/ParseWithLimits
    alt no parse errors
        P->>Doc: PopulateInterfaceTypeDefinitionImplementedByObjects()
        Doc->>IF: set ImplementedByObjectDefinitions
    end
Loading
sequenceDiagram
    rect rgba(240,250,230,0.35)
    participant Builder as NodeSelectionBuilder
    participant Visitor as nodeSelectionVisitor
    participant Filter as DataSourceFilter
    participant Collector as nodesCollector
    participant DS1 as DataSource#1
    participant DSn as DataSource#N
    end

    Builder->>Visitor: SelectNodes()
    Visitor->>Visitor: init newFieldRefs
    Visitor->>Filter: NewDataSourceFilter(..., dataSources, newFieldRefs)
    Filter->>Collector: init per-DS visitors
    par per-DS visits
        Collector->>DS1: collect via collectNodesDSVisitor
        Collector->>DSn: collect via collectNodesDSVisitor
    end
    Collector-->>Filter: aggregate per-DS keys/reports
    Filter-->>Visitor: used data sources & NodeSuggestions
    Visitor->>Visitor: merge discovered newFieldRefs (may trigger rerun)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas to focus review on:

  • datasource per-DS visitor orchestration and error/report aggregation (datasource_filter_collect_nodes_visitor.go, datasource_filter_visitor.go).
  • collectKeysForPath error propagation and walker lifecycle changes (key_fields_visitor.go).
  • Parser precalc integration and interface implemented-by population correctness (parser.go, ast_interface_type_definition.go).
  • Walker API additions and all call-sites updated to use NewWalkerWithID (astvisitor/visitor.go and all updated visitors).

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "fix: improve query planning time" directly aligns with the primary objective of the changeset. The modifications across multiple files are specifically focused on optimizing query planning performance: pre-computing interface type definitions to avoid repeated computation, refactoring datasource filtering to use per-data-source visitors for more efficient collection, optimizing federation metadata lookups via direct map-based queries, and adding walker identifiers for better debugging/profiling. The title is concise, uses standard Conventional Commits format, and clearly communicates the main improvement target without being vague or misleading. A teammate scanning the commit history would immediately understand this PR addresses query planning performance.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sergiy/eng-8285-improve-query-planning-time

Comment @coderabbitai help to get the list of available commands and usage tips.

@devsergiy devsergiy force-pushed the sergiy/eng-8285-improve-query-planning-time branch from 85594c9 to 8cb0c3c Compare October 20, 2025 11:18
Copy link
Copy Markdown
Contributor

@ysmolski ysmolski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First half of review...

Comment thread v2/pkg/astvisitor/visitor.go Outdated
Comment thread v2/pkg/engine/datasource/graphql_datasource/representation_variable.go Outdated
Comment thread v2/pkg/astvisitor/visitor.go Outdated
Comment thread v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go Outdated
Comment thread v2/pkg/engine/plan/abstract_selection_rewriter.go Outdated
Comment thread v2/pkg/engine/plan/datasource_configuration.go Outdated
Comment thread v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go Outdated
Comment thread v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go Outdated
@devsergiy devsergiy marked this pull request as ready for review October 24, 2025 17:11
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
v2/pkg/engine/plan/visitor.go (1)

1023-1061: Clean up disabled code.

The TODO comment indicates that the field alias override logic has been disabled and cleanup is needed. The resolveFieldPath function (lines 1024-1061) is no longer called from EnterField and should be removed to avoid confusion.

Consider removing the unused resolveFieldPath function and the TODO comment once you've verified that the simplified path construction (line 394) works correctly across all use cases.

v2/pkg/engine/plan/datasource_filter_visitor.go (2)

109-114: Replace panic with a report error in applyLandedTo

A missing node can occur if landedTo references were pruned/rewritten. Panicking will crash planning.

Apply this diff:

-        if !ok {
-            panic("node not found")
-        }
+        if !ok {
+            f.report.AddInternalError(fmt.Errorf("applyLandedTo: node not found for fieldRef=%d (treeID=%d, path=%q)", fieldRef, treeNodeID, f.nodes.items[fieldRef].ParentPath))
+            continue
+        }

905-915: Guard against empty children in childsHasOnlyTypename

child.GetData() can be empty; accessing itemIds[0] risks panic.

Apply this diff:

-    for _, child := range children {
-        itemIds := child.GetData()
-        firstItem := itemIds[0]
+    for _, child := range children {
+        itemIds := child.GetData()
+        if len(itemIds) == 0 {
+            // no suggestions for this child; skip
+            continue
+        }
+        firstItem := itemIds[0]
🧹 Nitpick comments (6)
v2/pkg/astvisitor/visitor.go (1)

1383-1387: Consider removing or documenting commented profiling code.

The commented pprof code appears to be intentionally disabled. Either:

  1. Remove it if it's not needed, or
  2. Add a comment explaining when/how to enable it for profiling
v2/pkg/engine/plan/datasource_filter_visitor_test.go (1)

1072-1075: Use a stable sort (or a tie-breaker) to avoid flaky test order

You sort by Path only using an unstable sort. When multiple suggestions share the same Path, relative order is undefined and can cause sporadic failures.

Apply this diff:

-        slices.SortFunc(actualItems, func(a, b *NodeSuggestion) int {
-            return strings.Compare(a.Path, b.Path)
-        })
+        // Stable sort preserves insertion order for equal paths, avoiding flakiness.
+        slices.SortStableFunc(actualItems, func(a, b *NodeSuggestion) int {
+            return strings.Compare(a.Path, b.Path)
+        })
v2/pkg/engine/plan/datasource_filter_visitor.go (2)

50-54: Honor the max concurrency setting

WithMaxDataSourceCollectorsConcurrency sets a limit, but nodesCollector currently spawns one goroutine per data source unconditionally. Respect the cap to prevent oversubscription on large graphs.

Example adjustment (gate inside collector):

-    for i, ds := range f.dataSources { ... go func(...) { ... }(...) }
+    // inside nodesCollector.collectNodes():
+    semCap := int(c.maxConcurrency)
+    var sem chan struct{}
+    if semCap > 0 {
+        sem = make(chan struct{}, semCap)
+    }
+    for i, visitor := range c.dsVisitors {
+        if sem != nil { sem <- struct{}{} }
+        go func(visitor *collectNodesDSVisitor, report *operationreport.Report, nodesToVisit []nodeVisitTask) {
+            if sem != nil { defer func() { <-sem }() }
+            // existing body ...
+        }(visitor, c.dsVisitorsReports[i], nodesToVisit)
+    }

Also applies to: 143-195


775-779: Deterministic tie-breaking for duplicate selection order

Sorting by jumpCount with slices.SortFunc is unstable; ties can reorder duplicates nondeterministically, affecting “first available” behavior.

Apply this diff to use a stable sort:

-    slices.SortFunc(jumpsCounts, func(a, b nodeJump) int {
+    slices.SortStableFunc(jumpsCounts, func(a, b nodeJump) int {
         // acs order from 0 to n
         return a.jumpCount - b.jumpCount
     })

Optionally add a secondary key (e.g., data source order or hash) if stricter determinism is needed.

v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (2)

259-263: Reset should also clear localSuggestionLookup and providesEntries

Persisting these across runs can suppress legitimate re-suggestions after rewrites and grow memory.

Apply this diff:

 func (f *collectNodesDSVisitor) reset() {
-    f.localSuggestions = f.localSuggestions[:0]
-    f.keys = f.keys[:0]
+    f.localSuggestions = f.localSuggestions[:0]
+    f.keys = f.keys[:0]
+    // clear per-run caches
+    if len(f.localSuggestionLookup) > 0 {
+        for k := range f.localSuggestionLookup {
+            delete(f.localSuggestionLookup, k)
+        }
+    }
+    if len(f.providesEntries) > 0 {
+        f.providesEntries = f.providesEntries[:0]
+    }
 }

Optionally clear notExternalKeyPaths if key composition can change between runs.


122-148: Respect maxConcurrency when dispatching per-DS visitors

collectNodes launches one goroutine per DS without honoring c.maxConcurrency. Gate execution to prevent resource spikes on large fleets.

Apply this diff:

-    wg := &sync.WaitGroup{}
-    wg.Add(len(c.dsVisitors))
+    wg := &sync.WaitGroup{}
+    wg.Add(len(c.dsVisitors))
+    var sem chan struct{}
+    if c.maxConcurrency > 0 {
+        sem = make(chan struct{}, c.maxConcurrency)
+    }
 
-    for i, visitor := range c.dsVisitors {
-        go func(visitor *collectNodesDSVisitor, report *operationreport.Report, nodesToVisit []nodeVisitTask) {
+    for i, visitor := range c.dsVisitors {
+        if sem != nil { sem <- struct{}{} }
+        go func(visitor *collectNodesDSVisitor, report *operationreport.Report, nodesToVisit []nodeVisitTask) {
             defer func() {
                 // recover from panic and add it to the report
                 if r := recover(); r != nil {
                     report.AddInternalError(fmt.Errorf("panic: %v stack: %s", r, debug.Stack()))
                 }
             }()
             defer func() {
-                wg.Done()
+                if sem != nil { <-sem }
+                wg.Done()
             }()
             // cleanup data from previous runs, but preserve indexes
             visitor.reset()
             for _, node := range nodesToVisit {
                 if err := visitor.EnterField(node.fieldRef, node.treeNodeData, node.treeNodeId); err != nil {
                     report.AddInternalError(fmt.Errorf("data source %s: %v", visitor.dataSource.Name(), err))
                     // stop processing on error
                     return
                 }
             }
-        }(visitor, c.dsVisitorsReports[i], nodesToVisit)
+        }(visitor, c.dsVisitorsReports[i], nodesToVisit)
     }

Also applies to: 150-163

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c4acc9 and 736ebf6.

📒 Files selected for processing (26)
  • v2/pkg/ast/ast_interface_type_definition.go (4 hunks)
  • v2/pkg/astnormalization/abstract_field_normalizer.go (1 hunks)
  • v2/pkg/astnormalization/astnormalization.go (6 hunks)
  • v2/pkg/astnormalization/variables_mapper.go (1 hunks)
  • v2/pkg/astparser/parser.go (2 hunks)
  • v2/pkg/asttransform/typename_visitor.go (1 hunks)
  • v2/pkg/astvalidation/operation_validation.go (2 hunks)
  • v2/pkg/astvisitor/visitor.go (4 hunks)
  • v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go (7 hunks)
  • v2/pkg/engine/plan/abstract_selection_rewriter.go (1 hunks)
  • v2/pkg/engine/plan/analyze_plan_kind.go (1 hunks)
  • v2/pkg/engine/plan/configuration.go (1 hunks)
  • v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (19 hunks)
  • v2/pkg/engine/plan/datasource_filter_node_suggestions.go (2 hunks)
  • v2/pkg/engine/plan/datasource_filter_visitor.go (5 hunks)
  • v2/pkg/engine/plan/datasource_filter_visitor_test.go (3 hunks)
  • v2/pkg/engine/plan/key_fields_visitor.go (3 hunks)
  • v2/pkg/engine/plan/key_fields_visitor_test.go (2 hunks)
  • v2/pkg/engine/plan/node_selection_builder.go (4 hunks)
  • v2/pkg/engine/plan/node_selection_visitor.go (5 hunks)
  • v2/pkg/engine/plan/path_builder.go (1 hunks)
  • v2/pkg/engine/plan/planner.go (1 hunks)
  • v2/pkg/engine/plan/provides_fields_visitor.go (2 hunks)
  • v2/pkg/engine/plan/required_fields_visitor.go (1 hunks)
  • v2/pkg/engine/plan/visitor.go (2 hunks)
  • v2/pkg/variablesvalidation/variablesvalidation.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (19)
v2/pkg/engine/plan/abstract_selection_rewriter.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/analyze_plan_kind.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/provides_fields_visitor.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/asttransform/typename_visitor.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/astnormalization/astnormalization.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/astnormalization/variables_mapper.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewDefaultWalkerWithID (125-127)
v2/pkg/variablesvalidation/variablesvalidation.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/datasource_filter_visitor_test.go (1)
v2/pkg/engine/plan/datasource_filter_visitor.go (1)
  • NewDataSourceFilter (35-44)
v2/pkg/engine/plan/key_fields_visitor.go (4)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (1)
  • SeenKeyPath (43-47)
v2/pkg/engine/plan/datasource_configuration.go (1)
  • DSHash (15-15)
v2/pkg/engine/datasource/graphql_datasource/configuration.go (1)
  • FederationConfiguration (130-133)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/astvalidation/operation_validation.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/path_builder.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/astnormalization/abstract_field_normalizer.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/datasource_filter_visitor.go (6)
v2/pkg/engine/plan/datasource_configuration.go (2)
  • DataSource (274-287)
  • DSHash (15-15)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (2)
  • KeyIndex (38-41)
  • SeenKeyPath (43-47)
v2/pkg/engine/plan/source_connection_graph.go (1)
  • DataSourceJumpsGraph (34-37)
v2/pkg/ast/ast.go (1)
  • Document (10-56)
v2/pkg/operationreport/operationreport.go (1)
  • Report (9-12)
v2/pkg/engine/plan/datasource_filter_node_suggestions.go (3)
  • NewNodeSuggestions (122-124)
  • NodeSuggestions (93-98)
  • TraverseBFS (100-120)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (5)
v2/pkg/operationreport/operationreport.go (2)
  • Report (9-12)
  • NewReport (14-16)
v2/pkg/engine/plan/datasource_filter_node_suggestions.go (2)
  • TraverseBFS (100-120)
  • NodeSuggestion (14-40)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/datasource_configuration.go (1)
  • DataSource (274-287)
v2/pkg/engine/datasource/graphql_datasource/configuration.go (1)
  • FederationConfiguration (130-133)
v2/pkg/engine/plan/planner.go (2)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/astnormalization/inline_fragment_add_on_type.go (1)
  • InlineFragmentAddOnType (11-17)
v2/pkg/engine/plan/node_selection_builder.go (2)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/datasource_filter_visitor.go (1)
  • NewDataSourceFilter (35-44)
v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go (1)
v2/pkg/engine/plan/type_field.go (1)
  • TypeField (3-8)
v2/pkg/astvisitor/visitor.go (2)
v2/pkg/engine/resolve/node.go (1)
  • Node (20-26)
v2/pkg/ast/path.go (2)
  • Path (34-34)
  • PathItem (27-32)
v2/pkg/engine/plan/required_fields_visitor.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
🔇 Additional comments (22)
v2/pkg/astnormalization/variables_mapper.go (1)

15-15: LGTM! Walker identification added for better traceability.

The change from NewDefaultWalker() to NewDefaultWalkerWithID("VariablesMapper") adds a meaningful identifier for debugging and tracing purposes without modifying behavior. The ID appropriately matches the struct name and aligns with the project-wide standardization effort.

v2/pkg/engine/plan/configuration.go (1)

118-118: The review comment is incorrect—the field is actively used in the codebase.

The script confirms that DisableDefaultMapping is read in v2/pkg/engine/plan/visitor.go:1046, where it controls conditional logic:

if v.Config.Fields[i].DisableDefaultMapping {
    return nil
}

The field clearly has an effect: it gates whether default mapping is applied. It's also set in tests and documented with examples. The TODO comment suggesting it "has no effect" is misleading and should be removed or corrected rather than following through on the suggested deletion.

Likely an incorrect or invalid review comment.

v2/pkg/asttransform/typename_visitor.go (1)

21-21: LGTM: Walker identifier added for traceability.

The walker initialization has been updated to include an identifier string for debugging/tracing purposes, consistent with the project-wide refactor.

v2/pkg/engine/plan/path_builder.go (1)

20-20: LGTM: Walker identifier added for traceability.

Consistent with the project-wide refactor to add identifiers to walkers for debugging/tracing.

v2/pkg/engine/plan/planner.go (1)

56-56: LGTM: Walker identifiers added for traceability.

Both walker initializations have been updated with descriptive identifiers ("PrepareOperationWalker" and "PlanningWalker") for debugging/tracing, consistent with the project-wide refactor.

Also applies to: 61-61

v2/pkg/astvisitor/visitor.go (2)

66-66: LGTM: New walker constructors with ID support.

The additions of walkerID field and the new constructors NewWalkerWithID and NewDefaultWalkerWithID provide a clean way to identify walkers for debugging/tracing without breaking existing functionality.

Also applies to: 100-108, 125-127


114-114: The Path capacity change to a fixed value of 64 is safe and doesn't impact existing callers.

The code review concern can be resolved. Analysis shows:

  • All calls to NewWalker() use ancestorSize values of 4, 8, or 24—all less than the fixed capacity of 64
  • No code validates or depends on Path capacity matching ancestorSize; they are independent allocations
  • Path usage only involves slicing operations (w.Path[:len(w.Path)-1]) and length checks, which work correctly with the larger capacity
  • No performance-sensitive deep nesting scenarios detected that would exceed the 64-item capacity
v2/pkg/engine/plan/analyze_plan_kind.go (1)

10-10: LGTM: Walker identifier added for traceability.

Consistent with the project-wide refactor to add identifiers to walkers.

v2/pkg/engine/plan/provides_fields_visitor.go (1)

42-42: LGTM: Walker identifiers added for traceability.

Both walker initializations have been updated with descriptive identifiers ("AddTypenamesVisitor" and "ProvidesVisitor") consistent with the project-wide refactor.

Also applies to: 69-69

v2/pkg/astvalidation/operation_validation.go (1)

33-33: LGTM: Walker identifiers added for traceability.

Both walker initializations in DefaultOperationValidator and NewOperationValidator have been updated with the identifier "OperationValidator", consistent with the project-wide refactor.

Also applies to: 67-67

v2/pkg/engine/plan/abstract_selection_rewriter.go (1)

695-695: LGTM! Walker identification improves observability.

The addition of the "AbstractFieldPathCollector" identifier to the walker initialization enhances debugging and tracing capabilities without affecting functionality.

v2/pkg/engine/plan/required_fields_visitor.go (1)

67-67: LGTM! Walker identification improves observability.

The addition of the "RequiredFieldsVisitor" identifier to the walker initialization enhances debugging and tracing capabilities without affecting functionality.

v2/pkg/engine/plan/key_fields_visitor.go (2)

90-172: LGTM! Error handling improvement enhances robustness.

The method signature change adding error return capability is well-implemented:

  • All early return paths correctly return nil (lines 98, 103, 111, 171)
  • Error condition properly returns the report (line 133)
  • Consistent with error propagation patterns in the codebase

175-175: LGTM! Walker identification improves observability.

The addition of the "KeyInfoVisitor" identifier to the walker initialization enhances debugging and tracing capabilities without affecting functionality.

v2/pkg/variablesvalidation/variablesvalidation.go (1)

81-81: Walker ID addition LGTM

Using NewWalkerWithID with a descriptive ID improves tracing; no behavior change.

v2/pkg/engine/plan/key_fields_visitor_test.go (1)

486-494: Tests updated appropriately for error-returning collector

Switch to collectNodesDSVisitor and assert.NoError around collectKeysForPath are correct and improve signal. LGTM.

Also applies to: 495-495, 497-497

v2/pkg/astparser/parser.go (1)

94-95: Post-parse precalc integration looks good

Calling precalculate() only when report has no errors is safe and keeps Parse/ParseWithLimits behavior stable while populating interface implementation caches. LGTM.

Please confirm that documents created without parser (e.g., via Import... helpers) either invoke PopulateInterfaceTypeDefinitionImplementedByObjects or rely on getters that fallback, to avoid regressions.

Also applies to: 111-112, 114-121

v2/pkg/astnormalization/astnormalization.go (1)

206-215: Walker IDs across normalization stages LGTM

Consistent NewWalkerWithID usage improves traceability without altering semantics.

Also applies to: 217-217, 221-221, 239-239, 248-248, 256-256, 264-264, 272-272, 286-286, 359-359, 367-367, 370-370, 374-374

v2/pkg/engine/plan/datasource_filter_visitor_test.go (1)

1042-1047: Ctor/signature migration looks good

NewDataSourceFilter(DataSources, newFieldRefs) and findBestDataSourceSet(nil) usage aligns with the refactor. Please confirm nil newFieldRefs is intended for these tests and that landedTo=nil is a supported path.

v2/pkg/engine/plan/node_selection_builder.go (1)

53-59: Walker IDs and newFieldRefs wiring LGTM

  • Using astvisitor.NewWalkerWithID for both walkers is consistent with the new instrumentation.
  • newFieldRefs initialization and reset are correct.
  • dsFilter constructed with config.DataSources and newFieldRefs, and subsequent FilterDataSources calls match the new API.

Also applies to: 65-79, 85-88, 91-91, 106-106, 141-141

v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (2)

100-121: Nice: BFS over responseTree and newFieldRefs filtering

Building a visit list via TraverseBFS and gating by newFieldRefs minimizes work on secondary runs. LGTM.


178-186: LGTM: Walker identity for tree building

Using NewWalkerWithID("TreeBuilderVisitor") and threading fieldInfo improves traceability without affecting behavior.

Comment thread v2/pkg/ast/ast_interface_type_definition.go
Comment thread v2/pkg/engine/plan/datasource_filter_node_suggestions.go
Comment thread v2/pkg/engine/plan/node_selection_visitor.go
Comment thread v2/pkg/engine/plan/visitor.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (2)

72-95: Remove commented-out code.

The initialization logic correctly sets up per-datasource visitors with isolated local state. However, the commented-out walker initialization at line 82 should be removed.

Apply this diff to clean up the commented code:

 		visitor := &collectNodesDSVisitor{
 			operation:  c.operation,
 			definition: c.definition,
-			// walker:         walker,
 			nodes:                 c.nodes,

251-271: Remove commented-out walker field.

The per-datasource visitor structure is well-designed for parallel execution. However, the commented-out walker field at line 252 should be removed if it's no longer needed.

Apply this diff to clean up:

 type collectNodesDSVisitor struct {
-	// walker     *astvisitor.Walker
 	operation  *ast.Document
 	definition *ast.Document
v2/pkg/ast/ast_interface_type_definition.go (3)

167-178: Nil-check cache to avoid redundant fallback; preallocate result slice

Use impl == nil (not len==0) to detect “not populated”; otherwise you re-enumerate even when the cache is a valid empty slice, hurting hot-path perf. Also preallocate typeNames.

-	implementedByObjectRefs := d.InterfaceTypeDefinitions[interfaceDefRef].ImplementedByObjectDefinitions
-	if len(implementedByObjectRefs) == 0 {
+	impl := d.InterfaceTypeDefinitions[interfaceDefRef].ImplementedByObjectDefinitions
+	if impl == nil {
 		// fallback for documents not precalculated (e.g., built programmatically)
 		for _, n := range d.InterfaceTypeDefinitionImplementedByRootNodes(interfaceDefRef) {
 			if n.Kind == NodeKindObjectTypeDefinition {
 				typeNames = append(typeNames, d.ObjectTypeDefinitionNameString(n.Ref))
 			}
 		}
 	} else {
-		for _, implementedByObjectRef := range d.InterfaceTypeDefinitions[interfaceDefRef].ImplementedByObjectDefinitions {
-			typeNames = append(typeNames, d.ObjectTypeDefinitionNameString(implementedByObjectRef))
-		}
+		typeNames = make([]string, 0, len(impl))
+		for _, ref := range impl {
+			typeNames = append(typeNames, d.ObjectTypeDefinitionNameString(ref))
+		}
 	}

190-201: Mirror nil-check and prealloc in bytes variant

Same rationale as above: distinguish “not populated” via nil and preallocate.

-	implementedByObjectRefs := d.InterfaceTypeDefinitions[interfaceDefRef].ImplementedByObjectDefinitions
-	if len(implementedByObjectRefs) == 0 {
+	impl := d.InterfaceTypeDefinitions[interfaceDefRef].ImplementedByObjectDefinitions
+	if impl == nil {
 		// fallback for documents not precalculated (e.g., built programmatically)
 		for _, n := range d.InterfaceTypeDefinitionImplementedByRootNodes(interfaceDefRef) {
 			if n.Kind == NodeKindObjectTypeDefinition {
 				typeNames = append(typeNames, d.ObjectTypeDefinitionNameBytes(n.Ref))
 			}
 		}
 	} else {
-		for _, implementedByObjectRef := range d.InterfaceTypeDefinitions[interfaceDefRef].ImplementedByObjectDefinitions {
-			typeNames = append(typeNames, d.ObjectTypeDefinitionNameBytes(implementedByObjectRef))
-		}
+		typeNames = make([][]byte, 0, len(impl))
+		for _, ref := range impl {
+			typeNames = append(typeNames, d.ObjectTypeDefinitionNameBytes(ref))
+		}
 	}

212-225: Clarify cache lifecycle and usage with a doc comment

Add a doc comment explaining when to call PopulateInterfaceTypeDefinitionImplementedByObjects (parser precalc and after programmatic AST changes). This reduces misuse and reliance on slower fallbacks.

+// PopulateInterfaceTypeDefinitionImplementedByObjects precomputes the
+// ImplementedByObjectDefinitions cache for all interfaces.
+// Call this after parsing (parser precalc) and after programmatic AST mutations
+// that change interface implementations (e.g., Import* helpers).
 func (d *Document) PopulateInterfaceTypeDefinitionImplementedByObjects() {
 	for ref := 0; ref < len(d.InterfaceTypeDefinitions); ref++ {
 		implementedByNodes := d.InterfaceTypeDefinitionImplementedByRootNodes(ref)
 		implementedByObjectRefs := make([]int, 0, len(implementedByNodes))
 		for _, implementedByNode := range implementedByNodes {
 			if implementedByNode.Kind != NodeKindObjectTypeDefinition {
 				continue
 			}
 
 			implementedByObjectRefs = append(implementedByObjectRefs, implementedByNode.Ref)
 		}
 		d.InterfaceTypeDefinitions[ref].ImplementedByObjectDefinitions = implementedByObjectRefs
 	}
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 736ebf6 and ac1d67c.

📒 Files selected for processing (2)
  • v2/pkg/ast/ast_interface_type_definition.go (4 hunks)
  • v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (19 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
v2/pkg/ast/ast_interface_type_definition.go (5)
v2/pkg/ast/ast_description.go (1)
  • Description (12-17)
v2/pkg/engine/resolve/node_object.go (1)
  • Position (173-176)
v2/pkg/ast/ast_object_type_definition.go (1)
  • TypeList (10-12)
v2/pkg/ast/ast_directive.go (1)
  • DirectiveList (11-13)
v2/pkg/ast/ast_field_definition.go (1)
  • FieldDefinitionList (11-15)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (3)
v2/pkg/operationreport/operationreport.go (2)
  • Report (9-12)
  • NewReport (14-16)
v2/pkg/engine/plan/datasource_filter_node_suggestions.go (2)
  • TraverseBFS (100-120)
  • NodeSuggestion (14-40)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
🔇 Additional comments (18)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (17)

24-28: LGTM: Well-structured additions for per-datasource visitor pattern.

The new fields support efficient parallel node collection with per-datasource state isolation and incremental field processing via newFieldRefs filtering.


66-70: LGTM: Clean abstraction for work distribution.

The nodeVisitTask struct appropriately encapsulates the data needed for each visitor task with value types that are safe for concurrent access.


97-120: LGTM: Efficient task building with incremental filtering.

The BFS traversal with newFieldRefs filtering (lines 106-111) enables efficient incremental processing by skipping fields that were processed in previous iterations. The task list is built before goroutine dispatch, ensuring safe concurrent access.


122-162: LGTM: Well-implemented concurrent visitor execution.

The concurrency pattern is solid:

  • Goroutines receive visitor/report/tasks as parameters, avoiding closure pitfalls
  • Proper defer ordering ensures cleanup (lines 136-143)
  • Panic recovery with stack traces aids debugging (lines 144-149)
  • Per-visitor state isolation prevents data races
  • Optional semaphore provides backpressure control

164-189: LGTM: Correct error aggregation and safe post-processing.

The implementation correctly waits for all goroutines (line 164), aggregates errors from all reports (lines 166-176), and only modifies shared state after synchronization (lines 180-188). The comment at lines 178-179 is valuable documentation of the safety invariant.


191-204: LGTM: Walker identification enhances debuggability.

Using NewWalkerWithID with the identifier "TreeBuilderVisitor" (line 192) enables tracing and debugging across the visitor infrastructure.


219-236: LGTM: Efficient field info collection.

The logic correctly collects field information only for newly seen fields (line 235), avoiding redundant work while maintaining the deduplication invariant with IsFieldSeen (line 220).


273-276: Verify whether maps should be reset.

The reset() method clears slices but doesn't reset localSuggestionLookup or localSeenKeys maps. Please confirm this is intentional—if these maps should persist across iterations, consider adding a clarifying comment.


278-330: LGTM: Methods correctly updated for per-datasource visitor pattern.

The helper methods (hasSuggestionForFieldOnCurrentDataSource, hasProvidesConfiguration, isEntityInterface, etc.) are appropriately updated to work with the collectNodesDSVisitor receiver without changing their core logic.


331-377: LGTM: Improved error handling with explicit returns.

Converting from side-effect error logging to explicit error returns (lines 353, 358, 372) enables proper error propagation in the concurrent visitor execution model. The early validation checks are well-placed.


379-402: LGTM: Correctly adapted to use fieldInfo.

The method properly uses info.enclosingTypeDefinition (line 384) from the fieldInfo map instead of walker state, aligning with the stateless visitor design.


409-518: LGTM: Well-refactored with proper error propagation.

The method is correctly updated to:

  • Accept treeNodeId as a parameter for tree correlation (line 409)
  • Return errors explicitly rather than using report side effects (lines 415-417, 422-424, 431-433)
  • Use fieldInfo map instead of walker state (line 410)
  • Store treeNodeId in node suggestions for proper tree node correlation (line 510)

The error handling is thorough and the logic flow is cleaner than side-effect-based reporting.


520-530: LGTM: Safe shared state updates.

The method correctly mutates shared state (f.nodes) after all concurrent visitors complete. The tree node data updates (lines 525-528) properly correlate suggestions with their tree locations.


539-541: LGTM: Correct inverse mapping helper.

The function properly inverts TreeNodeID by subtracting the offset, enabling bidirectional tree node ↔ field reference mapping.


552-559: LGTM: Enhanced fieldInfo for stateless visitors.

Adding enclosingTypeDefinition (line 558) enables visitors to access type context without walker state, supporting the stateless per-datasource visitor architecture.


561-596: LGTM: Key enabler of stateless visitor pattern.

The method precomputes comprehensive field metadata, including enclosingTypeDefinition (line 594), during tree building. This enables per-datasource visitors to operate without walker state, supporting efficient parallel execution.


49-64: Verification complete: All callers updated for signature change.

The search found exactly one call to CollectNodes() at v2/pkg/engine/plan/datasource_filter_visitor.go:160. The caller correctly assigns the result to a single variable (keysInfo := f.nodesCollector.CollectNodes()), which matches the new signature that returns only []DSKeyInfo. No legacy code using the old two-value return pattern was found.

v2/pkg/ast/ast_interface_type_definition.go (1)

18-26: ****

Verification confirms the implementation is sound:

  • No external mutations: Codebase search found zero writes to ImplementedByObjectDefinitions outside the definition file.
  • Proper lifecycle: PopulateInterfaceTypeDefinitionImplementedByObjects() is wired into the parser precalc phase (parser.go:119).
  • Correct fallback logic: The len() == 0 check intentionally handles both nil and empty slices, enabling fallback for non-precalculated documents—a feature, not a flaw.
  • Preallocation already present: Line 215 uses make([]int, 0, len(implementedByNodes)), avoiding unnecessary allocations.

The exported field is managed safely within its intended lifecycle; the theoretical mutation risk does not manifest in practice.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
v2/pkg/ast/ast_interface_type_definition.go (3)

167-182: Fallback logic correctly implemented; minor refactor suggested.

The nil-check fallback successfully addresses the previous review concern about backward compatibility for documents not run through precalculate(). Based on learnings.

However, line 179 re-accesses the struct field instead of using the local variable implementedByObjectRefs captured at line 167.

Apply this diff to use the local variable:

   } else {
     typeNames = make([]string, 0, len(implementedByObjectRefs))
-    for _, implementedByObjectRef := range d.InterfaceTypeDefinitions[interfaceDefRef].ImplementedByObjectDefinitions {
+    for _, implementedByObjectRef := range implementedByObjectRefs {
       typeNames = append(typeNames, d.ObjectTypeDefinitionNameString(implementedByObjectRef))
     }
   }

193-208: Same refactor opportunity as lines 167-182.

Line 205 should use the local variable implementedByObjectRefs instead of re-accessing the struct field.

Apply this diff:

   } else {
     typeNames = make([][]byte, 0, len(implementedByObjectRefs))
-    for _, implementedByObjectRef := range d.InterfaceTypeDefinitions[interfaceDefRef].ImplementedByObjectDefinitions {
+    for _, implementedByObjectRef := range implementedByObjectRefs {
       typeNames = append(typeNames, d.ObjectTypeDefinitionNameBytes(implementedByObjectRef))
     }
   }

218-231: Add doc comment for exported method.

Public methods in Go should have doc comments explaining their purpose and usage.

Add a doc comment above the method:

// PopulateInterfaceTypeDefinitionImplementedByObjects populates the ImplementedByObjectDefinitions
// cache for all interface type definitions in the document. This optimization is typically called
// during parsing to improve query planning performance.
func (d *Document) PopulateInterfaceTypeDefinitionImplementedByObjects() {

Otherwise, the implementation correctly filters and caches object type implementors.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac1d67c and e8368e0.

📒 Files selected for processing (2)
  • v2/pkg/ast/ast_interface_type_definition.go (4 hunks)
  • v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (19 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
v2/pkg/ast/ast_interface_type_definition.go (5)
v2/pkg/ast/ast_description.go (1)
  • Description (12-17)
v2/pkg/engine/resolve/node_object.go (1)
  • Position (173-176)
v2/pkg/ast/ast_object_type_definition.go (1)
  • TypeList (10-12)
v2/pkg/ast/ast_directive.go (1)
  • DirectiveList (11-13)
v2/pkg/ast/ast_field_definition.go (1)
  • FieldDefinitionList (11-15)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (4)
v2/pkg/operationreport/operationreport.go (2)
  • Report (9-12)
  • NewReport (14-16)
v2/pkg/engine/plan/datasource_filter_node_suggestions.go (2)
  • TraverseBFS (100-120)
  • NodeSuggestion (14-40)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/datasource_configuration.go (1)
  • DataSource (274-287)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
🔇 Additional comments (15)
v2/pkg/ast/ast_interface_type_definition.go (1)

18-27: LGTM! Cache field added appropriately.

The ImplementedByObjectDefinitions field provides an optional cache that enables performance optimization while maintaining backward compatibility through nil initialization.

v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (14)

66-94: LGTM! Well-structured per-DS initialization.

The nodeVisitTask struct and initVisitors method cleanly prepare per-data-source visitors with independent state (local keys, suggestions, reports). This design prevents cross-DS contamination and enables parallel processing.


96-188: LGTM! Solid parallelization with proper error handling.

The refactored collectNodes method introduces robust per-DS parallel processing:

  • Tree traversal with BFS and task queuing (lines 98-119).
  • Goroutine-per-DS-visitor pattern with optional concurrency limiting via semaphore (lines 121-161).
  • Panic recovery with stack traces for debugging (lines 143-148).
  • Error propagation via per-DS reports, aggregated after all visitors complete (lines 165-175).
  • Post-goroutine suggestion application prevents data races (lines 179-187).

The pattern is well-implemented and should improve query planning performance.


190-203: LGTM! Walker identification added.

The buildTree method now uses NewWalkerWithID (line 191) for walker identification and passes fieldInfo to the visitor (line 197) to enable field metadata collection.


205-248: LGTM! Tree builder now captures field metadata.

The treeBuilderVisitor now collects field information (line 234) including enclosing type definitions, enabling downstream per-DS visitors to access this context.


250-274: LGTM! Per-DS visitor state management.

The collectNodesDSVisitor maintains per-DS state (localSuggestions, localSuggestionLookup, providesEntries) and the reset method correctly clears state between runs while preserving capacity.


276-327: LGTM! Helper methods correctly scoped to per-DS visitor.

These helper methods (hasSuggestionForFieldOnCurrentDataSource, hasProvidesConfiguration, isEntityInterface, isInterfaceObject, allKeysHasDisabledEntityResolver) are correctly scoped to the per-DS visitor, enabling independent DS-specific checks.


329-375: LGTM! Provides handling with proper error propagation.

The handleProvidesSuggestions method now returns errors, enabling proper propagation to the per-DS report. The checks for object type definitions (line 339) and field definitions (line 343) correctly use the new enclosingTypeDefinition from fieldInfo. Error messages include helpful context.


377-405: LGTM! Union typename and external key checks.

Both helper methods correctly use the enclosingTypeDefinition from fieldInfo (line 382) and provide clear boolean checks for union typename suggestions and external key paths.


407-516: LGTM! EnterField refactored with error propagation.

The EnterField method signature now includes itemIds []int and treeNodeId uint parameters and returns an error, enabling proper error propagation from provides handling (lines 413-415) and key collection (lines 420-431). The method correctly:

  • Checks both global and local suggestions to prevent duplicates (lines 437-445).
  • Propagates treeNodeId to node suggestions (line 508).
  • Tracks local suggestions for deduplication (line 512).

518-528: LGTM! Safe suggestion application after parallel collection.

The applySuggestions method correctly applies per-DS local suggestions to the global NodeSuggestions structure. Called after all goroutines complete (line 180), this avoids data races.


530-539: LGTM! Tree node ID mapping functions.

The newly exported TreeNodeFieldRef function (lines 537-539) correctly reverses the TreeNodeID calculation, enabling mapping from tree node IDs back to field references. The offset of 100 ensures tree node ID 0 remains reserved for the root.


550-594: LGTM! Field info now includes enclosing type definition.

The fieldInfo struct now includes enclosingTypeDefinition ast.Node (line 556), and collectFieldInfo correctly captures this from the walker (line 592). This enables per-DS visitors to access type context for provides handling and other type-specific logic.


49-64: Verification confirmed: signature change fully updated.

The codebase contains exactly one caller of CollectNodes at v2/pkg/engine/plan/datasource_filter_visitor.go:160, which correctly assigns the result to a single variable matching the new signature. No breaking patterns found.


14-29: ****

The newFieldRefs map is not dead code. It's an input parameter populated by the caller before being passed to NewDataSourceFilter. The map is populated by nodeSelectionVisitor.addNewFieldRefs() in node_selection_builder.go and passed to DataSourceFilter at construction time. The gating logic at line 105-109 correctly implements incremental field collection—when len(c.newFieldRefs) > 0, only fields present in the map are visited. This is a designed feature, not dead code.

Likely an incorrect or invalid review comment.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (2)

329-375: Verify enclosingTypeDefinition is always valid.

At line 339, enclosingTypeDefinition.Kind is accessed directly. While the collectFieldInfo method (line 595) sets this from f.walker.EnclosingTypeDefinition, there's no explicit validation that it's a valid non-zero node before accessing its Kind field.

If fieldInfo is missing for a fieldRef, line 410 returns nil early, so this should be safe. However, consider adding a defensive check at line 339 to ensure enclosingTypeDefinition.Ref is valid if the ast.Node type supports zero values.


105-110: Add a comment explaining newFieldRefs lifecycle and the incremental filtering design.

The verification confirms the filtering logic is correct. The newFieldRefs map is passed from nodeSelectionVisitor (where it's populated by addNewFieldRefs()), through the visitor hierarchy to nodesCollector. The guard clause if len(c.newFieldRefs) > 0 properly handles empty maps (processes all fields) versus populated maps (incremental filtering). However, add a brief comment at lines 105-109 explaining this is intentional incremental processing, clarifying that an empty map means first iteration (process all) and a populated map means subsequent iteration (process only new fields).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8368e0 and dc50526.

📒 Files selected for processing (3)
  • v2/pkg/engine/plan/datasource_configuration.go (1 hunks)
  • v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (19 hunks)
  • v2/pkg/engine/plan/federation_metadata.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
v2/pkg/engine/plan/datasource_configuration.go (1)
v2/pkg/engine/plan/federation_metadata.go (1)
  • FederationMetaData (10-18)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (4)
v2/pkg/operationreport/operationreport.go (2)
  • Report (9-12)
  • NewReport (14-16)
v2/pkg/engine/plan/datasource_filter_node_suggestions.go (2)
  • TraverseBFS (100-120)
  • NodeSuggestion (14-40)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/datasource_configuration.go (1)
  • DataSource (277-290)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
🔇 Additional comments (11)
v2/pkg/engine/plan/datasource_configuration.go (1)

90-101: LGTM! Efficient entity type name indexing.

The map initialization and population logic is correct. Building the entityTypeNames index during initialization enables O(1) lookups in HasEntity(), which should improve query planning performance as intended by this PR.

v2/pkg/engine/plan/federation_metadata.go (2)

10-18: LGTM! Appropriate field for caching entity type names.

The entityTypeNames field provides an efficient lookup structure for entity type membership checks. The private visibility is correct since this is an internal optimization detail.


38-41: LGTM! Clean O(1) entity lookup.

The direct map lookup is efficient and correct. The nil-map safety is implicit (returns false for missing keys), which matches the expected behavior when the map is uninitialized.

v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (8)

121-188: LGTM: Parallel execution is correctly synchronized.

The parallelization is well-designed:

  • Each DS visitor operates on its own local state during the parallel phase
  • Shared state modifications (applySuggestions, key aggregation) occur only after wg.Wait()
  • Per-DS error handling and panic recovery are properly implemented
  • The semaphore-based concurrency limiting (lines 126-128, 139-142) is correctly applied

190-203: LGTM: Walker initialization updated correctly.

The change to NewWalkerWithID and the addition of fieldInfo to the visitor align with the broader refactoring to support per-data-source processing.


205-248: LGTM: Field info collection integrated properly.

The treeBuilderVisitor now collects field metadata during tree construction, which is then used by per-DS visitors. The integration is clean and maintains separation of concerns.


407-519: LGTM: Per-DS visitor logic is well-structured.

The EnterField method correctly:

  • Handles provides suggestions with error propagation
  • Collects keys for entities and possible types
  • Checks for duplicate suggestions (global and local)
  • Creates node suggestions with appropriate metadata
  • Uses local state to prevent cross-DS contamination during parallel execution

533-542: LGTM: Tree node ID mapping is correct.

The TreeNodeFieldRef function correctly inverts TreeNodeID by subtracting the same offset (100) that was added. This ensures field refs and tree node IDs don't collide with the root node ID.


553-597: LGTM: Field info collection is comprehensive.

The fieldInfo struct and collectFieldInfo method properly capture all necessary metadata for per-DS processing, including the enclosingTypeDefinition which enables proper type-based validation downstream.


72-94: The original review concern is incorrect.

The verification confirms that initVisitors() is called at line 157 in datasource_filter_visitor.go, immediately before CollectNodes() is invoked at line 160. The method initialization order is correct, and there is no risk of incomplete key collection due to missing initialization.

Likely an incorrect or invalid review comment.


49-64: No issues found. Error handling is properly implemented via shared report.

The caller at line 79-82 correctly checks f.report.HasErrors() immediately after calling f.collectNodes(). Since nodesCollector and DataSourceFilter share the same report instance, errors from CollectNodes() are properly propagated and checked before the result is used.

Copy link
Copy Markdown
Contributor

@ysmolski ysmolski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@devsergiy devsergiy marked this pull request as draft October 25, 2025 08:35
@devsergiy devsergiy force-pushed the sergiy/eng-8285-improve-query-planning-time branch from dc50526 to 0305727 Compare October 29, 2025 10:12
@devsergiy devsergiy marked this pull request as ready for review October 29, 2025 11:47
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
v2/pkg/engine/plan/key_fields_visitor.go (1)

269-270: Fix critical stack bug in currentKeyPath initialization

The bug is confirmed. Line 269 incorrectly appends to v.keyPaths instead of v.currentKeyPath, breaking the stack invariant needed for nested field traversal. This causes:

  • currentKeyPath to contain duplicated entries from the entire keyPaths accumulator
  • LeaveField pops incorrectly since the stack was never properly built
  • isRootKeyPathExternal() to check wrong indices

The suggested fix is correct:

-	v.currentKeyPath = append(v.keyPaths, fieldKeyPath)
+	v.currentKeyPath = append(v.currentKeyPath, fieldKeyPath)
🧹 Nitpick comments (9)
v2/pkg/engine/plan/configuration.go (1)

118-118: Consider removing the field now or tracking its deprecation in an issue.

The TODO comment helpfully documents that DisableDefaultMapping has no effect. Since the PR is already refactoring related code and the enriched summary indicates other files are moving away from this field, consider addressing this now rather than deferring it:

  1. Option 1 (preferred if truly unused): Remove the field in this PR if it's confirmed to have no effect and no external consumers rely on it.
  2. Option 2 (if breaking change needs coordination): Open an issue to track its deprecation and removal, then reference that issue in the comment (e.g., // TODO(#ISSUE): deprecated, remove in v3).

Leaving untracked TODO comments can accumulate technical debt.

Would you like me to search the codebase to verify whether DisableDefaultMapping is still referenced elsewhere, or help draft an issue to track its removal?

v2/pkg/engine/plan/key_fields_visitor_test.go (1)

495-498: Good: assert errors from collectKeysForPath and dedupe behavior

Consider adding one negative test case where a key field is missing (to exercise the TODO error path in getKeyPaths).

v2/pkg/astvisitor/visitor.go (3)

66-108: Expose a setter and update doc to reflect NewWalkerWithID

  • Add Walker.SetID(id string) so pooled walkers can be labeled post‑construction.
  • Update the “Always use NewWalker” comment to mention NewWalkerWithID/NewDefaultWalkerWithID.
 type Walker struct {
-    walkerID string
+    walkerID string
     ...
 }
 
+// SetID sets a human-readable identifier for profiling/debug.
+func (w *Walker) SetID(id string) { w.walkerID = id }

Also applies to: 125-128


114-114: Path capacity constant

You changed Path capacity to 64. Extract a package‑level const (e.g., defaultPathCap = 64) to avoid magic numbers in both constructors.


1383-1388: pprof labeling stub

Consider guarding with a build tag or debug flag so this can be enabled without editing source.

v2/pkg/engine/plan/key_fields_visitor.go (2)

131-134: Error propagation shape

You return the local report as error. Ensure operationreport.Report implements error (Error() string) and that callers don’t also rely on input.report side effects. If not guaranteed, return fmt.Errorf with details.


212-215: TODO: missing-node should surface as an error

Replace the TODO with a proper external error on input.report so collectKeysForPath returns a failure when a key field isn’t present in any DS.

v2/pkg/engine/plan/datasource_filter_node_suggestions.go (1)

100-120: Minor: guard nil root and avoid enqueuing nil

Function is correct, but an early return avoids pushing nil and one PopFront.

 func TraverseBFS(data tree.Tree[[]int]) iter.Seq2[uint, tree.Node[[]int]] {
   return func(yield func(uint, tree.Node[[]int]) bool) {
-    q := queue.New()
-    q.PushBack(data.Root())
+    root := data.Root()
+    if root == nil {
+      return
+    }
+    q := queue.New()
+    q.PushBack(root)
     for {
       current := q.PopFront()
       switch node := current.(type) {
v2/pkg/engine/plan/node_selection_visitor.go (1)

136-168: Ensure newFieldRefs map is always initialized

newFieldRefs is written in addNewFieldRefs; please confirm it’s allocated by the builder before any visit, or initialize/reset it here to be defensive.

 func (c *nodeSelectionVisitor) EnterDocument(operation, definition *ast.Document) {
   c.hasNewFields = false
   ...
   if c.skipFieldsRefs == nil {
     c.skipFieldsRefs = make([]int, 0, 8)
   }
+  if c.newFieldRefs == nil {
+    c.newFieldRefs = make(map[int]struct{}, 16)
+  } else {
+    for k := range c.newFieldRefs {
+      delete(c.newFieldRefs, k)
+    }
+  }
   ...
 }

If builder already guarantees this, consider a brief comment here.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc50526 and 41b3461.

📒 Files selected for processing (28)
  • v2/pkg/ast/ast_interface_type_definition.go (4 hunks)
  • v2/pkg/astnormalization/abstract_field_normalizer.go (1 hunks)
  • v2/pkg/astnormalization/astnormalization.go (6 hunks)
  • v2/pkg/astnormalization/variables_mapper.go (1 hunks)
  • v2/pkg/astparser/parser.go (2 hunks)
  • v2/pkg/asttransform/typename_visitor.go (1 hunks)
  • v2/pkg/astvalidation/operation_validation.go (2 hunks)
  • v2/pkg/astvisitor/visitor.go (4 hunks)
  • v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go (7 hunks)
  • v2/pkg/engine/plan/abstract_selection_rewriter.go (1 hunks)
  • v2/pkg/engine/plan/analyze_plan_kind.go (1 hunks)
  • v2/pkg/engine/plan/configuration.go (1 hunks)
  • v2/pkg/engine/plan/datasource_configuration.go (1 hunks)
  • v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (19 hunks)
  • v2/pkg/engine/plan/datasource_filter_node_suggestions.go (2 hunks)
  • v2/pkg/engine/plan/datasource_filter_visitor.go (5 hunks)
  • v2/pkg/engine/plan/datasource_filter_visitor_test.go (3 hunks)
  • v2/pkg/engine/plan/federation_metadata.go (2 hunks)
  • v2/pkg/engine/plan/key_fields_visitor.go (3 hunks)
  • v2/pkg/engine/plan/key_fields_visitor_test.go (2 hunks)
  • v2/pkg/engine/plan/node_selection_builder.go (4 hunks)
  • v2/pkg/engine/plan/node_selection_visitor.go (5 hunks)
  • v2/pkg/engine/plan/path_builder.go (1 hunks)
  • v2/pkg/engine/plan/planner.go (1 hunks)
  • v2/pkg/engine/plan/provides_fields_visitor.go (2 hunks)
  • v2/pkg/engine/plan/required_fields_visitor.go (1 hunks)
  • v2/pkg/engine/plan/visitor.go (2 hunks)
  • v2/pkg/variablesvalidation/variablesvalidation.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (15)
  • v2/pkg/ast/ast_interface_type_definition.go
  • v2/pkg/astvalidation/operation_validation.go
  • v2/pkg/engine/plan/abstract_selection_rewriter.go
  • v2/pkg/engine/plan/datasource_configuration.go
  • v2/pkg/engine/plan/analyze_plan_kind.go
  • v2/pkg/astnormalization/variables_mapper.go
  • v2/pkg/engine/plan/provides_fields_visitor.go
  • v2/pkg/engine/plan/path_builder.go
  • v2/pkg/engine/plan/visitor.go
  • v2/pkg/variablesvalidation/variablesvalidation.go
  • v2/pkg/astnormalization/abstract_field_normalizer.go
  • v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go
  • v2/pkg/engine/plan/required_fields_visitor.go
  • v2/pkg/astparser/parser.go
  • v2/pkg/asttransform/typename_visitor.go
🧰 Additional context used
🧬 Code graph analysis (8)
v2/pkg/engine/plan/key_fields_visitor.go (2)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (1)
  • SeenKeyPath (43-47)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/astnormalization/astnormalization.go (1)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/datasource_filter_visitor_test.go (1)
v2/pkg/engine/plan/datasource_filter_visitor.go (1)
  • NewDataSourceFilter (35-44)
v2/pkg/engine/plan/planner.go (2)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/astnormalization/inline_fragment_add_on_type.go (1)
  • InlineFragmentAddOnType (11-17)
v2/pkg/astvisitor/visitor.go (1)
v2/pkg/ast/path.go (2)
  • Path (34-34)
  • PathItem (27-32)
v2/pkg/engine/plan/datasource_filter_visitor.go (3)
v2/pkg/engine/plan/datasource_configuration.go (2)
  • DataSource (277-290)
  • DSHash (15-15)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (2)
  • KeyIndex (38-41)
  • SeenKeyPath (43-47)
v2/pkg/engine/plan/datasource_filter_node_suggestions.go (3)
  • NewNodeSuggestions (122-124)
  • NodeSuggestions (93-98)
  • TraverseBFS (100-120)
v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (4)
v2/pkg/operationreport/operationreport.go (2)
  • Report (9-12)
  • NewReport (14-16)
v2/pkg/engine/plan/datasource_filter_node_suggestions.go (2)
  • TraverseBFS (100-120)
  • NodeSuggestion (14-40)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/datasource_configuration.go (1)
  • DataSource (277-290)
v2/pkg/engine/plan/node_selection_builder.go (2)
v2/pkg/astvisitor/visitor.go (1)
  • NewWalkerWithID (100-108)
v2/pkg/engine/plan/datasource_filter_visitor.go (1)
  • NewDataSourceFilter (35-44)
🔇 Additional comments (27)
v2/pkg/engine/plan/federation_metadata.go (2)

16-17: No action needed — initialization is correct and complete.

The entityTypeNames map is properly initialized and populated:

  • Allocated at line 91 in InitKeys() with make(map[string]struct{})
  • Populated at line 97 by iterating through Keys and adding each TypeName
  • Called during initialization (line 87), before HasEntity() is used

The optimization correctly replaces O(n) key lookup with O(1) map access while preserving semantic equivalence.


38-41: Code implementation is correct; review comment mischaracterizes the change.

The HasEntity method implementation shown (lines 38-41) is identical to the previous version in HEAD~1. It already uses O(1) map lookup and is correctly populated from the Keys configuration in InitKeys(). All callers properly use the boolean result to check entity existence.

However, the review comment incorrectly frames this as a "refactoring optimization" when git history shows no actual code change here. The method wasn't refactored—it was already optimized.

Likely an incorrect or invalid review comment.

v2/pkg/engine/plan/key_fields_visitor_test.go (1)

486-493: Rename to collectNodesDSVisitor looks right

Construction aligns with per-DS visitor pattern; maps preallocated appropriately.

v2/pkg/engine/plan/key_fields_visitor.go (1)

175-176: Nice: labeled walker for profiling

Adopting NewWalkerWithID("KeyInfoVisitor") improves traceability.

v2/pkg/engine/plan/planner.go (1)

56-57: Adopt labeled walkers

Clear IDs (“PrepareOperationWalker”, “PlanningWalker”) aid profiling; no behavior change.

Also applies to: 61-67, 69-73

v2/pkg/astnormalization/astnormalization.go (1)

206-215: Consistent walker IDs across normalization stages

Good instrumentation pass; descriptive IDs make traces readable.

Also applies to: 217-235, 221-223, 239-244, 247-253, 255-261, 263-269, 271-278, 285-295, 356-383

v2/pkg/engine/plan/node_selection_visitor.go (2)

57-67: Helper centralization for skip/new field refs

Good consolidation; ensures new refs are tracked whenever skips are added.


500-501: Good: route all additions through addSkipFieldRefs/addNewFieldRefs

This keeps revisit logic consistent after adds/rewrites.

Also applies to: 590-591, 673-674, 717-719

v2/pkg/engine/plan/datasource_filter_visitor_test.go (1)

1042-1043: Tests updated to new DataSourceFilter API

Constructor and method arity changes reflected correctly; enabling selection reasons improves debuggability.

Also applies to: 1047-1048

v2/pkg/engine/plan/node_selection_builder.go (4)

53-53: LGTM: Walker initialization updated to use identifiable walkers.

The transition to NewWalkerWithID with string identifiers improves debugging and tracing capabilities.

Also applies to: 65-65


57-57: LGTM: New field reference tracking properly initialized and reset.

The newFieldRefs map enables tracking newly discovered fields across iterations, which is correctly initialized during construction and reset between runs.

Also applies to: 87-87


91-91: LGTM: DataSourceFilter construction updated with per-iteration state.

The constructor now receives dataSources and newFieldRefs upfront, aligning with the new internal state management pattern.


106-106: LGTM: FilterDataSources calls updated to match new signature.

The method signature simplification (removing dataSources and nodeSuggestions parameters) reflects the architectural shift to internal state management within DataSourceFilter.

Also applies to: 141-141

v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go (9)

24-28: LGTM: New fields support per-datasource visitor architecture.

The added fields (fieldInfo, newFieldRefs, dsVisitors, dsVisitorsReports) enable proper isolation of per-datasource state and incremental field processing.


49-64: LGTM: CollectNodes simplified to return only keys.

The return signature change reflects that nodes (NodeSuggestions) are now managed internally rather than returned. The explicit key reset on line 56 ensures clean state between iterations.


72-94: LGTM: Per-datasource visitor initialization with proper state isolation.

Each datasource visitor receives isolated local state (keys, localSeenKeys, localSuggestionLookup) while sharing read-only references to common structures. This design supports safe concurrent execution.


96-163: LGTM: Concurrent per-datasource node collection with proper synchronization.

The goroutine-based collection uses:

  • Semaphore for controlled concurrency
  • WaitGroup for completion tracking
  • Per-DS isolated state to avoid races
  • Panic recovery with error reporting (lines 143-148)

The newFieldRefs filtering (lines 105-110) correctly skips fields not added in the current iteration.


165-188: LGTM: Sequential result aggregation after concurrent collection.

Error checking and result aggregation (suggestions, keys, seenKeys) occur sequentially after all goroutines complete, avoiding any race conditions. The comment on line 177 correctly notes the safety requirement.


190-203: LGTM: Tree builder updated with identifiable walker and field info.

The tree builder now uses NewWalkerWithID and receives fieldInfo to enable enriched field metadata collection including enclosingTypeDefinition.


218-235: LGTM: Field info collection enriched with enclosing type definition.

The collectFieldInfo method now captures enclosingTypeDefinition from the walker (line 598), which is used for provides directive handling (line 339) and type checking (line 382).

Also applies to: 565-599


250-522: LGTM: Per-datasource visitor with isolated state and improved error handling.

The collectNodesDSVisitor:

  • Maintains isolated per-DS state (localSuggestions, localSuggestionLookup, localSeenKeys)
  • Returns errors from EnterField and handleProvidesSuggestions for proper propagation
  • Uses localSuggestionLookup (line 448) to prevent duplicate suggestions within an iteration
  • Properly resets state via reset() (lines 271-274)

543-545: LGTM: Helper function for bidirectional tree node ID mapping.

TreeNodeFieldRef correctly inverts TreeNodeID (line 536-541), enabling mapping from tree node IDs back to field references.

v2/pkg/engine/plan/datasource_filter_visitor.go (5)

25-26: LGTM: DataSourceFilter refactored with internal state management.

The addition of newFieldRefs (line 25), dataSources (line 26), and nodesCollector (line 32) fields supports the new architecture where datasources and iteration state are managed internally rather than passed as parameters.

Also applies to: 32-33, 35-43


56-76: LGTM: FilterDataSources signature simplified with internal datasource management.

The method signature reduction from 4 to 2 parameters reflects the architectural shift:

  • dataSources now managed internally (line 67)
  • nodeSuggestions managed internally via f.nodes
  • Only per-iteration parameters (landedTo, fieldDependsOn) passed

78-99: LGTM: findBestDataSourceSet updated to use internal node collection.

The method now calls f.collectNodes() (line 79) which manages node collection internally using f.nodesCollector.


143-195: LGTM: Internal nodesCollector with lazy initialization and proper lifecycle.

The collectNodes method now:

  • Lazily initializes nodesCollector on first call (line 144)
  • Calls initVisitors() once during initialization (line 157)
  • Maintains seenKeys across iterations for deduplication (line 152)
  • Preserves deterministic datasource ordering (lines 186-190)

384-627: LGTM: Duplicate node selection updated to use BFS traversal helper.

The traversal mechanism changed to use TraverseBFS(f.nodes.responseTree) (line 384), which provides an iterator-based BFS traversal. The selection logic remains unchanged.

@devsergiy devsergiy merged commit 373cf2a into master Oct 29, 2025
11 checks passed
@devsergiy devsergiy deleted the sergiy/eng-8285-improve-query-planning-time branch October 29, 2025 12:09
devsergiy pushed a commit that referenced this pull request Oct 29, 2025
🤖 I have created a release *beep* *boop*
---


##
[2.0.0-rc.235](v2.0.0-rc.234...v2.0.0-rc.235)
(2025-10-29)


### Bug Fixes

* improve query planning time
([#1326](#1326))
([373cf2a](373cf2a))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved query planning time performance.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants