use of com.blazebit.persistence.ObjectBuilder in project blaze-persistence by Blazebit.
the class OptimizedKeysetPaginationRowValueConstructorTest method keysetPaginationWithSimpleObjectQueryTest.
@Test
public void keysetPaginationWithSimpleObjectQueryTest() {
KeysetPage keyset = null;
PaginatedCriteriaBuilder<String> crit = cbf.create(em, String.class).from(Document.class, "d").orderByAsc("d.id").selectNew(new ObjectBuilder<String>() {
@Override
public <X extends SelectBuilder<X>> void applySelects(X selectBuilder) {
selectBuilder.select("d.name").select("d.owner.name");
}
@Override
public String build(Object[] tuple) {
return tuple[0] + " - " + tuple[1];
}
@Override
public List<String> buildList(List<String> list) {
return list;
}
}).page(keyset, 0, 1);
PagedList<String> result = crit.getResultList();
assertEquals(1, result.size());
assertEquals("doc1 - Karl1", result.get(0));
keyset = result.getKeysetPage();
crit = crit.page(keyset, 1, 1);
result = crit.getResultList();
assertEquals(1, result.size());
assertEquals("doc2 - Karl2", result.get(0));
}
use of com.blazebit.persistence.ObjectBuilder in project blaze-persistence by Blazebit.
the class OptimizedKeysetPaginationTest method keysetPaginationWithSimpleObjectQueryTest.
@Test
public void keysetPaginationWithSimpleObjectQueryTest() {
KeysetPage keyset = null;
PaginatedCriteriaBuilder<String> crit = cbf.create(em, String.class).from(DocumentWithNullableName.class, "d").orderByAsc("d.id").selectNew(new ObjectBuilder<String>() {
@Override
public <X extends SelectBuilder<X>> void applySelects(X selectBuilder) {
selectBuilder.select("d.name").select("d.owner.name");
}
@Override
public String build(Object[] tuple) {
return tuple[0] + " - " + tuple[1];
}
@Override
public List<String> buildList(List<String> list) {
return list;
}
}).page(keyset, 0, 1);
PagedList<String> result = crit.getResultList();
assertEquals(1, result.size());
assertEquals("doc1 - Karl1", result.get(0));
keyset = result.getKeysetPage();
crit = crit.page(keyset, 1, 1);
result = crit.getResultList();
assertEquals(1, result.size());
assertEquals("doc2 - Karl2", result.get(0));
}
use of com.blazebit.persistence.ObjectBuilder in project blaze-persistence by Blazebit.
the class KeysetPaginationTest method keysetPaginationWithSimpleObjectQueryTest.
@Test
public void keysetPaginationWithSimpleObjectQueryTest() {
KeysetPage keyset = null;
PaginatedCriteriaBuilder<String> crit = cbf.create(em, String.class).from(Document.class, "d").orderByAsc("d.id").selectNew(new ObjectBuilder<String>() {
@Override
public <X extends SelectBuilder<X>> void applySelects(X selectBuilder) {
selectBuilder.select("d.name").select("d.owner.name");
}
@Override
public String build(Object[] tuple) {
return tuple[0] + " - " + tuple[1];
}
@Override
public List<String> buildList(List<String> list) {
return list;
}
}).page(keyset, 0, 1);
PagedList<String> result = crit.getResultList();
assertEquals(1, result.size());
assertEquals("doc1 - Karl1", result.get(0));
keyset = result.getKeysetPage();
crit = crit.page(keyset, 1, 1);
result = crit.getResultList();
assertEquals(1, result.size());
assertEquals("doc2 - Karl2", result.get(0));
}
use of com.blazebit.persistence.ObjectBuilder in project blaze-persistence by Blazebit.
the class AbstractCorrelatedBatchTupleListTransformer method transform.
@Override
public List<Object[]> transform(List<Object[]> tuples) {
FixedArrayList correlationParams = new FixedArrayList(batchSize);
// We have the correlation key on the first position if we do batching
final int tupleOffset = (batchSize > 1 ? 1 : 0) + (indexCorrelator == null && indexExpression == null ? 0 : 1);
final String correlationRoot = applyAndGetCorrelationRoot(expectBatchCorrelationMode);
// Add select items so that macros are properly used and we can query usage
ObjectBuilder<?> objectBuilder = correlator.finish(criteriaBuilder, entityViewConfiguration, 0, tupleOffset, correlationRoot, embeddingViewJpqlMacro, true);
if (batchSize > 1) {
criteriaBuilder.select(correlationSelectExpression);
}
if (indexCorrelator != null) {
ObjectBuilder<?> indexBuilder = indexCorrelator.finish(criteriaBuilder, entityViewConfiguration, tupleOffset, 0, indexExpression, embeddingViewJpqlMacro, true);
if (indexBuilder != null) {
criteriaBuilder.selectNew(new LateAdditionalObjectBuilder(objectBuilder, indexBuilder, false));
}
}
// If a view macro is used, we have to decide whether we do batches for each view id or correlation param
if (embeddingViewJpqlMacro.usesViewMacroNonId() || !correlatesThis && embeddingViewJpqlMacro.usesViewMacro()) {
if (!(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!");
}
transformViewMacroAware(tuples, correlationParams, tupleOffset, correlationRoot, embeddingViewJpqlMacro, BatchCorrelationMode.EMBEDDING_VIEWS, embeddingViewType, embeddingViewIndex);
} else if (viewRootJpqlMacro.usesViewMacro()) {
if (!(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!");
}
transformViewMacroAware(tuples, correlationParams, tupleOffset, correlationRoot, viewRootJpqlMacro, BatchCorrelationMode.VIEW_ROOTS, viewRootType, viewRootIndex);
} else {
EntityManager em = criteriaBuilder.getEntityManager();
Iterator<Object[]> tupleListIter = tuples.iterator();
if (batchSize > 1) {
// If the expectation was wrong, we have to create a new criteria builder
if (expectBatchCorrelationMode != BatchCorrelationMode.VALUES) {
applyAndGetCorrelationRoot(BatchCorrelationMode.VALUES);
objectBuilder = correlator.finish(criteriaBuilder, entityViewConfiguration, 0, tupleOffset, correlationRoot, embeddingViewJpqlMacro, true);
criteriaBuilder.select(correlationSelectExpression);
if (indexCorrelator != null) {
ObjectBuilder<?> indexBuilder = indexCorrelator.finish(criteriaBuilder, entityViewConfiguration, tupleOffset, 0, indexExpression, embeddingViewJpqlMacro, true);
if (indexBuilder != null) {
criteriaBuilder.selectNew(new LateAdditionalObjectBuilder(objectBuilder, indexBuilder, false));
}
}
}
}
populateParameters(criteriaBuilder);
query = criteriaBuilder.getQuery();
Map<Object, TuplePromise> correlationValues = new HashMap<>(tuples.size());
while (tupleListIter.hasNext()) {
Object[] tuple = tupleListIter.next();
Object correlationValue = tuple[startIndex];
TuplePromise tupleIndexValue = correlationValues.get(correlationValue);
if (tupleIndexValue == null) {
tupleIndexValue = new TuplePromise(startIndex);
tupleIndexValue.add(tuple);
correlationValues.put(correlationValue, tupleIndexValue);
// Can't correlate null
if (correlationValue != null) {
if (correlationBasisEntity != null) {
correlationParams.add(em.getReference(correlationBasisEntity, correlationValue));
} else {
correlationParams.add(correlationValue);
}
if (batchSize == correlationParams.realSize()) {
Object defaultKey;
if (correlationBasisEntity != null) {
defaultKey = jpaProvider.getIdentifier(correlationParams.get(0));
} else {
defaultKey = correlationParams.get(0);
}
batchLoad(correlationValues, correlationParams, null, defaultKey, viewRootJpqlMacro, BatchCorrelationMode.VALUES);
}
}
} else {
tupleIndexValue.add(tuple);
}
}
if (correlationParams.realSize() > 0) {
batchLoad(correlationValues, correlationParams, null, null, viewRootJpqlMacro, BatchCorrelationMode.VALUES);
}
fillDefaultValues(Collections.singletonMap(null, correlationValues));
}
consumeTupleMacroViewValues(tuples);
return tuples;
}
use of com.blazebit.persistence.ObjectBuilder 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;
}
Aggregations