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
|
||||
public String toString(String alias) {
|
||||
|
||||
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) {
|
||||
|
||||
switch (type) {
|
||||
case IS_NULL:
|
||||
case IS_NOT_NULL:
|
||||
return String.format("%s NULL", getOperator(type));
|
||||
default:
|
||||
return String.format("%s $%s", getOperator(type), value.next());
|
||||
case FALSE:
|
||||
case TRUE:
|
||||
return String.format("%1$s %2$s", getOperator(type), Type.TRUE.equals(type));
|
||||
case IS_NULL:
|
||||
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
|
||||
*/
|
||||
private String getOperator(Type type) {
|
||||
|
||||
switch (type) {
|
||||
case IN:
|
||||
return "IN SET";
|
||||
case NOT_IN:
|
||||
return "NOT IN SET";
|
||||
case GREATER_THAN:
|
||||
return ">";
|
||||
case GREATER_THAN_EQUAL:
|
||||
return ">=";
|
||||
case LESS_THAN:
|
||||
return "<";
|
||||
case LESS_THAN_EQUAL:
|
||||
return "<=";
|
||||
case IS_NOT_NULL:
|
||||
case NEGATING_SIMPLE_PROPERTY:
|
||||
return "!=";
|
||||
case LIKE:
|
||||
case STARTING_WITH:
|
||||
case ENDING_WITH:
|
||||
case CONTAINING:
|
||||
return "LIKE";
|
||||
case IS_NULL:
|
||||
case SIMPLE_PROPERTY:
|
||||
return "=";
|
||||
default:
|
||||
throw new IllegalArgumentException(String.format("Unsupported operator %s!", type));
|
||||
case IN:
|
||||
return "IN SET";
|
||||
case NOT_IN:
|
||||
return "NOT IN SET";
|
||||
case GREATER_THAN:
|
||||
return ">";
|
||||
case GREATER_THAN_EQUAL:
|
||||
return ">=";
|
||||
case LESS_THAN:
|
||||
return "<";
|
||||
case LESS_THAN_EQUAL:
|
||||
return "<=";
|
||||
case IS_NOT_NULL:
|
||||
case NEGATING_SIMPLE_PROPERTY:
|
||||
return "!=";
|
||||
/*
|
||||
NOTE unfortunately, 'NOT LIKE' operator is not supported by GemFire's Query/OQL syntax
|
||||
case NOT_LIKE:
|
||||
return "NOT LIKE";
|
||||
*/
|
||||
case LIKE:
|
||||
case STARTING_WITH:
|
||||
case ENDING_WITH:
|
||||
case CONTAINING:
|
||||
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;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -29,6 +31,7 @@ import org.springframework.data.repository.query.parser.Part;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class PredicatesUnitTests {
|
||||
|
||||
@Test
|
||||
@@ -68,9 +71,24 @@ public class PredicatesUnitTests {
|
||||
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 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