use of com.blazebit.persistence.LimitBuilder 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;
}
use of com.blazebit.persistence.LimitBuilder in project blaze-persistence by Blazebit.
the class ExpressionCorrelationJoinTupleElementMapper method applyMapping.
@Override
public void applyMapping(SelectBuilder<?> queryBuilder, ParameterHolder<?> parameterHolder, Map<String, Object> optionalParameters, ViewJpqlMacro viewJpqlMacro, EmbeddingViewJpqlMacro embeddingViewJpqlMacro, boolean asString) {
String oldViewPath = viewJpqlMacro.getViewPath();
String oldEmbeddingViewPath = embeddingViewJpqlMacro.getEmbeddingViewPath();
viewJpqlMacro.setViewPath(embeddingViewPath);
embeddingViewJpqlMacro.setEmbeddingViewPath(embeddingViewPath);
FullQueryBuilder<?, ?> fullQueryBuilder;
if (queryBuilder instanceof ConstrainedSelectBuilder) {
fullQueryBuilder = ((ConstrainedSelectBuilder) queryBuilder).getQueryBuilder();
} else {
fullQueryBuilder = (FullQueryBuilder<?, ?>) queryBuilder;
}
int originalFirstResult = -1;
int originalMaxResults = -1;
if (queryBuilder instanceof LimitBuilder<?>) {
originalFirstResult = ((LimitBuilder<?>) queryBuilder).getFirstResult();
originalMaxResults = ((LimitBuilder<?>) queryBuilder).getMaxResults();
}
JoinCorrelationBuilder correlationBuilder = new JoinCorrelationBuilder(parameterHolder, optionalParameters, fullQueryBuilder, joinBase, correlationAlias, correlationExternalAlias, attributePath, JoinType.LEFT, limiter);
provider.applyCorrelation(correlationBuilder, correlationBasis);
if (queryBuilder instanceof LimitBuilder<?>) {
if (originalFirstResult != ((LimitBuilder<?>) queryBuilder).getFirstResult() || originalMaxResults != ((LimitBuilder<?>) queryBuilder).getMaxResults()) {
throw new IllegalArgumentException("Correlation provider '" + provider + "' wrongly uses setFirstResult() or setMaxResults() on the query builder which might lead to wrong results. Use SELECT fetching with batch size 1 or reformulate the correlation provider to use the limit/offset in a subquery!");
}
}
correlationBuilder.finish();
// Basic element has an alias, subviews don't
if (alias != null) {
viewJpqlMacro.setViewPath(null);
queryBuilder.select(correlationResult, alias);
}
viewJpqlMacro.setViewPath(oldViewPath);
embeddingViewJpqlMacro.setEmbeddingViewPath(oldEmbeddingViewPath);
if (fetches.length != 0) {
for (int i = 0; i < fetches.length; i++) {
fullQueryBuilder.fetch(correlationBuilder.getCorrelationAlias() + "." + fetches[i]);
}
}
}
use of com.blazebit.persistence.LimitBuilder in project blaze-persistence by Blazebit.
the class AbstractCorrelatedSubselectTupleTransformer method prepare.
private void prepare() {
JpaProvider jpaProvider = entityViewConfiguration.getCriteriaBuilder().getService(JpaProvider.class);
FullQueryBuilder<?, ?> queryBuilder = entityViewConfiguration.getCriteriaBuilder();
Map<String, Object> optionalParameters = entityViewConfiguration.getOptionalParameters();
Class<?> correlationBasisEntityType = correlationBasisEntity;
String viewRootExpression = viewRootAlias;
EmbeddingViewJpqlMacro embeddingViewJpqlMacro = entityViewConfiguration.getEmbeddingViewJpqlMacro();
ViewJpqlMacro viewJpqlMacro = entityViewConfiguration.getViewJpqlMacro();
if (queryBuilder instanceof PaginatedCriteriaBuilder<?>) {
criteriaBuilder = queryBuilder.copyCriteriaBuilder(Object[].class, false);
} else {
LimitBuilder<?> limitBuilder = (LimitBuilder<?>) queryBuilder;
// To set the limit, we need the JPA provider to support this
if (jpaProvider.supportsSubqueryInFunction() && (limitBuilder.getFirstResult() > 0 || limitBuilder.getMaxResults() < Integer.MAX_VALUE)) {
// we must turn this query builder into a paginated criteria builder first
try {
criteriaBuilder = queryBuilder.copyCriteriaBuilder(Object[].class, true).page(limitBuilder.getFirstResult(), limitBuilder.getMaxResults()).copyCriteriaBuilder(Object[].class, false);
} catch (IllegalStateException ex) {
LOG.log(Level.WARNING, "Could not create a paginated criteria builder for SUBSELECT fetching which might lead to bad performance", ex);
criteriaBuilder = queryBuilder.copyCriteriaBuilder(Object[].class, false);
}
} else {
// Regular query without limit/offset
criteriaBuilder = queryBuilder.copyCriteriaBuilder(Object[].class, false);
}
}
int originalFirstResult = 0;
int originalMaxResults = Integer.MAX_VALUE;
// A copied query that is extended with further joins can't possibly use the limits provided by the outer query
((LimitBuilder<?>) criteriaBuilder).setFirstResult(originalFirstResult);
((LimitBuilder<?>) criteriaBuilder).setMaxResults(originalMaxResults);
this.viewRootJpqlMacro = new CorrelatedSubqueryViewRootJpqlMacro(criteriaBuilder, optionalParameters, false, viewRootEntityClass, idAttributePath, viewRootExpression);
criteriaBuilder.registerMacro("view", viewJpqlMacro);
criteriaBuilder.registerMacro("view_root", viewRootJpqlMacro);
criteriaBuilder.registerMacro("embedding_view", embeddingViewJpqlMacro);
String oldViewPath = viewJpqlMacro.getViewPath();
String oldEmbeddingViewPath = embeddingViewJpqlMacro.getEmbeddingViewPath();
viewJpqlMacro.setViewPath(correlationResultExpression);
embeddingViewJpqlMacro.setEmbeddingViewPath(embeddingViewPath);
String joinBase = embeddingViewPath;
SubqueryCorrelationBuilder correlationBuilder = new SubqueryCorrelationBuilder(queryBuilder, optionalParameters, criteriaBuilder, correlationAlias, correlationExternalAlias, correlationResultExpression, correlationBasisType, correlationBasisEntityType, joinBase, attributePath, 1, limiter, true);
CorrelationProvider provider = correlationProviderFactory.create(entityViewConfiguration.getCriteriaBuilder(), entityViewConfiguration.getOptionalParameters());
provider.applyCorrelation(correlationBuilder, correlationBasisExpression);
if (criteriaBuilder instanceof LimitBuilder<?>) {
if (originalFirstResult != ((LimitBuilder<?>) criteriaBuilder).getFirstResult() || originalMaxResults != ((LimitBuilder<?>) criteriaBuilder).getMaxResults()) {
throw new IllegalArgumentException("Correlation provider '" + provider + "' wrongly uses setFirstResult() or setMaxResults() on the query builder which might lead to wrong results. Use SELECT fetching with batch size 1 or reformulate the correlation provider to use the limit/offset in a subquery!");
}
}
if (fetches.length != 0) {
for (int i = 0; i < fetches.length; i++) {
criteriaBuilder.fetch(fetches[i]);
}
}
if (indexFetches.length != 0) {
for (int i = 0; i < indexFetches.length; i++) {
criteriaBuilder.fetch(indexFetches[i]);
}
}
// Before we can determine whether we use view roots or embedding views, we need to add all selects, otherwise macros might report false although they are used
final String correlationRoot = correlationBuilder.getCorrelationRoot();
final int tupleSuffix = maximumViewMapperCount + 1 + (indexCorrelator == null && indexExpression == null ? 0 : 1);
ObjectBuilder<Object[]> objectBuilder = (ObjectBuilder<Object[]>) correlator.finish(criteriaBuilder, entityViewConfiguration, 0, tupleSuffix, correlationRoot, embeddingViewJpqlMacro, true);
final boolean usesViewRoot = viewRootJpqlMacro.usesViewMacro();
final boolean usesEmbeddingView = embeddingViewJpqlMacro.usesEmbeddingView();
if (usesEmbeddingView && !(embeddingViewType instanceof ViewType<?>)) {
throw new IllegalStateException("The use of EMBEDDING_VIEW in the correlation for '" + embeddingViewType.getJavaType().getName() + "." + attributePath.substring(attributePath.lastIndexOf('.') + 1) + "' is illegal because the embedding view type '" + embeddingViewType.getJavaType().getName() + "' does not declare a @IdMapping!");
} else if (usesViewRoot && !(viewRootType instanceof ViewType<?>)) {
throw new IllegalStateException("The use of VIEW_ROOT in the correlation for '" + embeddingViewType.getJavaType().getName() + "." + attributePath.substring(attributePath.lastIndexOf('.') + 1) + "' is illegal because the view root type '" + viewRootType.getJavaType().getName() + "' does not declare a @IdMapping!");
}
final int maximumSlotsFilled;
final int elementKeyIndex;
final int elementViewIndex;
if (usesEmbeddingView) {
maximumSlotsFilled = embeddingViewIdMapperCount == 0 ? 1 : embeddingViewIdMapperCount;
elementKeyIndex = (maximumViewMapperCount - maximumSlotsFilled) + 2 + valueIndex;
elementViewIndex = (maximumViewMapperCount - maximumSlotsFilled) + 1 + valueIndex;
viewIndex = embeddingViewIndex;
} else if (usesViewRoot) {
maximumSlotsFilled = viewRootIdMapperCount == 0 ? 1 : viewRootIdMapperCount;
elementKeyIndex = (maximumViewMapperCount - maximumSlotsFilled) + 2 + valueIndex;
elementViewIndex = (maximumViewMapperCount - maximumSlotsFilled) + 1 + valueIndex;
viewIndex = viewRootIndex;
} else {
maximumSlotsFilled = 0;
elementKeyIndex = maximumViewMapperCount + 1 + valueIndex;
elementViewIndex = 1 + valueIndex;
viewIndex = -1;
}
for (int i = maximumSlotsFilled; i < maximumViewMapperCount; i++) {
criteriaBuilder.select("NULL");
}
ExpressionFactory ef = criteriaBuilder.getService(ExpressionFactory.class);
if (usesEmbeddingView) {
EntityViewConfiguration configuration = new EntityViewConfiguration(criteriaBuilder, ef, new MutableViewJpqlMacro(), new MutableEmbeddingViewJpqlMacro(), Collections.<String, Object>emptyMap(), Collections.<String, Object>emptyMap(), entityViewConfiguration.getFetches(), attributePath);
ObjectBuilder<Object[]> embeddingViewObjectBuilder = createViewAwareObjectBuilder(criteriaBuilder, embeddingViewType, configuration, embeddingViewIdExpression);
if (embeddingViewObjectBuilder == null) {
criteriaBuilder.select(embeddingViewIdExpression);
} else {
criteriaBuilder.selectNew(objectBuilder = new LateAdditionalObjectBuilder(objectBuilder, embeddingViewObjectBuilder, true));
}
} else if (usesViewRoot) {
EntityViewConfiguration configuration = new EntityViewConfiguration(criteriaBuilder, ef, new MutableViewJpqlMacro(), new MutableEmbeddingViewJpqlMacro(), Collections.<String, Object>emptyMap(), Collections.<String, Object>emptyMap(), entityViewConfiguration.getFetches(), attributePath);
ObjectBuilder<Object[]> viewRootObjectBuilder = createViewAwareObjectBuilder(criteriaBuilder, viewRootType, configuration, viewRootIdExpression);
if (viewRootObjectBuilder == null) {
criteriaBuilder.select(viewRootIdExpression);
} else {
criteriaBuilder.selectNew(objectBuilder = new LateAdditionalObjectBuilder(objectBuilder, viewRootObjectBuilder, true));
}
}
criteriaBuilder.select(correlationKeyExpression);
if (indexCorrelator != null) {
ObjectBuilder<?> indexBuilder = indexCorrelator.finish(criteriaBuilder, entityViewConfiguration, maximumViewMapperCount + 2, 0, indexExpression, embeddingViewJpqlMacro, true);
if (indexBuilder != null) {
criteriaBuilder.selectNew(new LateAdditionalObjectBuilder(objectBuilder, indexBuilder, false));
}
}
populateParameters(entityViewConfiguration, criteriaBuilder);
viewJpqlMacro.setViewPath(oldViewPath);
embeddingViewJpqlMacro.setEmbeddingViewPath(oldEmbeddingViewPath);
List<Object[]> resultList = (List<Object[]>) criteriaBuilder.getResultList();
Map<Object, Map<Object, Object>> collections = new HashMap<>(resultList.size());
for (int i = 0; i < resultList.size(); i++) {
Object[] element = resultList.get(i);
Map<Object, Object> viewRootResult = collections.get(element[elementViewIndex]);
if (viewRootResult == null) {
viewRootResult = new HashMap<>();
collections.put(element[elementViewIndex], viewRootResult);
}
if (this.containerAccumulator == null) {
viewRootResult.put(element[elementKeyIndex], element[valueIndex]);
} else {
Object result = viewRootResult.get(element[elementKeyIndex]);
if (result == null) {
result = createDefaultResult();
viewRootResult.put(element[elementKeyIndex], result);
}
Object indexObject = null;
if (indexCorrelator != null || indexExpression != null) {
indexObject = element[elementKeyIndex + 1];
}
this.containerAccumulator.add(result, indexObject, element[valueIndex], isRecording());
}
}
this.collections = collections;
}
use of com.blazebit.persistence.LimitBuilder in project blaze-persistence by Blazebit.
the class CorrelatedSubviewJoinTupleTransformerFactory method create.
@Override
public TupleTransformer create(ParameterHolder<?> parameterHolder, Map<String, Object> optionalParameters, EntityViewConfiguration entityViewConfiguration) {
if (!entityViewConfiguration.hasSubFetches(attributePath)) {
return new NullTupleTransformer(template);
}
// For now it's ok, but at some point we will want to support correlated attributes somehow and need to think of a fallback solution here
if (parameterHolder instanceof FullQueryBuilder<?, ?>) {
FullQueryBuilder<?, ?> queryBuilder = (FullQueryBuilder<?, ?>) parameterHolder;
CorrelationProvider provider = correlationProviderFactory.create(parameterHolder, optionalParameters);
JoinCorrelationBuilder correlationBuilder = new JoinCorrelationBuilder(parameterHolder, optionalParameters, queryBuilder, joinBase, correlationAlias, correlationExternalAlias, attributePath, JoinType.LEFT, limiter);
int originalFirstResult = -1;
int originalMaxResults = -1;
if (queryBuilder instanceof LimitBuilder<?>) {
originalFirstResult = ((LimitBuilder<?>) queryBuilder).getFirstResult();
originalMaxResults = ((LimitBuilder<?>) queryBuilder).getMaxResults();
}
ViewJpqlMacro viewJpqlMacro = entityViewConfiguration.getViewJpqlMacro();
EmbeddingViewJpqlMacro embeddingViewJpqlMacro = entityViewConfiguration.getEmbeddingViewJpqlMacro();
String oldViewPath = viewJpqlMacro.getViewPath();
String oldEmbeddingViewPath = embeddingViewJpqlMacro.getEmbeddingViewPath();
// If this uses a static path, we need to avoid setting the embedding view path etc.
if (!(provider instanceof StaticPathCorrelationProvider)) {
viewJpqlMacro.setViewPath(correlationBuilder.getCorrelationAlias());
embeddingViewJpqlMacro.setEmbeddingViewPath(embeddingViewPath);
}
provider.applyCorrelation(correlationBuilder, correlationBasis);
if (queryBuilder instanceof LimitBuilder<?>) {
if (originalFirstResult != ((LimitBuilder<?>) queryBuilder).getFirstResult() || originalMaxResults != ((LimitBuilder<?>) queryBuilder).getMaxResults()) {
throw new IllegalArgumentException("Correlation provider '" + provider + "' wrongly uses setFirstResult() or setMaxResults() on the query builder which might lead to wrong results. Use SELECT fetching with batch size 1 or reformulate the correlation provider to use the limit/offset in a subquery!");
}
}
correlationBuilder.finish();
if (!(provider instanceof StaticPathCorrelationProvider)) {
viewJpqlMacro.setViewPath(oldViewPath);
embeddingViewJpqlMacro.setEmbeddingViewPath(oldEmbeddingViewPath);
}
if (fetches.length != 0) {
for (int i = 0; i < fetches.length; i++) {
queryBuilder.fetch(correlationBuilder.getCorrelationAlias() + "." + fetches[i]);
}
}
ObjectBuilder<Object[]> objectBuilder = template.createObjectBuilder(parameterHolder, optionalParameters, entityViewConfiguration, 0, true, false);
return new CorrelatedSubviewJoinTupleTransformer(template, objectBuilder);
} else {
throw new UnsupportedOperationException("Converting views with correlated attributes isn't supported!");
}
}
use of com.blazebit.persistence.LimitBuilder in project blaze-persistence by Blazebit.
the class ParameterizedExpressionCorrelationJoinTupleElementMapper method applyMapping.
@Override
public void applyMapping(SelectBuilder<?> queryBuilder, ParameterHolder<?> parameterHolder, Map<String, Object> optionalParameters, ViewJpqlMacro viewJpqlMacro, EmbeddingViewJpqlMacro embeddingViewJpqlMacro, boolean asString) {
String oldViewPath = viewJpqlMacro.getViewPath();
String oldEmbeddingViewPath = embeddingViewJpqlMacro.getEmbeddingViewPath();
viewJpqlMacro.setViewPath(embeddingViewPath);
embeddingViewJpqlMacro.setEmbeddingViewPath(embeddingViewPath);
FullQueryBuilder<?, ?> fullQueryBuilder;
if (queryBuilder instanceof ConstrainedSelectBuilder) {
fullQueryBuilder = ((ConstrainedSelectBuilder) queryBuilder).getQueryBuilder();
} else {
fullQueryBuilder = (FullQueryBuilder<?, ?>) queryBuilder;
}
int originalFirstResult = -1;
int originalMaxResults = -1;
if (queryBuilder instanceof LimitBuilder<?>) {
originalFirstResult = ((LimitBuilder<?>) queryBuilder).getFirstResult();
originalMaxResults = ((LimitBuilder<?>) queryBuilder).getMaxResults();
}
JoinCorrelationBuilder correlationBuilder = new JoinCorrelationBuilder(parameterHolder, optionalParameters, fullQueryBuilder, joinBase, correlationAlias, correlationExternalAlias, attributePath, JoinType.LEFT, limiter);
CorrelationProvider provider = providerFactory.create(parameterHolder, optionalParameters);
provider.applyCorrelation(correlationBuilder, correlationBasis);
if (queryBuilder instanceof LimitBuilder<?>) {
if (originalFirstResult != ((LimitBuilder<?>) queryBuilder).getFirstResult() || originalMaxResults != ((LimitBuilder<?>) queryBuilder).getMaxResults()) {
throw new IllegalArgumentException("Correlation provider '" + provider + "' wrongly uses setFirstResult() or setMaxResults() on the query builder which might lead to wrong results. Use SELECT fetching with batch size 1 or reformulate the correlation provider to use the limit/offset in a subquery!");
}
}
correlationBuilder.finish();
// Basic element has an alias, subviews don't
if (alias != null) {
viewJpqlMacro.setViewPath(null);
queryBuilder.select(correlationResult, alias);
}
viewJpqlMacro.setViewPath(oldViewPath);
embeddingViewJpqlMacro.setEmbeddingViewPath(oldEmbeddingViewPath);
if (fetches.length != 0) {
for (int i = 0; i < fetches.length; i++) {
fullQueryBuilder.fetch(correlationBuilder.getCorrelationAlias() + "." + fetches[i]);
}
}
}
Aggregations