DATAJPA-29, DATAJPA-30 - Fixed invalid page metadata in pagination queries.
JpaCountQueryCreator now correctly applies the predicate. Added test cases and support for 'In' keywords.
This commit is contained in:
@@ -63,6 +63,6 @@ public class JpaCountQueryCreator extends JpaQueryCreator {
|
||||
protected CriteriaQuery<Object> complete(Predicate predicate, Sort sort,
|
||||
CriteriaQuery<Object> query, CriteriaBuilder builder, Root<?> root) {
|
||||
|
||||
return query.select(builder.count(root));
|
||||
return query.select(builder.count(root)).where(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
@@ -34,6 +36,7 @@ import org.springframework.data.repository.query.parser.Part;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.data.repository.query.parser.Property;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
|
||||
/**
|
||||
@@ -175,6 +178,8 @@ public class JpaQueryCreator extends
|
||||
return path.isNull();
|
||||
case IS_NOT_NULL:
|
||||
return path.isNotNull();
|
||||
case IN:
|
||||
return path.in(nextAsCollection(iterator));
|
||||
case LIKE:
|
||||
return builder.like(root.<String> get(part.getProperty()
|
||||
.toDotPath()), iterator.next().toString());
|
||||
@@ -248,4 +253,18 @@ public class JpaQueryCreator extends
|
||||
|
||||
return (Comparable<?>) next;
|
||||
}
|
||||
|
||||
|
||||
private Collection<?> nextAsCollection(Iterator<Object> iterator) {
|
||||
|
||||
Object next = iterator.next();
|
||||
|
||||
if (next instanceof Collection) {
|
||||
return (Collection<?>) next;
|
||||
} else if (next.getClass().isArray()) {
|
||||
return CollectionUtils.arrayToList(next);
|
||||
}
|
||||
|
||||
return Arrays.asList(next);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008-2011 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
|
||||
*
|
||||
* http://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.query;
|
||||
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
import org.springframework.data.repository.query.parser.Part;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* JPA specific {@link Part}. Allows creating JPQL snippets via
|
||||
* {@link #createQueryPart(Type, String, Parameter)}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class JpaQueryPart extends Part {
|
||||
|
||||
/**
|
||||
* @param part
|
||||
* @param method
|
||||
* @param parameter
|
||||
*/
|
||||
public JpaQueryPart(String part, Class<?> method) {
|
||||
|
||||
super(part, method);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the query part.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getQueryPart(Parameter parameter) {
|
||||
|
||||
return createQueryPart(getType(), getProperty().toDotPath(), parameter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the actual query part for the given property. Creates a simple
|
||||
* assignment of the following shape by default. {@code x.$
|
||||
* property} ${operator} ${parameterPlaceholder}}.
|
||||
*
|
||||
* @param property the actual clean property
|
||||
* @param parameters
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
private String createQueryPart(Type type, String property,
|
||||
Parameter parameter) {
|
||||
|
||||
switch (type) {
|
||||
case BETWEEN:
|
||||
String first = parameter.getPlaceholder();
|
||||
String second = parameter.getNext().getPlaceholder();
|
||||
|
||||
return String.format("x.%s between %s and %s", property, first,
|
||||
second);
|
||||
case IS_NOT_NULL:
|
||||
return String.format("x.%s is not null", property);
|
||||
case IS_NULL:
|
||||
return String.format("x.%s is null", property);
|
||||
default:
|
||||
Assert.notNull(parameter);
|
||||
return String.format("x.%s %s %s", property, type.getOperator(),
|
||||
parameter.getPlaceholder());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,7 @@ public class ParameterBinder {
|
||||
public Query bind(Query query) {
|
||||
|
||||
int methodParameterPosition = 0;
|
||||
int queryParameterPosition = 1;
|
||||
|
||||
for (Parameter parameter : parameters) {
|
||||
|
||||
@@ -118,7 +119,7 @@ public class ParameterBinder {
|
||||
if (hasNamedParameter(query) && parameter.isNamedParameter()) {
|
||||
query.setParameter(parameter.getName(), value);
|
||||
} else {
|
||||
query.setParameter(parameter.getIndex() + 1, value);
|
||||
query.setParameter(queryParameterPosition++, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,27 +49,22 @@ public class UserRepositoryFinderTests {
|
||||
@Autowired
|
||||
UserRepository userRepository;
|
||||
|
||||
User firstUser, secondUser;
|
||||
User dave, carter, oliver;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
// This one matches both criterias
|
||||
firstUser = new User();
|
||||
firstUser.setEmailAddress("foo");
|
||||
firstUser.setLastname("bar");
|
||||
firstUser.setFirstname("foobar");
|
||||
|
||||
userRepository.save(firstUser);
|
||||
dave = new User("Dave", "Matthews", "dave@dmband.com");
|
||||
userRepository.save(dave);
|
||||
|
||||
// This one matches only the second one
|
||||
secondUser = new User();
|
||||
secondUser.setEmailAddress("bar");
|
||||
secondUser.setLastname("foo");
|
||||
secondUser.setFirstname("foobar");
|
||||
carter = new User("Carter", "Beauford", "carter@dmband.com");
|
||||
userRepository.save(carter);
|
||||
|
||||
userRepository.save(secondUser);
|
||||
oliver = new User("Oliver August", "Matthews", "oliver@dmband.com");
|
||||
userRepository.save(oliver);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,8 +74,10 @@ public class UserRepositoryFinderTests {
|
||||
@Test
|
||||
public void testSimpleCustomCreatedFinder() {
|
||||
|
||||
User user = userRepository.findByEmailAddressAndLastname("foo", "bar");
|
||||
assertEquals(firstUser, user);
|
||||
User user =
|
||||
userRepository.findByEmailAddressAndLastname("dave@dmband.com",
|
||||
"Matthews");
|
||||
assertEquals(dave, user);
|
||||
}
|
||||
|
||||
|
||||
@@ -104,13 +101,13 @@ public class UserRepositoryFinderTests {
|
||||
public void testAndOrFinder() {
|
||||
|
||||
List<User> users =
|
||||
userRepository.findByEmailAddressAndLastnameOrFirstname("bar",
|
||||
"foo", "foobar");
|
||||
userRepository.findByEmailAddressAndLastnameOrFirstname(
|
||||
"dave@dmband.com", "Matthews", "Carter");
|
||||
|
||||
assertNotNull(users);
|
||||
assertEquals(2, users.size());
|
||||
assertTrue(users.contains(firstUser));
|
||||
assertTrue(users.contains(secondUser));
|
||||
assertTrue(users.contains(dave));
|
||||
assertTrue(users.contains(carter));
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +115,8 @@ public class UserRepositoryFinderTests {
|
||||
public void executesPagingMethodToPageCorrectly() throws Exception {
|
||||
|
||||
Page<User> page =
|
||||
userRepository.findByFirstname(new PageRequest(0, 1), "foobar");
|
||||
userRepository
|
||||
.findByLastname(new PageRequest(0, 1), "Matthews");
|
||||
assertThat(page.getNumberOfElements(), is(1));
|
||||
assertThat(page.getTotalElements(), is(2L));
|
||||
assertThat(page.getTotalPages(), is(2));
|
||||
@@ -129,7 +127,20 @@ public class UserRepositoryFinderTests {
|
||||
public void executesPagingMethodToListCorrectly() throws Exception {
|
||||
|
||||
List<User> list =
|
||||
userRepository.findByFirstname("foobar", new PageRequest(0, 1));
|
||||
userRepository.findByFirstname("Carter", new PageRequest(0, 1));
|
||||
assertThat(list.size(), is(1));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testname() throws Exception {
|
||||
|
||||
Page<User> page =
|
||||
userRepository.findByFirstnameIn(new PageRequest(0, 1), "Dave",
|
||||
"Oliver August");
|
||||
|
||||
assertThat(page.getNumberOfElements(), is(1));
|
||||
assertThat(page.getTotalElements(), is(2L));
|
||||
assertThat(page.getTotalPages(), is(2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ public class JpaQueryMethodUnitTests {
|
||||
throws Exception {
|
||||
|
||||
Method method =
|
||||
UserRepository.class.getMethod("findByFirstname",
|
||||
UserRepository.class.getMethod("findByLastname",
|
||||
Pageable.class, String.class);
|
||||
|
||||
when(extractor.canExtractQuery()).thenReturn(false);
|
||||
|
||||
@@ -115,10 +115,10 @@ public interface UserRepository extends JpaRepository<User, Integer>,
|
||||
* parameter to be regarded on query execution.
|
||||
*
|
||||
* @param pageable
|
||||
* @param firstname
|
||||
* @param lastname
|
||||
* @return
|
||||
*/
|
||||
Page<User> findByFirstname(Pageable pageable, String firstname);
|
||||
Page<User> findByLastname(Pageable pageable, String lastname);
|
||||
|
||||
|
||||
/**
|
||||
@@ -133,6 +133,9 @@ public interface UserRepository extends JpaRepository<User, Integer>,
|
||||
List<User> findByFirstname(String firstname, Pageable pageable);
|
||||
|
||||
|
||||
Page<User> findByFirstnameIn(Pageable pageable, String... firstnames);
|
||||
|
||||
|
||||
/**
|
||||
* Manipulating query to set all {@link User}'s names to the given one.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user