spring-data-redis QueryByExampleRedisExecutor 源码
spring-data-redis QueryByExampleRedisExecutor 代码
文件路径:/src/main/java/org/springframework/data/redis/repository/support/QueryByExampleRedisExecutor.java
/*
* Copyright 2018-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.redis.repository.support;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.convert.DtoInstantiatingConverter;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
import org.springframework.data.mapping.model.EntityInstantiators;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.redis.core.RedisKeyValueTemplate;
import org.springframework.data.redis.core.convert.IndexResolver;
import org.springframework.data.redis.core.convert.PathIndexResolver;
import org.springframework.data.redis.repository.query.ExampleQueryMapper;
import org.springframework.data.redis.repository.query.RedisOperationChain;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.query.FluentQuery;
import org.springframework.data.repository.query.QueryByExampleExecutor;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.data.util.Streamable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Repository fragment implementing Redis {@link QueryByExampleExecutor Query-by-Example} operations.
* <p>
* This executor uses {@link ExampleQueryMapper} to map {@link Example}s into {@link KeyValueQuery} to execute its query
* methods.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.1
*/
@SuppressWarnings("unchecked")
public class QueryByExampleRedisExecutor<T>
implements QueryByExampleExecutor<T>, BeanFactoryAware, BeanClassLoaderAware {
private final EntityInformation<T, ?> entityInformation;
private final RedisKeyValueTemplate keyValueTemplate;
private final ExampleQueryMapper mapper;
private final SpelAwareProxyProjectionFactory projectionFactory;
private final EntityInstantiators entityInstantiators = new EntityInstantiators();
/**
* Create a new {@link QueryByExampleRedisExecutor} given {@link EntityInformation} and {@link RedisKeyValueTemplate}.
* This constructor uses the configured {@link IndexResolver} from the converter.
*
* @param entityInformation must not be {@literal null}.
* @param keyValueTemplate must not be {@literal null}.
*/
public QueryByExampleRedisExecutor(EntityInformation<T, ?> entityInformation,
RedisKeyValueTemplate keyValueTemplate) {
this(entityInformation, keyValueTemplate,
keyValueTemplate.getConverter().getIndexResolver() != null ? keyValueTemplate.getConverter().getIndexResolver()
: new PathIndexResolver(keyValueTemplate.getMappingContext()));
}
/**
* Create a new {@link QueryByExampleRedisExecutor} given {@link EntityInformation} and {@link RedisKeyValueTemplate}.
*
* @param entityInformation must not be {@literal null}.
* @param keyValueTemplate must not be {@literal null}.
*/
public QueryByExampleRedisExecutor(EntityInformation<T, ?> entityInformation, RedisKeyValueTemplate keyValueTemplate,
IndexResolver indexResolver) {
Assert.notNull(entityInformation, "EntityInformation must not be null");
Assert.notNull(keyValueTemplate, "RedisKeyValueTemplate must not be null");
Assert.notNull(indexResolver, "IndexResolver must not be null");
this.entityInformation = entityInformation;
this.keyValueTemplate = keyValueTemplate;
this.mapper = new ExampleQueryMapper(keyValueTemplate.getMappingContext(), indexResolver);
this.projectionFactory = new SpelAwareProxyProjectionFactory();
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.projectionFactory.setBeanFactory(beanFactory);
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.projectionFactory.setBeanClassLoader(classLoader);
}
@Override
public <S extends T> Optional<S> findOne(Example<S> example) {
return Optional.ofNullable(doFindOne(example));
}
@Nullable
private <S extends T> S doFindOne(Example<S> example) {
Iterator<S> iterator = doFind(example);
if (iterator.hasNext()) {
S result = iterator.next();
if (iterator.hasNext()) {
throw new IncorrectResultSizeDataAccessException(1);
}
return result;
}
return null;
}
private <S extends T> Iterator<S> doFind(Example<S> example) {
RedisOperationChain operationChain = createQuery(example);
KeyValueQuery<RedisOperationChain> query = new KeyValueQuery<>(operationChain);
return (Iterator<S>) keyValueTemplate.find(query.limit(2), entityInformation.getJavaType()).iterator();
}
@Override
public <S extends T> Iterable<S> findAll(Example<S> example) {
RedisOperationChain operationChain = createQuery(example);
return (Iterable<S>) keyValueTemplate.find(new KeyValueQuery<>(operationChain), entityInformation.getJavaType());
}
@Override
public <S extends T> Iterable<S> findAll(Example<S> example, Sort sort) {
throw new UnsupportedOperationException("Ordering is not supported");
}
@Override
public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
Assert.notNull(pageable, "Pageable must not be null");
RedisOperationChain operationChain = createQuery(example);
KeyValueQuery<RedisOperationChain> query = new KeyValueQuery<>(operationChain);
List<S> result = (List<S>) keyValueTemplate.find(
query.orderBy(pageable.getSort()).skip(pageable.getOffset()).limit(pageable.getPageSize()),
entityInformation.getJavaType());
return PageableExecutionUtils.getPage(result, pageable,
() -> operationChain.isEmpty() ? keyValueTemplate.count(entityInformation.getJavaType())
: keyValueTemplate.count(query, entityInformation.getJavaType()));
}
@Override
public <S extends T> long count(Example<S> example) {
RedisOperationChain operationChain = createQuery(example);
return keyValueTemplate.count(new KeyValueQuery<>(operationChain), entityInformation.getJavaType());
}
@Override
public <S extends T> boolean exists(Example<S> example) {
return count(example) > 0;
}
@Override
public <S extends T, R> R findBy(Example<S> example,
Function<org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery<S>, R> queryFunction) {
Assert.notNull(example, "Example must not be null");
Assert.notNull(queryFunction, "Query function must not be null");
return queryFunction.apply(new FluentQueryByExample<>(example, example.getProbeType()));
}
private <S extends T> RedisOperationChain createQuery(Example<S> example) {
Assert.notNull(example, "Example must not be null");
return mapper.getMappedExample(example);
}
/**
* {@link org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery} using {@link Example}.
*
* @author Mark Paluch
* @since 2.6
*/
class FluentQueryByExample<S extends T, R> implements FluentQuery.FetchableFluentQuery<R> {
private final Example<S> example;
private final Sort sort;
private final Class<?> domainType;
private final Class<R> resultType;
FluentQueryByExample(Example<S> example, Class<R> resultType) {
this(example, Sort.unsorted(), resultType, resultType);
}
FluentQueryByExample(Example<S> example, Sort sort, Class<?> domainType, Class<R> resultType) {
this.example = example;
this.sort = sort;
this.domainType = domainType;
this.resultType = resultType;
}
@Override
public FetchableFluentQuery<R> sortBy(Sort sort) {
return new FluentQueryByExample<>(example, sort, domainType, resultType);
}
@Override
public <R1> FetchableFluentQuery<R1> as(Class<R1> resultType) {
return new FluentQueryByExample<>(example, sort, domainType, resultType);
}
@Override
public FetchableFluentQuery<R> project(Collection<String> properties) {
return this;
}
@Nullable
@Override
public R oneValue() {
S one = doFindOne(example);
if (one != null) {
return getConversionFunction(entityInformation.getJavaType(), resultType).apply(one);
}
return null;
}
@Nullable
@Override
public R firstValue() {
Iterator<S> iterator = doFind(example);
if (iterator.hasNext()) {
return getConversionFunction(entityInformation.getJavaType(), resultType).apply(iterator.next());
}
return null;
}
@Override
public List<R> all() {
return stream().collect(Collectors.toList());
}
@Override
public Page<R> page(Pageable pageable) {
Assert.notNull(pageable, "Pageable must not be null");
Function<Object, R> conversionFunction = getConversionFunction(entityInformation.getJavaType(), resultType);
List<R> content = findAll(example, pageable).stream().map(conversionFunction).collect(Collectors.toList());
return PageableExecutionUtils.getPage(content, pageable, this::count);
}
@Override
public Stream<R> stream() {
Function<Object, R> conversionFunction = getConversionFunction(entityInformation.getJavaType(), resultType);
if (sort.isSorted()) {
return findAll(example, PageRequest.of(0, Integer.MAX_VALUE, sort)).stream().map(conversionFunction);
}
return Streamable.of(findAll(example)).map(conversionFunction).stream();
}
@Override
public long count() {
return QueryByExampleRedisExecutor.this.count(example);
}
@Override
public boolean exists() {
return QueryByExampleRedisExecutor.this.exists(example);
}
private <P> Function<Object, P> getConversionFunction(Class<?> inputType, Class<P> targetType) {
if (targetType.isAssignableFrom(inputType)) {
return (Function<Object, P>) Function.identity();
}
if (targetType.isInterface()) {
return o -> projectionFactory.createProjection(targetType, o);
}
DtoInstantiatingConverter converter = new DtoInstantiatingConverter(targetType,
keyValueTemplate.getMappingContext(), entityInstantiators);
return o -> (P) converter.convert(o);
}
}
}
相关信息
相关文章
spring-data-redis RedisRepositoryFactory 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦