/* * Copyright 2014 - 2017 Blazebit. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.blazebit.persistence.view.impl.objectbuilder.transformer.correlation; import com.blazebit.persistence.FullQueryBuilder; import com.blazebit.persistence.view.CorrelationProvider; import com.blazebit.persistence.view.impl.CorrelationProviderFactory; import com.blazebit.persistence.view.impl.EntityViewConfiguration; import com.blazebit.persistence.view.impl.macro.CorrelatedSubqueryViewRootJpqlMacro; import com.blazebit.persistence.view.metamodel.ManagedViewType; import java.util.HashMap; import java.util.List; import java.util.Map; /** * * @author Christian Beikov * @since 1.2.0 */ public abstract class AbstractCorrelatedSubselectTupleListTransformer extends AbstractCorrelatedTupleListTransformer { protected final String viewRootAlias; protected final String correlationKeyExpression; protected FullQueryBuilder<?, ?> criteriaBuilder; protected CorrelatedSubqueryViewRootJpqlMacro viewRootJpqlMacro; public AbstractCorrelatedSubselectTupleListTransformer(Correlator correlator, Class<?> criteriaBuilderRoot, ManagedViewType<?> viewRootType, String viewRootAlias, String correlationResult, String correlationKeyExpression, CorrelationProviderFactory correlationProviderFactory, String attributePath, String[] fetches, int tupleIndex, Class<?> correlationBasisType, Class<?> correlationBasisEntity, EntityViewConfiguration entityViewConfiguration) { super(correlator, criteriaBuilderRoot, viewRootType, correlationResult, correlationProviderFactory, attributePath, fetches, tupleIndex, correlationBasisType, correlationBasisEntity, entityViewConfiguration); this.viewRootAlias = viewRootAlias; this.correlationKeyExpression = correlationKeyExpression; } private String applyAndGetCorrelationRoot() { Class<?> viewRootEntityClass = viewRootType.getEntityClass(); String idAttributePath = getEntityIdName(viewRootEntityClass); FullQueryBuilder<?, ?> queryBuilder = entityViewConfiguration.getCriteriaBuilder(); Map<String, Object> optionalParameters = entityViewConfiguration.getOptionalParameters(); Class<?> correlationBasisEntityType = correlationBasisEntity; String viewRootExpression = viewRootAlias; this.criteriaBuilder = queryBuilder.copy(Object[].class); this.viewRootJpqlMacro = new CorrelatedSubqueryViewRootJpqlMacro(criteriaBuilder, optionalParameters, viewRootEntityClass, idAttributePath, viewRootExpression); this.criteriaBuilder.registerMacro("view_root", viewRootJpqlMacro); SubqueryCorrelationBuilder correlationBuilder = new SubqueryCorrelationBuilder(criteriaBuilder, correlationResult, correlationBasisType, correlationBasisEntityType, null, 1, true, attributePath); CorrelationProvider provider = correlationProviderFactory.create(entityViewConfiguration.getCriteriaBuilder(), entityViewConfiguration.getOptionalParameters()); provider.applyCorrelation(correlationBuilder, correlationKeyExpression); if (fetches.length != 0) { for (int i = 0; i < fetches.length; i++) { criteriaBuilder.fetch(correlationBuilder.getCorrelationAlias() + "." + fetches[i]); } } return correlationBuilder.getCorrelationRoot(); } @Override public List<Object[]> transform(List<Object[]> tuples) { final String correlationRoot = applyAndGetCorrelationRoot(); final boolean usesViewRoot = viewRootJpqlMacro.usesViewRoot(); int totalSize = tuples.size(); Map<Object, Map<Object, TuplePromise>> viewRoots = new HashMap<Object, Map<Object, TuplePromise>>(totalSize); if (usesViewRoot) { criteriaBuilder.select(viewRootAlias + "." + getEntityIdName(viewRootType.getEntityClass())); // Group tuples by view roots and correlation values and create tuple promises for (Object[] tuple : tuples) { Object viewRootKey = tuple[0]; Object correlationValueKey = tuple[startIndex]; Map<Object, TuplePromise> viewRootCorrelationValues = viewRoots.get(viewRootKey); if (viewRootCorrelationValues == null) { viewRootCorrelationValues = new HashMap<Object, TuplePromise>(); viewRoots.put(viewRootKey, viewRootCorrelationValues); } TuplePromise viewRootPromise = viewRootCorrelationValues.get(correlationValueKey); if (viewRootPromise == null) { viewRootPromise = new TuplePromise(startIndex); viewRootCorrelationValues.put(correlationValueKey, viewRootPromise); } viewRootPromise.add(tuple); } } else { Map<Object, TuplePromise> viewRootCorrelationValues = new HashMap<Object, TuplePromise>(tuples.size()); viewRoots.put(null, viewRootCorrelationValues); // Group tuples by correlation values and create tuple promises for (Object[] tuple : tuples) { Object correlationValueKey = tuple[startIndex]; TuplePromise viewRootPromise = viewRootCorrelationValues.get(correlationValueKey); if (viewRootPromise == null) { viewRootPromise = new TuplePromise(startIndex); viewRootCorrelationValues.put(correlationValueKey, viewRootPromise); } viewRootPromise.add(tuple); } } criteriaBuilder.select(correlationKeyExpression); // We have the view root id on the first and the correlation key on the second position correlator.finish(criteriaBuilder, entityViewConfiguration, usesViewRoot ? 2 : 1, correlationRoot); populateParameters(criteriaBuilder); List<Object[]> resultList = (List<Object[]>) criteriaBuilder.getResultList(); populateResult(usesViewRoot, viewRoots, resultList); fillDefaultValues(viewRoots); return tuples; } protected abstract void populateResult(boolean usesViewRoot, Map<Object, Map<Object, TuplePromise>> correlationValues, List<Object[]> list); }