MethodQueryDescriptionExtractor implements QueryDescriptionExtractor<Method> { @Override public QueryDescriptor extract(RepositoryMetadata repositoryMetadata, RepositoryFactoryConfiguration configuration, Method method) { String methodName = method.getName(); boolean allIgnoreCase = methodName.matches(".*" + ALL_IGNORE_CASE_SUFFIX); methodName = allIgnoreCase ? methodName.replaceFirst(ALL_IGNORE_CASE_SUFFIX, "") : methodName; final DocumentReader reader = new DefaultDocumentReader(methodName); String function = parseFunctionName(method, reader); final QueryModifiers queryModifiers = parseQueryModifiers(method, reader); final PageParameterExtractor pageExtractor; SortParameterExtractor sortExtractor = null; final List<List<Parameter>> branches = new ArrayList<>(); if (!reader.hasMore()) { pageExtractor = null; } else { reader.expect("By"); if (!reader.hasMore()) { throw new QueryParserException(method.getDeclaringClass(), "Query method name cannot end with `By`"); } int index = parseExpression(repositoryMetadata, method, allIgnoreCase, reader, branches); final com.mmnaseri.utils.spring.data.query.Sort sort = parseSort(repositoryMetadata, method, reader); pageExtractor = getPageParameterExtractor(method, index, sort); sortExtractor = getSortParameterExtractor(method, index, sort); } return new DefaultQueryDescriptor(queryModifiers.isDistinct(), function, queryModifiers.getLimit(), pageExtractor, sortExtractor, branches, configuration, repositoryMetadata); } MethodQueryDescriptionExtractor(OperatorContext operatorContext); @Override QueryDescriptor extract(RepositoryMetadata repositoryMetadata, RepositoryFactoryConfiguration configuration,
                                   Method method); OperatorContext getOperatorContext();  }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Malformed query method name.*") public void testMethodNameNotStartingWithNormalWord() throws Exception { configuration = new DefaultRepositoryFactoryConfiguration(); extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("Malformed")); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: There is already a limit of 5 specified for this query:.*") public void testMultipleLimitsUsingFirst() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findFirst5First10")); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: There is already a limit of 1 specified for this query:.*") public void testMultipleLimitsUsingFirstOne() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findFirstFirst10")); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: There is already a limit of 10 specified for this query:.*") public void testMultipleLimits() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findTop10Top5")); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: You have already stated that this query should return distinct " + "items:.*") public void testMultipleDistinctFlags() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findDistinctDistinct")); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Query method name cannot end with `By`") public void testNonSimpleQueryEndingInBy() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findTop10DistinctBy")); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Could not find property `unknownProperty`.*") public void testUnknownPropertyInExpression() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findByUnknownProperty")); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Expected to see parameter with index 0") public void testTooFewParameterNumber() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findByFirstName")); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Expected more tokens to follow AND/OR operator") public void testTooFewExpressionEndingInOr() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findByFirstNameOr", String.class)); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Expected more tokens to follow AND/OR operator") public void testTooFewExpressionEndingInAnd() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findByFirstNameOr", String.class)); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*: Invalid parameter types for operator IS on property firstName: \\[class java\\.lang\\.Object]") public void testBadParameterType() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findByFirstName", Object.class)); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Invalid last argument: expected paging or sorting.*?") public void testBadLastParameter() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findByFirstName", String.class, Object.class)); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Too many parameters.*?") public void testTooManyParameters() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class .getMethod("findByFirstName", String.class, Object.class, Object.class)); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Could not find property `firstNameOrderBy` on `class com.mmnaseri" + ".utils.spring.data.sample.models.Person`") public void testWithTrailingOrderBy() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findByFirstNameOrderBy", String.class)); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Failed to get a property descriptor for expression: Xyz") public void testWithOrderByInvalidProperty() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findByFirstNameOrderByXyzDesc", String.class)); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: You cannot specify both an order-by clause and a dynamic ordering") public void testWithMultipleOrders() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class .getMethod("findByFirstNameOrderByFirstNameAsc", String.class, org.springframework.data.domain.Sort.class)); }
@Test(expectedExceptions = QueryParserException.class, expectedExceptionsMessageRegExp = ".*?: Sort property `address` is not comparable in " + "`findByFirstNameOrderByAddressAsc`") public void testWithOrderByNonComparableProperty() throws Exception { extractor.extract(malformedRepositoryMetadata, configuration, MalformedRepository.class.getMethod("findByFirstNameOrderByAddressAsc", String.class)); }
@Test public void testReadMethodWithoutAnyCriteria() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class.getMethod("find")); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getConfiguration(), is(configuration)); assertThat(descriptor.getFunction(), is(nullValue())); assertThat(descriptor.getLimit(), is(0)); assertThat(descriptor.getRepositoryMetadata(), is(sampleRepositoryMetadata)); assertThat(descriptor.getBranches(), is(empty())); }
@Test public void testCustomFunctionWithoutAnyCriteria() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class.getMethod("test")); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getConfiguration(), is(configuration)); assertThat(descriptor.getFunction(), is("test")); assertThat(descriptor.getLimit(), is(0)); assertThat(descriptor.getRepositoryMetadata(), is(sampleRepositoryMetadata)); assertThat(descriptor.getBranches(), is(empty())); }
@Test public void testQueryMethodWithSingleBranch() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class .getMethod("findByFirstNameAndLastNameEquals", String.class, String.class)); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getConfiguration(), is(configuration)); assertThat(descriptor.getFunction(), is(nullValue())); assertThat(descriptor.getLimit(), is(0)); assertThat(descriptor.getRepositoryMetadata(), is(sampleRepositoryMetadata)); assertThat(descriptor.getBranches(), hasSize(1)); final List<Parameter> parameters = descriptor.getBranches().get(0); assertThat(parameters, hasSize(2)); assertThat(parameters.get(0).getIndices().length, is(1)); assertThat(parameters.get(0).getIndices()[0], is(0)); assertThat(parameters.get(0).getModifiers(), is(empty())); assertThat(parameters.get(0).getPath(), is("firstName")); assertThat(parameters.get(0).getOperator().getName(), is("IS")); assertThat(parameters.get(1).getIndices().length, is(1)); assertThat(parameters.get(1).getIndices()[0], is(1)); assertThat(parameters.get(1).getModifiers(), is(empty())); assertThat(parameters.get(1).getPath(), is("lastName")); assertThat(parameters.get(1).getOperator().getName(), is("IS")); }
@Test public void testModifierOnSingleParameter() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class .getMethod("findByFirstNameAndLastNameIgnoreCase", String.class, String.class)); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getConfiguration(), is(configuration)); assertThat(descriptor.getFunction(), is(nullValue())); assertThat(descriptor.getLimit(), is(0)); assertThat(descriptor.getRepositoryMetadata(), is(sampleRepositoryMetadata)); assertThat(descriptor.getBranches(), hasSize(1)); final List<Parameter> parameters = descriptor.getBranches().get(0); assertThat(parameters, hasSize(2)); assertThat(parameters.get(0).getIndices().length, is(1)); assertThat(parameters.get(0).getIndices()[0], is(0)); assertThat(parameters.get(0).getModifiers(), is(empty())); assertThat(parameters.get(0).getPath(), is("firstName")); assertThat(parameters.get(0).getOperator().getName(), is("IS")); assertThat(parameters.get(1).getIndices().length, is(1)); assertThat(parameters.get(1).getIndices()[0], is(1)); assertThat(parameters.get(1).getModifiers(), is(not(empty()))); assertThat(parameters.get(1).getModifiers(), contains(Modifier.IGNORE_CASE)); assertThat(parameters.get(1).getPath(), is("lastName")); assertThat(parameters.get(1).getOperator().getName(), is("IS")); }
@Test public void testWithOrderBy() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class.getMethod( "findByFirstNameOrderByLastNameDescAgeAsc", String.class)); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getBranches(), hasSize(1)); assertThat(descriptor.getBranches().get(0), hasSize(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices().length, is(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices()[0], is(0)); assertThat(descriptor.getBranches().get(0).get(0).getModifiers(), is(empty())); assertThat(descriptor.getBranches().get(0).get(0).getOperator().getName(), is("IS")); assertThat(descriptor.getBranches().get(0).get(0).getPath(), is("firstName")); assertThat(descriptor.getFunction(), is(nullValue())); assertThat(descriptor.getLimit(), is(0)); final Sort sort = descriptor.getSort(new ImmutableInvocation(null, new Object[0])); assertThat(sort.getOrders(), hasSize(2)); assertThat(sort.getOrders().get(0).getDirection(), is(SortDirection.DESCENDING)); assertThat(sort.getOrders().get(0).getProperty(), is("lastName")); assertThat(sort.getOrders().get(1).getDirection(), is(SortDirection.ASCENDING)); assertThat(sort.getOrders().get(1).getProperty(), is("age")); }
@Test public void testWithMultipleBranches() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class .getMethod("findByFirstNameOrLastName", String.class, String.class)); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getBranches(), hasSize(2)); assertThat(descriptor.getBranches().get(0), hasSize(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices().length, is(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices()[0], is(0)); assertThat(descriptor.getBranches().get(0).get(0).getModifiers(), is(empty())); assertThat(descriptor.getBranches().get(0).get(0).getOperator().getName(), is("IS")); assertThat(descriptor.getBranches().get(0).get(0).getPath(), is("firstName")); assertThat(descriptor.getBranches().get(1), hasSize(1)); assertThat(descriptor.getBranches().get(1).get(0).getIndices().length, is(1)); assertThat(descriptor.getBranches().get(1).get(0).getIndices()[0], is(1)); assertThat(descriptor.getBranches().get(1).get(0).getModifiers(), is(empty())); assertThat(descriptor.getBranches().get(1).get(0).getOperator().getName(), is("IS")); assertThat(descriptor.getBranches().get(1).get(0).getPath(), is("lastName")); assertThat(descriptor.getFunction(), is(nullValue())); assertThat(descriptor.getLimit(), is(0)); }
@Test public void testWithStaticSortingAndDynamicPaging() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class .getMethod("findByFirstNameOrderByLastNameDesc", String.class, Pageable.class)); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getBranches(), hasSize(1)); assertThat(descriptor.getBranches().get(0), hasSize(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices().length, is(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices()[0], is(0)); assertThat(descriptor.getBranches().get(0).get(0).getModifiers(), is(empty())); assertThat(descriptor.getBranches().get(0).get(0).getOperator().getName(), is("IS")); assertThat(descriptor.getBranches().get(0).get(0).getPath(), is("firstName")); assertThat(descriptor.getFunction(), is(nullValue())); assertThat(descriptor.getLimit(), is(0)); final List<Order> orders = descriptor.getSort(new ImmutableInvocation(null, null)).getOrders(); assertThat(orders, hasSize(1)); assertThat(orders.get(0).getProperty(), is("lastName")); assertThat(orders.get(0).getDirection(), is(SortDirection.DESCENDING)); final Page page = descriptor.getPage(new ImmutableInvocation(null, new Object[]{null, PageRequest.of(0, 1)})); assertThat(page, is(notNullValue())); assertThat(page.getPageSize(), is(1)); assertThat(page.getPageNumber(), is(0)); }
@Test public void testWithDynamicSortingAndDynamicPaging() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class .getMethod("findByFirstName", String.class, Pageable.class)); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getBranches(), hasSize(1)); assertThat(descriptor.getBranches().get(0), hasSize(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices().length, is(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices()[0], is(0)); assertThat(descriptor.getBranches().get(0).get(0).getModifiers(), is(empty())); assertThat(descriptor.getBranches().get(0).get(0).getOperator().getName(), is("IS")); assertThat(descriptor.getBranches().get(0).get(0).getPath(), is("firstName")); assertThat(descriptor.getFunction(), is(nullValue())); assertThat(descriptor.getLimit(), is(0)); final ImmutableInvocation invocation = new ImmutableInvocation(null, new Object[]{null, PageRequest.of(0, 1, org.springframework.data.domain.Sort .by(org.springframework.data.domain.Sort.Direction.ASC, "firstName", "lastName"))}); final List<Order> orders = descriptor.getSort(invocation).getOrders(); assertThat(orders, hasSize(2)); assertThat(orders.get(0).getProperty(), is("firstName")); assertThat(orders.get(0).getDirection(), is(SortDirection.ASCENDING)); assertThat(orders.get(1).getProperty(), is("lastName")); assertThat(orders.get(1).getDirection(), is(SortDirection.ASCENDING)); final Page page = descriptor.getPage(invocation); assertThat(page, is(notNullValue())); assertThat(page.getPageSize(), is(1)); assertThat(page.getPageNumber(), is(0)); }
@Test public void testWithDynamicSortAndNoPaging() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class .getMethod("findByFirstName", String.class, org.springframework.data.domain.Sort.class)); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getBranches(), hasSize(1)); assertThat(descriptor.getBranches().get(0), hasSize(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices().length, is(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices()[0], is(0)); assertThat(descriptor.getBranches().get(0).get(0).getModifiers(), is(empty())); assertThat(descriptor.getBranches().get(0).get(0).getOperator().getName(), is("IS")); assertThat(descriptor.getBranches().get(0).get(0).getPath(), is("firstName")); assertThat(descriptor.getFunction(), is(nullValue())); assertThat(descriptor.getLimit(), is(0)); final ImmutableInvocation invocation = new ImmutableInvocation(null, new Object[]{null, org.springframework.data.domain.Sort.by( org.springframework.data.domain.Sort.Direction.ASC, "firstName", "lastName")}); final List<Order> orders = descriptor.getSort(invocation).getOrders(); assertThat(orders, hasSize(2)); assertThat(orders.get(0).getProperty(), is("firstName")); assertThat(orders.get(0).getDirection(), is(SortDirection.ASCENDING)); assertThat(orders.get(1).getProperty(), is("lastName")); assertThat(orders.get(1).getDirection(), is(SortDirection.ASCENDING)); final Page page = descriptor.getPage(invocation); assertThat(page, is(nullValue())); }
@Test public void testAllIgnoreCase() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class.getMethod( "findByFirstNameAndLastNameAllIgnoreCase", String.class, String.class)); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getBranches(), hasSize(1)); assertThat(descriptor.getBranches().get(0), hasSize(2)); assertThat(descriptor.getBranches().get(0).get(0).getIndices().length, is(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices()[0], is(0)); assertThat(descriptor.getBranches().get(0).get(0).getModifiers(), contains(Modifier.IGNORE_CASE)); assertThat(descriptor.getBranches().get(0).get(0).getOperator().getName(), is("IS")); assertThat(descriptor.getBranches().get(0).get(0).getPath(), is("firstName")); assertThat(descriptor.getBranches().get(0).get(1).getIndices().length, is(1)); assertThat(descriptor.getBranches().get(0).get(1).getIndices()[0], is(1)); assertThat(descriptor.getBranches().get(0).get(1).getModifiers(), contains(Modifier.IGNORE_CASE)); assertThat(descriptor.getBranches().get(0).get(1).getOperator().getName(), is("IS")); assertThat(descriptor.getBranches().get(0).get(1).getPath(), is("lastName")); assertThat(descriptor.getFunction(), is(nullValue())); assertThat(descriptor.getLimit(), is(0)); }
@Test public void testFunction() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class .getMethod("functionNameByFirstName", String.class)); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getBranches(), hasSize(1)); assertThat(descriptor.getBranches().get(0), hasSize(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices().length, is(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices()[0], is(0)); assertThat(descriptor.getBranches().get(0).get(0).getModifiers(), is(empty())); assertThat(descriptor.getBranches().get(0).get(0).getOperator().getName(), is("IS")); assertThat(descriptor.getBranches().get(0).get(0).getPath(), is("firstName")); assertThat(descriptor.getFunction(), is("function")); assertThat(descriptor.getLimit(), is(0)); }
@Test public void testInOperator() throws Exception { final QueryDescriptor descriptor = extractor.extract(sampleRepositoryMetadata, configuration, RepositoryWithValidMethods.class.getMethod("findByFirstNameIn", Collection.class)); assertThat(descriptor, is(notNullValue())); assertThat(descriptor.getBranches(), hasSize(1)); assertThat(descriptor.getBranches().get(0), hasSize(1)); assertThat(descriptor.getBranches().get(0).get(0).getIndices().length, is(1)); assertThat(descriptor.getBranches().get(0).get(0).getOperator().getName(), is("IN")); assertThat(descriptor.getBranches().get(0).get(0).getPath(), is("firstName")); }