下面列出了org.springframework.data.domain.SliceImpl#org.springframework.data.keyvalue.core.query.KeyValueQuery 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Execute a "delete" query, not really a query more of an operation.
* <p>
*
* @param query The query to run
* @param queryMethod Used here to find the type of object to match the query
* @return Collection of deleted objects or the number of deleted objects
*/
private Object executeDeleteQuery(final KeyValueQuery<?> query, final QueryMethod queryMethod) {
Iterable<?> resultSet = this.keyValueOperations.find(query, queryMethod.getEntityInformation().getJavaType());
Iterator<?> iterator = resultSet.iterator();
List<Object> result = new ArrayList<>();
while (iterator.hasNext()) {
result.add(this.keyValueOperations.delete(iterator.next()));
}
if (queryMethod.isCollectionQuery()) {
return result;
} else if (long.class.equals(queryMethod.getReturnedObjectType()) || Long.class
.equals(queryMethod.getReturnedObjectType())) {
return result.size();
} else {
throw new UnsupportedOperationException(String.format(
"Illegal returned type: %s. The operation 'deleteBy' accepts only 'long' and 'Collection' as the returned "
+ "object type", queryMethod.getReturnedObjectType()));
}
}
/**
* <p>
* Execute a retrieval query. The query engine will return this in an iterator, which may need conversion to a single
* domain entity or a stream.
* </P>
*
* @param query The query to run
* @param queryMethod Holds metadata about the query, is paging etc
* @return Query result
*/
private Object executeFindQuery(final KeyValueQuery<?> query, final QueryMethod queryMethod, final boolean distinct) {
Iterable<?> resultSet = this.keyValueOperations.find(query, queryMethod.getEntityInformation().getJavaType());
if (!queryMethod.isCollectionQuery() && !queryMethod.isPageQuery() && !queryMethod.isSliceQuery() && !queryMethod
.isStreamQuery()) {
// Singleton result
return resultSet.iterator().hasNext() ? resultSet.iterator().next() : null;
}
if (queryMethod.isStreamQuery()) {
if (distinct) {
return StreamUtils.createStreamFromIterator(resultSet.iterator()).distinct();
}
return StreamUtils.createStreamFromIterator(resultSet.iterator());
}
if (distinct) {
return StreamUtils.createStreamFromIterator(resultSet.iterator()).distinct().collect(Collectors.toList());
}
return resultSet;
}
@Override
protected KeyValueQuery<Predicate<?, ?>> complete(Predicate<?, ?> criteria, Sort sort) {
KeyValueQuery<Predicate<?, ?>> keyValueQuery;
if (this.limit == 0) {
keyValueQuery = new KeyValueQuery<>(criteria);
} else {
keyValueQuery = new KeyValueQuery<Predicate<?, ?>>(new PagingPredicateImpl(criteria, this.limit));
}
if (sort != null) {
keyValueQuery.setSort(sort);
}
return keyValueQuery;
}
/**
* @param A query in Spring form
* @return The same in Hazelcast form
*/
public Predicate<?, ?> resolve(KeyValueQuery<?> query) {
if (query == null) {
return null;
}
final Object criteria = query.getCriteria();
if (criteria == null) {
return null;
}
if (criteria instanceof PagingPredicateImpl) {
PagingPredicateImpl pagingPredicate = (PagingPredicateImpl) criteria;
query.limit(pagingPredicate.getPageSize());
return pagingPredicate.getPredicate();
}
if (criteria instanceof Predicate) {
return (Predicate<?, ?>) criteria;
}
throw new UnsupportedOperationException(query.toString());
}
@Override
public SpelCriteria resolve(KeyValueQuery<?> query) {
if (query.getCriteria() == null) {
return null;
}
if (query.getCriteria() instanceof SpelExpression) {
return new SpelCriteria((SpelExpression) query.getCriteria());
}
if (query.getCriteria() instanceof String) {
return new SpelCriteria(parser.parseRaw((String) query.getCriteria()));
}
if (query.getCriteria() instanceof SpelCriteria) {
return (SpelCriteria) query.getCriteria();
}
throw new IllegalArgumentException("Cannot create SpelCriteria for " + query.getCriteria());
}
@Override
public <T> Iterable<T> find(KeyValueQuery<?> query, Class<T> type) {
return executeRequired((KeyValueCallback<Iterable<T>>) adapter -> {
Iterable<?> result = adapter.find(query, resolveKeySpace(type), type);
List<T> filtered = new ArrayList<>();
for (Object candidate : result) {
if (typeCheck(type, candidate)) {
filtered.add(type.cast(candidate));
}
}
return filtered;
});
}
private KeyValueQuery<SpelExpression> createQueryForMethodWithArgs(String methodName, Object... args)
throws NoSuchMethodException, SecurityException {
Class<?>[] argTypes = new Class<?>[args.length];
if (!ObjectUtils.isEmpty(args)) {
for (int i = 0; i < args.length; i++) {
argTypes[i] = args[i].getClass();
}
}
Method method = PersonRepository.class.getMethod(methodName, argTypes);
doReturn(Person.class).when(metadataMock).getReturnedDomainClass(method);
PartTree partTree = new PartTree(method.getName(), method.getReturnType());
SpelQueryCreator creator = new SpelQueryCreator(partTree, new ParametersParameterAccessor(
new QueryMethod(method, metadataMock, new SpelAwareProxyProjectionFactory()).getParameters(), args));
KeyValueQuery<SpelExpression> q = creator.createQuery();
q.getCriteria().setEvaluationContext(
SimpleEvaluationContext.forReadOnlyDataBinding().withRootObject(args).withInstanceMethods().build());
return q;
}
@Test // DATAKV-142
@SuppressWarnings({ "unchecked", "rawtypes" })
public void shouldApplyPageableParameterToCollectionQuery() throws SecurityException, NoSuchMethodException {
when(metadataMock.getDomainType()).thenReturn((Class) Person.class);
when(metadataMock.getReturnedDomainClass(any(Method.class))).thenReturn((Class) Person.class);
QueryMethod qm = new QueryMethod(Repo.class.getMethod("findBy", Pageable.class), metadataMock,
projectionFactoryMock);
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, QueryMethodEvaluationContextProvider.DEFAULT,
kvOpsMock, SpelQueryCreator.class);
KeyValueQuery<?> query = partTreeQuery.prepareQuery(new Object[] { PageRequest.of(2, 3) });
assertThat(query.getOffset()).isEqualTo(6L);
assertThat(query.getRows()).isEqualTo(3);
}
@Test // DATAKV-142
@SuppressWarnings({ "unchecked", "rawtypes" })
public void shouldApplyDerivedMaxResultsToQueryWithParameters() throws SecurityException, NoSuchMethodException {
when(metadataMock.getDomainType()).thenReturn((Class) Person.class);
when(metadataMock.getReturnedDomainClass(any(Method.class))).thenReturn((Class) Person.class);
QueryMethod qm = new QueryMethod(Repo.class.getMethod("findTop3ByFirstname", String.class), metadataMock,
projectionFactoryMock);
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, QueryMethodEvaluationContextProvider.DEFAULT,
kvOpsMock, SpelQueryCreator.class);
KeyValueQuery<?> query = partTreeQuery.prepareQuery(new Object[] { "firstname" });
assertThat(query.getCriteria()).isInstanceOf(SpelCriteria.class);
assertThat(((SpelCriteria) query.getCriteria()).getExpression().getExpressionString())
.isEqualTo("#it?.firstname?.equals([0])");
assertThat(query.getRows()).isEqualTo(3);
}
@Override
protected KeyValueQuery<VaultQuery> complete(VaultQuery vaultQuery, Sort sort) {
KeyValueQuery<VaultQuery> query = new KeyValueQuery<>(vaultQuery);
if (sort.isSorted()) {
query.orderBy(sort);
}
return query;
}
/**
* <p>
* Execute this query instance, using any invocation parameters.
* </P>
* <p>
* Expecting {@code findBy...()}, {@code countBy...()} or {@code deleteBy...()}
* </P>
*
* @param parameters Any parameters
* @return Query result
*/
@Override
public Object execute(Object[] parameters) {
KeyValueQuery<?> query = prepareQuery(parameters);
if (this.isCount) {
final Class<?> javaType = queryMethod.getEntityInformation().getJavaType();
if (this.isDistinct) {
final Iterable<?> iterable = this.keyValueOperations.find(query, javaType);
return StreamUtils.createStreamFromIterator(iterable.iterator()).distinct().count();
} else {
return this.keyValueOperations.count(query, javaType);
}
}
if (this.isDelete) {
return this.executeDeleteQuery(query, queryMethod);
}
if (this.isExists) {
query.setOffset(0);
query.setRows(1);
final Iterable<?> result = this.keyValueOperations.find(query, queryMethod.getEntityInformation().getJavaType());
return result.iterator().hasNext();
}
if (queryMethod.isPageQuery() || queryMethod.isSliceQuery()) {
return this.executePageSliceQuery(parameters, query, queryMethod);
}
if (queryMethod.isCollectionQuery() || queryMethod.isQueryForEntity() || queryMethod.isStreamQuery()) {
return this.executeFindQuery(query, queryMethod, this.isDistinct);
}
String message = String.format("Query method '%s' not supported.", queryMethod.getName());
throw new UnsupportedOperationException(message);
}
/**
* <p>
* Slices and pages are similar ways to iterate through the result set in blocks, mimicking a cursor. A
* {@link org.springframework.data.domain.Slice Slice} is a simpler concept, only requiring to know if further blocks
* of data are available. A {@link org.springframework.data.domain.Page Page} requires to know how many blocks of data
* are available in total.
* </P>
*
* @param parameters For the query
* @param query The query to run
* @param queryMethod Holds metadata about the query
* @return Query result
*/
@SuppressWarnings({"rawtypes", "unchecked"})
private Object executePageSliceQuery(final Object[] parameters, final KeyValueQuery<?> query, final QueryMethod queryMethod) {
long totalElements = -1;
int indexOfPageRequest = queryMethod.getParameters().getPageableIndex();
Pageable pageRequest = (Pageable) parameters[indexOfPageRequest];
/* TODO Eliminate count call for Slice, retrieve "rows+1" instead to determine if next page exists.
*/
if (query.getCriteria() == null) {
totalElements = this.keyValueOperations.count(queryMethod.getEntityInformation().getJavaType());
} else {
totalElements = this.keyValueOperations.count(query, queryMethod.getEntityInformation().getJavaType());
}
int requiredRows = pageRequest.getPageSize();
query.setOffset(pageRequest.getOffset());
query.setRows(pageRequest.getPageSize());
Iterable<?> resultSet = this.keyValueOperations.find(query, queryMethod.getEntityInformation().getJavaType());
List<?> content = IterableConverter.toList(resultSet);
if (queryMethod.isPageQuery()) {
return new PageImpl(content, pageRequest, totalElements);
} else {
boolean hasNext = totalElements > (query.getOffset() + query.getRows());
if (content.size() > requiredRows) {
content = content.subList(0, requiredRows);
}
return new SliceImpl(content, pageRequest, hasNext);
}
}
/**
* <p>
* Sort on a sequence of fields, possibly none.
* </P>
*
* @param query If not null, will contain one of more {@link Sort.Order} objects.
* @return A sequence of comparators or {@code null}
*/
public Comparator<Entry<?, ?>> resolve(KeyValueQuery<?> query) {
if (query == null || query.getSort() == Sort.unsorted()) {
return null;
}
Comparator hazelcastPropertyComparator = null;
for (Order order : query.getSort()) {
if (order.getProperty().indexOf('.') > -1) {
throw new UnsupportedOperationException("Embedded fields not implemented: " + order);
}
if (order.isIgnoreCase()) {
throw new UnsupportedOperationException("Ignore case not implemented: " + order);
}
if (NullHandling.NATIVE != order.getNullHandling()) {
throw new UnsupportedOperationException("Null handling not implemented: " + order);
}
if (hazelcastPropertyComparator == null) {
hazelcastPropertyComparator = new HazelcastPropertyComparator(order.getProperty(),
order.isAscending());
} else {
hazelcastPropertyComparator = hazelcastPropertyComparator.thenComparing(
new HazelcastPropertyComparator(order.getProperty(),
order.isAscending()));
}
}
return hazelcastPropertyComparator;
}
@Test(expected = UnsupportedOperationException.class)
public void testResolvingNonNativeNullHandlingOrderIsUnsupported() {
// given
KeyValueQuery<String> keyValueQuery = new KeyValueQuery<>("^pg~]=P");
Sort.Order sortOrder1 = Sort.Order.asc("^pg~]=P");
Sort.Order sortOrder2 = sortOrder1.nullsLast();
keyValueQuery.setSort(Sort.by(sortOrder1, sortOrder2));
HazelcastSortAccessor hazelcastSortAccessor = new HazelcastSortAccessor();
// when
hazelcastSortAccessor.resolve(keyValueQuery);
// Then expect UnsupportedOperationException
}
@Test(expected = UnsupportedOperationException.class)
public void testResolvingIgnoreCaseOrderIsUnsupported() {
// given
HazelcastSortAccessor hazelcastSortAccessor = new HazelcastSortAccessor();
KeyValueQuery<Object> keyValueQuery = new KeyValueQuery<>(RevisionSort.asc());
Sort.Order sortOrderA = Sort.Order.asc("Cannot resolve nest mates of a latent type description: ");
Sort.Order sortOrderB = sortOrderA.ignoreCase();
keyValueQuery.setSort(Sort.by(sortOrderA, sortOrderB));
// when
hazelcastSortAccessor.resolve(keyValueQuery);
// Then expect UnsupportedOperationException
}
@Test
public void testResolvingNonEmptyKeyValueQueryReturnsNonNullComparator() {
//given
KeyValueQuery<Object> keyValueQuery = new KeyValueQuery<>(RevisionSort.asc());
//when
HazelcastSortAccessor hazelcastSortAccessor = new HazelcastSortAccessor();
Comparator<Map.Entry<?, ?>> comparator = hazelcastSortAccessor.resolve(keyValueQuery);
//then
assertNotNull(comparator);
}
@Test
public void testResolvingEmptyKeyValueQueryReturnsNullComparator() {
//given
KeyValueQuery<Object> keyValueQuery = new KeyValueQuery<>();
//when
HazelcastSortAccessor hazelcastSortAccessor = new HazelcastSortAccessor();
Comparator<Map.Entry<?, ?>> comparator = hazelcastSortAccessor.resolve(keyValueQuery);
//then
assertNull(comparator);
}
@Test
public void testResolvingMultipleSortOrdersReturnsCompositeComparator() {
//given
KeyValueQuery<Predicate<String, Foo>> query = new KeyValueQuery<>();
Sort.Order fooOrder = new Sort.Order(Sort.Direction.DESC, "foo");
Sort.Order barOrder = new Sort.Order(Sort.Direction.DESC, "bar");
query.setSort(Sort.by(fooOrder, barOrder));
HazelcastSortAccessorTest.Foo testData1 = new HazelcastSortAccessorTest.Foo("zzz", "def");
HazelcastSortAccessorTest.Foo testData2 = new HazelcastSortAccessorTest.Foo("aaa", "aaa");
Map.Entry<String, HazelcastSortAccessorTest.Foo> entry1 = entryOf("testData1", testData1);
Map.Entry<String, HazelcastSortAccessorTest.Foo> entry2 = entryOf("testData2", testData2);
HazelcastSortAccessorTest.Foo testData3 = new HazelcastSortAccessorTest.Foo("aaa", "aaa");
HazelcastSortAccessorTest.Foo testData4 = new HazelcastSortAccessorTest.Foo("aaa", "def");
Map.Entry<String, HazelcastSortAccessorTest.Foo> entry3 = entryOf("testData3", testData3);
Map.Entry<String, HazelcastSortAccessorTest.Foo> entry4 = entryOf("testData4", testData4);
//when
HazelcastSortAccessor hazelcastSortAccessor = new HazelcastSortAccessor();
Comparator<Map.Entry<?, ?>> comparator = (Comparator<Map.Entry<?, ?>>) hazelcastSortAccessor.resolve((KeyValueQuery<?>) query);
//then
assertNotNull(comparator);
assertTrue(comparator.compare(entry1, entry2) < 0);
assertTrue(comparator.compare(entry2, entry1) > 0);
assertFalse(comparator.compare(entry3, entry4) == 0);
assertTrue((comparator.compare(entry3, entry4) > 0));
}
@Override
public Object execute(Object[] parameters) {
ParameterAccessor accessor = new ParametersParameterAccessor(getQueryMethod().getParameters(), parameters);
KeyValueQuery<?> query = prepareQuery(parameters);
ResultProcessor processor = queryMethod.getResultProcessor().withDynamicProjection(accessor);
return processor.processResult(doExecute(parameters, query));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected KeyValueQuery<?> prepareQuery(KeyValueQuery<?> instance, Object[] parameters) {
ParametersParameterAccessor accessor = new ParametersParameterAccessor(getQueryMethod().getParameters(),
parameters);
Object criteria = instance.getCriteria();
if (criteria instanceof SpelCriteria || criteria instanceof SpelExpression) {
SpelExpression spelExpression = getSpelExpression(criteria);
EvaluationContext context = this.evaluationContextProvider.getEvaluationContext(getQueryMethod().getParameters(),
parameters);
criteria = new SpelCriteria(spelExpression, context);
}
KeyValueQuery<?> query = new KeyValueQuery(criteria);
Pageable pageable = accessor.getPageable();
Sort sort = accessor.getSort();
query.setOffset(pageable.toOptional().map(Pageable::getOffset).orElse(-1L));
if (pageable.isPaged()) {
query.setRows(pageable.getPageSize());
} else if (instance.getRows() >= 0) {
query.setRows(instance.getRows());
}
query.setSort(sort.isUnsorted() ? instance.getSort() : sort);
return query;
}
/**
* Create a {@link KeyValueQuery} given {@link ParameterAccessor}.
*
* @param accessor must not be {@literal null}.
* @return the {@link KeyValueQuery}.
*/
public KeyValueQuery<?> createQuery(ParameterAccessor accessor) {
PartTree tree = new PartTree(getQueryMethod().getName(), getQueryMethod().getEntityInformation().getJavaType());
AbstractQueryCreator<? extends KeyValueQuery<?>, ?> queryCreator = queryCreatorFactory.queryCreatorFor(tree,
accessor);
KeyValueQuery<?> query = queryCreator.createQuery();
if (tree.isLimiting()) {
query.setRows(tree.getMaxResults());
}
return query;
}
@Override
public AbstractQueryCreator<KeyValueQuery<?>, ?> queryCreatorFor(PartTree partTree, ParameterAccessor accessor) {
Assert.state(constructor != null,
() -> String.format("No constructor (PartTree, ParameterAccessor) could be found on type %s!", type));
return (AbstractQueryCreator<KeyValueQuery<?>, ?>) BeanUtils.instantiateClass(constructor, partTree, accessor);
}
protected KeyValueQuery<?> prepareQuery(Object[] parameters) {
if (cachedQuery == null) {
cachedQuery = super.prepareQuery(parameters);
}
return prepareQuery(cachedQuery, parameters);
}
@Override
protected KeyValueQuery<SpelExpression> complete(String criteria, Sort sort) {
KeyValueQuery<SpelExpression> query = new KeyValueQuery<>(this.expression);
if (sort.isSorted()) {
query.orderBy(sort);
}
return query;
}
/**
* Extract query attributes and delegate to concrete execution.
*
* @param query
* @param keyspace
* @return
*/
public Collection<?> execute(KeyValueQuery<?> query, String keyspace) {
CRITERIA criteria = this.criteriaAccessor.map(it -> it.resolve(query)).orElse(null);
SORT sort = this.sortAccessor.map(it -> it.resolve(query)).orElse(null);
return execute(criteria, sort, query.getOffset(), query.getRows(), keyspace);
}
/**
* Extract query attributes and delegate to concrete execution.
*
* @param query
* @param keyspace
* @return
*/
public <T> Collection<T> execute(KeyValueQuery<?> query, String keyspace, Class<T> type) {
CRITERIA criteria = this.criteriaAccessor.map(it -> it.resolve(query)).orElse(null);
SORT sort = this.sortAccessor.map(it -> it.resolve(query)).orElse(null);
return execute(criteria, sort, query.getOffset(), query.getRows(), keyspace, type);
}
@Override
public Comparator<?> resolve(KeyValueQuery<?> query) {
if (query.getSort().isUnsorted()) {
return null;
}
Optional<Comparator<?>> comparator = Optional.empty();
for (Order order : query.getSort()) {
SpelPropertyComparator<Object> spelSort = new SpelPropertyComparator<>(order.getProperty(), parser);
if (Direction.DESC.equals(order.getDirection())) {
spelSort.desc();
if (!NullHandling.NATIVE.equals(order.getNullHandling())) {
spelSort = NullHandling.NULLS_FIRST.equals(order.getNullHandling()) ? spelSort.nullsFirst()
: spelSort.nullsLast();
}
}
if (!comparator.isPresent()) {
comparator = Optional.of(spelSort);
} else {
SpelPropertyComparator<Object> spelSortToUse = spelSort;
comparator = comparator.map(it -> it.thenComparing(spelSortToUse));
}
}
return comparator.orElseThrow(
() -> new IllegalStateException("No sort definitions have been added to this CompoundComparator to compare"));
}
@Test // DATACMNS-525
@SuppressWarnings("rawtypes")
public void findInRangeShouldRespectOffset() {
ArgumentCaptor<KeyValueQuery> captor = ArgumentCaptor.forClass(KeyValueQuery.class);
template.findInRange(1, 5, Foo.class);
verify(adapterMock, times(1)).find(captor.capture(), eq(Foo.class.getName()), eq(Foo.class));
assertThat(captor.getValue().getOffset()).isEqualTo(1L);
assertThat(captor.getValue().getRows()).isEqualTo(5);
assertThat(captor.getValue().getCriteria()).isNull();
}
@Override
public VaultQuery resolve(KeyValueQuery<?> query) {
return (VaultQuery) query.getCriteria();
}
protected KeyValueQuery<?> prepareQuery(Object[] parameters) {
return prepareQuery(createQuery(new ParametersParameterAccessor(getQueryMethod().getParameters(), parameters)),
parameters);
}