use of com.blazebit.persistence.Queryable in project blaze-persistence by Blazebit.
the class BlazeCriteriaBuilderRenderer method serializeSubQuery.
private Object serializeSubQuery(Object criteriaBuilder, Expression<?> expression) {
Object result = expression.accept(new Visitor<Object, Object>() {
@Override
public Object visit(Constant<?> constant, Object criteriaBuilder) {
throw new UnsupportedOperationException();
}
@Override
public Object visit(FactoryExpression<?> factoryExpression, Object criteriaBuilder) {
throw new UnsupportedOperationException();
}
@Override
public Object visit(Operation<?> setOperation, Object criteriaBuilder) {
Expression<?> lhs = setOperation.getArg(0);
SubQueryExpression<?> lhsSubquery = lhs.accept(GetSubQueryVisitor.INSTANCE, null);
SetOperationFlag setOperationFlag = lhsSubquery != null ? getSetOperationFlag(lhsSubquery.getMetadata()) : null;
boolean lhsNestedSet = setOperationFlag != null && LEFT_NESTED_SET_OPERATIONS.contains(setOperation.getOperator());
if (lhsNestedSet) {
if (criteriaBuilder instanceof StartOngoingSetOperationBuilder) {
StartOngoingSetOperationBuilder<?, ?, ?> ob = (StartOngoingSetOperationBuilder<?, ?, ?>) criteriaBuilder;
criteriaBuilder = ob.startSet();
} else if (criteriaBuilder instanceof SubqueryInitiator) {
SubqueryInitiator<?> subqueryInitiator = (SubqueryInitiator<?>) criteriaBuilder;
criteriaBuilder = subqueryInitiator.startSet();
} else {
criteriaBuilder = criteriaBuilderFactory.startSet(entityManager, Object.class);
}
criteriaBuilder = setOperationFlag.getFlag().accept(this, criteriaBuilder);
if (criteriaBuilder instanceof OngoingSetOperationBuilder) {
criteriaBuilder = ((OngoingSetOperationBuilder<?, ?, ?>) criteriaBuilder).endSetWith();
renderOrderBy(lhsSubquery.getMetadata(), (OrderByBuilder<?>) criteriaBuilder);
renderModifiers(lhsSubquery.getMetadata().getModifiers(), (LimitBuilder<?>) criteriaBuilder);
criteriaBuilder = ((BaseOngoingFinalSetOperationBuilder) criteriaBuilder).endSet();
} else {
throw new UnsupportedOperationException();
}
} else {
criteriaBuilder = lhs.accept(this, criteriaBuilder);
}
Expression<?> rhs = setOperation.getArg(1);
SubQueryExpression<?> rhsSubquery = rhs.accept(GetSubQueryVisitor.INSTANCE, null);
setOperationFlag = rhsSubquery != null ? getSetOperationFlag(rhsSubquery.getMetadata()) : null;
boolean isNestedSet = setOperationFlag != null;
SetOperationBuilder<?, ?> setOperationBuilder = (SetOperationBuilder<?, ?>) criteriaBuilder;
switch((JPQLNextOps) setOperation.getOperator()) {
// CHECKSTYLE:OFF: FallThrough
case SET_UNION:
case LEFT_NESTED_SET_UNION:
criteriaBuilder = isNestedSet ? setOperationBuilder.startUnion() : setOperationBuilder.union();
break;
case SET_UNION_ALL:
case LEFT_NESTED_SET_UNION_ALL:
criteriaBuilder = isNestedSet ? setOperationBuilder.startUnionAll() : setOperationBuilder.unionAll();
break;
case SET_EXCEPT:
case LEFT_NESTED_SET_EXCEPT:
criteriaBuilder = isNestedSet ? setOperationBuilder.startExcept() : setOperationBuilder.except();
break;
case SET_EXCEPT_ALL:
case LEFT_NESTED_SET_EXCEPT_ALL:
criteriaBuilder = isNestedSet ? setOperationBuilder.startExceptAll() : setOperationBuilder.exceptAll();
break;
case SET_INTERSECT:
case LEFT_NESTED_SET_INTERSECT:
criteriaBuilder = isNestedSet ? setOperationBuilder.startIntersect() : setOperationBuilder.intersect();
break;
case SET_INTERSECT_ALL:
case LEFT_NESTED_SET_INTERSECT_ALL:
criteriaBuilder = isNestedSet ? setOperationBuilder.startIntersectAll() : setOperationBuilder.intersectAll();
break;
default:
throw new UnsupportedOperationException("No support for set operation " + setOperation.getOperator());
}
if (isNestedSet) {
criteriaBuilder = setOperationFlag.getFlag().accept(this, criteriaBuilder);
if (criteriaBuilder instanceof OngoingSetOperationBuilder) {
criteriaBuilder = ((OngoingSetOperationBuilder<?, ?, ?>) criteriaBuilder).endSetWith();
renderOrderBy(rhsSubquery.getMetadata(), (OrderByBuilder<?>) criteriaBuilder);
renderModifiers(rhsSubquery.getMetadata().getModifiers(), (LimitBuilder<?>) criteriaBuilder);
criteriaBuilder = ((BaseOngoingFinalSetOperationBuilder) criteriaBuilder).endSet();
} else {
throw new UnsupportedOperationException();
}
} else {
criteriaBuilder = rhs.accept(this, criteriaBuilder);
}
return criteriaBuilder;
}
@Override
public Object visit(ParamExpression<?> paramExpression, Object criteriaBuilder) {
throw new UnsupportedOperationException();
}
@Override
public Object visit(Path<?> path, Object criteriaBuilder) {
throw new UnsupportedOperationException();
}
@Override
public Object visit(SubQueryExpression<?> subQuery, Object criteriaBuilder) {
QueryMetadata subQueryMetadata = subQuery.getMetadata();
SetOperationFlag setOperationFlag = getSetOperationFlag(subQueryMetadata);
if (setOperationFlag != null) {
return setOperationFlag.getFlag().accept(this, criteriaBuilder);
}
renderCTEs(subQueryMetadata);
criteriaBuilder = renderJoins(subQueryMetadata, (FromBaseBuilder) criteriaBuilder);
criteriaBuilder = renderNamedWindows(subQueryMetadata, (WindowContainerBuilder) criteriaBuilder);
renderDistinct(subQueryMetadata, (DistinctBuilder<?>) criteriaBuilder);
renderWhere(subQueryMetadata, (WhereBuilder<?>) criteriaBuilder);
renderGroupBy(subQueryMetadata, (GroupByBuilder<?>) criteriaBuilder);
renderHaving(subQueryMetadata, (HavingBuilder<?>) criteriaBuilder);
Expression<?> select = subQueryMetadata.getProjection();
if (select instanceof FactoryExpression<?> && criteriaBuilder instanceof FullQueryBuilder<?, ?>) {
FactoryExpression<T> factoryExpression = (FactoryExpression<T>) select;
FullQueryBuilder<?, ?> fullQueryBuilder = (FullQueryBuilder<?, ?>) criteriaBuilder;
criteriaBuilder = fullQueryBuilder.selectNew(new FactoryExpressionObjectBuilder(factoryExpression));
} else {
List<? extends Expression<?>> projection = expandProjection(subQueryMetadata.getProjection());
if (criteriaBuilder instanceof SelectBaseCTECriteriaBuilder) {
SelectBaseCTECriteriaBuilder<?> selectBaseCriteriaBuilder = (SelectBaseCTECriteriaBuilder<?>) criteriaBuilder;
boolean bindEntity = projection.size() == 1 && subQueryMetadata.getJoins().get(0).getTarget().accept(new JoinTargetAliasPathResolver(), null).equals(projection.get(0));
if (bindEntity) {
EntityMetamodel metamodel = criteriaBuilderFactory.getService(EntityMetamodel.class);
Path<?> pathExpression = (Path<?>) projection.get(0);
ExtendedManagedType<?> managedType = metamodel.getManagedType(ExtendedManagedType.class, pathExpression.getType());
Map<String, ? extends ExtendedAttribute<?, ?>> ownedSingularAttributes = managedType.getOwnedSingularAttributes();
for (Map.Entry<String, ? extends ExtendedAttribute<?, ?>> ownedSingularAttribute : ownedSingularAttributes.entrySet()) {
String attributeName = ownedSingularAttribute.getKey();
ExtendedAttribute<?, ?> attribute = ownedSingularAttribute.getValue();
if (!JpaMetamodelUtils.isAssociation(attribute.getAttribute())) {
final SelectBuilder<?> bindBuilder = selectBaseCriteriaBuilder.bind(attributeName);
BeanPath<?> beanPath = new BeanPath<Object>(attribute.getElementClass(), pathExpression, attributeName);
setExpressionSubqueries(beanPath, null, bindBuilder, SelectBuilderExpressionSetter.INSTANCE);
}
}
} else {
for (int i = 0; i < projection.size(); i++) {
Expression<?> projExpression = projection.get(i);
BindResolverContext bindResolverContext = new BindResolverContext();
projExpression = projExpression.accept(BindResolver.INSTANCE, bindResolverContext);
Path<?> cteAttribute = bindResolverContext.getCteAttribute();
String alias = bindResolverContext.getAliasString();
if (cteAttribute == null && cteAliases != null) {
cteAttribute = cteAliases.get(i);
}
if (cteAttribute != null) {
Path<?> cteEntityPath = cteAttribute.getRoot();
String relativeCteAttributePath = relativePathString(cteEntityPath, cteAttribute);
final SelectBuilder<?> bindBuilder = selectBaseCriteriaBuilder.bind(relativeCteAttributePath);
setExpressionSubqueries(projExpression, alias, bindBuilder, SelectBuilderExpressionSetter.INSTANCE);
} else {
throw new UnsupportedOperationException("Select statement should be bound to any CTE attribute");
}
}
}
} else {
for (Expression<?> selection : projection) {
renderSingleSelect(selection, (SelectBuilder<?>) criteriaBuilder);
}
}
}
renderOrderBy(subQueryMetadata, (OrderByBuilder<?>) criteriaBuilder);
renderParameters(subQueryMetadata, (ParameterHolder<?>) criteriaBuilder);
// Limit / offset on full query is set outside of the renderer, based on whether we're rendering a full count query or not
if (!(criteriaBuilder instanceof Queryable)) {
renderModifiers(subQueryMetadata.getModifiers(), (LimitBuilder<?>) criteriaBuilder);
}
return criteriaBuilder;
}
@Override
public Object visit(TemplateExpression<?> templateExpression, Object criteriaBuilder) {
throw new UnsupportedOperationException();
}
}, criteriaBuilder);
if (result instanceof BaseOngoingSetOperationBuilder) {
result = ((BaseOngoingSetOperationBuilder<?, ?, ?>) result).endSet();
}
if ((result instanceof FinalSetOperationCriteriaBuilder || result instanceof FinalSetOperationCTECriteriaBuilder || result instanceof FinalSetOperationSubqueryBuilder) && expression instanceof SubQueryExpression<?>) {
QueryMetadata metadata = ((SubQueryExpression<?>) expression).getMetadata();
renderOrderBy(metadata, (OrderByBuilder<?>) result);
// Limit / offset on full query is set outside of the renderer, based on whether we're rendering a full count query or not
if (!(criteriaBuilder instanceof Queryable)) {
renderModifiers(metadata.getModifiers(), (LimitBuilder<?>) result);
}
}
return result;
}
Aggregations