Skip to content

Introduce modification container abstraction#823

Open
Meklo wants to merge 57 commits into
mainfrom
marcellinh/modifications_containers
Open

Introduce modification container abstraction#823
Meklo wants to merge 57 commits into
mainfrom
marcellinh/modifications_containers

Conversation

@Meklo

@Meklo Meklo commented May 28, 2026

Copy link
Copy Markdown
Contributor

PR Summary

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors modification ownership from group-only to a polymorphic container model (GROUP/COMPOSITE): adds container enum and interface, updates entities to use container_id/container_type, rewrites repository queries and composite recursion, implements container-aware move logic, updates service/controller APIs and tests, and adds DB migrations to backfill container columns.

Changes

Polymorphic Container Model Refactoring

Layer / File(s) Summary
Container type abstraction and interface
src/main/java/org/gridsuite/modification/server/entities/ModificationContainerType.java, src/main/java/org/gridsuite/modification/server/entities/ModificationContainer.java
ModificationContainerType enum defines GROUP and COMPOSITE; ModificationContainer interface declares container identity, type, and child-management methods.
Modification entity: container fields & lifecycle
src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java
Add containerId and containerType, remove group association, switch to manually-assigned identifier superclass, add attach/detach lifecycle methods and a container index.
ModificationGroupEntity container implementation
src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java
ModificationGroupEntity implements ModificationContainer, maps children via container_id with SQL restriction for GROUP, provides positional add via ContainerOps, and updates setModifications.
CompositeModificationEntity container implementation
src/main/java/org/gridsuite/modification/server/entities/CompositeModificationEntity.java
CompositeModificationEntity implements ModificationContainer, maps children via container_id with SQL restriction for COMPOSITE, narrows cascade, replaces setModifications, and delegates positional add to ContainerOps.
Shared container child-management utility
src/main/java/org/gridsuite/modification/server/entities/ContainerOps.java
Package-private helper with static insert that clamps index, attaches child to owner, inserts into list, and renumbers modificationsOrder.
Repository query refactor: container-scoped lookups
src/main/java/org/gridsuite/modification/server/repositories/ModificationRepository.java
Replace group-id queries with containerId/containerType equivalents, add container-filtered methods and bulk container IN support.
Composite traversal: recursive CTE rewrite
src/main/java/org/gridsuite/modification/server/repositories/ModificationRepository.java
Rewrite composite descendant resolution and composites max-depth calculation using native recursive CTEs constrained to container_type = 'COMPOSITE'.
Application mapping & repo updates
src/main/java/org/gridsuite/modification/server/entities/ModificationApplicationEntity.java, src/main/java/org/gridsuite/modification/server/repositories/ModificationApplicationRepository.java
toModificationApplicationInfos() uses modification.containerId for groupUuid; repository replaces group-id delete methods with container-id variants and updates EntityGraph to load only modification.
Network repository: container-aware move core
src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java
New container-type-aware moveModifications overload loads source/target by type+id, filters non-stashed items, prevents composite cycles, performs same-container reorder or cross-container insertion, conditionally deletes application infos, and auto-creates GROUP targets when missing.
Network repository: integration and deletions
src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java
Switch internal query paths and mutation logic to container model: metadata/active retrieval, composite checks, reorder lookups, deletion validation, composite-subtree deletion breadth traversal, and getContainerType classifier.
Service & controller: container-aware moves
src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java, src/main/java/org/gridsuite/modification/server/NetworkModificationController.java, src/main/java/org/gridsuite/modification/server/CompositeController.java, src/main/java/org/gridsuite/modification/server/elasticsearch/ModificationApplicationInfosService.java
Service resolves container types and invokes repository move overload, computes conditional apply; controller forwards container params and updated MOVE semantics; composite-specific move endpoint removed; application-info deletions use container-based repo methods.
Elasticsearch supervision update
src/main/java/org/gridsuite/modification/server/service/SupervisionService.java
reindexByNetworkUuid now uses findWithModificationByNetworkUuid (no group join) as the source for indexing documents.
Database migration to container model
src/main/resources/db/changelog/changesets/changelog_20260522T151740Z.xml, src/main/resources/db/changelog/db.changelog-master.yaml
Add container_id and container_type columns, backfill from existing group_id and composite relationships, create (container_type, container_id) index, drop legacy group_id FK/column and composite link table with rollback.
Equipment entities: ID cleanup
src/main/java/org/gridsuite/modification/server/entities/equipment/creation/ConverterStationCreationEntity.java, src/main/java/org/gridsuite/modification/server/entities/equipment/creation/LccConverterStationCreationEntity.java
Remove duplicate JPA id fields and unused imports; rely on inherited identifier from superclass.
Tests: controller & ownership assertions
src/test/java/org/gridsuite/modification/server/CompositeControllerTest.java
Sub-modification move tests now use generic /v1/groups/{groupUuid} MOVE endpoint with originGroupUuid and assert containerId values instead of group references.
Tests: repository/service updates
src/test/java/org/gridsuite/modification/server/service/ModificationRepositoryTest.java, src/test/java/org/gridsuite/modification/server/service/ModificationIndexationTest.java
Update move calls to container-type-aware overloads (explicit ModificationContainerType.GROUP where applicable), prepare empty target groups in setups, and adjust expected SQL statement counts.
Tests: supervision & SQL-count adjustments
src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java, src/test/java/org/gridsuite/modification/server/modifications/CompositeModificationsTest.java, src/test/java/org/gridsuite/modification/server/modifications/tabularmodifications/TabularGeneratorModificationsTest.java
SupervisionTest stubs getContainerId() and uses findWithModificationByNetworkUuid; other tests adjust SQL request-count expectations to match container-model query changes.

Suggested reviewers

  • Mathieu-Deharbe
  • SlimaneAmar
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is empty, providing no details about the changes, rationale, testing, or migration considerations for this significant architectural refactor. Add a detailed description explaining what the modification container abstraction is, why it was introduced, what changed in the architecture, and any migration or testing notes for reviewers.
Docstring Coverage ⚠️ Warning Docstring coverage is 7.48% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Introduce modification container abstraction' accurately captures the main change—introducing a new ModificationContainer interface and refactoring the codebase to use containers instead of groups as the primary modification organization model.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 14

🧹 Nitpick comments (1)
src/main/java/org/gridsuite/modification/server/repositories/ModificationApplicationRepository.java (1)

21-23: ⚡ Quick win

Align parameter names with the container model.

groupUuid is now misleading in both signatures since the method contract is container-based. Renaming to containerIds (or modificationContainerIds) will make call sites clearer and reduce migration confusion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/org/gridsuite/modification/server/repositories/ModificationApplicationRepository.java`
around lines 21 - 23, Rename the misleading parameter name groupUuid to a
container-based name in the two repository method signatures: change the
parameter in deleteAllByNetworkUuidAndModificationContainerIdIn(UUID
networkUuid, List<UUID> groupUuid) and
deleteAllByModificationContainerIdIn(List<UUID> groupUuid) to something like
containerIds or modificationContainerIds to reflect the container model; update
all call sites and tests that reference these method signatures to use the new
parameter name so compilation and code clarity are preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/org/gridsuite/modification/server/entities/CompositeModificationEntity.java`:
- Around line 80-90: setModifications currently clears the `@OneToMany` collection
(this.modifications.clear()) which causes Hibernate to mark existing children as
orphans and schedule deletes before you re-add them; instead, modify the
association incrementally in setModifications(List<ModificationEntity>
newChildren): validate newChildren non-null, iterate newChildren to update each
child's setModificationsOrder(i) and attachToContainer(this) for new or existing
children, add only genuinely new entities to this.modifications, and remove only
those children present in this.modifications but absent from newChildren so
orphanRemoval behaves correctly; this preserves managed instances and avoids
delete/insert churn and constraint/order issues.

In
`@src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java`:
- Around line 142-149: The attachToContainer/detachFromContainer helpers in
ModificationEntity currently only update containerType but must also keep the
mapped scalar FK containerId in sync; update
attachToContainer(ModificationContainer) to assign this.containerId =
container.getId() (or the container's identifier accessor) and update
detachFromContainer() to set this.containerId = null so the in-memory entity
matches the collection-managed FK (this is required because
ModificationApplicationEntity.toModificationApplicationInfos() reads
getModification().getContainerId()).

In
`@src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java`:
- Around line 68-78: setModifications currently clears the modifications list
then re-attaches only survivors, leaving omitted children with stale container
metadata; modify setModifications in ModificationGroupEntity to first compute
the set of removed children (elements in the existing modifications collection
that are not present in the incoming newChildren list) and for each removed
child call the appropriate detach logic on ModificationEntity (e.g. clear
container id/type or invoke a detachFromContainer method) before
clearing/replacing the collection, then attach and setModificationsOrder on the
surviving newChildren as today; ensure you update the modifications collection
only after detaching removed children so container ownership remains consistent.

In
`@src/main/java/org/gridsuite/modification/server/NetworkModificationController.java`:
- Line 18: Remove the unused import of ModificationContainerType from
NetworkModificationController: locate the import line "import
org.gridsuite.modification.server.entities.ModificationContainerType;" in the
NetworkModificationController class and delete it so Checkstyle no longer fails
for an unused import.
- Around line 104-116: The MOVE branch passes sourceContainerId
(originGroupUuid) directly to networkModificationService.moveModifications even
when it's null; restore the previous fallback by defaulting sourceContainerId to
targetContainerId when null for MOVE. Update the switch MOVE case to use
(sourceContainerId == null ? targetContainerId : sourceContainerId) before
calling networkModificationService.moveModifications (and keep passing
targetContainerId, beforeModificationUuid, modificationContextInfos.getFirst(),
modificationContextInfos.getSecond()) so same-container moves work when
originGroupUuid is omitted.

In
`@src/main/java/org/gridsuite/modification/server/repositories/ModificationRepository.java`:
- Around line 110-175: Fix the Checkstyle failures in the multi-line
`@NativeQuery` text blocks by normalizing indentation and blank-line placement:
ensure each triple-quoted SQL block aligns with the annotation (no leading
spaces inside the text block), remove or add blank lines so there are no extra
blank lines inside the text blocks, and keep consistent indentation for all
three methods findOnlyCompositeChildrenUuids, findAllChildrenUuids, and
getCompositesMaxDepth (and the preceding CompositeDepth interface section) so
the opening and closing triple quotes are directly under `@NativeQuery` and the
SQL lines have consistent left alignment; after fixing the text-block formatting
re-run the formatter/checkstyle to confirm the errors on the affected blocks are
resolved.

In
`@src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java`:
- Line 227: The code in NetworkModificationRepository creates
destinationModificationEntities with improper spacing and missing braces; split
the combined statements into two properly spaced lines (one for creating the
ArrayList from destinationModificationGroupEntity.getModifications() and a
separate line calling removeIf(Objects::isNull)), normalize spaces so there is a
single space around operators and after commas, and add braces for the
single-line if statements referenced (the two ifs around lines noted) so they
become full-blocks with { ... } — apply the same formatting and brace fixes to
the other occurrences mentioned (the similar hunk at the other lines 335 and
384-385) to satisfy SingleSpaceSeparator, EmptyLineSeparator, and NeedBraces
checkstyle rules.
- Around line 188-191: The loop over modifications is double-incrementing the
order: modificationGroupEntity.addModification(m, order++) consumes one
post-increment and then m.setModificationsOrder(order); order++ increments
again, producing gaps. Fix by using a single increment operation: pass the
current order into addModification and set the same value on m, then increment
order once (or use a single post-increment consistently). Update the loop around
modificationGroupEntity.addModification(...), ModificationEntity m,
setModificationsOrder(...) and the order variable so only one increment occurs
per iteration.
- Around line 1064-1071: The getContainerType method in
NetworkModificationRepository should not return null for unknown container
UUIDs; replace the final return null with throwing a
NetworkModificationException (include a clear message like "Unknown container
UUID: <uuid>") so callers receive a domain error. Locate getContainerType and
after checking modificationGroupRepository.findById(containerUuid) and
compositeModificationRepository.findById(containerUuid), throw new
NetworkModificationException including the containerUuid and a descriptive
message instead of returning null; ensure the method signature and imports
reference NetworkModificationException and that any callers (e.g., move flow)
will handle or propagate this domain exception.
- Around line 266-287: The same-container branch drops stashed children because
sourceChildren is created by filtering out stashed items before reordering; when
sameContainer is true you must preserve stashed modifications. Change the logic
so you build a fullChildren list from source.getModifications() that includes
stashed items and use that full list for publishChildren (and for re-inserting
order via insertModifications), while still computing moved via
removeModifications(fullChildren, modificationUuids) or by deriving moved
separately; ensure functions referenced (source.getModifications(),
removeModifications, insertModifications, publishChildren, sameContainer)
operate on the full list so stashed children are not detached during
same-container reorders.

In
`@src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java`:
- Line 36: The import of ModificationGroupRepository in
NetworkModificationService is unused and causing a Checkstyle failure; open
NetworkModificationService.java and remove the line importing
org.gridsuite.modification.server.repositories.ModificationGroupRepository
(ensure there are no references to ModificationGroupRepository in methods of
NetworkModificationService or replace them with the correct repository type if
mistakenly used), then recompile/run checks to confirm the Checkstyle error is
resolved.

In `@src/main/resources/config/application.yaml`:
- Line 18: The default config enables Hibernate SQL logging via the show_sql
property (hibernate.show_sql), which should not be on in the default runtime
profile; remove or set show_sql: false from the base application.yaml and
instead place show_sql: true in a non-production profile (e.g.,
application-dev.yaml or under a spring.profiles: dev section) so only the
development/local profile (referencing the show_sql / hibernate.show_sql
property) emits SQL logs.

In `@src/main/resources/db/changelog/changesets/changelog_20260522T151740Z.xml`:
- Around line 4-40: The migration leaves modification.container_id and
modification.container_type nullable; add a step to make them NOT NULL after the
backfill and ensure there are no leftover NULLs: first run the existing backfill
UPDATEs (they reference group_id, composite_modification_sub_modifications, and
set container_id/container_type), then add a precondition or validation that
SELECT COUNT(*) FROM modification WHERE container_id IS NULL OR container_type
IS NULL returns zero, and finally run ALTER TABLE modification ALTER COLUMN
container_id SET NOT NULL and ALTER COLUMN container_type SET NOT NULL (or the
equivalent <modifyDataType>/<addNotNullConstraint> in your changelog), keeping
the index modification_container_idx and drop steps unchanged; if any rows
remain, fail the migration so you can handle or backfill them explicitly.

In
`@src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java`:
- Line 90: Restore the Mockito stubbing for modificationMock.getContainerId() in
testReindexElements so groupUuid is set and asserted: re-add a line stubbing
modificationMock.getContainerId() to return groupMock (or the UUID/value used
elsewhere), then update the test to assert that
ModificationApplicationEntity.toModificationApplicationInfos() propagates that
container id (groupUuid) into the resulting infos; target the modificationMock
and groupMock stubs and the testReindexElements method where
toModificationApplicationInfos() is exercised.

---

Nitpick comments:
In
`@src/main/java/org/gridsuite/modification/server/repositories/ModificationApplicationRepository.java`:
- Around line 21-23: Rename the misleading parameter name groupUuid to a
container-based name in the two repository method signatures: change the
parameter in deleteAllByNetworkUuidAndModificationContainerIdIn(UUID
networkUuid, List<UUID> groupUuid) and
deleteAllByModificationContainerIdIn(List<UUID> groupUuid) to something like
containerIds or modificationContainerIds to reflect the container model; update
all call sites and tests that reference these method signatures to use the new
parameter name so compilation and code clarity are preserved.
🪄 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: 8e51e903-6868-420a-bb45-cff1571d66ed

📥 Commits

Reviewing files that changed from the base of the PR and between 33db2f2 and 2511fb3.

📒 Files selected for processing (19)
  • src/main/java/org/gridsuite/modification/server/CompositeController.java
  • src/main/java/org/gridsuite/modification/server/NetworkModificationController.java
  • src/main/java/org/gridsuite/modification/server/elasticsearch/ModificationApplicationInfosService.java
  • src/main/java/org/gridsuite/modification/server/entities/CompositeModificationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/ContainerOps.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationApplicationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationContainer.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationContainerType.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java
  • src/main/java/org/gridsuite/modification/server/repositories/ModificationApplicationRepository.java
  • src/main/java/org/gridsuite/modification/server/repositories/ModificationRepository.java
  • src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java
  • src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java
  • src/main/resources/config/application.yaml
  • src/main/resources/db/changelog/changesets/changelog_20260522T151740Z.xml
  • src/main/resources/db/changelog/db.changelog-master.yaml
  • src/test/java/org/gridsuite/modification/server/CompositeControllerTest.java
  • src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java
💤 Files with no reviewable changes (1)
  • src/main/java/org/gridsuite/modification/server/CompositeController.java

Comment thread src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java Outdated
Comment thread src/main/resources/config/application.yaml Outdated
Comment thread src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java (1)

227-239: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Delay destination creation until the move set is known to be non-empty.

Line 229 loads or creates the target container before Line 237 knows whether any requested UUID actually belongs to the source. A move request containing only unknown UUIDs will return an empty result but still persist a brand-new empty destination group.

Suggested change
         ModificationContainer source = loadContainer(sourceType, sourceContainerId);
         boolean sameContainer = sourceType == targetType && sourceContainerId.equals(targetContainerId);
-        ModificationContainer target = sameContainer ? source : loadOrCreateContainer(targetType, targetContainerId);
 
         List<ModificationEntity> sourceChildren = source.getModifications().stream()
                 .filter(Objects::nonNull)
                 .filter(m -> !Boolean.TRUE.equals(m.getStashed()))
@@
         if (moved.isEmpty()) {
             return List.of();
         }
+
+        ModificationContainer target = sameContainer ? source : loadOrCreateContainer(targetType, targetContainerId);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java`
around lines 227 - 239, The code currently calls
loadOrCreateContainer(targetType, targetContainerId) before knowing if any
modifications will be moved, causing empty target groups to be persisted; change
the flow so you first load the source via loadContainer(sourceType,
sourceContainerId), build sourceChildren, compute moved =
removeModifications(sourceChildren, modificationUuids) and if moved is empty
return early, and only then (when moved is non-empty and sameContainer is false)
call loadOrCreateContainer(targetType, targetContainerId) to obtain the target
ModificationContainer; update any logic that assumed target was already
available to run after this deferred creation.
♻️ Duplicate comments (3)
src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java (1)

90-90: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore getContainerId() stubbing to keep this test meaningful.

The commented-out stub leaves containerId unverified in testReindexElements. Since ModificationApplicationEntity.toModificationApplicationInfos() now reads modification.getContainerId(), this test should stub that value explicitly and assert it is propagated.

Proposed fix
-        //Mockito.when(modificationMock.getContainerId()).thenReturn(groupMock);
+        Mockito.when(modificationMock.getContainerId()).thenReturn(groupUuid);

Add assertion after line 102:

         verify(modificationApplicationInfosRepository, times(1)).saveAll(modificationListCaptor.capture());
         assertThat(modificationListCaptor.getValue()).usingRecursiveComparison().isEqualTo(allModifications.stream().map(ModificationApplicationEntity::toModificationApplicationInfos).toList());
+        assertThat(modificationListCaptor.getValue()).allSatisfy(infos -> assertEquals(groupUuid, infos.getGroupUuid()));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java`
at line 90, Restore the Mockito stub for modificationMock.getContainerId() in
testReindexElements so the test supplies a deterministic containerId (e.g.,
return groupMock) because
ModificationApplicationEntity.toModificationApplicationInfos() now reads
modification.getContainerId(); add a
Mockito.when(modificationMock.getContainerId()).thenReturn(groupMock) near the
other stubs for modificationMock and then add an assertion after the existing
assertions that the produced ModificationApplicationInfo(s) contain the expected
containerId value to verify propagation.
src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java (1)

55-66: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Detach children that drop out of setModifications().

clear() unlinks every current child, but only the surviving ones are re-attached. Children omitted from newChildren keep stale container_id metadata while the collection update clears the reference. With insertable = false, updatable = false on the @JoinColumn (line 32), this entity cannot update container_id, leaving the orphaned children with inconsistent ownership.

Suggested direction
 public void setModifications(List<ModificationEntity> newChildren) {
+    // Detach children being removed
+    if (newChildren != null && !newChildren.isEmpty()) {
+        Set<UUID> survivorIds = newChildren.stream()
+            .map(ModificationEntity::getId)
+            .collect(Collectors.toSet());
+        this.modifications.stream()
+            .filter(child -> !survivorIds.contains(child.getId()))
+            .forEach(child -> child.detachFromContainer());
+    } else {
+        this.modifications.forEach(ModificationEntity::detachFromContainer);
+    }
     this.modifications.clear();
     if (newChildren == null || newChildren.isEmpty()) {
         return;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java`
around lines 55 - 66, setModifications currently clears the collection then
re-attaches survivors, leaving omitted children with stale container metadata;
before calling this.modifications.clear() compute which existing children are
not present in newChildren and explicitly detach them (e.g., call a detach
method or clear their container reference) so their container_id is nulled, then
attach survivors with child.attachToContainer(this) and setModificationsOrder(i)
as you already do.
src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java (1)

231-247: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Preserve stashed children when reordering inside the same container.

sourceChildren strips out every stashed modification, and Line 247 writes that filtered list back to the container. A same-container move therefore detaches all stashed children from the container instead of just reordering the unstashed ones.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java`
around lines 231 - 247, sourceChildren currently filters out stashed
modifications from source.getModifications(), then on same-container reorders
writes the filtered list back with source.setModifications(), which
inadvertently removes stashed children; change the same-container path to
preserve stashed items by performing removeModifications/insertModifications
only on the unstashed subset without overwriting the container's full
modification list—i.e., use source.getModifications() to reconstruct the final
list by replacing only the moved unstashed entries (using removeModifications,
insertModifications and beforeModificationUuid) and then call
source.setModifications(...) with the merged list so stashed ModificationEntity
(getStashed()) elements remain in place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java`:
- Around line 227-239: The code currently calls
loadOrCreateContainer(targetType, targetContainerId) before knowing if any
modifications will be moved, causing empty target groups to be persisted; change
the flow so you first load the source via loadContainer(sourceType,
sourceContainerId), build sourceChildren, compute moved =
removeModifications(sourceChildren, modificationUuids) and if moved is empty
return early, and only then (when moved is non-empty and sameContainer is false)
call loadOrCreateContainer(targetType, targetContainerId) to obtain the target
ModificationContainer; update any logic that assumed target was already
available to run after this deferred creation.

---

Duplicate comments:
In
`@src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java`:
- Around line 55-66: setModifications currently clears the collection then
re-attaches survivors, leaving omitted children with stale container metadata;
before calling this.modifications.clear() compute which existing children are
not present in newChildren and explicitly detach them (e.g., call a detach
method or clear their container reference) so their container_id is nulled, then
attach survivors with child.attachToContainer(this) and setModificationsOrder(i)
as you already do.

In
`@src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java`:
- Around line 231-247: sourceChildren currently filters out stashed
modifications from source.getModifications(), then on same-container reorders
writes the filtered list back with source.setModifications(), which
inadvertently removes stashed children; change the same-container path to
preserve stashed items by performing removeModifications/insertModifications
only on the unstashed subset without overwriting the container's full
modification list—i.e., use source.getModifications() to reconstruct the final
list by replacing only the moved unstashed entries (using removeModifications,
insertModifications and beforeModificationUuid) and then call
source.setModifications(...) with the merged list so stashed ModificationEntity
(getStashed()) elements remain in place.

In
`@src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java`:
- Line 90: Restore the Mockito stub for modificationMock.getContainerId() in
testReindexElements so the test supplies a deterministic containerId (e.g.,
return groupMock) because
ModificationApplicationEntity.toModificationApplicationInfos() now reads
modification.getContainerId(); add a
Mockito.when(modificationMock.getContainerId()).thenReturn(groupMock) near the
other stubs for modificationMock and then add an assertion after the existing
assertions that the produced ModificationApplicationInfo(s) contain the expected
containerId value to verify propagation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8b53da69-abd1-49da-a313-c80d53b3e03e

📥 Commits

Reviewing files that changed from the base of the PR and between 8ef549b and 9b4fde7.

📒 Files selected for processing (15)
  • src/main/java/org/gridsuite/modification/server/NetworkModificationController.java
  • src/main/java/org/gridsuite/modification/server/entities/CompositeModificationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/ContainerOps.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationContainer.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java
  • src/main/java/org/gridsuite/modification/server/repositories/ModificationApplicationRepository.java
  • src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java
  • src/main/java/org/gridsuite/modification/server/service/SupervisionService.java
  • src/test/java/org/gridsuite/modification/server/CompositeControllerTest.java
  • src/test/java/org/gridsuite/modification/server/modifications/CompositeModificationsTest.java
  • src/test/java/org/gridsuite/modification/server/modifications/tabularmodifications/TabularGeneratorModificationsTest.java
  • src/test/java/org/gridsuite/modification/server/service/ModificationIndexationTest.java
  • src/test/java/org/gridsuite/modification/server/service/ModificationRepositoryTest.java
  • src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java
💤 Files with no reviewable changes (1)
  • src/main/java/org/gridsuite/modification/server/entities/ContainerOps.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/java/org/gridsuite/modification/server/entities/ModificationContainer.java
  • src/main/java/org/gridsuite/modification/server/entities/CompositeModificationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java`:
- Around line 113-117: The code sets this.stashed directly from
modificationInfos.getStashed() which can be null and overwrite the default; make
null-handling consistent with activated by checking
modificationInfos.getStashed() for null before assigning so the default field
value in ModificationEntity (stashed default false) is preserved when
getStashed() is null; update the assignment near the existing activated check
(the same block that references this.stashed, this.activated,
modificationInfos.getStashed(), and modificationInfos.getActivated()) to only
assign this.stashed when modificationInfos.getStashed() != null.
🪄 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: 729b77e2-a49a-422a-b2f7-ffff332541c9

📥 Commits

Reviewing files that changed from the base of the PR and between 9b4fde7 and 77fa5ee.

📒 Files selected for processing (12)
  • src/main/java/org/gridsuite/modification/server/entities/CompositeModificationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/ContainerOps.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationContainer.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/equipment/creation/ConverterStationCreationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/equipment/creation/LccConverterStationCreationEntity.java
  • src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java
  • src/main/resources/db/changelog/changesets/changelog_20260522T151740Z.xml
  • src/main/resources/db/changelog/db.changelog-master.yaml
  • src/test/java/org/gridsuite/modification/server/modifications/tabularmodifications/TabularGeneratorModificationsTest.java
  • src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java
💤 Files with no reviewable changes (1)
  • src/main/java/org/gridsuite/modification/server/entities/ModificationContainer.java
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/main/java/org/gridsuite/modification/server/entities/ContainerOps.java
  • src/main/resources/db/changelog/changesets/changelog_20260522T151740Z.xml
  • src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java
  • src/main/resources/db/changelog/db.changelog-master.yaml
  • src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java
  • src/test/java/org/gridsuite/modification/server/modifications/tabularmodifications/TabularGeneratorModificationsTest.java
  • src/main/java/org/gridsuite/modification/server/entities/CompositeModificationEntity.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java`:
- Around line 113-117: The code sets this.stashed directly from
modificationInfos.getStashed() which can be null and overwrite the default; make
null-handling consistent with activated by checking
modificationInfos.getStashed() for null before assigning so the default field
value in ModificationEntity (stashed default false) is preserved when
getStashed() is null; update the assignment near the existing activated check
(the same block that references this.stashed, this.activated,
modificationInfos.getStashed(), and modificationInfos.getActivated()) to only
assign this.stashed when modificationInfos.getStashed() != null.
🪄 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: 729b77e2-a49a-422a-b2f7-ffff332541c9

📥 Commits

Reviewing files that changed from the base of the PR and between 9b4fde7 and 77fa5ee.

📒 Files selected for processing (12)
  • src/main/java/org/gridsuite/modification/server/entities/CompositeModificationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/ContainerOps.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationContainer.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/equipment/creation/ConverterStationCreationEntity.java
  • src/main/java/org/gridsuite/modification/server/entities/equipment/creation/LccConverterStationCreationEntity.java
  • src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java
  • src/main/resources/db/changelog/changesets/changelog_20260522T151740Z.xml
  • src/main/resources/db/changelog/db.changelog-master.yaml
  • src/test/java/org/gridsuite/modification/server/modifications/tabularmodifications/TabularGeneratorModificationsTest.java
  • src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java
💤 Files with no reviewable changes (1)
  • src/main/java/org/gridsuite/modification/server/entities/ModificationContainer.java
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/main/java/org/gridsuite/modification/server/entities/ContainerOps.java
  • src/main/resources/db/changelog/changesets/changelog_20260522T151740Z.xml
  • src/main/java/org/gridsuite/modification/server/entities/ModificationGroupEntity.java
  • src/main/resources/db/changelog/db.changelog-master.yaml
  • src/test/java/org/gridsuite/modification/server/service/SupervisionTest.java
  • src/test/java/org/gridsuite/modification/server/modifications/tabularmodifications/TabularGeneratorModificationsTest.java
  • src/main/java/org/gridsuite/modification/server/entities/CompositeModificationEntity.java
🛑 Comments failed to post (1)
src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java (1)

113-117: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Inconsistent null handling between stashed and activated.

activated preserves its default (true) when modificationInfos.getActivated() is null, but stashed can be overwritten with null, losing its default (false). If getStashed() returns null, downstream code expecting a non-null Boolean may encounter NPE.

🛡️ Proposed fix for consistent null handling
         // Do not put this stashed status in assignAttributes, it's not part of a network modification as such.
-        this.stashed = modificationInfos.getStashed();
+        if (modificationInfos.getStashed() != null) {
+            this.stashed = modificationInfos.getStashed();
+        }
         // Preserve the default activation flag when missing
         if (modificationInfos.getActivated() != null) {
             this.activated = modificationInfos.getActivated();
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        this.stashed = modificationInfos.getStashed();
        // Preserve the default activation flag when missing
        if (modificationInfos.getActivated() != null) {
            this.activated = modificationInfos.getActivated();
        }
        // Do not put this stashed status in assignAttributes, it's not part of a network modification as such.
        if (modificationInfos.getStashed() != null) {
            this.stashed = modificationInfos.getStashed();
        }
        // Preserve the default activation flag when missing
        if (modificationInfos.getActivated() != null) {
            this.activated = modificationInfos.getActivated();
        }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/org/gridsuite/modification/server/entities/ModificationEntity.java`
around lines 113 - 117, The code sets this.stashed directly from
modificationInfos.getStashed() which can be null and overwrite the default; make
null-handling consistent with activated by checking
modificationInfos.getStashed() for null before assigning so the default field
value in ModificationEntity (stashed default false) is preserved when
getStashed() is null; update the assignment near the existing activated check
(the same block that references this.stashed, this.activated,
modificationInfos.getStashed(), and modificationInfos.getActivated()) to only
assign this.stashed when modificationInfos.getStashed() != null.

@sonarqubecloud

sonarqubecloud Bot commented Jul 7, 2026

Copy link
Copy Markdown

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.

1 participant