/* * Copyright 2016-2017 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.redis.repository.query; import static org.hamcrest.collection.IsCollectionWithSize.*; import static org.hamcrest.core.Is.*; import static org.hamcrest.core.IsCollectionContaining.*; import static org.hamcrest.core.IsNull.*; import static org.junit.Assert.*; import java.lang.reflect.Method; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.Mock; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.geo.Box; import org.springframework.data.geo.Circle; import org.springframework.data.geo.Distance; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; import org.springframework.data.geo.Shape; import org.springframework.data.keyvalue.core.query.KeyValueQuery; import org.springframework.data.redis.core.convert.ConversionTestEntities.Person; import org.springframework.data.redis.repository.query.RedisOperationChain.PathAndValue; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.query.DefaultParameters; import org.springframework.data.repository.query.ParametersParameterAccessor; import org.springframework.data.repository.query.parser.PartTree; /** * @author Christoph Strobl * @author Mark Paluch */ public class RedisQueryCreatorUnitTests { public @Rule ExpectedException exception = ExpectedException.none(); private @Mock RepositoryMetadata metadataMock; @Test // DATAREDIS-425 public void findBySingleSimpleProperty() throws SecurityException, NoSuchMethodException { RedisQueryCreator creator = createQueryCreatorForMethodWithArgs( SampleRepository.class.getMethod("findByFirstname", String.class), new Object[] { "eddard" }); KeyValueQuery<RedisOperationChain> query = creator.createQuery(); assertThat(query.getCriteria().getSismember(), hasSize(1)); assertThat(query.getCriteria().getSismember(), hasItem(new PathAndValue("firstname", "eddard"))); } @Test // DATAREDIS-425 public void findByMultipleSimpleProperties() throws SecurityException, NoSuchMethodException { RedisQueryCreator creator = createQueryCreatorForMethodWithArgs( SampleRepository.class.getMethod("findByFirstnameAndAge", String.class, Integer.class), new Object[] { "eddard", 43 }); KeyValueQuery<RedisOperationChain> query = creator.createQuery(); assertThat(query.getCriteria().getSismember(), hasSize(2)); assertThat(query.getCriteria().getSismember(), hasItem(new PathAndValue("firstname", "eddard"))); assertThat(query.getCriteria().getSismember(), hasItem(new PathAndValue("age", 43))); } @Test // DATAREDIS-425 public void findByMultipleSimplePropertiesUsingOr() throws SecurityException, NoSuchMethodException { RedisQueryCreator creator = createQueryCreatorForMethodWithArgs( SampleRepository.class.getMethod("findByAgeOrFirstname", Integer.class, String.class), new Object[] { 43, "eddard" }); KeyValueQuery<RedisOperationChain> query = creator.createQuery(); assertThat(query.getCriteria().getOrSismember(), hasSize(2)); assertThat(query.getCriteria().getOrSismember(), hasItem(new PathAndValue("age", 43))); assertThat(query.getCriteria().getOrSismember(), hasItem(new PathAndValue("firstname", "eddard"))); } @Test // DATAREDIS-533 public void findWithinCircle() throws SecurityException, NoSuchMethodException { RedisQueryCreator creator = createQueryCreatorForMethodWithArgs( SampleRepository.class.getMethod("findByLocationWithin", Circle.class), new Object[] { new Circle(new Point(1, 2), new Distance(200, Metrics.KILOMETERS)) }); KeyValueQuery<RedisOperationChain> query = creator.createQuery(); assertThat(query.getCriteria().getNear(), is(notNullValue())); assertThat(query.getCriteria().getNear().getPoint(), is(new Point(1, 2))); assertThat(query.getCriteria().getNear().getDistance(), is(new Distance(200, Metrics.KILOMETERS))); } @Test // DATAREDIS-533 public void findNearWithPointAndDistance() throws SecurityException, NoSuchMethodException { RedisQueryCreator creator = createQueryCreatorForMethodWithArgs( SampleRepository.class.getMethod("findByLocationNear", Point.class, Distance.class), new Object[] { new Point(1, 2), new Distance(200, Metrics.KILOMETERS) }); KeyValueQuery<RedisOperationChain> query = creator.createQuery(); assertThat(query.getCriteria().getNear(), is(notNullValue())); assertThat(query.getCriteria().getNear().getPoint(), is(new Point(1, 2))); assertThat(query.getCriteria().getNear().getDistance(), is(new Distance(200, Metrics.KILOMETERS))); } @Test // DATAREDIS-533 public void findNearWithPointAndNumericValueDefaultsToKilometers() throws SecurityException, NoSuchMethodException { RedisQueryCreator creator = createQueryCreatorForMethodWithArgs( SampleRepository.class.getMethod("findByLocationNear", Shape.class, Object.class), new Object[] { new Point(1, 2), 200F }); KeyValueQuery<RedisOperationChain> query = creator.createQuery(); assertThat(query.getCriteria().getNear(), is(notNullValue())); assertThat(query.getCriteria().getNear().getPoint(), is(new Point(1, 2))); assertThat(query.getCriteria().getNear().getDistance(), is(new Distance(200, Metrics.KILOMETERS))); } @Test // DATAREDIS-533 public void findNearWithInvalidShapeParameter() throws SecurityException, NoSuchMethodException { exception.expect(InvalidDataAccessApiUsageException.class); exception.expectMessage("Expected to find a Circle or Point/Distance"); RedisQueryCreator creator = createQueryCreatorForMethodWithArgs( SampleRepository.class.getMethod("findByLocationNear", Shape.class, Object.class), new Object[] { new Box(new Point(0, 0), new Point(1, 1)), 200F }); creator.createQuery(); } @Test // DATAREDIS-533 public void findNearWithInvalidDistanceParameter() throws SecurityException, NoSuchMethodException { exception.expect(InvalidDataAccessApiUsageException.class); exception.expectMessage("Expected to find Distance or Numeric value"); RedisQueryCreator creator = createQueryCreatorForMethodWithArgs( SampleRepository.class.getMethod("findByLocationNear", Shape.class, Object.class), new Object[] { new Point(0, 0), "200" }); creator.createQuery(); } @Test // DATAREDIS-533 public void findNearWithMissingDistanceParameter() throws SecurityException, NoSuchMethodException { exception.expect(InvalidDataAccessApiUsageException.class); exception.expectMessage("Are you missing a parameter?"); RedisQueryCreator creator = createQueryCreatorForMethodWithArgs( SampleRepository.class.getMethod("findByLocationNear", Shape.class), new Object[] { new Point(0, 0) }); creator.createQuery(); } private RedisQueryCreator createQueryCreatorForMethodWithArgs(Method method, Object[] args) { PartTree partTree = new PartTree(method.getName(), method.getReturnType()); RedisQueryCreator creator = new RedisQueryCreator(partTree, new ParametersParameterAccessor(new DefaultParameters(method), args)); return creator; } private interface SampleRepository extends Repository<Person, String> { Person findByFirstname(String firstname); Person findByFirstnameAndAge(String firstname, Integer age); Person findByAgeOrFirstname(Integer age, String firstname); Person findByLocationWithin(Circle circle); Person findByLocationNear(Point point, Distance distance); Person findByLocationNear(Shape point, Object distance); Person findByLocationNear(Shape point); } }