Skip to content

chore(DataMapper): Add ForEachGroupItem and GroupingStrategy#3154

Merged
lordrip merged 1 commit intoKaotoIO:mainfrom
igarashitm:2321-2861
Apr 23, 2026
Merged

chore(DataMapper): Add ForEachGroupItem and GroupingStrategy#3154
lordrip merged 1 commit intoKaotoIO:mainfrom
igarashitm:2321-2861

Conversation

@igarashitm
Copy link
Copy Markdown
Member

@igarashitm igarashitm commented Apr 22, 2026

Fixes: #2861

Summary by CodeRabbit

  • New Features

    • Added support for for-each-group mapping constructs with four configurable grouping strategies: group-by, group-adjacent, group-starting-with, and group-ending-with
    • Grouping expressions can now be specified per for-each-group item
  • Tests

    • Comprehensive test coverage for for-each-group functionality
    • Enhanced regression tests for path resolution in for-each items

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e4f2c5c2-55c6-4624-935d-811d23453edd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.88%. Comparing base (e309e18) to head (474d515).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##             main    #3154    +/-   ##
========================================
  Coverage   91.88%   91.88%            
========================================
  Files         606      606            
  Lines       23350    23373    +23     
  Branches     5534     5342   -192     
========================================
+ Hits        21454    21477    +23     
- Misses       1786     1894   +108     
+ Partials      110        2   -108     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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: 1

🧹 Nitpick comments (1)
packages/ui/src/models/datamapper/mapping.ts (1)

263-274: Optional: extract the shared sortItems clone logic.

doClone() here and in ForEachItem (lines 217-226) duplicate identical sortItems.map(...) logic. A small helper (e.g., cloneSortItems(sortItems: SortItem[])) would remove the duplication and reduce drift risk if SortItem grows fields.

♻️ Proposed refactor
+const cloneSortItems = (sortItems: SortItem[]): SortItem[] =>
+  sortItems.map((sort) => ({ expression: sort.expression, order: sort.order }) as SortItem);
+
 export class ForEachItem extends InstructionItem implements IExpressionHolder {
   ...
   doClone() {
     const cloned = new ForEachItem(this.parent);
-    cloned.sortItems = this.sortItems.map((sort) => {
-      return {
-        expression: sort.expression,
-        order: sort.order,
-      } as SortItem;
-    });
+    cloned.sortItems = cloneSortItems(this.sortItems);
     return cloned;
   }
 ...
 export class ForEachGroupItem extends InstructionItem implements IExpressionHolder {
   ...
   doClone() {
     const cloned = new ForEachGroupItem(this.parent);
-    cloned.sortItems = this.sortItems.map((sort) => {
-      return {
-        expression: sort.expression,
-        order: sort.order,
-      } as SortItem;
-    });
+    cloned.sortItems = cloneSortItems(this.sortItems);
     return cloned;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/models/datamapper/mapping.ts` around lines 263 - 274, The two
doClone implementations in ForEachGroupItem and ForEachItem duplicate the same
sortItems.map(...) cloning logic; extract that into a small helper function
(e.g., cloneSortItems(sortItems: SortItem[]): SortItem[]) that returns a deep
copy of each SortItem, then replace the inline map in ForEachGroupItem.doClone
and ForEachItem.doClone to call cloneSortItems(this.sortItems) to remove
duplication and centralize future changes to SortItem cloning.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/ui/src/models/datamapper/mapping.test.ts`:
- Around line 199-211: The current test for ForEachGroupItem.contextPath only
compares firstCall.contextPath to secondCall.contextPath which can be the same
MappingTree reference and thus masks mutations; update the test to assert on the
specific PathExpression fields that extractContextPath populates (e.g.,
pathSegments, isRelative, documentReferenceName) for both firstCall and
secondCall to ensure the returned PathExpression objects are independent and
stable across calls, and apply the same replacement to the analogous ForEachItem
test that mirrors this block; locate the contextPath getter usage on the
ForEachGroupItem and ForEachItem tests and replace the weak toEqual check with
explicit assertions on those PathExpression fields.

---

Nitpick comments:
In `@packages/ui/src/models/datamapper/mapping.ts`:
- Around line 263-274: The two doClone implementations in ForEachGroupItem and
ForEachItem duplicate the same sortItems.map(...) cloning logic; extract that
into a small helper function (e.g., cloneSortItems(sortItems: SortItem[]):
SortItem[]) that returns a deep copy of each SortItem, then replace the inline
map in ForEachGroupItem.doClone and ForEachItem.doClone to call
cloneSortItems(this.sortItems) to remove duplication and centralize future
changes to SortItem cloning.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d4f421f4-d1b6-4f05-b66e-9777c25407df

📥 Commits

Reviewing files that changed from the base of the PR and between e309e18 and 2bdd882.

📒 Files selected for processing (2)
  • packages/ui/src/models/datamapper/mapping.test.ts
  • packages/ui/src/models/datamapper/mapping.ts

Comment thread packages/ui/src/models/datamapper/mapping.test.ts
@sonarqubecloud
Copy link
Copy Markdown

@igarashitm igarashitm marked this pull request as ready for review April 23, 2026 00:35
@igarashitm igarashitm requested a review from a team April 23, 2026 00:35
@lordrip lordrip merged commit 9d54d1a into KaotoIO:main Apr 23, 2026
14 of 15 checks passed
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.

for-each-group: S.2: Create mapping model classes

2 participants