Skip to content

fix: merge inline fragment and field selections together#1240

Merged
ysmolski merged 1 commit intomasterfrom
yury/eng-7133-fix-merging-fields-and-fragments-in-normalization
Jul 22, 2025
Merged

fix: merge inline fragment and field selections together#1240
ysmolski merged 1 commit intomasterfrom
yury/eng-7133-fix-merging-fields-and-fragments-in-normalization

Conversation

@ysmolski
Copy link
Copy Markdown
Contributor

@ysmolski ysmolski commented Jul 18, 2025

This change fixes normalization for cases like the following:

query fragmentsWithFields {
    dog {
	    extras {
		    ... on DogExtra {
			    string
		    }
	    }
	    extras {
		    ... on DogExtra {
			    string
			    string1
		    }
	    }
    }
}

I have marged two different visitors and their tests into a single visitor. EnterSelectionSets from two stages were merged into one, but with the following differences:

* Internal loop was optimized,
* Early return happens only when something is merged.

Summary by CodeRabbit

  • Refactor

    • Improved merging logic by consolidating field and inline fragment merging into a single process, enhancing normalization of GraphQL queries.
    • Removed redundant and obsolete field selection merging code and related methods.
    • Updated and expanded test coverage to reflect the new merging approach, including more complex scenarios involving fields, fragments, aliases, and directives.
    • Refined comments and documentation for greater clarity throughout the normalization codebase.
  • Tests

    • Enhanced and reorganized tests to cover both field and fragment merging, ensuring robust validation of the updated normalization logic.
    • Added new test cases verifying deep nested fragment and field merging behavior in normalization.

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 Jul 18, 2025

Walkthrough

This change removes the dedicated field selection merging logic and its tests, integrates field merging into the existing inline fragment merging visitor (renamed and expanded to handle both fields and inline fragments), updates or adds comments for clarity, and consolidates and broadens test coverage to reflect the new merging approach.

Changes

File(s) Change Summary
v2/pkg/ast/ast_selection.go Removed two Document methods: SelectionIsFieldSelection and SelectionIsInlineFragmentSelection.
v2/pkg/astnormalization/abstract_field_normalizer.go Removed call to mergeFieldSelections from normalizer initialization sequence.
v2/pkg/astnormalization/astnormalization.go Updated comments, removed mergeFieldSelections from walker setup, and refined documentation.
v2/pkg/astnormalization/field_deduplication.go
v2/pkg/astnormalization/fragment_definition_removal.go
v2/pkg/astnormalization/remove_self_aliasing.go
Added or updated comments describing function purposes; no logic changes.
v2/pkg/astnormalization/field_selection_merging.go
v2/pkg/astnormalization/field_selection_merging_test.go
Deleted field selection merging logic and its associated tests.
v2/pkg/astnormalization/inline_fragment_selection_merging.go Renamed and expanded visitor to handle both inline fragment and field merging; added supporting methods.
v2/pkg/astnormalization/inline_fragment_selection_merging_test.go Renamed and significantly expanded test suite to cover both field and fragment merging scenarios.
v2/pkg/astnormalization/astnormalization_test.go Added new test cases verifying deep inline fragment spreads and nested fragment merging in normalization.

Estimated code review effort

4 (60–120 minutes)
This change involves removal and consolidation of core AST normalization logic, significant test restructuring, and expansion of merging algorithms, requiring a thorough review of both logic and test coverage.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d56e3d0 and a6a620b.

📒 Files selected for processing (11)
  • v2/pkg/ast/ast_selection.go (0 hunks)
  • v2/pkg/astnormalization/abstract_field_normalizer.go (0 hunks)
  • v2/pkg/astnormalization/astnormalization.go (5 hunks)
  • v2/pkg/astnormalization/astnormalization_test.go (1 hunks)
  • v2/pkg/astnormalization/field_deduplication.go (1 hunks)
  • v2/pkg/astnormalization/field_selection_merging.go (0 hunks)
  • v2/pkg/astnormalization/field_selection_merging_test.go (0 hunks)
  • v2/pkg/astnormalization/fragment_definition_removal.go (1 hunks)
  • v2/pkg/astnormalization/inline_fragment_selection_merging.go (2 hunks)
  • v2/pkg/astnormalization/inline_fragment_selection_merging_test.go (6 hunks)
  • v2/pkg/astnormalization/remove_self_aliasing.go (1 hunks)
💤 Files with no reviewable changes (4)
  • v2/pkg/astnormalization/abstract_field_normalizer.go
  • v2/pkg/ast/ast_selection.go
  • v2/pkg/astnormalization/field_selection_merging.go
  • v2/pkg/astnormalization/field_selection_merging_test.go
✅ Files skipped from review due to trivial changes (1)
  • v2/pkg/astnormalization/fragment_definition_removal.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • v2/pkg/astnormalization/remove_self_aliasing.go
  • v2/pkg/astnormalization/field_deduplication.go
  • v2/pkg/astnormalization/astnormalization.go
  • v2/pkg/astnormalization/inline_fragment_selection_merging.go
  • v2/pkg/astnormalization/astnormalization_test.go
⏰ 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). (2)
  • GitHub Check: Build and test (go 1.23 / windows-latest)
  • GitHub Check: Build and test (go 1.23 / windows-latest)
🔇 Additional comments (4)
v2/pkg/astnormalization/inline_fragment_selection_merging_test.go (4)

5-6: LGTM! Test structure properly reflects the merged functionality.

The function rename and reorganization into distinct test groups ("just fragments", "just fields", "fragments and fields") clearly reflects the consolidation of inline fragment and field selection merging logic into a single visitor.


6-125: Comprehensive fragment merging test coverage.

The "just fragments" section provides excellent coverage of inline fragment merging scenarios, including edge cases for type conditions, directive handling, and field deduplication. The expected outputs correctly demonstrate GraphQL merging semantics.


126-219: Well-designed field selection merging tests.

The "just fields" section effectively tests the integrated field selection merging functionality with good coverage of edge cases including alias conflicts, directive handling, and nested field merging. The expected outputs correctly demonstrate proper field merging behavior.


220-335: Excellent validation of the core PR objective.

The "fragments and fields" section provides crucial test coverage for the main issue addressed by this PR - merging multiple selections on the same field with overlapping inline fragments. The complex "mixed heavily fields with deep inline fragments" test case is particularly valuable as it validates the fix in realistic, nested scenarios.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch yury/eng-7133-fix-merging-fields-and-fragments-in-normalization

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@ysmolski ysmolski force-pushed the yury/eng-7133-fix-merging-fields-and-fragments-in-normalization branch from 2489f15 to e9d0f5b Compare July 18, 2025 17:21
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 (1)
v2/pkg/astnormalization/inline_fragment_field_selection_merging_test.go (1)

1-335: Excellent test suite consolidation and coverage.

This comprehensive test file successfully replaces the previous separate fragment and field merging tests with a unified, well-structured test suite. The tests thoroughly validate the new mergeInlineFragmentFieldSelections function across a wide range of scenarios from simple cases to complex nested structures.

Consider adding brief comments for the more complex test cases to document the expected merging behavior, particularly around duplicate field preservation.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2489f15 and e9d0f5b.

📒 Files selected for processing (1)
  • v2/pkg/astnormalization/inline_fragment_field_selection_merging_test.go (1 hunks)
⏰ 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). (2)
  • GitHub Check: Build and test (go 1.23 / windows-latest)
  • GitHub Check: Build and test (go 1.23 / windows-latest)
🔇 Additional comments (5)
v2/pkg/astnormalization/inline_fragment_field_selection_merging_test.go (5)

1-3: LGTM! Clean package structure.

The package declaration and imports are minimal and appropriate for this test file.


5-6: LGTM! Well-structured test organization.

The test function is properly organized with clear categorization using t.Run for different merging scenarios.


6-125: LGTM! Comprehensive fragment merging tests.

The fragment tests thoroughly cover the merging scenarios including edge cases with directives and type conditions. The expected behavior of preserving duplicate fields in merged fragments appears intentional for the normalization process.


126-219: LGTM! Thorough field merging test coverage.

The field tests appropriately cover various merging scenarios including depth variations, aliasing, and directive handling. The test cases correctly demonstrate when fields should and shouldn't merge.


220-335: LGTM! Excellent comprehensive test coverage.

The mixed fragment and field tests provide thorough coverage of complex real-world scenarios. The "mixed heavily fields with deep inline fragments" test is particularly valuable as it validates the merging behavior across multiple levels of nesting and different fragment types.

@ysmolski ysmolski force-pushed the yury/eng-7133-fix-merging-fields-and-fragments-in-normalization branch 2 times, most recently from 5c73a0d to 4dc12a6 Compare July 21, 2025 09:07
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/astnormalization/inline_fragment_selection_merging.go (2)

10-18: Consider renaming the function to match the expanded functionality.

The function name mergeInlineFragmentSelections doesn't reflect that it now also merges field selections. Consider renaming it to mergeInlineFragmentFieldSelections for consistency with the visitor name and actual functionality.

-// mergeInlineFragmentSelections registers a visitor that
-// merges inline fragment and field selections.
-func mergeInlineFragmentSelections(walker *astvisitor.Walker) {
+// mergeInlineFragmentFieldSelections registers a visitor that
+// merges inline fragment and field selections.
+func mergeInlineFragmentFieldSelections(walker *astvisitor.Walker) {

107-107: Use conventional loop variable naming.

Consider using j instead of k for the inner loop variable, as this is the standard convention for nested loops.

-		for k := i + 1; k < len(selectionRefs); k++ {
+		for j := i + 1; j < len(selectionRefs); j++ {

Also update all references to k within the loop to j.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9d0f5b and 5c73a0d.

📒 Files selected for processing (10)
  • v2/pkg/ast/ast_selection.go (0 hunks)
  • v2/pkg/astnormalization/abstract_field_normalizer.go (0 hunks)
  • v2/pkg/astnormalization/astnormalization.go (4 hunks)
  • v2/pkg/astnormalization/field_deduplication.go (1 hunks)
  • v2/pkg/astnormalization/field_selection_merging.go (0 hunks)
  • v2/pkg/astnormalization/field_selection_merging_test.go (0 hunks)
  • v2/pkg/astnormalization/fragment_definition_removal.go (1 hunks)
  • v2/pkg/astnormalization/inline_fragment_selection_merging.go (3 hunks)
  • v2/pkg/astnormalization/inline_fragment_selection_merging_test.go (6 hunks)
  • v2/pkg/astnormalization/remove_self_aliasing.go (1 hunks)
💤 Files with no reviewable changes (4)
  • v2/pkg/astnormalization/abstract_field_normalizer.go
  • v2/pkg/ast/ast_selection.go
  • v2/pkg/astnormalization/field_selection_merging_test.go
  • v2/pkg/astnormalization/field_selection_merging.go
✅ Files skipped from review due to trivial changes (1)
  • v2/pkg/astnormalization/field_deduplication.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • v2/pkg/astnormalization/remove_self_aliasing.go
  • v2/pkg/astnormalization/fragment_definition_removal.go
  • v2/pkg/astnormalization/astnormalization.go
🧰 Additional context used
🧬 Code Graph Analysis (1)
v2/pkg/astnormalization/inline_fragment_selection_merging.go (1)
v2/pkg/ast/ast_selection.go (3)
  • SelectionKind (11-11)
  • SelectionKindInlineFragment (17-17)
  • SelectionKindField (15-15)
⏰ 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). (2)
  • GitHub Check: Build and test (go 1.23 / windows-latest)
  • GitHub Check: Build and test (go 1.23 / windows-latest)
🔇 Additional comments (4)
v2/pkg/astnormalization/inline_fragment_selection_merging_test.go (1)

5-334: Comprehensive test coverage for the expanded functionality.

The test restructuring and expansion effectively covers the new field merging capabilities alongside the existing inline fragment merging. The organization into "just fragments", "just fields", and "fragments and fields" sections provides clear separation of concerns and makes the tests easy to understand and maintain.

v2/pkg/astnormalization/inline_fragment_selection_merging.go (3)

59-93: Well-implemented field merging logic.

The new methods follow the same pattern as the existing fragment merging logic, ensuring consistency. The checks for field name, alias, and directive equality are comprehensive and correct for determining when fields can be safely merged.


94-143: Correct implementation with early return optimization.

The unified handling of inline fragments and fields is well-structured. The early return after each merge is a good optimization that prevents index-related issues and ensures the selection set is re-evaluated after modifications.

Note that the algorithm has O(n²) complexity for n selections, which could be a concern for deeply nested queries with many selections. However, this is likely acceptable given typical GraphQL query structures.


129-140: RemoveFromSelectionSet slicing is correct; no index-shift issues
RemoveFromSelectionSet simply removes the element at the given index via a slice operation, and every call is followed by RevisitNode() and an immediate return—so you never continue iterating on a shifted slice. No changes needed.

@ysmolski ysmolski force-pushed the yury/eng-7133-fix-merging-fields-and-fragments-in-normalization branch 5 times, most recently from 799b16e to d56e3d0 Compare July 21, 2025 13:57
Comment thread v2/pkg/astnormalization/inline_fragment_selection_merging.go
Copy link
Copy Markdown
Member

@jensneuse jensneuse left a comment

Choose a reason for hiding this comment

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

Looks ok but also check with @devsergiy
One comment you could look into or ignore.

@devsergiy
Copy link
Copy Markdown
Member

we won't merge this PR immediately, we need to run it through regression test suite

This change fixes normalization for cases like the following:

    query fragmentsWithFields {
	    dog {
		    extras {
			    ... on DogExtra {
				    string
			    }
		    }
		    extras {
			    ... on DogExtra {
				    string
				    string1
			    }
		    }
	    }
    }

I have marged two different visitors and their tests into a single
visitor "mergeInlineFragmentSelections".
EnterSelectionSets from two stages were merged into one,
but with the following differences:

    * Internal loop was optimized,
    * Early return happens only when something is merged.
@ysmolski ysmolski force-pushed the yury/eng-7133-fix-merging-fields-and-fragments-in-normalization branch from d56e3d0 to a6a620b Compare July 22, 2025 10:57
@ysmolski ysmolski changed the title fix: merge infline fragment and field selections together fix: merge inline fragment and field selections together Jul 22, 2025
@ysmolski ysmolski merged commit 99f2b32 into master Jul 22, 2025
11 checks passed
@ysmolski ysmolski deleted the yury/eng-7133-fix-merging-fields-and-fragments-in-normalization branch July 22, 2025 16:16
ysmolski pushed a commit that referenced this pull request Jul 22, 2025
🤖 I have created a release *beep* *boop*
---


##
[2.0.0-rc.209](v2.0.0-rc.208...v2.0.0-rc.209)
(2025-07-22)


### Bug Fixes

* merge inline fragment and field selections together
([#1240](#1240))
([99f2b32](99f2b32))

---
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**
* Resolved an issue where inline fragment and field selections were not
merged correctly.

* **Documentation**
* Added a changelog entry for version 2.0.0-rc.209 detailing the latest
bug fix.

<!-- 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.

3 participants