org.springframework.data.jpa.repository.support.FetchableFluentQueryByExample Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-data-jpa Show documentation
Show all versions of spring-data-jpa Show documentation
Spring Data module for JPA repositories.
/*
* Copyright 2021-2022 the original author or authors.
*
* 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
*
* https://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 org.springframework.data.jpa.repository.support;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.query.EscapeCharacter;
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.util.Assert;
/**
* Immutable implementation of {@link FetchableFluentQuery} based on Query by {@link Example}. All methods that return a
* {@link FetchableFluentQuery} will return a new instance, not the original.
*
* @param Domain type
* @param Result type
* @author Greg Turnquist
* @author Mark Paluch
* @author Jens Schauder
* @author J.R. Onyschak
* @since 2.6
*/
class FetchableFluentQueryByExample extends FluentQuerySupport implements FetchableFluentQuery {
private final Example example;
private final Function> finder;
private final Function, Long> countOperation;
private final Function, Boolean> existsOperation;
private final EntityManager entityManager;
private final EscapeCharacter escapeCharacter;
public FetchableFluentQueryByExample(Example example, Function> finder,
Function, Long> countOperation, Function, Boolean> existsOperation,
EntityManager entityManager, EscapeCharacter escapeCharacter) {
this(example, example.getProbeType(), (Class) example.getProbeType(), Sort.unsorted(), Collections.emptySet(),
finder, countOperation, existsOperation, entityManager, escapeCharacter);
}
private FetchableFluentQueryByExample(Example example, Class entityType, Class returnType, Sort sort,
Collection properties, Function> finder, Function, Long> countOperation,
Function, Boolean> existsOperation,
EntityManager entityManager, EscapeCharacter escapeCharacter) {
super(returnType, sort, properties, entityType);
this.example = example;
this.finder = finder;
this.countOperation = countOperation;
this.existsOperation = existsOperation;
this.entityManager = entityManager;
this.escapeCharacter = escapeCharacter;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#sortBy(org.springframework.data.domain.Sort)
*/
@Override
public FetchableFluentQuery sortBy(Sort sort) {
Assert.notNull(sort, "Sort must not be null!");
return new FetchableFluentQueryByExample<>(example, entityType, resultType, this.sort.and(sort), properties,
finder, countOperation, existsOperation, entityManager, escapeCharacter);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#as(java.lang.Class)
*/
@Override
public FetchableFluentQuery as(Class resultType) {
Assert.notNull(resultType, "Projection target type must not be null!");
if (!resultType.isInterface()) {
throw new UnsupportedOperationException("Class-based DTOs are not yet supported.");
}
return new FetchableFluentQueryByExample<>(example, entityType, resultType, sort, properties, finder,
countOperation, existsOperation, entityManager, escapeCharacter);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#project(java.util.Collection)
*/
@Override
public FetchableFluentQuery project(Collection properties) {
return new FetchableFluentQueryByExample<>(example, entityType, resultType, sort, mergeProperties(properties),
finder, countOperation, existsOperation, entityManager, escapeCharacter);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#oneValue()
*/
@Override
public R oneValue() {
TypedQuery limitedQuery = createSortedAndProjectedQuery();
limitedQuery.setMaxResults(2); // Never need more than 2 values
List results = limitedQuery.getResultList();
if (results.size() > 1) {
throw new IncorrectResultSizeDataAccessException(1);
}
return results.isEmpty() ? null : getConversionFunction().apply(results.get(0));
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#firstValue()
*/
@Override
public R firstValue() {
TypedQuery limitedQuery = createSortedAndProjectedQuery();
limitedQuery.setMaxResults(1); // Never need more than 1 value
List results = limitedQuery.getResultList();
return results.isEmpty() ? null : getConversionFunction().apply(results.get(0));
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#all()
*/
@Override
public List all() {
List resultList = createSortedAndProjectedQuery().getResultList();
return convert(resultList);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#page(org.springframework.data.domain.Pageable)
*/
@Override
public Page page(Pageable pageable) {
return pageable.isUnpaged() ? new PageImpl<>(all()) : readPage(pageable);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#stream()
*/
@Override
public Stream stream() {
return createSortedAndProjectedQuery() //
.getResultStream() //
.map(getConversionFunction());
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#count()
*/
@Override
public long count() {
return countOperation.apply(example);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#exists()
*/
@Override
public boolean exists() {
return existsOperation.apply(example);
}
private Page readPage(Pageable pageable) {
TypedQuery pagedQuery = createSortedAndProjectedQuery();
if (pageable.isPaged()) {
pagedQuery.setFirstResult((int) pageable.getOffset());
pagedQuery.setMaxResults(pageable.getPageSize());
}
List paginatedResults = convert(pagedQuery.getResultList());
return PageableExecutionUtils.getPage(paginatedResults, pageable, () -> countOperation.apply(example));
}
private TypedQuery createSortedAndProjectedQuery() {
TypedQuery query = finder.apply(sort);
if (!properties.isEmpty()) {
query.setHint(EntityGraphFactory.HINT, EntityGraphFactory.create(entityManager, entityType, properties));
}
return query;
}
private List convert(List resultList) {
Function