/* * Copyright 2012-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.solr.repository.query; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Date; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.data.domain.Sort; import org.springframework.data.geo.Box; import org.springframework.data.geo.Distance; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.support.AbstractRepositoryMetadata; import org.springframework.data.repository.query.parser.PartTree; import org.springframework.data.solr.core.DefaultQueryParser; import org.springframework.data.solr.core.QueryParser; import org.springframework.data.solr.core.mapping.SimpleSolrMappingContext; import org.springframework.data.solr.core.mapping.SolrPersistentProperty; import org.springframework.data.solr.core.query.Query; import org.springframework.data.solr.repository.ProductBean; /** * @author Christoph Strobl * @author John Dorman * @author Francisco Spaeth * @author Oliver Gierke */ @RunWith(MockitoJUnitRunner.class) public class SolrQueryCreatorTests { private @Mock SolrEntityInformationCreator entityInformationCreatorMock; private MappingContext<?, SolrPersistentProperty> mappingContext; private RepositoryMetadata metadata = AbstractRepositoryMetadata.getMetadata(SampleRepository.class); private QueryParser queryParser; @Before public void setUp() { mappingContext = new SimpleSolrMappingContext(); queryParser = new DefaultQueryParser(); } @Test public void testCreateFindBySingleCriteria() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularity", Integer.class); Query query = createQueryForMethodWithArgs(method, new Object[] { 100 }); Assert.assertEquals("popularity:100", queryParser.getQueryString(query)); } @Test public void testCreateFindByNotCriteria() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityIsNot", Integer.class); Query query = createQueryForMethodWithArgs(method, new Object[] { 100 }); Assert.assertEquals("-popularity:100", queryParser.getQueryString(query)); } @Test public void testCreateFindByNotNullCriteria() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityIsNotNull"); Query query = createQueryForMethodWithArgs(method, new Object[] {}); Assert.assertEquals("popularity:[* TO *]", queryParser.getQueryString(query)); } @Test public void testCreateFindByNullCriteria() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityIsNull"); Query query = createQueryForMethodWithArgs(method, new Object[] {}); Assert.assertEquals("-popularity:[* TO *]", queryParser.getQueryString(query)); } @Test public void testCreateFindByAndQuery() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityAndPrice", Integer.class, Float.class); Query query = createQueryForMethodWithArgs(method, new Object[] { 100, 200f }); Assert.assertEquals("popularity:100 AND price:200.0", queryParser.getQueryString(query)); } @Test public void testCreateFindByOrQuery() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityOrPrice", Integer.class, Float.class); Query query = createQueryForMethodWithArgs(method, new Object[] { 100, 200f }); Assert.assertEquals("popularity:100 OR price:200.0", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithTrueClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByAvailableTrue"); Query query = createQueryForMethodWithArgs(method, new Object[] {}); Assert.assertEquals("inStock:true", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithFalseClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByAvailableFalse"); Query query = createQueryForMethodWithArgs(method, new Object[] {}); Assert.assertEquals("inStock:false", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithLikeClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleLike", String.class); Query query = createQueryForMethodWithArgs(method, new Object[] { "j73x73r" }); Assert.assertEquals("title:j73x73r*", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithLikeClauseUsingCollection() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleLike", Collection.class); Query query = createQueryForMethodWithArgs(method, new Object[] { Arrays.asList("one", "two", "three") }); Assert.assertEquals("title:(one* two* three*)", queryParser.getQueryString(query)); } @Test(expected = IllegalArgumentException.class) public void testCreateQueryWithInvalidCollectionType() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityLike", Collection.class); createQueryForMethodWithArgs(method, new Object[] { Arrays.asList(1L, 2L, 3L) }); } @Test public void testCreateQueryWithArrayType() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityLike", String[].class); Query query = createQueryForMethodWithArgs(method, new Object[] { new String[] { "one", "two", "three" } }); Assert.assertEquals("popularity:(one* two* three*)", queryParser.getQueryString(query)); } @Test(expected = IllegalArgumentException.class) public void testCreateQueryWithInvalidArrayType() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityLike", Long[].class); createQueryForMethodWithArgs(method, new Object[] { new Long[] { 1L, 2L, 3L } }); } @Test public void testCreateQueryWithLikeNotClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleNotLike", String.class); Query query = createQueryForMethodWithArgs(method, new Object[] { "j73x73r" }); Assert.assertEquals("-title:j73x73r*", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithLikeNotClauseUsingCollection() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleNotLike", Collection.class); Query query = createQueryForMethodWithArgs(method, new Object[] { Arrays.asList("one", "two", "three") }); Assert.assertEquals("-title:(one* two* three*)", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithStartsWithClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleStartingWith", String.class); Query query = createQueryForMethodWithArgs(method, new Object[] { "j73x73r" }); Assert.assertEquals("title:j73x73r*", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithStartsWithClauseUsingCollection() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleStartingWith", Collection.class); Query query = createQueryForMethodWithArgs(method, new Object[] { Arrays.asList("one", "two", "three") }); Assert.assertEquals("title:(one* two* three*)", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithEndingWithClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleEndingWith", String.class); Query query = createQueryForMethodWithArgs(method, new Object[] { "christoph" }); Assert.assertEquals("title:*christoph", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithEndingWithClauseUsingCollection() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleEndingWith", Collection.class); Query query = createQueryForMethodWithArgs(method, new Object[] { Arrays.asList("one", "two", "three") }); Assert.assertEquals("title:(*one *two *three)", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithContainingClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleContaining", String.class); Query query = createQueryForMethodWithArgs(method, new Object[] { "solr" }); Assert.assertEquals("title:*solr*", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithContainingClauseUsingCollection() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleContaining", Collection.class); Query query = createQueryForMethodWithArgs(method, new Object[] { Arrays.asList("one", "two", "three") }); Assert.assertEquals("title:(*one* *two* *three*)", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithRegexClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByTitleRegex", String.class); Query query = createQueryForMethodWithArgs(method, new Object[] { "(\\+ \\*)" }); Assert.assertEquals("title:(\\+ \\*)", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithBetweenClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityBetween", Integer.class, Integer.class); Query query = createQueryForMethodWithArgs(method, new Object[] { 100, 200 }); Assert.assertEquals("popularity:[100 TO 200]", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithBeforeClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByLastModifiedBefore", Date.class); Query query = createQueryForMethodWithArgs(method, new Object[] { new DateTime(2012, 10, 15, 5, 31, 0, DateTimeZone.UTC) }); Assert.assertEquals("last_modified:[* TO 2012\\-10\\-15T05\\:31\\:00.000Z}", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithLessThanClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPriceLessThan", Float.class); Query query = createQueryForMethodWithArgs(method, new Object[] { 100f }); Assert.assertEquals("price:[* TO 100.0}", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithLessThanEqualsClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPriceLessThanEqual", Float.class); Query query = createQueryForMethodWithArgs(method, new Object[] { 100f }); Assert.assertEquals("price:[* TO 100.0]", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithAfterClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByLastModifiedAfter", Date.class); Query query = createQueryForMethodWithArgs(method, new Object[] { new DateTime(2012, 10, 15, 5, 31, 0, DateTimeZone.UTC) }); Assert.assertEquals("last_modified:{2012\\-10\\-15T05\\:31\\:00.000Z TO *]", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithGreaterThanClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPriceGreaterThan", Float.class); Query query = createQueryForMethodWithArgs(method, new Object[] { 10f }); Assert.assertEquals("price:{10.0 TO *]", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithGreaterThanEqualsClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPriceGreaterThanEqual", Float.class); Query query = createQueryForMethodWithArgs(method, new Object[] { 10f }); Assert.assertEquals("price:[10.0 TO *]", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithInClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityIn", Integer[].class); Query query = createQueryForMethodWithArgs(method, new Object[] { new Object[] { 1, 2, 3 } }); Assert.assertEquals("popularity:(1 2 3)", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithNotInClause() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityNotIn", Integer[].class); Query query = createQueryForMethodWithArgs(method, new Object[] { new Object[] { 1, 2, 3 } }); Assert.assertEquals("-popularity:(1 2 3)", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithNear() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByLocationNear", Point.class, Distance.class); Query query = createQueryForMethodWithArgs(method, new Object[] { new Point(48.303056, 14.290556), new Distance(5) }); Assert.assertEquals("{!bbox pt=48.303056,14.290556 sfield=store d=5.0}", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithNearWhereUnitIsMiles() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByLocationNear", Point.class, Distance.class); Query query = createQueryForMethodWithArgs(method, new Object[] { new Point(48.303056, 14.290556), new Distance(1, Metrics.MILES) }); Assert.assertEquals("{!bbox pt=48.303056,14.290556 sfield=store d=1.609344}", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithWithin() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByLocationWithin", Point.class, Distance.class); Query query = createQueryForMethodWithArgs(method, new Object[] { new Point(48.303056, 14.290556), new Distance(5) }); Assert.assertEquals("{!geofilt pt=48.303056,14.290556 sfield=store d=5.0}", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithWithinWhereUnitIsMiles() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByLocationWithin", Point.class, Distance.class); Query query = createQueryForMethodWithArgs(method, new Object[] { new Point(48.303056, 14.290556), new Distance(1, Metrics.MILES) }); Assert.assertEquals("{!geofilt pt=48.303056,14.290556 sfield=store d=1.609344}", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithNearUsingBox() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByLocationNear", Box.class); Query query = createQueryForMethodWithArgs(method, new Object[] { new Box(new Point(48.303056, 14.290556), new Point(48.306377, 14.283128)) }); Assert.assertEquals("store:[48.303056,14.290556 TO 48.306377,14.283128]", queryParser.getQueryString(query)); } @Test public void testCreateQueryWithSortDesc() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByPopularityOrderByTitleDesc", Integer.class); Query query = createQueryForMethodWithArgs(method, new Object[] { 1 }); Assert.assertNotNull(query.getSort()); Assert.assertEquals(Sort.Direction.DESC, query.getSort().getOrderFor("title").getDirection()); } @Test // DATASOLR-139 public void testCombinationsOfOrAndShouldBeCreatedCorrectly() throws NoSuchMethodException, SecurityException { Method method = SampleRepository.class.getMethod("findByNameOrDescriptionAndLastModifiedAfter", String.class, String.class, Date.class); Query query = createQueryForMethodWithArgs(method, new Object[] { "mail", "domain", new DateTime(2012, 10, 15, 5, 31, 0, DateTimeZone.UTC) }); Assert.assertEquals("name:mail OR description:domain AND last_modified:{2012\\-10\\-15T05\\:31\\:00.000Z TO *]", queryParser.getQueryString(query)); } private Query createQueryForMethodWithArgs(Method method, Object[] args) { PartTree partTree = new PartTree(method.getName(), method.getReturnType()); SolrQueryMethod queryMethod = new SolrQueryMethod(method, metadata, new SpelAwareProxyProjectionFactory(), entityInformationCreatorMock); SolrQueryCreator creator = new SolrQueryCreator(partTree, new SolrParametersParameterAccessor(queryMethod, args), mappingContext); return creator.createQuery(); } private interface SampleRepository extends Repository<ProductBean, String> { ProductBean findByPopularity(Integer popularity); ProductBean findByPopularityIsNot(Integer popularity); ProductBean findByPopularityIsNotNull(); ProductBean findByPopularityIsNull(); ProductBean findByPopularityAndPrice(Integer popularity, Float price); ProductBean findByPopularityOrPrice(Integer popularity, Float price); ProductBean findByAvailableTrue(); ProductBean findByAvailableFalse(); ProductBean findByTitleLike(String prefix); ProductBean findByTitleLike(Collection<String> prefix); ProductBean findByPopularityLike(Collection<Long> prefix); ProductBean findByPopularityLike(String[] prefix); ProductBean findByPopularityLike(Long[] prefix); ProductBean findByTitleNotLike(String prefix); ProductBean findByTitleNotLike(Collection<String> prefix); ProductBean findByTitleStartingWith(String prefix); ProductBean findByTitleStartingWith(Collection<String> prefix); ProductBean findByTitleEndingWith(String postfix); ProductBean findByTitleEndingWith(Collection<String> postfix); ProductBean findByTitleContaining(String fragment); ProductBean findByTitleContaining(Collection<String> fragment); ProductBean findByTitleRegex(String expression); ProductBean findByPopularityBetween(Integer lower, Integer upper); ProductBean findByLastModifiedBefore(Date date); ProductBean findByPriceLessThan(Float price); ProductBean findByPriceLessThanEqual(Float price); ProductBean findByLastModifiedAfter(Date date); ProductBean findByPriceGreaterThan(Float price); ProductBean findByPriceGreaterThanEqual(Float price); ProductBean findByPopularityIn(Integer... values); ProductBean findByPopularityNotIn(Integer... values); ProductBean findByPopularityOrderByTitleDesc(Integer popularity); ProductBean findByLocationWithin(Point location, Distance distance); ProductBean findByLocationNear(Point location, Distance distance); ProductBean findByLocationNear(Box bbox); ProductBean findByNameOrDescriptionAndLastModifiedAfter(String name, String description, Date date); } }