diff --git a/src/main/java/org/springframework/data/gemfire/repository/query/Predicates.java b/src/main/java/org/springframework/data/gemfire/repository/query/Predicates.java index 593cce7d..3149d221 100644 --- a/src/main/java/org/springframework/data/gemfire/repository/query/Predicates.java +++ b/src/main/java/org/springframework/data/gemfire/repository/query/Predicates.java @@ -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)); } } } diff --git a/src/test/java/org/springframework/data/gemfire/repository/query/PredicatesUnitTests.java b/src/test/java/org/springframework/data/gemfire/repository/query/PredicatesUnitTests.java index 5bf25632..7b1b49fd 100644 --- a/src/test/java/org/springframework/data/gemfire/repository/query/PredicatesUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/repository/query/PredicatesUnitTests.java @@ -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 indexes = Collections.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; + } + } diff --git a/src/test/java/org/springframework/data/gemfire/repository/sample/User.java b/src/test/java/org/springframework/data/gemfire/repository/sample/User.java new file mode 100644 index 00000000..c777845a --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/repository/sample/User.java @@ -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. + *

+ * @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(); + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/repository/sample/UserRepository.java b/src/test/java/org/springframework/data/gemfire/repository/sample/UserRepository.java new file mode 100644 index 00000000..11e73679 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/repository/sample/UserRepository.java @@ -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. + *

+ * @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 { + + //@Query("SELECT DISTINCT * FROM /Users u WHERE u.active = true") + public List findDistinctByActiveTrue(); + + //@Query("SELECT DISTINCT * FROM /Users u WHERE u.active = false") + public List findDistinctByActiveFalse(); + + public List findDistinctByUsernameLike(String username); + + // NOTE unfortunately, the 'NOT LIKE' operator is unsupported in GemFire's Query/OQL syntax + //public List findDistinctByUsernameNotLike(String username); + +} diff --git a/src/test/java/org/springframework/data/gemfire/repository/sample/UserRepositoryQueriesIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/repository/sample/UserRepositoryQueriesIntegrationTest.java new file mode 100644 index 00000000..838f2ff0 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/repository/sample/UserRepositoryQueriesIntegrationTest.java @@ -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. + *

+ * @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 actualUsers, final String... expectedUsernames) { + assertNotNull("The query did not return any results!", actualUsers); + + List actualUsernames = new ArrayList(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 activeUsers = userRepository.findDistinctByActiveTrue(); + + assertQueryResults(activeUsers, "blumj", "blums", "handyj", "doej"); + + List inactiveUsers = userRepository.findDistinctByActiveFalse(); + + assertQueryResults(inactiveUsers, "blume", "bloomr", "handys", "doep", "doec"); + + List blumUsers = userRepository.findDistinctByUsernameLike("blum%"); + + assertQueryResults(blumUsers, "blumj", "blums", "blume"); + + /* + List nonHandyUsers = userRepository.findDistinctByUsernameNotLike("handy%"); + + assertQueryResults(nonHandyUsers, "blumj", "blums", "blume", "bloomr", "doej", "doep", "doec"); + */ + } + +} diff --git a/src/test/resources/org/springframework/data/gemfire/repository/sample/userRepositoryQueriesIntegrationTest.xml b/src/test/resources/org/springframework/data/gemfire/repository/sample/userRepositoryQueriesIntegrationTest.xml new file mode 100644 index 00000000..332a09ea --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/repository/sample/userRepositoryQueriesIntegrationTest.xml @@ -0,0 +1,28 @@ + + + + + repositoryQueriesTest + localhost[11235] + config + 0 + localhost[11235] + + + + + + + + +