DATACMNS-10 - Introduce method name parser to build criteria based queries.

Minor tweaks to Parameter and Parameters to remove some JPA implications (1-based position indexes). Introduced PartTree abstraction that results from query parsing and allows simple API to traverse the query parts. Added AbstractQueryCreator to implement general traversing logic on PartTree and provide typed callback hooks for persistence technology specific creation of a criteria query.
This commit is contained in:
Oliver Gierke
2010-12-02 18:55:55 +01:00
parent e82b896fa9
commit 4bd005d17b
10 changed files with 780 additions and 11 deletions

View File

@@ -103,8 +103,8 @@ public class ParametersUnitTests {
Parameters parameters = new Parameters(method);
assertThat(parameters.getParameter(0).getParameterPosition(), is(0));
assertThat(parameters.getParameter(1).getParameterPosition(), is(1));
assertThat(parameters.getParameter(0).getParameterIndex(), is(-1));
assertThat(parameters.getParameter(1).getParameterIndex(), is(0));
method =
SampleDao.class.getMethod("validWithSortInBetween",
@@ -112,9 +112,9 @@ public class ParametersUnitTests {
parameters = new Parameters(method);
assertThat(parameters.getParameter(0).getParameterPosition(), is(1));
assertThat(parameters.getParameter(1).getParameterPosition(), is(0));
assertThat(parameters.getParameter(2).getParameterPosition(), is(2));
assertThat(parameters.getParameter(0).getParameterIndex(), is(0));
assertThat(parameters.getParameter(1).getParameterIndex(), is(-1));
assertThat(parameters.getParameter(2).getParameterIndex(), is(1));
}

View File

@@ -0,0 +1,143 @@
/*
* Copyright 2008-2010 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.repository.query;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
/**
* Unit tests for {@link SimpleParameterAccessor}.
*
* @author Oliver Gierke
*/
public class SimpleParameterAccessorUnitTests {
Parameters parameters, sortParameters, pageableParameters;
@Before
public void setUp() throws SecurityException, NoSuchMethodException {
parameters =
new Parameters(Sample.class.getMethod("sample", String.class));
sortParameters =
new Parameters(Sample.class.getMethod("sample1", String.class,
Sort.class));
pageableParameters =
new Parameters(Sample.class.getMethod("sample2", String.class,
Pageable.class));
}
@Test
public void testname() throws Exception {
new SimpleParameterAccessor(parameters, new Object[] { "test" });
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullParameters() throws Exception {
new SimpleParameterAccessor(null, new Object[0]);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullValues() throws Exception {
new SimpleParameterAccessor(parameters, null);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsTooLittleNumberOfArguments() throws Exception {
new SimpleParameterAccessor(parameters, new Object[0]);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsTooManyArguments() throws Exception {
new SimpleParameterAccessor(parameters, new Object[] { "test", "test" });
}
@Test
public void returnsNullForPageableAndSortIfNoneAvailable() throws Exception {
SimpleParameterAccessor accessor =
new SimpleParameterAccessor(parameters, new Object[] { "test" });
assertThat(accessor.getPageable(), is(nullValue()));
assertThat(accessor.getSort(), is(nullValue()));
}
@Test
public void returnsSortIfAvailable() {
Sort sort = new Sort("foo");
SimpleParameterAccessor accessor =
new SimpleParameterAccessor(sortParameters, new Object[] {
"test", sort });
assertThat(accessor.getSort(), is(sort));
assertThat(accessor.getPageable(), is(nullValue()));
}
@Test
public void returnsPageableIfAvailable() {
Pageable pageable = new PageRequest(0, 10);
SimpleParameterAccessor accessor =
new SimpleParameterAccessor(pageableParameters, new Object[] {
"test", pageable });
assertThat(accessor.getPageable(), is(pageable));
assertThat(accessor.getSort(), is(nullValue()));
}
@Test
public void returnsSortFromPageableIfAvailable() throws Exception {
Sort sort = new Sort("foo");
Pageable pageable = new PageRequest(0, 10, sort);
SimpleParameterAccessor accessor =
new SimpleParameterAccessor(pageableParameters, new Object[] {
"test", pageable });
assertThat(accessor.getPageable(), is(pageable));
assertThat(accessor.getSort(), is(sort));
}
interface Sample {
void sample(String firstname);
void sample1(String firstname, Sort sort);
void sample2(String firstname, Pageable pageable);
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2008-2010 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.repository.query.parser;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.Iterator;
import org.junit.Test;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.repository.query.parser.PartTree.OrPart;
/**
* Unit tests for {@link PartTree}.
*
* @author Oliver Gierke
*/
public class PartTreeUnitTests {
@Test(expected = IllegalArgumentException.class)
public void rejectsNullSource() throws Exception {
new PartTree(null, getClass());
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullDomainClass() throws Exception {
new PartTree("test", null);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsMultipleOrderBy() throws Exception {
new PartTree("firstnameOrderByLastnameOrderByFirstname", User.class);
}
@Test
public void parsesSimplePropertyCorrectly() throws Exception {
PartTree partTree = new PartTree("firstname", User.class);
assertPart(partTree, new Part[] { new Part("firstname", User.class) });
}
@Test
public void parsesAndPropertiesCorrectly() throws Exception {
PartTree partTree = new PartTree("firstnameAndLastname", User.class);
assertPart(partTree, new Part[] { new Part("firstname", User.class),
new Part("lastname", User.class) });
assertThat(partTree.getSort(), is(nullValue()));
}
@Test
public void parsesOrPropertiesCorrectly() throws Exception {
PartTree partTree = new PartTree("firstnameOrLastname", User.class);
assertPart(partTree, new Part[] { new Part("firstname", User.class) },
new Part[] { new Part("lastname", User.class) });
assertThat(partTree.getSort(), is(nullValue()));
}
@Test
public void hasSortIfOrderByIsGiven() throws Exception {
PartTree partTree =
new PartTree("firstnameOrderByLastnameDesc", User.class);
assertThat(partTree.getSort(), is(new Sort(Direction.DESC, "lastname")));
}
private void assertPart(PartTree tree, Part[]... parts) {
Iterator<OrPart> iterator = tree.iterator();
for (Part[] part : parts) {
assertThat(iterator.hasNext(), is(true));
Iterator<Part> partIterator = iterator.next().iterator();
for (int k = 0; k < part.length; k++) {
assertThat(String.format("Expected %d parts but have %d",
part.length, k + 1), partIterator.hasNext(), is(true));
Part next = partIterator.next();
assertThat(
String.format("Expected %s but got %s!", part[k], next),
part[k], is(next));
}
assertThat("Too many parts!", partIterator.hasNext(), is(false));
}
assertThat("Too many or parts!", iterator.hasNext(), is(false));
}
class User {
String firstname;
String lastname;
}
}