Fixed JIRA issue SGF-247 - boolean-based Repository queries generate UnsupportedOperationException.
This commit is contained in:
@@ -121,20 +121,22 @@ class Predicates implements Predicate {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString(String alias) {
|
public String toString(String alias) {
|
||||||
|
|
||||||
Type type = part.getType();
|
Type type = part.getType();
|
||||||
return String.format("%s.%s %s", alias == null ? QueryBuilder.DEFAULT_ALIAS : alias, part.getProperty()
|
|
||||||
.toDotPath(), toClause(type));
|
return String.format("%s.%s %s", alias == null ? QueryBuilder.DEFAULT_ALIAS : alias,
|
||||||
|
part.getProperty().toDotPath(), toClause(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String toClause(Type type) {
|
private String toClause(Type type) {
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case IS_NULL:
|
case FALSE:
|
||||||
case IS_NOT_NULL:
|
case TRUE:
|
||||||
return String.format("%s NULL", getOperator(type));
|
return String.format("%1$s %2$s", getOperator(type), Type.TRUE.equals(type));
|
||||||
default:
|
case IS_NULL:
|
||||||
return String.format("%s $%s", getOperator(type), value.next());
|
case IS_NOT_NULL:
|
||||||
|
return String.format("%s NULL", getOperator(type));
|
||||||
|
default:
|
||||||
|
return String.format("%s $%s", getOperator(type), value.next());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,33 +147,39 @@ class Predicates implements Predicate {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private String getOperator(Type type) {
|
private String getOperator(Type type) {
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case IN:
|
case IN:
|
||||||
return "IN SET";
|
return "IN SET";
|
||||||
case NOT_IN:
|
case NOT_IN:
|
||||||
return "NOT IN SET";
|
return "NOT IN SET";
|
||||||
case GREATER_THAN:
|
case GREATER_THAN:
|
||||||
return ">";
|
return ">";
|
||||||
case GREATER_THAN_EQUAL:
|
case GREATER_THAN_EQUAL:
|
||||||
return ">=";
|
return ">=";
|
||||||
case LESS_THAN:
|
case LESS_THAN:
|
||||||
return "<";
|
return "<";
|
||||||
case LESS_THAN_EQUAL:
|
case LESS_THAN_EQUAL:
|
||||||
return "<=";
|
return "<=";
|
||||||
case IS_NOT_NULL:
|
case IS_NOT_NULL:
|
||||||
case NEGATING_SIMPLE_PROPERTY:
|
case NEGATING_SIMPLE_PROPERTY:
|
||||||
return "!=";
|
return "!=";
|
||||||
case LIKE:
|
/*
|
||||||
case STARTING_WITH:
|
NOTE unfortunately, 'NOT LIKE' operator is not supported by GemFire's Query/OQL syntax
|
||||||
case ENDING_WITH:
|
case NOT_LIKE:
|
||||||
case CONTAINING:
|
return "NOT LIKE";
|
||||||
return "LIKE";
|
*/
|
||||||
case IS_NULL:
|
case LIKE:
|
||||||
case SIMPLE_PROPERTY:
|
case STARTING_WITH:
|
||||||
return "=";
|
case ENDING_WITH:
|
||||||
default:
|
case CONTAINING:
|
||||||
throw new IllegalArgumentException(String.format("Unsupported operator %s!", type));
|
return "LIKE";
|
||||||
|
case FALSE:
|
||||||
|
case IS_NULL:
|
||||||
|
case SIMPLE_PROPERTY:
|
||||||
|
case TRUE:
|
||||||
|
return "=";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(String.format("Unsupported operator %s!", type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.gemfire.repository.query;
|
package org.springframework.data.gemfire.repository.query;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -29,6 +31,7 @@ import org.springframework.data.repository.query.parser.Part;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class PredicatesUnitTests {
|
public class PredicatesUnitTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -68,9 +71,24 @@ public class PredicatesUnitTests {
|
|||||||
assertThat(predicate.toString(null), is("x.firstname = $1 OR x.lastname = $2"));
|
assertThat(predicate.toString(null), is("x.firstname = $1 OR x.lastname = $2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Person {
|
@Test
|
||||||
|
public void testBooleanBasedPredicate() {
|
||||||
|
Part part = new Part("activeTrue", User.class);
|
||||||
|
Iterator<Integer> indexes = Collections.<Integer>emptyList().iterator();
|
||||||
|
Predicates predicate = Predicates.create(part, indexes);
|
||||||
|
|
||||||
|
assertNotNull(predicate);
|
||||||
|
assertThat(predicate.toString("user"), is("user.active = true"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Person {
|
||||||
String firstname;
|
String firstname;
|
||||||
String lastname;
|
String lastname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class User {
|
||||||
|
Boolean active;
|
||||||
|
String username;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 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.gemfire.repository.sample;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.gemfire.mapping.Region;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The User class represents an authorized user of a service or computer system, etc.
|
||||||
|
* <p/>
|
||||||
|
* @author John Blum
|
||||||
|
* @since 1.3.3 (Spring Data GemFire)
|
||||||
|
* @since 7.0.1 (GemFire)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Region("Users")
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
private Boolean active = true;
|
||||||
|
|
||||||
|
private Calendar since;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private final String username;
|
||||||
|
|
||||||
|
public User(final String username) {
|
||||||
|
Assert.hasText(username, "The username is required!");
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getActive() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return Boolean.TRUE.equals(getActive());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActive(final Boolean active) {
|
||||||
|
this.active = Boolean.TRUE.equals(active);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(final String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Calendar getSince() {
|
||||||
|
return since;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSince(final Calendar since) {
|
||||||
|
this.since = since;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean equalsIgnoreNull(final Object obj1, final Object obj2) {
|
||||||
|
return (obj1 == null ? obj2 == null : obj1.equals(obj2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof User)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
User that = (User) obj;
|
||||||
|
|
||||||
|
return this.getUsername().equals(that.getUsername())
|
||||||
|
&& ObjectUtils.nullSafeEquals(this.getEmail(), that.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hashValue = 17;
|
||||||
|
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getEmail());
|
||||||
|
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getUsername());
|
||||||
|
return hashValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 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.gemfire.repository.sample;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.gemfire.repository.GemfireRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UserRepository class is a DAO for accessing and persisting Users.
|
||||||
|
* <p/>
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.springframework.data.gemfire.repository.GemfireRepository
|
||||||
|
* @since 1.3.3 (Spring Data GemFire)
|
||||||
|
* @since 7.0.1 (GemFire)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public interface UserRepository extends GemfireRepository<User, String> {
|
||||||
|
|
||||||
|
//@Query("SELECT DISTINCT * FROM /Users u WHERE u.active = true")
|
||||||
|
public List<User> findDistinctByActiveTrue();
|
||||||
|
|
||||||
|
//@Query("SELECT DISTINCT * FROM /Users u WHERE u.active = false")
|
||||||
|
public List<User> findDistinctByActiveFalse();
|
||||||
|
|
||||||
|
public List<User> findDistinctByUsernameLike(String username);
|
||||||
|
|
||||||
|
// NOTE unfortunately, the 'NOT LIKE' operator is unsupported in GemFire's Query/OQL syntax
|
||||||
|
//public List<User> findDistinctByUsernameNotLike(String username);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 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.gemfire.repository.sample;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import com.gemstone.gemfire.cache.Region;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The RepositoryQueriesTest class is a test suite of test cases testing the GemFire Query capability of Spring Data
|
||||||
|
* GemFire Repositories.
|
||||||
|
* <p/>
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.junit.Test
|
||||||
|
* @see org.junit.runner.RunWith
|
||||||
|
* @see org.springframework.test.context.ContextConfiguration
|
||||||
|
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
|
||||||
|
* @since 1.3.3 (Spring Data GemFire)
|
||||||
|
* @since 7.0.1 (GemFire)
|
||||||
|
*/
|
||||||
|
@ContextConfiguration("userRepositoryQueriesIntegrationTest.xml")
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class UserRepositoryQueriesIntegrationTest {
|
||||||
|
|
||||||
|
@Resource(name = "Users")
|
||||||
|
private Region users;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
protected static void assertQueryResults(final Iterable<User> actualUsers, final String... expectedUsernames) {
|
||||||
|
assertNotNull("The query did not return any results!", actualUsers);
|
||||||
|
|
||||||
|
List<String> actualUsernames = new ArrayList<String>(expectedUsernames.length);
|
||||||
|
|
||||||
|
for (User actualUser : actualUsers) {
|
||||||
|
actualUsernames.add(actualUser.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(expectedUsernames.length, actualUsernames.size());
|
||||||
|
assertTrue(actualUsernames.containsAll(Arrays.asList(expectedUsernames)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static User createUser(final String username) {
|
||||||
|
return createUser(username, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static User createUser(final String username, final Boolean active) {
|
||||||
|
return createUser(username, active, Calendar.getInstance(), String.format("%1$s@xcompany.com", username));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static User createUser(final String username, final Boolean active, final Calendar since, final String email) {
|
||||||
|
User user = new User(username);
|
||||||
|
|
||||||
|
user.setActive(active);
|
||||||
|
user.setEmail(email);
|
||||||
|
user.setSince(since);
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
assertNotNull("The Users Region cannot be null!", users);
|
||||||
|
|
||||||
|
if (users.isEmpty()) {
|
||||||
|
userRepository.save(createUser("blumj", true));
|
||||||
|
userRepository.save(createUser("blums", true));
|
||||||
|
userRepository.save(createUser("blume", false));
|
||||||
|
userRepository.save(createUser("bloomr", false));
|
||||||
|
userRepository.save(createUser("handyj", true));
|
||||||
|
userRepository.save(createUser("handys", false));
|
||||||
|
userRepository.save(createUser("doej", true));
|
||||||
|
userRepository.save(createUser("doep", false));
|
||||||
|
userRepository.save(createUser("doec", false));
|
||||||
|
|
||||||
|
assertFalse(users.isEmpty());
|
||||||
|
assertEquals(9, users.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueries() {
|
||||||
|
List<User> activeUsers = userRepository.findDistinctByActiveTrue();
|
||||||
|
|
||||||
|
assertQueryResults(activeUsers, "blumj", "blums", "handyj", "doej");
|
||||||
|
|
||||||
|
List<User> inactiveUsers = userRepository.findDistinctByActiveFalse();
|
||||||
|
|
||||||
|
assertQueryResults(inactiveUsers, "blume", "bloomr", "handys", "doep", "doec");
|
||||||
|
|
||||||
|
List<User> blumUsers = userRepository.findDistinctByUsernameLike("blum%");
|
||||||
|
|
||||||
|
assertQueryResults(blumUsers, "blumj", "blums", "blume");
|
||||||
|
|
||||||
|
/*
|
||||||
|
List<User> nonHandyUsers = userRepository.findDistinctByUsernameNotLike("handy%");
|
||||||
|
|
||||||
|
assertQueryResults(nonHandyUsers, "blumj", "blums", "blume", "bloomr", "doej", "doep", "doec");
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:gfe="http://www.springframework.org/schema/gemfire"
|
||||||
|
xmlns:gfe-data="http://www.springframework.org/schema/data/gemfire"
|
||||||
|
xmlns:util="http://www.springframework.org/schema/util"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="
|
||||||
|
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
|
http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd
|
||||||
|
http://www.springframework.org/schema/data/gemfire http://www.springframework.org/schema/data/gemfire/spring-data-gemfire.xsd
|
||||||
|
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
|
||||||
|
">
|
||||||
|
|
||||||
|
<util:properties id="peerCacheConfigurationSettings">
|
||||||
|
<prop key="name">repositoryQueriesTest</prop>
|
||||||
|
<prop key="locators">localhost[11235]</prop>
|
||||||
|
<prop key="log-level">config</prop>
|
||||||
|
<prop key="mcast-port">0</prop>
|
||||||
|
<prop key="start-locator">localhost[11235]</prop>
|
||||||
|
</util:properties>
|
||||||
|
|
||||||
|
<gfe:cache/>
|
||||||
|
|
||||||
|
<gfe:replicated-region id="Users" persistent="false"/>
|
||||||
|
|
||||||
|
<gfe-data:repositories base-package="org.springframework.data.gemfire.repository.sample"/>
|
||||||
|
|
||||||
|
</beans>
|
||||||
Reference in New Issue
Block a user