Merge pull request #3240 from ebean-orm/feature/OneToOne-softDelete-join

OneToOne with SoftDelete join missing deleted predicate
This commit is contained in:
Rob Bygrave
2023-10-10 21:38:50 +13:00
committed by GitHub
7 changed files with 125 additions and 5 deletions
@@ -148,4 +148,10 @@ public interface DbSqlContext {
* Add extra joins *IF* required to support inheritance discriminator in projection.
*/
void flushExtraJoins();
/**
* Return true if the last join was added and false means the join was suppressed
* as it was already added to the query.
*/
boolean joinAdded();
}
@@ -38,6 +38,7 @@ final class DefaultDbSqlContext implements DbSqlContext {
private final CQueryDraftSupport draftSupport;
private final CQueryHistorySupport historySupport;
private final boolean historyQuery;
private boolean joinSuppressed;
DefaultDbSqlContext(SqlTreeAlias alias, String columnAliasPrefix, CQueryHistorySupport historySupport,
CQueryDraftSupport draftSupport, String fromForUpdate) {
@@ -50,6 +51,11 @@ final class DefaultDbSqlContext implements DbSqlContext {
this.fromForUpdate = fromForUpdate;
}
@Override
public boolean joinAdded() {
return !joinSuppressed;
}
@Override
public boolean isIncludeSoftDelete() {
return alias.isIncludeSoftDelete();
@@ -118,9 +124,10 @@ final class DefaultDbSqlContext implements DbSqlContext {
}
String joinKey = table + "-" + a1 + "-" + a2;
if (tableJoins.contains(joinKey)) {
joinSuppressed = true;
return;
}
joinSuppressed = false;
tableJoins.add(joinKey);
sb.append(' ').append(type);
boolean addAsOfOnClause = false;
@@ -10,6 +10,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static io.ebeaninternal.api.SpiQuery.TemporalMode.SOFT_DELETED;
/**
* The purpose is to add an extra join to the query.
* <p>
@@ -145,7 +147,7 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode {
assocBeanProperty.appendFrom(ctx, joinType, null);
}
joinType = assocBeanProperty.addJoin(joinType, prefix, ctx);
if (!oneToOneExported && assocBeanProperty.isTargetSoftDelete() && temporalMode != SpiQuery.TemporalMode.SOFT_DELETED) {
if (temporalMode != SOFT_DELETED && ctx.joinAdded() && assocBeanProperty.isTargetSoftDelete()) {
ctx.append(" and ").append(assocBeanProperty.softDeletePredicate(ctx.tableAlias(prefix)));
}
}
@@ -88,14 +88,14 @@ final class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
if (nodeBeanProp instanceof STreePropertyAssocOne) {
nodeBeanProp.addJoin(joinType, parentAlias, alias, ctx);
if (softDelete) {
if (softDelete && ctx.joinAdded()) {
ctx.append(" and ").append(target.softDeletePredicate(alias));
}
} else {
STreePropertyAssocMany manyProp = (STreePropertyAssocMany) nodeBeanProp;
if (!manyProp.hasJoinTable()) {
manyProp.addJoin(joinType, parentAlias, alias, ctx);
if (softDelete) {
if (softDelete && ctx.joinAdded()) {
ctx.append(" and ").append(target.softDeletePredicate(alias));
}
} else {
@@ -331,7 +331,6 @@ public class TestMergeCustomer extends BaseTestCase {
assertThat(sql.get(17)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?");
assertSqlBind(sql, 18, 21);
assertThat(sql.get(23)).contains("update mcontact_message set title=?, subject=?, notes=?, version=?, contact_id=? where id=? and version=?");
assertSqlBind(sql, 24, 29);
}
}
@@ -0,0 +1,59 @@
package org.tests.model.softdelete;
import io.ebean.annotation.SoftDelete;
import jakarta.persistence.*;
@SuppressWarnings("unused")
@Entity
public class ESoftDelOneBOwner {
@Id
long id;
String name;
@ManyToOne
ESoftDelOneB oneb;
@SoftDelete
boolean deleted;
@Version
long version;
public ESoftDelOneBOwner(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ESoftDelOneB oneb() {
return oneb;
}
public void setOneb(ESoftDelOneB oneb) {
this.oneb = oneb;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
}
@@ -0,0 +1,47 @@
package org.tests.softdelete;
import io.ebean.DB;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Test;
import org.tests.model.softdelete.ESoftDelOneA;
import org.tests.model.softdelete.ESoftDelOneB;
import org.tests.model.softdelete.ESoftDelOneBOwner;
import static org.assertj.core.api.Assertions.assertThat;
class TestSoftDeleteOtoImported extends BaseTestCase {
@Test
void extraJoinToOtoImported_expect_softDeletePredicate() {
ESoftDelOneB b = new ESoftDelOneB("xbImported");
DB.save(b);
ESoftDelOneA a = new ESoftDelOneA("xaImported");
a.setOneb(b);
DB.save(a);
ESoftDelOneBOwner co = new ESoftDelOneBOwner("xoImport");
co.setOneb(b);
DB.save(co);
LoggedSql.start();
var listResult = DB.find(ESoftDelOneBOwner.class)
.where()
.eq("oneb.onea.name", "xaImported")
.findList();
var countResult = DB.find(ESoftDelOneBOwner.class)
.where()
.eq("oneb.onea.name", "xaImported")
.findCount();
var sql = LoggedSql.stop();
assertThat(sql).hasSize(2);
assertThat(listResult).hasSize(1);
assertThat(countResult).isEqualTo(1);
assertThat(sql.get(0)).contains("and t2.deleted = ");
assertThat(sql.get(1)).contains("and t2.deleted = ");
}
}