package io.ebeaninternal.server.query;
import io.ebean.Version;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
The purpose is to add an extra join to the query.
This is used to support the where clause or order by clause that refers
to properties that are NOT included in the select. To support the where clause
etc in this case we must add an extra join.
/**
* The purpose is to add an extra join to the query.
* <p>
* This is used to support the where clause or order by clause that refers
* to properties that are NOT included in the select. To support the where clause
* etc in this case we must add an extra join.
* </p>
*/
class SqlTreeNodeExtraJoin implements SqlTreeNode {
private final STreePropertyAssoc assocBeanProperty;
private final String prefix;
private final boolean manyJoin;
private final boolean pathContainsMany;
private List<SqlTreeNodeExtraJoin> children;
SqlTreeNodeExtraJoin(String prefix, STreePropertyAssoc assocBeanProperty, boolean pathContainsMany) {
this.prefix = prefix;
this.assocBeanProperty = assocBeanProperty;
this.pathContainsMany = pathContainsMany;
this.manyJoin = assocBeanProperty instanceof STreePropertyAssocMany;
}
@Override
public boolean isSingleProperty() {
return false;
}
@Override
public void buildRawSqlSelectChain(List<String> selectChain) {
// nothing to add
}
@Override
public void addAsOfTableAlias(SpiQuery<?> query) {
// nothing to do here
}
@Override
public void addSoftDeletePredicate(SpiQuery<?> query) {
// nothing to do here
}
@Override
public void appendDistinctOn(DbSqlContext ctx, boolean subQuery) {
// do nothing here ...
}
@Override
public boolean isAggregation() {
return false;
}
@Override
public void appendGroupBy(DbSqlContext ctx, boolean subQuery) {
// nothing to do here
}
@Override
public ScalarType<?> getSingleAttributeReader() {
throw new IllegalStateException("No expected");
}
Return true if the extra join is a many join.
This means we need to add distinct to the sql query.
/**
* Return true if the extra join is a many join.
* <p>
* This means we need to add distinct to the sql query.
* </p>
*/
boolean isManyJoin() {
return manyJoin;
}
public String getName() {
return prefix;
}
public void addChild(SqlTreeNodeExtraJoin child) {
if (children == null) {
children = new ArrayList<>();
}
children.add(child);
}
@Override
public void dependentTables(Set<String> tables) {
tables.add(assocBeanProperty.target().getBaseTable(SpiQuery.TemporalMode.CURRENT));
if (children != null) {
for (SqlTreeNode child : children) {
child.dependentTables(tables);
}
}
}
@Override
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
boolean manyToMany = false;
if (assocBeanProperty instanceof STreePropertyAssocMany) {
STreePropertyAssocMany manyProp = (STreePropertyAssocMany) assocBeanProperty;
if (manyProp.hasJoinTable()) {
manyToMany = true;
String alias = ctx.getTableAlias(prefix);
String[] split = SplitName.split(prefix);
String parentAlias = ctx.getTableAlias(split[0]);
String alias2 = alias + "z_";
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
assocBeanProperty.addJoin(joinType, alias2, alias, ctx);
}
}
if (pathContainsMany) {
// "promote" to left join as the path contains a many
joinType = SqlJoinType.OUTER;
}
if (!manyToMany) {
if (assocBeanProperty.isFormula()) {
// add joins for formula beans
assocBeanProperty.appendFrom(ctx, joinType);
}
joinType = assocBeanProperty.addJoin(joinType, prefix, ctx);
}
if (children != null) {
if (manyJoin || pathContainsMany) {
// if AUTO then make all descendants use OUTER JOIN
joinType = joinType.autoToOuter();
}
for (SqlTreeNodeExtraJoin child : children) {
child.appendFrom(ctx, joinType);
}
}
}
Does nothing.
/**
* Does nothing.
*/
@Override
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
}
Does nothing.
/**
* Does nothing.
*/
@Override
public void appendWhere(DbSqlContext ctx) {
}
Does nothing.
/**
* Does nothing.
*/
@Override
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) {
return null;
}
Does nothing.
/**
* Does nothing.
*/
@Override
public <T> Version<T> loadVersion(DbReadContext ctx) {
return null;
}
@Override
public boolean hasMany() {
return manyJoin;
}
}