This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/master by this push:
     new cca99eae9 CAY-2868 Regression: DefaultDbRowOpSorter shouldn't sort 
update operations
cca99eae9 is described below

commit cca99eae99f290adb67c44fd9ae66565ff7ddfff
Author: Nikita Timofeev <stari...@gmail.com>
AuthorDate: Fri Aug 16 12:26:35 2024 +0300

    CAY-2868 Regression: DefaultDbRowOpSorter shouldn't sort update operations
---
 RELEASE-NOTES.txt                                  |  1 +
 .../flush/operation/DefaultDbRowOpSorter.java      |  7 ++++---
 .../access/flush/DefaultDbRowOpSorterTest.java     | 24 ++++++++++++++++++++++
 3 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 3a5031e99..19ed50585 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -126,3 +126,4 @@ CAY-2851 Replace Existing OneToOne From New Object
 CAY-2853 Incorrect deletion of entities from flattened attributes
 CAY-2854 Improve delete prevention detection of flattened attribute row
 CAY-2866 DefaultDataDomainFlushAction breaks on circular relationship update
+CAY-2868 Regression: DefaultDbRowOpSorter shouldn't sort update operations
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/flush/operation/DefaultDbRowOpSorter.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/flush/operation/DefaultDbRowOpSorter.java
index ed431719e..f02eb7eb8 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/flush/operation/DefaultDbRowOpSorter.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/flush/operation/DefaultDbRowOpSorter.java
@@ -64,7 +64,8 @@ public class DefaultDbRowOpSorter implements DbRowOpSorter {
         for (int i = 0; i < sortedDbRows.size(); i++) {
             DbRowOp row = sortedDbRows.get(i);
             if (row.getEntity() != lastEntity) {
-                if(lastEntity != null && sorter.isReflexive(lastEntity)) {
+                // we do not sort update operations
+                if(lastEntity != null && !(lastRow instanceof UpdateDbRowOp) 
&& sorter.isReflexive(lastEntity)) {
                     ObjEntity objEntity = 
resolver.getObjEntity(lastRow.getObject().getObjectId().getEntityName());
                     List<DbRowOp> reflexiveSublist = 
sortedDbRows.subList(start, idx);
                     sorter.sortObjectsForEntity(objEntity, reflexiveSublist, 
lastRow instanceof DeleteDbRowOp);
@@ -76,7 +77,7 @@ public class DefaultDbRowOpSorter implements DbRowOpSorter {
             idx++;
         }
         // sort last chunk
-        if(lastEntity != null && sorter.isReflexive(lastEntity)) {
+        if(lastEntity != null && !(lastRow instanceof UpdateDbRowOp) && 
sorter.isReflexive(lastEntity)) {
             ObjEntity objEntity = 
resolver.getObjEntity(lastRow.getObject().getObjectId().getEntityName());
             List<DbRowOp> reflexiveSublist = sortedDbRows.subList(start, idx);
             sorter.sortObjectsForEntity(objEntity, reflexiveSublist, lastRow 
instanceof DeleteDbRowOp);
@@ -116,7 +117,7 @@ public class DefaultDbRowOpSorter implements DbRowOpSorter {
                 return result;
             }
 
-            // 2. sort by entity relations
+            // 2. sort by entity relations, we don't really need this for 
updates, but do it for the stable result
             result = 
entitySorter.getDbEntityComparator().compare(left.getEntity(), 
right.getEntity());
             if(result != 0) {
                 // invert result for delete
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/flush/DefaultDbRowOpSorterTest.java
 
b/cayenne/src/test/java/org/apache/cayenne/access/flush/DefaultDbRowOpSorterTest.java
index b4bd0217b..8fbb3ddd4 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/access/flush/DefaultDbRowOpSorterTest.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/flush/DefaultDbRowOpSorterTest.java
@@ -192,8 +192,32 @@ public class DefaultDbRowOpSorterTest {
 
         List<DbRowOp> sorted = sorter.sort(rows);
         assertEquals(expected, sorted); // no actual sorting is done
+        verify(entitySorter, times(3)).getDbEntityComparator();
         verify(entitySorter) // should call entity sorter
                 .sortObjectsForEntity(isNull(), any(List.class), eq(false));
+        verifyNoMoreInteractions(entitySorter);
+    }
+
+    @Test
+    public void sortReflexiveUpdates() {
+        ObjectId id1 = ObjectId.of("reflexive", "id", 1);
+        ObjectId id2 = ObjectId.of("reflexive", "id", 2);
+        ObjectId id3 = ObjectId.of("reflexive", "id", 3);
+        ObjectId id4 = ObjectId.of("reflexive", "id", 4);
+
+        DbEntity reflexive = mockEntity("reflexive");
+        DbRowOp op1 = new UpdateDbRowOp(mockObject(id1), reflexive, id1);
+        DbRowOp op2 = new UpdateDbRowOp(mockObject(id2), reflexive, id2);
+        DbRowOp op3 = new UpdateDbRowOp(mockObject(id3), reflexive, id3);
+        DbRowOp op4 = new UpdateDbRowOp(mockObject(id4), reflexive, id4);
+
+        List<DbRowOp> rows = Arrays.asList(op1, op2, op3, op4);
+        List<DbRowOp> expected = Arrays.asList(op1, op2, op3, op4);
+
+        List<DbRowOp> sorted = sorter.sort(rows);
+        assertEquals(expected, sorted); // no actual sorting is done
+        verify(entitySorter, times(3)).getDbEntityComparator();
+        verifyNoMoreInteractions(entitySorter); // shouldn't call entity sorter
     }
 
     private Persistent mockObject(ObjectId id) {

Reply via email to