Skip to content

Commit 201b957

Browse files
committed
Extract QuerydslPredicateExecutor to its own fragment.
Closes #398
1 parent 44ab6db commit 201b957

File tree

4 files changed

+284
-101
lines changed

4 files changed

+284
-101
lines changed

src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueRepositoryFactory.java

+39-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
package org.springframework.data.keyvalue.repository.support;
1717

1818
import static org.springframework.data.querydsl.QuerydslUtils.*;
19+
import static org.springframework.data.repository.core.support.RepositoryComposition.*;
1920

2021
import java.lang.reflect.Constructor;
2122
import java.lang.reflect.Method;
2223
import java.util.Optional;
2324

2425
import org.springframework.beans.BeanUtils;
26+
import org.springframework.dao.InvalidDataAccessApiUsageException;
2527
import org.springframework.data.keyvalue.core.KeyValueOperations;
2628
import org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery;
2729
import org.springframework.data.keyvalue.repository.query.SpelQueryCreator;
@@ -136,8 +138,43 @@ protected Object getTargetRepository(RepositoryInformation repositoryInformation
136138
*/
137139
@Override
138140
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
139-
return isQueryDslRepository(metadata.getRepositoryInterface()) ? QuerydslKeyValueRepository.class
140-
: SimpleKeyValueRepository.class;
141+
return SimpleKeyValueRepository.class;
142+
}
143+
144+
/*
145+
* (non-Javadoc)
146+
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryFragments(org.springframework.data.repository.core.RepositoryMetadata)
147+
*/
148+
@Override
149+
protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
150+
return getRepositoryFragments(metadata, keyValueOperations);
151+
}
152+
153+
/**
154+
* Creates {@link RepositoryFragments} based on {@link RepositoryMetadata} to add Key-Value-specific extensions.
155+
* Typically adds a {@link QuerydslMongoPredicateExecutor} if the repository interface uses Querydsl.
156+
* <p>
157+
* Can be overridden by subclasses to customize {@link RepositoryFragments}.
158+
*
159+
* @param metadata repository metadata.
160+
* @param operations the MongoDB operations manager.
161+
* @return
162+
* @since 2.6
163+
*/
164+
protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata, KeyValueOperations operations) {
165+
166+
if (isQueryDslRepository(metadata.getRepositoryInterface())) {
167+
168+
if (metadata.isReactiveRepository()) {
169+
throw new InvalidDataAccessApiUsageException(
170+
"Cannot combine Querydsl and reactive repository support in a single interface");
171+
}
172+
173+
return RepositoryFragments
174+
.just(new QuerydslKeyValuePredicateExecutor<>(getEntityInformation(metadata.getDomainType()), operations));
175+
}
176+
177+
return RepositoryFragments.empty();
141178
}
142179

143180
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.keyvalue.repository.support;
17+
18+
import static org.springframework.data.keyvalue.repository.support.KeyValueQuerydslUtils.*;
19+
20+
import java.util.Optional;
21+
import java.util.function.Function;
22+
import java.util.function.Supplier;
23+
24+
import org.springframework.dao.IncorrectResultSizeDataAccessException;
25+
import org.springframework.data.domain.Page;
26+
import org.springframework.data.domain.PageImpl;
27+
import org.springframework.data.domain.Pageable;
28+
import org.springframework.data.domain.Sort;
29+
import org.springframework.data.keyvalue.core.KeyValueOperations;
30+
import org.springframework.data.querydsl.EntityPathResolver;
31+
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
32+
import org.springframework.data.querydsl.SimpleEntityPathResolver;
33+
import org.springframework.data.repository.core.EntityInformation;
34+
import org.springframework.data.repository.query.FluentQuery;
35+
import org.springframework.lang.Nullable;
36+
import org.springframework.util.Assert;
37+
38+
import com.querydsl.collections.AbstractCollQuery;
39+
import com.querydsl.collections.CollQuery;
40+
import com.querydsl.core.NonUniqueResultException;
41+
import com.querydsl.core.types.EntityPath;
42+
import com.querydsl.core.types.OrderSpecifier;
43+
import com.querydsl.core.types.Predicate;
44+
import com.querydsl.core.types.dsl.PathBuilder;
45+
46+
/**
47+
* {@link QuerydslPredicateExecutor} capable of applying {@link Predicate}s using {@link CollQuery}.
48+
*
49+
* @author Mark Paluch
50+
* @since 2.6
51+
*/
52+
public class QuerydslKeyValuePredicateExecutor<T> implements QuerydslPredicateExecutor<T> {
53+
54+
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
55+
56+
private final PathBuilder<T> builder;
57+
private final Supplier<Iterable<T>> findAll;
58+
59+
/**
60+
* Creates a new {@link QuerydslKeyValuePredicateExecutor} for the given {@link EntityInformation}.
61+
*
62+
* @param entityInformation must not be {@literal null}.
63+
* @param operations must not be {@literal null}.
64+
*/
65+
public QuerydslKeyValuePredicateExecutor(EntityInformation<T, ?> entityInformation, KeyValueOperations operations) {
66+
this(entityInformation, operations, DEFAULT_ENTITY_PATH_RESOLVER);
67+
}
68+
69+
/**
70+
* Creates a new {@link QuerydslKeyValuePredicateExecutor} for the given {@link EntityInformation}, and
71+
* {@link EntityPathResolver}.
72+
*
73+
* @param entityInformation must not be {@literal null}.
74+
* @param operations must not be {@literal null}.
75+
* @param resolver must not be {@literal null}.
76+
*/
77+
public QuerydslKeyValuePredicateExecutor(EntityInformation<T, ?> entityInformation, KeyValueOperations operations,
78+
EntityPathResolver resolver) {
79+
80+
Assert.notNull(resolver, "EntityPathResolver must not be null!");
81+
82+
EntityPath<T> path = resolver.createPath(entityInformation.getJavaType());
83+
this.builder = new PathBuilder<>(path.getType(), path.getMetadata());
84+
findAll = () -> operations.findAll(entityInformation.getJavaType());
85+
}
86+
87+
/*
88+
* (non-Javadoc)
89+
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findOne(com.querydsl.core.types.Predicate)
90+
*/
91+
@Override
92+
public Optional<T> findOne(Predicate predicate) {
93+
94+
Assert.notNull(predicate, "Predicate must not be null!");
95+
96+
try {
97+
return Optional.ofNullable(prepareQuery(predicate).fetchOne());
98+
} catch (NonUniqueResultException o_O) {
99+
throw new IncorrectResultSizeDataAccessException("Expected one or no result but found more than one!", 1, o_O);
100+
}
101+
}
102+
103+
/*
104+
* (non-Javadoc)
105+
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.Predicate)
106+
*/
107+
@Override
108+
public Iterable<T> findAll(Predicate predicate) {
109+
110+
Assert.notNull(predicate, "Predicate must not be null!");
111+
112+
return prepareQuery(predicate).fetchResults().getResults();
113+
}
114+
115+
/*
116+
* (non-Javadoc)
117+
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, com.querydsl.core.types.OrderSpecifier[])
118+
*/
119+
@Override
120+
public Iterable<T> findAll(Predicate predicate, OrderSpecifier<?>... orders) {
121+
122+
Assert.notNull(predicate, "Predicate must not be null!");
123+
Assert.notNull(orders, "OrderSpecifiers must not be null!");
124+
125+
AbstractCollQuery<T, ?> query = prepareQuery(predicate);
126+
query.orderBy(orders);
127+
128+
return query.fetchResults().getResults();
129+
}
130+
131+
/*
132+
* (non-Javadoc)
133+
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, org.springframework.data.domain.Sort)
134+
*/
135+
@Override
136+
public Iterable<T> findAll(Predicate predicate, Sort sort) {
137+
138+
Assert.notNull(predicate, "Predicate must not be null!");
139+
Assert.notNull(sort, "Sort must not be null!");
140+
141+
return findAll(predicate, toOrderSpecifier(sort, builder));
142+
}
143+
144+
/*
145+
* (non-Javadoc)
146+
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, org.springframework.data.domain.Pageable)
147+
*/
148+
@Override
149+
public Page<T> findAll(Predicate predicate, Pageable pageable) {
150+
151+
Assert.notNull(predicate, "Predicate must not be null!");
152+
Assert.notNull(pageable, "Pageable must not be null!");
153+
154+
AbstractCollQuery<T, ?> query = prepareQuery(predicate);
155+
156+
if (pageable.isPaged() || pageable.getSort().isSorted()) {
157+
158+
query.offset(pageable.getOffset());
159+
query.limit(pageable.getPageSize());
160+
161+
if (pageable.getSort().isSorted()) {
162+
query.orderBy(toOrderSpecifier(pageable.getSort(), builder));
163+
}
164+
}
165+
166+
return new PageImpl<>(query.fetchResults().getResults(), pageable, count(predicate));
167+
}
168+
169+
/*
170+
* (non-Javadoc)
171+
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.OrderSpecifier[])
172+
*/
173+
@Override
174+
public Iterable<T> findAll(OrderSpecifier<?>... orders) {
175+
176+
Assert.notNull(orders, "OrderSpecifiers must not be null!");
177+
178+
if (orders.length == 0) {
179+
return findAll.get();
180+
}
181+
182+
AbstractCollQuery<T, ?> query = prepareQuery(null);
183+
query.orderBy(orders);
184+
185+
return query.fetchResults().getResults();
186+
}
187+
188+
/*
189+
* (non-Javadoc)
190+
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#count(com.querydsl.core.types.Predicate)
191+
*/
192+
@Override
193+
public long count(Predicate predicate) {
194+
195+
Assert.notNull(predicate, "Predicate must not be null!");
196+
197+
return prepareQuery(predicate).fetchCount();
198+
}
199+
200+
/*
201+
* (non-Javadoc)
202+
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#exists(com.querydsl.core.types.Predicate)
203+
*/
204+
@Override
205+
public boolean exists(Predicate predicate) {
206+
207+
Assert.notNull(predicate, "Predicate must not be null!");
208+
209+
return count(predicate) > 0;
210+
}
211+
212+
@Override
213+
public <S extends T, R> R findBy(Predicate predicate,
214+
Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction) {
215+
throw new UnsupportedOperationException("Not yet supported");
216+
}
217+
218+
/**
219+
* Creates executable query for given {@link Predicate}.
220+
*
221+
* @param predicate
222+
* @return
223+
*/
224+
protected AbstractCollQuery<T, ?> prepareQuery(@Nullable Predicate predicate) {
225+
226+
CollQuery<T> query = new CollQuery<>();
227+
query.from(builder, findAll.get());
228+
229+
return predicate != null ? query.where(predicate) : query;
230+
}
231+
}

0 commit comments

Comments
 (0)