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

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

commit c2bb731fde8967eda4cf5e148698e808289bd42d
Author: Andrus Adamchik <[email protected]>
AuthorDate: Fri Jul 3 11:43:08 2026 -0400

    CAY-2969 Make "soft" delete the first-class citizen
---
 .../batch/SoftDeleteBatchTranslator.java           |  4 +++-
 .../configuration/runtime/CoreModuleExtender.java  | 22 ++++++++++++++++++++++
 .../org/apache/cayenne/access/SoftDeleteIT.java    |  6 ++----
 3 files changed, 27 insertions(+), 5 deletions(-)

diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java
index d08a39a6e..a52f597b7 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java
@@ -37,7 +37,9 @@ import static 
org.apache.cayenne.access.sqlbuilder.SQLBuilder.*;
  * A delete {@link BatchTranslator} that performs a 'soft' delete (an UPDATE 
setting the 'deleted' field
  * to true) for entities that have a boolean 'deleted' field, and falls back 
to the regular SQL DELETE of
  * the {@link DeleteBatchTranslator} superclass for the rest. Bind it under 
the {@link BatchTranslator#DELETE}
- * name to enable soft deletes.
+ * name to enable soft deletes. The preferred way to do this is
+ * {@code CoreModule.extend(binder).useSoftDeleteIfColumnPresent(columnName)} 
(see
+ * {@link 
org.apache.cayenne.configuration.runtime.CoreModuleExtender#useSoftDeleteIfColumnPresent(String)}).
  *
  * @since 4.2
  */
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/CoreModuleExtender.java
 
b/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/CoreModuleExtender.java
index eba9fd36a..cc64c09b1 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/CoreModuleExtender.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/CoreModuleExtender.java
@@ -21,6 +21,8 @@ package org.apache.cayenne.configuration.runtime;
 
 import org.apache.cayenne.DataChannelQueryFilter;
 import org.apache.cayenne.DataChannelSyncFilter;
+import org.apache.cayenne.access.translator.batch.BatchTranslator;
+import org.apache.cayenne.access.translator.batch.SoftDeleteBatchTranslator;
 import org.apache.cayenne.access.types.ExtendedType;
 import org.apache.cayenne.access.types.ExtendedTypeFactory;
 import org.apache.cayenne.access.types.ValueObjectType;
@@ -32,6 +34,7 @@ import org.apache.cayenne.configuration.Constants;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dba.PkGenerator;
 import org.apache.cayenne.di.Binder;
+import org.apache.cayenne.di.Key;
 import org.apache.cayenne.di.ListBuilder;
 import org.apache.cayenne.di.MapBuilder;
 import org.apache.cayenne.graph.GraphChangeHandler;
@@ -105,6 +108,25 @@ public class CoreModuleExtender {
         return this;
     }
 
+    /**
+     * Enables "soft delete" for entities whose tables contain a BOOLEAN 
column with the given name. Instead of a SQL
+     * DELETE, such entities are deleted by an {@code UPDATE ... SET 
<columnName> = true}, so the row physically stays
+     * in the table. Tables that have no column with the given name (or whose 
column of that name is not BOOLEAN) are
+     * unaffected and are deleted with a regular SQL DELETE. A NULL value in 
the column is treated as "not deleted".
+     *
+     * <p>This setting only affects the delete path. Hiding soft-deleted rows 
from queries remains the responsibility
+     * of the mapping, e.g. a DbEntity qualifier like {@code DELETED = false 
or DELETED = null}.
+     *
+     * @param columnName the name of the BOOLEAN column marking soft-deleted 
rows
+     * @see SoftDeleteBatchTranslator
+     * @since 5.0
+     */
+    public CoreModuleExtender useSoftDeleteIfColumnPresent(String columnName) {
+        binder.bind(Key.get(BatchTranslator.class, BatchTranslator.DELETE))
+                .toInstance(new SoftDeleteBatchTranslator(columnName));
+        return this;
+    }
+
     /**
      * Sets max size of snapshot cache.
      *
diff --git a/cayenne/src/test/java/org/apache/cayenne/access/SoftDeleteIT.java 
b/cayenne/src/test/java/org/apache/cayenne/access/SoftDeleteIT.java
index 18e175d81..863ab1462 100644
--- a/cayenne/src/test/java/org/apache/cayenne/access/SoftDeleteIT.java
+++ b/cayenne/src/test/java/org/apache/cayenne/access/SoftDeleteIT.java
@@ -19,9 +19,7 @@
 package org.apache.cayenne.access;
 
 import org.apache.cayenne.PersistenceState;
-import org.apache.cayenne.access.translator.batch.BatchTranslator;
-import org.apache.cayenne.access.translator.batch.SoftDeleteBatchTranslator;
-import org.apache.cayenne.di.Key;
+import org.apache.cayenne.configuration.runtime.CoreModule;
 import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.soft_delete.HardDelete;
@@ -41,7 +39,7 @@ public class SoftDeleteIT {
     @RegisterExtension
     static final CayenneTestsEnv env = CayenneTestsEnv
             .forProject(CayenneProjects.SOFT_DELETE_PROJECT)
-            .withExtraModules(b -> b.bind(Key.get(BatchTranslator.class, 
BatchTranslator.DELETE)).toInstance(new SoftDeleteBatchTranslator()));
+            .withExtraModules(b -> 
CoreModule.extend(b).useSoftDeleteIfColumnPresent("DELETED"));
 
     private TableHelper tSoftDelete;
 

Reply via email to