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;
