use of com.blazebit.persistence.JoinOnBuilder in project blaze-persistence by Blazebit.
the class BlazeCriteriaBuilderRenderer method renderJoins.
private <X extends FromBuilder<X>> X renderJoins(QueryMetadata metadata, FromBaseBuilder<X> fromBuilder) {
X criteriaBuilder = null;
for (final JoinExpression joinExpression : metadata.getJoins()) {
boolean fetch = joinExpression.hasFlag(JPAQueryMixin.FETCH);
boolean hasCondition = joinExpression.getCondition() != null;
Expression<?> target = joinExpression.getTarget();
String alias = null;
if (target instanceof Operation<?>) {
Operation<?> operation = (Operation<?>) target;
if (operation.getOperator() == Ops.ALIAS) {
target = operation.getArg(0);
alias = ((Path<?>) operation.getArg(1)).getMetadata().getName();
}
}
if (target instanceof ValuesExpression<?>) {
ValuesExpression<?> valuesExpression = (ValuesExpression<?>) target;
Class type = valuesExpression.getRoot().getType();
String name = valuesExpression.getAlias().getMetadata().getName();
Collection<?> elements = valuesExpression.getElements();
if (!valuesExpression.getMetadata().isRoot()) {
String attribute = relativePathString(valuesExpression.getRoot(), valuesExpression);
if (valuesExpression.isIdentifiable()) {
criteriaBuilder = (X) fromBuilder.fromIdentifiableValues(type, attribute, name, elements);
} else {
criteriaBuilder = (X) fromBuilder.fromValues(type, attribute, name, elements);
}
} else if (valuesExpression.isIdentifiable()) {
criteriaBuilder = (X) fromBuilder.fromIdentifiableValues(type, name, elements);
} else {
criteriaBuilder = (X) fromBuilder.fromValues(type, name, elements);
}
} else if (target instanceof Path<?>) {
Path<?> entityPath = (Path<?>) target;
boolean entityJoin = entityPath.getMetadata().isRoot();
String renderedExpression = renderExpression(entityPath);
// While this looks suspicious, this is actually in line with Querydsl's default behaviour in JPQLSerializer.handleJoinTarget
if (alias == null && entityJoin) {
alias = renderedExpression;
}
switch(joinExpression.getType()) {
case DEFAULT:
if (fromBuilder instanceof FromBuilder) {
criteriaBuilder = (X) fromBuilder;
From from = criteriaBuilder.getFrom(alias);
// TODO find a clean way to detect FROM clauses that are already set by fromEntitySubquery...
if (from != null) {
if (entityPath instanceof CollectionExpressionBase<?, ?> && ((CollectionExpressionBase<?, ?>) entityPath).getElementType().equals(from.getJavaType()) || from.getJavaType().equals(entityPath.getType())) {
break;
}
}
}
if (entityJoin) {
criteriaBuilder = fromBuilder.from(entityPath.getType(), alias);
} else {
if (fromBuilder instanceof BaseSubqueryBuilder) {
criteriaBuilder = (X) ((BaseSubqueryBuilder<?>) fromBuilder).from(renderedExpression, alias);
} else if (fromBuilder instanceof SubqueryInitiator<?>) {
criteriaBuilder = (X) ((SubqueryInitiator<?>) fromBuilder).from(renderedExpression, alias);
} else {
throw new IllegalArgumentException(renderedExpression + " join not supported here");
}
}
break;
default:
JoinType joinType = getJoinType(joinExpression);
if (hasCondition && fetch) {
LOG.warning("Fetch is ignored due to on-clause");
}
if (entityJoin) {
if (!hasCondition) {
throw new IllegalStateException("No on-clause for entity join!");
}
final JoinOnBuilder<X> xJoinOnBuilder = criteriaBuilder.joinOn(entityPath.getType(), alias, joinType);
setExpressionSubqueries(joinExpression.getCondition(), null, xJoinOnBuilder, JoinOnBuilderExpressionSetter.INSTANCE);
} else if (!hasCondition) {
// If there is no alias, assume a default join
boolean defaultJoin = alias == null || joinExpression.hasFlag(AbstractBlazeJPAQuery.DEFAULT);
if (fetch) {
if (defaultJoin) {
((FullQueryBuilder<?, ?>) criteriaBuilder).joinDefault(renderedExpression, alias, joinType, fetch);
} else {
((FullQueryBuilder<?, ?>) criteriaBuilder).join(renderedExpression, alias, joinType, fetch);
}
} else {
if (defaultJoin) {
criteriaBuilder.joinDefault(renderedExpression, alias, joinType);
} else {
criteriaBuilder.join(renderedExpression, alias, joinType);
}
}
} else {
if (alias == null) {
throw new IllegalArgumentException("This association join requires an alias, like so: .join(" + renderedExpression + ", " + entityPath.getClass().getSimpleName() + "." + entityPath.getMetadata().getName() + ")");
}
final JoinOnBuilder<X> xJoinOnBuilder = criteriaBuilder.joinOn(renderedExpression, alias, joinType);
setExpressionSubqueries(joinExpression.getCondition(), null, xJoinOnBuilder, JoinOnBuilderExpressionSetter.INSTANCE);
}
break;
}
} else if (target instanceof SubQueryExpression) {
switch(joinExpression.getType()) {
case DEFAULT:
{
FullSelectCTECriteriaBuilder<X> xFullSelectCTECriteriaBuilder = fromBuilder.fromSubquery(target.getType(), alias);
Object o = serializeSubQuery(xFullSelectCTECriteriaBuilder, target);
criteriaBuilder = o instanceof FinalSetOperationCTECriteriaBuilder ? ((FinalSetOperationCTECriteriaBuilder<X>) o).end() : ((FullSelectCTECriteriaBuilder<X>) o).end();
break;
}
default:
{
JoinType joinType = getJoinType(joinExpression);
boolean isLateral = joinExpression.hasFlag(AbstractBlazeJPAQuery.LATERAL);
if (fetch) {
LOG.warning("Fetch is ignored due to subquery entity join!");
}
SubQueryExpression<?> subQueryExpression = target.accept(new FirstSubqueryResolver(), null);
Path<?> fromPath = subQueryExpression.getMetadata().getJoins().get(0).getTarget().accept(new FirstSubqueryTargetPathResolver(), null);
boolean entityJoin = fromPath.getMetadata().isRoot();
if (hasCondition) {
FullSelectCTECriteriaBuilder<JoinOnBuilder<X>> joinOnBuilderFullSelectCTECriteriaBuilder;
if (isLateral) {
String subqueryAlias = subQueryExpression.getMetadata().getJoins().get(0).getTarget().accept(new JoinTargetAliasPathResolver(), null).getMetadata().getName();
if (entityJoin) {
joinOnBuilderFullSelectCTECriteriaBuilder = criteriaBuilder.joinLateralOnSubquery(target.getType(), alias, joinType);
} else {
joinOnBuilderFullSelectCTECriteriaBuilder = criteriaBuilder.joinLateralOnSubquery(renderExpression(fromPath), alias, subqueryAlias, joinType);
}
} else {
if (!entityJoin) {
throw new IllegalStateException("Entity join to association");
}
joinOnBuilderFullSelectCTECriteriaBuilder = criteriaBuilder.joinOnSubquery(target.getType(), alias, joinType);
}
Object o = serializeSubQuery(joinOnBuilderFullSelectCTECriteriaBuilder, target);
final JoinOnBuilder<X> joinOnBuilder = o instanceof FinalSetOperationCTECriteriaBuilder ? ((FinalSetOperationCTECriteriaBuilder<JoinOnBuilder<X>>) o).end() : ((FullSelectCTECriteriaBuilder<JoinOnBuilder<X>>) o).end();
criteriaBuilder = (X) setExpressionSubqueries(joinExpression.getCondition(), null, joinOnBuilder, JoinOnBuilderExpressionSetter.INSTANCE);
} else {
if (isLateral) {
FullSelectCTECriteriaBuilder<X> xFullSelectCTECriteriaBuilder;
String subqueryAlias = subQueryExpression.getMetadata().getJoins().get(0).getTarget().accept(new JoinTargetAliasPathResolver(), null).getMetadata().getName();
if (entityJoin) {
xFullSelectCTECriteriaBuilder = criteriaBuilder.joinLateralSubquery(target.getType(), alias, joinType);
} else {
xFullSelectCTECriteriaBuilder = criteriaBuilder.joinLateralSubquery(renderExpression(fromPath), alias, subqueryAlias, joinType);
}
Object o = serializeSubQuery(xFullSelectCTECriteriaBuilder, target);
criteriaBuilder = o instanceof FinalSetOperationCTECriteriaBuilder ? ((FinalSetOperationCTECriteriaBuilder<X>) o).end() : ((FullSelectCTECriteriaBuilder<X>) o).end();
} else {
throw new IllegalStateException("No on-clause for subquery entity join!");
}
}
break;
}
}
} else {
throw new UnsupportedOperationException("Joins for " + target + " is not yet implemented");
}
}
return criteriaBuilder;
}
use of com.blazebit.persistence.JoinOnBuilder in project blaze-persistence by Blazebit.
the class JoinOnBuilderImpl method onExpressionSubqueries.
@Override
public MultipleSubqueryInitiator<JoinOnBuilder<T>> onExpressionSubqueries(String expression) {
Predicate predicate = expressionFactory.createBooleanExpression(expression, true);
// We don't need a listener or marker here, because the resulting restriction builder can only be ended, when the initiator is ended
MultipleSubqueryInitiator<JoinOnBuilder<T>> initiator = new MultipleSubqueryInitiatorImpl<JoinOnBuilder<T>>(this, predicate, new ExpressionBuilderEndedListener() {
@Override
public void onBuilderEnded(ExpressionBuilder builder) {
rootPredicate.getPredicate().getChildren().add((Predicate) builder.getExpression());
currentMultipleSubqueryInitiator = null;
}
}, subqueryInitFactory, ClauseType.JOIN);
currentMultipleSubqueryInitiator = initiator;
return initiator;
}
use of com.blazebit.persistence.JoinOnBuilder in project blaze-persistence by Blazebit.
the class JoinOnBuilderImpl method onSubqueries.
@Override
public MultipleSubqueryInitiator<RestrictionBuilder<JoinOnBuilder<T>>> onSubqueries(String expression) {
Expression expr = expressionFactory.createSimpleExpression(expression, true);
RestrictionBuilderImpl<JoinOnBuilder<T>> restrictionBuilder = startBuilder(new RestrictionBuilderImpl<JoinOnBuilder<T>>(this, this, subqueryInitFactory, expressionFactory, parameterManager, ClauseType.JOIN));
// We don't need a listener or marker here, because the resulting restriction builder can only be ended, when the initiator is ended
MultipleSubqueryInitiator<RestrictionBuilder<JoinOnBuilder<T>>> initiator = new MultipleSubqueryInitiatorImpl<RestrictionBuilder<JoinOnBuilder<T>>>(restrictionBuilder, expr, new RestrictionBuilderExpressionBuilderListener(restrictionBuilder), subqueryInitFactory, ClauseType.JOIN);
return initiator;
}
Aggregations