PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java

http://github.com/SpringSource/spring-data-mongodb
Java | 700 lines | 479 code | 199 blank | 22 comment | 0 complexity | 4d465f548096b1433ace4f693895f3a4 MD5 | raw file
  1. /*
  2. * Copyright 2011-2021 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * https://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.data.mongodb.repository.query;
  17. import static org.mockito.Mockito.*;
  18. import static org.springframework.data.mongodb.core.query.Criteria.*;
  19. import static org.springframework.data.mongodb.core.query.Query.*;
  20. import static org.springframework.data.mongodb.repository.query.StubParameterAccessor.*;
  21. import static org.springframework.data.mongodb.test.util.Assertions.*;
  22. import java.lang.reflect.Method;
  23. import java.util.List;
  24. import java.util.regex.Pattern;
  25. import org.bson.Document;
  26. import org.bson.types.ObjectId;
  27. import org.junit.jupiter.api.BeforeEach;
  28. import org.junit.jupiter.api.Test;
  29. import org.springframework.data.domain.Range;
  30. import org.springframework.data.domain.Range.Bound;
  31. import org.springframework.data.geo.Distance;
  32. import org.springframework.data.geo.Metrics;
  33. import org.springframework.data.geo.Point;
  34. import org.springframework.data.geo.Polygon;
  35. import org.springframework.data.geo.Shape;
  36. import org.springframework.data.mapping.context.MappingContext;
  37. import org.springframework.data.mongodb.MongoDatabaseFactory;
  38. import org.springframework.data.mongodb.core.MongoExceptionTranslator;
  39. import org.springframework.data.mongodb.core.Person;
  40. import org.springframework.data.mongodb.core.Venue;
  41. import org.springframework.data.mongodb.core.convert.DbRefResolver;
  42. import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
  43. import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
  44. import org.springframework.data.mongodb.core.convert.MongoConverter;
  45. import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
  46. import org.springframework.data.mongodb.core.geo.GeoJsonLineString;
  47. import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
  48. import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
  49. import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
  50. import org.springframework.data.mongodb.core.mapping.DBRef;
  51. import org.springframework.data.mongodb.core.mapping.Field;
  52. import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
  53. import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
  54. import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
  55. import org.springframework.data.mongodb.core.query.Criteria;
  56. import org.springframework.data.mongodb.core.query.Query;
  57. import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
  58. import org.springframework.data.repository.Repository;
  59. import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
  60. import org.springframework.data.repository.query.parser.PartTree;
  61. /**
  62. * Unit test for {@link MongoQueryCreator}.
  63. *
  64. * @author Oliver Gierke
  65. * @author Thomas Darimont
  66. * @author Christoph Strobl
  67. */
  68. class MongoQueryCreatorUnitTests {
  69. private MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context;
  70. private MongoConverter converter;
  71. @BeforeEach
  72. void beforeEach() {
  73. context = new MongoMappingContext();
  74. converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, context);
  75. }
  76. @Test
  77. void createsQueryCorrectly() {
  78. PartTree tree = new PartTree("findByFirstName", Person.class);
  79. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "Oliver"), context);
  80. Query query = creator.createQuery();
  81. assertThat(query).isEqualTo(query(where("firstName").is("Oliver")));
  82. }
  83. @Test // DATAMONGO-469
  84. void createsAndQueryCorrectly() {
  85. Person person = new Person();
  86. MongoQueryCreator creator = new MongoQueryCreator(new PartTree("findByFirstNameAndFriend", Person.class),
  87. getAccessor(converter, "Oliver", person), context);
  88. Query query = creator.createQuery();
  89. assertThat(query).isEqualTo(query(where("firstName").is("Oliver").and("friend").is(person)));
  90. }
  91. @Test
  92. void createsNotNullQueryCorrectly() {
  93. PartTree tree = new PartTree("findByFirstNameNotNull", Person.class);
  94. Query query = new MongoQueryCreator(tree, getAccessor(converter), context).createQuery();
  95. assertThat(query).isEqualTo(new Query(Criteria.where("firstName").ne(null)));
  96. }
  97. @Test
  98. void createsIsNullQueryCorrectly() {
  99. PartTree tree = new PartTree("findByFirstNameIsNull", Person.class);
  100. Query query = new MongoQueryCreator(tree, getAccessor(converter), context).createQuery();
  101. assertThat(query).isEqualTo(new Query(Criteria.where("firstName").is(null)));
  102. }
  103. @Test
  104. void bindsMetricDistanceParameterToNearSphereCorrectly() throws Exception {
  105. Point point = new Point(10, 20);
  106. Distance distance = new Distance(2.5, Metrics.KILOMETERS);
  107. Query query = query(
  108. where("location").nearSphere(point).maxDistance(distance.getNormalizedValue()).and("firstname").is("Dave"));
  109. assertBindsDistanceToQuery(point, distance, query);
  110. }
  111. @Test
  112. void bindsDistanceParameterToNearCorrectly() throws Exception {
  113. Point point = new Point(10, 20);
  114. Distance distance = new Distance(2.5);
  115. Query query = query(
  116. where("location").near(point).maxDistance(distance.getNormalizedValue()).and("firstname").is("Dave"));
  117. assertBindsDistanceToQuery(point, distance, query);
  118. }
  119. @Test
  120. void createsLessThanEqualQueryCorrectly() {
  121. PartTree tree = new PartTree("findByAgeLessThanEqual", Person.class);
  122. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, 18), context);
  123. Query reference = query(where("age").lte(18));
  124. assertThat(creator.createQuery()).isEqualTo(reference);
  125. }
  126. @Test
  127. void createsGreaterThanEqualQueryCorrectly() {
  128. PartTree tree = new PartTree("findByAgeGreaterThanEqual", Person.class);
  129. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, 18), context);
  130. Query reference = query(where("age").gte(18));
  131. assertThat(creator.createQuery()).isEqualTo(reference);
  132. }
  133. @Test // DATAMONGO-338
  134. void createsExistsClauseCorrectly() {
  135. PartTree tree = new PartTree("findByAgeExists", Person.class);
  136. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, true), context);
  137. Query query = query(where("age").exists(true));
  138. assertThat(creator.createQuery()).isEqualTo(query);
  139. }
  140. @Test // DATAMONGO-338
  141. void createsRegexClauseCorrectly() {
  142. PartTree tree = new PartTree("findByFirstNameRegex", Person.class);
  143. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, ".*"), context);
  144. Query query = query(where("firstName").regex(".*"));
  145. assertThat(creator.createQuery()).isEqualTo(query);
  146. }
  147. @Test // DATAMONGO-338
  148. void createsTrueClauseCorrectly() {
  149. PartTree tree = new PartTree("findByActiveTrue", Person.class);
  150. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter), context);
  151. Query query = query(where("active").is(true));
  152. assertThat(creator.createQuery()).isEqualTo(query);
  153. }
  154. @Test // DATAMONGO-338
  155. void createsFalseClauseCorrectly() {
  156. PartTree tree = new PartTree("findByActiveFalse", Person.class);
  157. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter), context);
  158. Query query = query(where("active").is(false));
  159. assertThat(creator.createQuery()).isEqualTo(query);
  160. }
  161. @Test // DATAMONGO-413
  162. void createsOrQueryCorrectly() {
  163. PartTree tree = new PartTree("findByFirstNameOrAge", Person.class);
  164. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "Dave", 42), context);
  165. Query query = creator.createQuery();
  166. assertThat(query).isEqualTo(query(new Criteria().orOperator(where("firstName").is("Dave"), where("age").is(42))));
  167. }
  168. @Test // DATAMONGO-347
  169. void createsQueryReferencingADBRefCorrectly() {
  170. User user = new User();
  171. user.id = new ObjectId();
  172. PartTree tree = new PartTree("findByCreator", User.class);
  173. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, user), context);
  174. Document queryObject = creator.createQuery().getQueryObject();
  175. assertThat(queryObject.get("creator")).isEqualTo(user);
  176. }
  177. @Test // DATAMONGO-418
  178. void createsQueryWithStartingWithPredicateCorrectly() {
  179. PartTree tree = new PartTree("findByUsernameStartingWith", User.class);
  180. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "Matt"), context);
  181. Query query = creator.createQuery();
  182. assertThat(query).isEqualTo(query(where("username").regex("^Matt")));
  183. }
  184. @Test // DATAMONGO-418
  185. void createsQueryWithEndingWithPredicateCorrectly() {
  186. PartTree tree = new PartTree("findByUsernameEndingWith", User.class);
  187. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "ews"), context);
  188. Query query = creator.createQuery();
  189. assertThat(query).isEqualTo(query(where("username").regex("ews$")));
  190. }
  191. @Test // DATAMONGO-418
  192. void createsQueryWithContainingPredicateCorrectly() {
  193. PartTree tree = new PartTree("findByUsernameContaining", User.class);
  194. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "thew"), context);
  195. Query query = creator.createQuery();
  196. assertThat(query).isEqualTo(query(where("username").regex(".*thew.*")));
  197. }
  198. private void assertBindsDistanceToQuery(Point point, Distance distance, Query reference) throws Exception {
  199. PartTree tree = new PartTree("findByLocationNearAndFirstname",
  200. org.springframework.data.mongodb.repository.Person.class);
  201. Method method = PersonRepository.class.getMethod("findByLocationNearAndFirstname", Point.class, Distance.class,
  202. String.class);
  203. MongoQueryMethod queryMethod = new MongoQueryMethod(method, new DefaultRepositoryMetadata(PersonRepository.class),
  204. new SpelAwareProxyProjectionFactory(), new MongoMappingContext());
  205. MongoParameterAccessor accessor = new MongoParametersParameterAccessor(queryMethod,
  206. new Object[] { point, distance, "Dave" });
  207. Query query = new MongoQueryCreator(tree, new ConvertingParameterAccessor(converter, accessor), context)
  208. .createQuery();
  209. assertThat(query).isEqualTo(query);
  210. }
  211. @Test // DATAMONGO-770
  212. void createsQueryWithFindByIgnoreCaseCorrectly() {
  213. PartTree tree = new PartTree("findByfirstNameIgnoreCase", Person.class);
  214. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "dave"), context);
  215. Query query = creator.createQuery();
  216. assertThat(query).isEqualTo(query(where("firstName").regex("^dave$", "i")));
  217. }
  218. @Test // DATAMONGO-770
  219. void createsQueryWithFindByNotIgnoreCaseCorrectly() {
  220. PartTree tree = new PartTree("findByFirstNameNotIgnoreCase", Person.class);
  221. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "dave"), context);
  222. Query query = creator.createQuery();
  223. assertThat(query.toString()).isEqualTo(query(where("firstName").not().regex("^dave$", "i")).toString());
  224. }
  225. @Test // DATAMONGO-770
  226. void createsQueryWithFindByStartingWithIgnoreCaseCorrectly() {
  227. PartTree tree = new PartTree("findByFirstNameStartingWithIgnoreCase", Person.class);
  228. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "dave"), context);
  229. Query query = creator.createQuery();
  230. assertThat(query).isEqualTo(query(where("firstName").regex("^dave", "i")));
  231. }
  232. @Test // DATAMONGO-770
  233. void createsQueryWithFindByEndingWithIgnoreCaseCorrectly() {
  234. PartTree tree = new PartTree("findByFirstNameEndingWithIgnoreCase", Person.class);
  235. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "dave"), context);
  236. Query query = creator.createQuery();
  237. assertThat(query).isEqualTo(query(where("firstName").regex("dave$", "i")));
  238. }
  239. @Test // DATAMONGO-770
  240. void createsQueryWithFindByContainingIgnoreCaseCorrectly() {
  241. PartTree tree = new PartTree("findByFirstNameContainingIgnoreCase", Person.class);
  242. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "dave"), context);
  243. Query query = creator.createQuery();
  244. assertThat(query).isEqualTo(query(where("firstName").regex(".*dave.*", "i")));
  245. }
  246. @Test // DATAMONGO-770
  247. void shouldThrowExceptionForQueryWithFindByIgnoreCaseOnNonStringProperty() {
  248. PartTree tree = new PartTree("findByFirstNameAndAgeIgnoreCase", Person.class);
  249. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "foo", 42), context);
  250. assertThatIllegalArgumentException().isThrownBy(creator::createQuery)
  251. .withMessageContaining("must be of type String");
  252. }
  253. @Test // DATAMONGO-770
  254. void shouldOnlyGenerateLikeExpressionsForStringPropertiesIfAllIgnoreCase() {
  255. PartTree tree = new PartTree("findByFirstNameAndAgeAllIgnoreCase", Person.class);
  256. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "dave", 42), context);
  257. Query query = creator.createQuery();
  258. assertThat(query).isEqualTo(query(where("firstName").regex("^dave$", "i").and("age").is(42)));
  259. }
  260. @Test // DATAMONGO-566
  261. void shouldCreateDeleteByQueryCorrectly() {
  262. PartTree tree = new PartTree("deleteByFirstName", Person.class);
  263. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "dave", 42), context);
  264. Query query = creator.createQuery();
  265. assertThat(tree.isDelete()).isTrue();
  266. assertThat(query).isEqualTo(query(where("firstName").is("dave")));
  267. }
  268. @Test // DATAMONGO-566
  269. void shouldCreateDeleteByQueryCorrectlyForMultipleCriteriaAndCaseExpressions() {
  270. PartTree tree = new PartTree("deleteByFirstNameAndAgeAllIgnoreCase", Person.class);
  271. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "dave", 42), context);
  272. Query query = creator.createQuery();
  273. assertThat(tree.isDelete()).isTrue();
  274. assertThat(query).isEqualTo(query(where("firstName").regex("^dave$", "i").and("age").is(42)));
  275. }
  276. @Test // DATAMONGO-1075
  277. void shouldCreateInClauseWhenUsingContainsOnCollectionLikeProperty() {
  278. PartTree tree = new PartTree("findByEmailAddressesContaining", User.class);
  279. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "dave"), context);
  280. Query query = creator.createQuery();
  281. assertThat(query).isEqualTo(query(where("emailAddresses").in("dave")));
  282. }
  283. @Test // DATAMONGO-1075
  284. void shouldCreateInClauseWhenUsingNotContainsOnCollectionLikeProperty() {
  285. PartTree tree = new PartTree("findByEmailAddressesNotContaining", User.class);
  286. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "dave"), context);
  287. Query query = creator.createQuery();
  288. assertThat(query).isEqualTo(query(where("emailAddresses").not().in("dave")));
  289. }
  290. @Test // DATAMONGO-1075, DATAMONGO-1425
  291. void shouldCreateRegexWhenUsingNotContainsOnStringProperty() {
  292. PartTree tree = new PartTree("findByUsernameNotContaining", User.class);
  293. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "thew"), context);
  294. Query query = creator.createQuery();
  295. assertThat(query.getQueryObject().toJson())
  296. .isEqualTo(query(where("username").not().regex(".*thew.*")).getQueryObject().toJson());
  297. }
  298. @Test // DATAMONGO-1139
  299. void createsNonSphericalNearForDistanceWithDefaultMetric() {
  300. Point point = new Point(1.0, 1.0);
  301. Distance distance = new Distance(1.0);
  302. PartTree tree = new PartTree("findByLocationNear", Venue.class);
  303. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, point, distance), context);
  304. Query query = creator.createQuery();
  305. assertThat(query).isEqualTo(query(where("location").near(point).maxDistance(1.0)));
  306. }
  307. @Test // DATAMONGO-1136
  308. void shouldCreateWithinQueryCorrectly() {
  309. Point first = new Point(1, 1);
  310. Point second = new Point(2, 2);
  311. Point third = new Point(3, 3);
  312. Shape shape = new Polygon(first, second, third);
  313. PartTree tree = new PartTree("findByAddress_GeoWithin", User.class);
  314. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, shape), context);
  315. Query query = creator.createQuery();
  316. assertThat(query).isEqualTo(query(where("address.geo").within(shape)));
  317. }
  318. @Test // DATAMONGO-1110
  319. void shouldCreateNearSphereQueryForSphericalProperty() {
  320. Point point = new Point(10, 20);
  321. PartTree tree = new PartTree("findByAddress2dSphere_GeoNear", User.class);
  322. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, point), context);
  323. Query query = creator.createQuery();
  324. assertThat(query).isEqualTo(query(where("address2dSphere.geo").nearSphere(point)));
  325. }
  326. @Test // DATAMONGO-1110
  327. void shouldCreateNearSphereQueryForSphericalPropertyHavingDistanceWithDefaultMetric() {
  328. Point point = new Point(1.0, 1.0);
  329. Distance distance = new Distance(1.0);
  330. PartTree tree = new PartTree("findByAddress2dSphere_GeoNear", User.class);
  331. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, point, distance), context);
  332. Query query = creator.createQuery();
  333. assertThat(query).isEqualTo(query(where("address2dSphere.geo").nearSphere(point).maxDistance(1.0)));
  334. }
  335. @Test // DATAMONGO-1110
  336. void shouldCreateNearQueryForMinMaxDistance() {
  337. Point point = new Point(10, 20);
  338. Range<Distance> range = Distance.between(new Distance(10), new Distance(20));
  339. PartTree tree = new PartTree("findByAddress_GeoNear", User.class);
  340. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, point, range), context);
  341. Query query = creator.createQuery();
  342. assertThat(query).isEqualTo(query(where("address.geo").near(point).minDistance(10D).maxDistance(20D)));
  343. }
  344. @Test // DATAMONGO-1229
  345. void appliesIgnoreCaseToLeafProperty() {
  346. PartTree tree = new PartTree("findByAddressStreetIgnoreCase", User.class);
  347. ConvertingParameterAccessor accessor = getAccessor(converter, "Street");
  348. assertThat(new MongoQueryCreator(tree, accessor, context).createQuery()).isNotNull();
  349. }
  350. @Test // DATAMONGO-1232
  351. void ignoreCaseShouldEscapeSource() {
  352. PartTree tree = new PartTree("findByUsernameIgnoreCase", User.class);
  353. ConvertingParameterAccessor accessor = getAccessor(converter, "con.flux+");
  354. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  355. assertThat(query).isEqualTo(query(where("username").regex("^\\Qcon.flux+\\E$", "i")));
  356. }
  357. @Test // DATAMONGO-1232
  358. void ignoreCaseShouldEscapeSourceWhenUsedForStartingWith() {
  359. PartTree tree = new PartTree("findByUsernameStartingWithIgnoreCase", User.class);
  360. ConvertingParameterAccessor accessor = getAccessor(converter, "dawns.light+");
  361. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  362. assertThat(query).isEqualTo(query(where("username").regex("^\\Qdawns.light+\\E", "i")));
  363. }
  364. @Test // DATAMONGO-1232
  365. void ignoreCaseShouldEscapeSourceWhenUsedForEndingWith() {
  366. PartTree tree = new PartTree("findByUsernameEndingWithIgnoreCase", User.class);
  367. ConvertingParameterAccessor accessor = getAccessor(converter, "new.ton+");
  368. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  369. assertThat(query).isEqualTo(query(where("username").regex("\\Qnew.ton+\\E$", "i")));
  370. }
  371. @Test // DATAMONGO-1232
  372. void likeShouldEscapeSourceWhenUsedWithLeadingAndTrailingWildcard() {
  373. PartTree tree = new PartTree("findByUsernameLike", User.class);
  374. ConvertingParameterAccessor accessor = getAccessor(converter, "*fire.fight+*");
  375. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  376. assertThat(query).isEqualTo(query(where("username").regex(".*\\Qfire.fight+\\E.*")));
  377. }
  378. @Test // DATAMONGO-1232
  379. void likeShouldEscapeSourceWhenUsedWithLeadingWildcard() {
  380. PartTree tree = new PartTree("findByUsernameLike", User.class);
  381. ConvertingParameterAccessor accessor = getAccessor(converter, "*steel.heart+");
  382. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  383. assertThat(query).isEqualTo(query(where("username").regex(".*\\Qsteel.heart+\\E")));
  384. }
  385. @Test // DATAMONGO-1232
  386. void likeShouldEscapeSourceWhenUsedWithTrailingWildcard() {
  387. PartTree tree = new PartTree("findByUsernameLike", User.class);
  388. ConvertingParameterAccessor accessor = getAccessor(converter, "cala.mity+*");
  389. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  390. assertThat(query).isEqualTo(query(where("username").regex("\\Qcala.mity+\\E.*")));
  391. }
  392. @Test // DATAMONGO-1232
  393. void likeShouldBeTreatedCorrectlyWhenUsedWithWildcardOnly() {
  394. PartTree tree = new PartTree("findByUsernameLike", User.class);
  395. ConvertingParameterAccessor accessor = getAccessor(converter, "*");
  396. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  397. assertThat(query).isEqualTo(query(where("username").regex(".*")));
  398. }
  399. @Test // DATAMONGO-1342
  400. void bindsNullValueToContainsClause() {
  401. PartTree partTree = new PartTree("emailAddressesContains", User.class);
  402. ConvertingParameterAccessor accessor = getAccessor(converter, new Object[] { null });
  403. Query query = new MongoQueryCreator(partTree, accessor, context).createQuery();
  404. assertThat(query).isEqualTo(query(where("emailAddresses").in((Object) null)));
  405. }
  406. @Test // DATAMONGO-1424
  407. void notLikeShouldEscapeSourceWhenUsedWithLeadingAndTrailingWildcard() {
  408. PartTree tree = new PartTree("findByUsernameNotLike", User.class);
  409. ConvertingParameterAccessor accessor = getAccessor(converter, "*fire.fight+*");
  410. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  411. assertThat(query.getQueryObject().toJson())
  412. .isEqualTo(query(where("username").not().regex(".*\\Qfire.fight+\\E.*")).getQueryObject().toJson());
  413. }
  414. @Test // DATAMONGO-1424
  415. void notLikeShouldEscapeSourceWhenUsedWithLeadingWildcard() {
  416. PartTree tree = new PartTree("findByUsernameNotLike", User.class);
  417. ConvertingParameterAccessor accessor = getAccessor(converter, "*steel.heart+");
  418. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  419. assertThat(query.getQueryObject().toJson())
  420. .isEqualTo(query(where("username").not().regex(".*\\Qsteel.heart+\\E")).getQueryObject().toJson());
  421. }
  422. @Test // DATAMONGO-1424
  423. void notLikeShouldEscapeSourceWhenUsedWithTrailingWildcard() {
  424. PartTree tree = new PartTree("findByUsernameNotLike", User.class);
  425. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "cala.mity+*"), context);
  426. Query query = creator.createQuery();
  427. assertThat(query.getQueryObject().toJson())
  428. .isEqualTo(query(where("username").not().regex("\\Qcala.mity+\\E.*")).getQueryObject().toJson());
  429. }
  430. @Test // DATAMONGO-1424
  431. void notLikeShouldBeTreatedCorrectlyWhenUsedWithWildcardOnly() {
  432. PartTree tree = new PartTree("findByUsernameNotLike", User.class);
  433. ConvertingParameterAccessor accessor = getAccessor(converter, "*");
  434. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  435. assertThat(query.getQueryObject().toJson())
  436. .isEqualTo(query(where("username").not().regex(".*")).getQueryObject().toJson());
  437. }
  438. @Test // DATAMONGO-1588
  439. void queryShouldAcceptSubclassOfDeclaredArgument() {
  440. PartTree tree = new PartTree("findByLocationNear", User.class);
  441. ConvertingParameterAccessor accessor = getAccessor(converter, new GeoJsonPoint(-74.044502D, 40.689247D));
  442. Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
  443. assertThat(query.getQueryObject()).containsKey("location");
  444. }
  445. @Test // DATAMONGO-1588
  446. void queryShouldThrowExceptionWhenArgumentDoesNotMatchDeclaration() {
  447. PartTree tree = new PartTree("findByLocationNear", User.class);
  448. ConvertingParameterAccessor accessor = getAccessor(converter,
  449. new GeoJsonLineString(new Point(-74.044502D, 40.689247D), new Point(-73.997330D, 40.730824D)));
  450. assertThatIllegalArgumentException().isThrownBy(() -> new MongoQueryCreator(tree, accessor, context).createQuery())
  451. .withMessageContaining("Expected parameter type of " + Point.class);
  452. }
  453. @Test // DATAMONGO-2003
  454. void createsRegexQueryForPatternCorrectly() {
  455. PartTree tree = new PartTree("findByFirstNameRegex", Person.class);
  456. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, Pattern.compile(".*")), context);
  457. assertThat(creator.createQuery()).isEqualTo(query(where("firstName").regex(".*")));
  458. }
  459. @Test // DATAMONGO-2003
  460. void createsRegexQueryForPatternWithOptionsCorrectly() {
  461. Pattern pattern = Pattern.compile(".*", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
  462. PartTree tree = new PartTree("findByFirstNameRegex", Person.class);
  463. MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, pattern), context);
  464. assertThat(creator.createQuery()).isEqualTo(query(where("firstName").regex(".*", "iu")));
  465. }
  466. @Test // DATAMONGO-2071
  467. void betweenShouldAllowSingleRageParameter() {
  468. PartTree tree = new PartTree("findByAgeBetween", Person.class);
  469. MongoQueryCreator creator = new MongoQueryCreator(tree,
  470. getAccessor(converter, Range.of(Bound.exclusive(10), Bound.exclusive(11))), context);
  471. assertThat(creator.createQuery()).isEqualTo(query(where("age").gt(10).lt(11)));
  472. }
  473. @Test // DATAMONGO-2394
  474. void nearShouldUseMetricDistanceForGeoJsonTypes() {
  475. GeoJsonPoint point = new GeoJsonPoint(27.987901, 86.9165379);
  476. PartTree tree = new PartTree("findByLocationNear", User.class);
  477. MongoQueryCreator creator = new MongoQueryCreator(tree,
  478. getAccessor(converter, point, new Distance(1, Metrics.KILOMETERS)), context);
  479. assertThat(creator.createQuery()).isEqualTo(query(where("location").nearSphere(point).maxDistance(1000.0D)));
  480. }
  481. interface PersonRepository extends Repository<Person, Long> {
  482. List<Person> findByLocationNearAndFirstname(Point location, Distance maxDistance, String firstname);
  483. }
  484. class User {
  485. ObjectId id;
  486. @Field("foo") String username;
  487. @DBRef User creator;
  488. List<String> emailAddresses;
  489. Address address;
  490. Address2dSphere address2dSphere;
  491. Point location;
  492. }
  493. static class Address {
  494. String street;
  495. Point geo;
  496. }
  497. static class Address2dSphere {
  498. String street;
  499. @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE) Point geo;
  500. }
  501. }