DATAKV-85 - Ported key-value infrastructure from Spring Data Commons.
This commit is contained in:
104
src/test/java/org/springframework/data/keyvalue/Person.java
Normal file
104
src/test/java/org/springframework/data/keyvalue/Person.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2014 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.keyvalue;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.mysema.query.annotations.QueryEntity;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@QueryEntity
|
||||
public class Person implements Serializable {
|
||||
|
||||
private @Id String id;
|
||||
private String firstname;
|
||||
private int age;
|
||||
|
||||
public Person(String firstname, int age) {
|
||||
super();
|
||||
this.firstname = firstname;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public void setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Person [id=" + id + ", firstname=" + firstname + ", age=" + age + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + age;
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.firstname);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.id);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Person)) {
|
||||
return false;
|
||||
}
|
||||
Person other = (Person) obj;
|
||||
if (!ObjectUtils.nullSafeEquals(this.id, other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(this.firstname, other.firstname)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(this.age, other.age)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2014 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.keyvalue.core;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.keyvalue.core.KeySpaceUtils.*;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.keyvalue.annotation.KeySpace;
|
||||
import org.springframework.data.keyvalue.core.KeyValueTemplateUnitTests.AliasedEntity;
|
||||
import org.springframework.data.keyvalue.core.KeyValueTemplateUnitTests.ClassWithDirectKeySpaceAnnotation;
|
||||
import org.springframework.data.keyvalue.core.KeyValueTemplateUnitTests.EntityWithPersistentAnnotation;
|
||||
import org.springframework.data.keyvalue.core.KeyValueTemplateUnitTests.Foo;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link KeySpaceUtils}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class KeySpaceUtilsUnitTests {
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldResolveKeySpaceDefaultValueCorrectly() {
|
||||
assertThat(getKeySpace(EntityWithDefaultKeySpace.class), is((Object) "daenerys"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldResolveKeySpaceCorrectly() {
|
||||
assertThat(getKeySpace(EntityWithSetKeySpace.class), is((Object) "viserys"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldReturnNullWhenNoKeySpaceFoundOnComposedPersistentAnnotation() {
|
||||
assertThat(getKeySpace(AliasedEntity.class), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldReturnNullWhenPersistentIsFoundOnNonComposedAnnotation() {
|
||||
assertThat(getKeySpace(EntityWithPersistentAnnotation.class), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldReturnNullWhenPersistentIsNotFound() {
|
||||
assertThat(getKeySpace(Foo.class), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldResolveInheritedKeySpaceCorrectly() {
|
||||
assertThat(getKeySpace(EntityWithInheritedKeySpace.class), is((Object) "viserys"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldResolveDirectKeySpaceAnnotationCorrectly() {
|
||||
assertThat(getKeySpace(ClassWithDirectKeySpaceAnnotation.class), is((Object) "rhaegar"));
|
||||
}
|
||||
|
||||
@PersistentAnnotationWithExplicitKeySpace
|
||||
static class EntityWithDefaultKeySpace {
|
||||
|
||||
}
|
||||
|
||||
@PersistentAnnotationWithExplicitKeySpace(firstname = "viserys")
|
||||
static class EntityWithSetKeySpace {
|
||||
|
||||
}
|
||||
|
||||
static class EntityWithInheritedKeySpace extends EntityWithSetKeySpace {
|
||||
|
||||
}
|
||||
|
||||
@Persistent
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
static @interface PersistentAnnotationWithExplicitKeySpace {
|
||||
|
||||
@KeySpace
|
||||
String firstname() default "daenerys";
|
||||
|
||||
String lastnamne() default "targaryen";
|
||||
}
|
||||
|
||||
@Persistent
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
static @interface ExplicitKeySpace {
|
||||
|
||||
@KeySpace
|
||||
String name() default "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2014 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.keyvalue.core;
|
||||
|
||||
import static org.hamcrest.core.IsInstanceOf.*;
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class KeyValuePersistenceExceptionTranslatorUnitTests {
|
||||
|
||||
KeyValuePersistenceExceptionTranslator translator = new KeyValuePersistenceExceptionTranslator();
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void translateExeptionShouldReturnDataAccessExceptionWhenGivenOne() {
|
||||
assertThat(translator.translateExceptionIfPossible(new DataRetrievalFailureException("booh")),
|
||||
instanceOf(DataRetrievalFailureException.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void translateExeptionShouldReturnNullWhenGivenNull() {
|
||||
assertThat(translator.translateExceptionIfPossible(null), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void translateExeptionShouldTranslateNoSuchElementExceptionToDataRetrievalFailureException() {
|
||||
assertThat(translator.translateExceptionIfPossible(new NoSuchElementException("")),
|
||||
instanceOf(DataRetrievalFailureException.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void translateExeptionShouldTranslateIndexOutOfBoundsExceptionToDataRetrievalFailureException() {
|
||||
assertThat(translator.translateExceptionIfPossible(new IndexOutOfBoundsException("")),
|
||||
instanceOf(DataRetrievalFailureException.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void translateExeptionShouldTranslateIllegalStateExceptionToDataRetrievalFailureException() {
|
||||
assertThat(translator.translateExceptionIfPossible(new IllegalStateException("")),
|
||||
instanceOf(DataRetrievalFailureException.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void translateExeptionShouldTranslateAnyJavaExceptionToUncategorizedKeyValueException() {
|
||||
assertThat(translator.translateExceptionIfPossible(new UnsupportedOperationException("")),
|
||||
instanceOf(UncategorizedKeyValueException.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void translateExeptionShouldReturnNullForNonJavaExceptions() {
|
||||
assertThat(translator.translateExceptionIfPossible(new NoSuchBeanDefinitionException("")), nullValue());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* Copyright 2014 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.keyvalue.core;
|
||||
|
||||
import static org.hamcrest.collection.IsCollectionWithSize.*;
|
||||
import static org.hamcrest.collection.IsEmptyCollection.*;
|
||||
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.*;
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.hamcrest.core.IsSame.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.keyvalue.annotation.KeySpace;
|
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.data.map.MapKeyValueAdapter;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class KeyValueTemplateTests {
|
||||
|
||||
static final Foo FOO_ONE = new Foo("one");
|
||||
static final Foo FOO_TWO = new Foo("two");
|
||||
static final Foo FOO_THREE = new Foo("three");
|
||||
static final Bar BAR_ONE = new Bar("one");
|
||||
static final ClassWithTypeAlias ALIASED = new ClassWithTypeAlias("super");
|
||||
static final SubclassOfAliasedType SUBCLASS_OF_ALIASED = new SubclassOfAliasedType("sub");
|
||||
static final KeyValueQuery<String> STRING_QUERY = new KeyValueQuery<String>("foo == 'two'");
|
||||
|
||||
KeyValueTemplate operations;
|
||||
|
||||
@Before
|
||||
public void setUp() throws InstantiationException, IllegalAccessException {
|
||||
this.operations = new KeyValueTemplate(new MapKeyValueAdapter());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
this.operations.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldNotThorwErrorWhenExecutedHavingNonExistingIdAndNonNullValue() {
|
||||
operations.insert("1", FOO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void insertShouldThrowExceptionForNullId() {
|
||||
operations.insert(null, FOO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void insertShouldThrowExceptionForNullObject() {
|
||||
operations.insert("some-id", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class)
|
||||
public void insertShouldThrowExecptionWhenObjectOfSameTypeAlreadyExists() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
operations.insert("1", FOO_TWO);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldWorkCorrectlyWhenObjectsOfDifferentTypesWithSameIdAreInserted() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
operations.insert("1", BAR_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void createShouldReturnSameInstanceGenerateId() {
|
||||
|
||||
ClassWithStringId source = new ClassWithStringId();
|
||||
ClassWithStringId target = operations.insert(source);
|
||||
|
||||
assertThat(target, sameInstance(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void createShouldRespectExistingId() {
|
||||
|
||||
ClassWithStringId source = new ClassWithStringId();
|
||||
source.id = "one";
|
||||
|
||||
operations.insert(source);
|
||||
|
||||
assertThat(operations.findById("one", ClassWithStringId.class), is(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findByIdShouldReturnObjectWithMatchingIdAndType() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
assertThat(operations.findById("1", Foo.class), is(FOO_ONE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findByIdSouldReturnNullIfNoMatchingIdFound() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
assertThat(operations.findById("2", Foo.class), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findByIdShouldReturnNullIfNoMatchingTypeFound() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
assertThat(operations.findById("1", Bar.class), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findShouldExecuteQueryCorrectly() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
operations.insert("2", FOO_TWO);
|
||||
|
||||
List<Foo> result = (List<Foo>) operations.find(STRING_QUERY, Foo.class);
|
||||
assertThat(result, hasSize(1));
|
||||
assertThat(result.get(0), is(FOO_TWO));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void readShouldReturnEmptyCollectionIfOffsetOutOfRange() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
operations.insert("2", FOO_TWO);
|
||||
operations.insert("3", FOO_THREE);
|
||||
|
||||
assertThat(operations.findInRange(5, 5, Foo.class), empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void updateShouldReplaceExistingObject() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
operations.update("1", FOO_TWO);
|
||||
assertThat(operations.findById("1", Foo.class), is(FOO_TWO));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void updateShouldRespectTypeInformation() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
operations.update("1", BAR_ONE);
|
||||
|
||||
assertThat(operations.findById("1", Foo.class), is(FOO_ONE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void deleteShouldRemoveObjectCorrectly() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
operations.delete("1", Foo.class);
|
||||
assertThat(operations.findById("1", Foo.class), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void deleteReturnsNullWhenNotExisting() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
assertThat(operations.delete("2", Foo.class), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void deleteReturnsRemovedObject() {
|
||||
|
||||
operations.insert("1", FOO_ONE);
|
||||
assertThat(operations.delete("1", Foo.class), is(FOO_ONE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void deleteThrowsExceptionWhenIdCannotBeExctracted() {
|
||||
operations.delete(FOO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void countShouldReturnZeroWhenNoElementsPresent() {
|
||||
assertThat(operations.count(Foo.class), is(0L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldRespectTypeAlias() {
|
||||
|
||||
operations.insert("1", ALIASED);
|
||||
operations.insert("2", SUBCLASS_OF_ALIASED);
|
||||
|
||||
assertThat(operations.findAll(ALIASED.getClass()), containsInAnyOrder(ALIASED, SUBCLASS_OF_ALIASED));
|
||||
}
|
||||
|
||||
static class Foo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8912754229220128922L;
|
||||
|
||||
String foo;
|
||||
|
||||
public Foo(String foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
public String getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.foo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Foo)) {
|
||||
return false;
|
||||
}
|
||||
Foo other = (Foo) obj;
|
||||
return ObjectUtils.nullSafeEquals(this.foo, other.foo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Bar implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 196011921826060210L;
|
||||
String bar;
|
||||
|
||||
public Bar(String bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
|
||||
public String getBar() {
|
||||
return bar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.bar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Bar)) {
|
||||
return false;
|
||||
}
|
||||
Bar other = (Bar) obj;
|
||||
return ObjectUtils.nullSafeEquals(this.bar, other.bar);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ClassWithStringId implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -7481030649267602830L;
|
||||
@Id String id;
|
||||
String value;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.id);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.value);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof ClassWithStringId)) {
|
||||
return false;
|
||||
}
|
||||
ClassWithStringId other = (ClassWithStringId) obj;
|
||||
if (!ObjectUtils.nullSafeEquals(this.id, other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(this.value, other.value)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ExplicitKeySpace(name = "aliased")
|
||||
static class ClassWithTypeAlias implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5921943364908784571L;
|
||||
@Id String id;
|
||||
String name;
|
||||
|
||||
public ClassWithTypeAlias(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.id);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.name);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof ClassWithTypeAlias)) {
|
||||
return false;
|
||||
}
|
||||
ClassWithTypeAlias other = (ClassWithTypeAlias) obj;
|
||||
if (!ObjectUtils.nullSafeEquals(this.id, other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(this.name, other.name)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SubclassOfAliasedType extends ClassWithTypeAlias {
|
||||
|
||||
private static final long serialVersionUID = -468809596668871479L;
|
||||
|
||||
public SubclassOfAliasedType(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Persistent
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
static @interface ExplicitKeySpace {
|
||||
|
||||
@KeySpace
|
||||
String name() default "";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,609 @@
|
||||
/*
|
||||
* Copyright 2014 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.keyvalue.core;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.annotation.TypeAlias;
|
||||
import org.springframework.data.keyvalue.annotation.KeySpace;
|
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class KeyValueTemplateUnitTests {
|
||||
|
||||
private static final Foo FOO_ONE = new Foo("one");
|
||||
private static final Foo FOO_TWO = new Foo("two");
|
||||
private static final ClassWithTypeAlias ALIASED = new ClassWithTypeAlias("super");
|
||||
private static final SubclassOfAliasedType SUBCLASS_OF_ALIASED = new SubclassOfAliasedType("sub");
|
||||
|
||||
private static final KeyValueQuery<String> STRING_QUERY = new KeyValueQuery<String>("foo == 'two'");
|
||||
|
||||
private @Mock KeyValueAdapter adapterMock;
|
||||
private KeyValueTemplate template;
|
||||
|
||||
@Before
|
||||
public void setUp() throws InstantiationException, IllegalAccessException {
|
||||
this.template = new KeyValueTemplate(adapterMock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenCreatingNewTempateWithNullAdapter() {
|
||||
new KeyValueTemplate(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenCreatingNewTempateWithNullMappingContext() {
|
||||
new KeyValueTemplate(adapterMock, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldLookUpValuesBeforeInserting() {
|
||||
|
||||
template.insert("1", FOO_ONE);
|
||||
|
||||
verify(adapterMock, times(1)).contains("1", Foo.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldInsertUseClassNameAsDefaultKeyspace() {
|
||||
|
||||
template.insert("1", FOO_ONE);
|
||||
|
||||
verify(adapterMock, times(1)).put("1", FOO_ONE, Foo.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class)
|
||||
public void insertShouldThrowExceptionWhenObectWithIdAlreadyExists() {
|
||||
|
||||
when(adapterMock.contains(anyString(), anyString())).thenReturn(true);
|
||||
|
||||
template.insert("1", FOO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void insertShouldThrowExceptionForNullId() {
|
||||
template.insert(null, FOO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void insertShouldThrowExceptionForNullObject() {
|
||||
template.insert("some-id", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldGenerateId() {
|
||||
|
||||
ClassWithStringId target = template.insert(new ClassWithStringId());
|
||||
|
||||
assertThat(target.id, notNullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void insertShouldThrowErrorWhenIdCannotBeResolved() {
|
||||
template.insert(FOO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldReturnSameInstanceGenerateId() {
|
||||
|
||||
ClassWithStringId source = new ClassWithStringId();
|
||||
ClassWithStringId target = template.insert(source);
|
||||
|
||||
assertThat(target, sameInstance(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldRespectExistingId() {
|
||||
|
||||
ClassWithStringId source = new ClassWithStringId();
|
||||
source.id = "one";
|
||||
|
||||
template.insert(source);
|
||||
|
||||
verify(adapterMock, times(1)).put("one", source, ClassWithStringId.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findByIdShouldReturnNullWhenNoElementsPresent() {
|
||||
assertNull(template.findById("1", Foo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findByIdShouldReturnObjectWithMatchingIdAndType() {
|
||||
|
||||
template.findById("1", Foo.class);
|
||||
|
||||
verify(adapterMock, times(1)).get("1", Foo.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void findByIdShouldThrowExceptionWhenGivenNullId() {
|
||||
template.findById((Serializable) null, Foo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findAllOfShouldReturnEntireCollection() {
|
||||
|
||||
template.findAll(Foo.class);
|
||||
|
||||
verify(adapterMock, times(1)).getAllOf(Foo.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void findAllOfShouldThrowExceptionWhenGivenNullType() {
|
||||
template.findAll(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findShouldCallFindOnAdapterToResolveMatching() {
|
||||
|
||||
template.find(STRING_QUERY, Foo.class);
|
||||
|
||||
verify(adapterMock, times(1)).find(STRING_QUERY, Foo.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void findInRangeShouldRespectOffset() {
|
||||
|
||||
ArgumentCaptor<KeyValueQuery> captor = ArgumentCaptor.forClass(KeyValueQuery.class);
|
||||
|
||||
template.findInRange(1, 5, Foo.class);
|
||||
|
||||
verify(adapterMock, times(1)).find(captor.capture(), eq(Foo.class.getName()));
|
||||
assertThat(captor.getValue().getOffset(), is(1));
|
||||
assertThat(captor.getValue().getRows(), is(5));
|
||||
assertThat(captor.getValue().getCritieria(), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void updateShouldReplaceExistingObject() {
|
||||
|
||||
template.update("1", FOO_TWO);
|
||||
|
||||
verify(adapterMock, times(1)).put("1", FOO_TWO, Foo.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void updateShouldThrowExceptionWhenGivenNullId() {
|
||||
template.update(null, FOO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void updateShouldThrowExceptionWhenGivenNullObject() {
|
||||
template.update("1", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void updateShouldUseExtractedIdInformation() {
|
||||
|
||||
ClassWithStringId source = new ClassWithStringId();
|
||||
source.id = "some-id";
|
||||
|
||||
template.update(source);
|
||||
|
||||
verify(adapterMock, times(1)).put(source.id, source, ClassWithStringId.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class)
|
||||
public void updateShouldThrowErrorWhenIdInformationCannotBeExtracted() {
|
||||
template.update(FOO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void deleteShouldRemoveObjectCorrectly() {
|
||||
|
||||
template.delete("1", Foo.class);
|
||||
|
||||
verify(adapterMock, times(1)).delete("1", Foo.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void deleteRemovesObjectUsingExtractedId() {
|
||||
|
||||
ClassWithStringId source = new ClassWithStringId();
|
||||
source.id = "some-id";
|
||||
|
||||
template.delete(source);
|
||||
|
||||
verify(adapterMock, times(1)).delete("some-id", ClassWithStringId.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void deleteThrowsExceptionWhenIdCannotBeExctracted() {
|
||||
template.delete(FOO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void countShouldReturnZeroWhenNoElementsPresent() {
|
||||
template.count(Foo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void countShouldReturnCollectionSize() {
|
||||
|
||||
Collection foo = Arrays.asList(FOO_ONE, FOO_ONE);
|
||||
when(adapterMock.getAllOf(Foo.class.getName())).thenReturn(foo);
|
||||
|
||||
assertThat(template.count(Foo.class), is(2L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void countShouldThrowErrorOnNullType() {
|
||||
template.count(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldRespectTypeAlias() {
|
||||
|
||||
template.insert("1", ALIASED);
|
||||
|
||||
verify(adapterMock, times(1)).put("1", ALIASED, "aliased");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldRespectTypeAliasOnSubClass() {
|
||||
|
||||
template.insert("1", SUBCLASS_OF_ALIASED);
|
||||
|
||||
verify(adapterMock, times(1)).put("1", SUBCLASS_OF_ALIASED, "aliased");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Test
|
||||
public void findAllOfShouldRespectTypeAliasAndFilterNonMatchingTypes() {
|
||||
|
||||
Collection foo = Arrays.asList(ALIASED, SUBCLASS_OF_ALIASED);
|
||||
when(adapterMock.getAllOf("aliased")).thenReturn(foo);
|
||||
|
||||
assertThat(template.findAll(SUBCLASS_OF_ALIASED.getClass()), containsInAnyOrder(SUBCLASS_OF_ALIASED));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void insertSouldRespectTypeAliasAndFilterNonMatching() {
|
||||
|
||||
template.insert("1", ALIASED);
|
||||
assertThat(template.findById("1", SUBCLASS_OF_ALIASED.getClass()), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setttingNullPersistenceExceptionTranslatorShouldThrowException() {
|
||||
template.setExceptionTranslator(null);
|
||||
}
|
||||
|
||||
static class Foo {
|
||||
|
||||
String foo;
|
||||
|
||||
public Foo(String foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
public String getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.foo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Foo)) {
|
||||
return false;
|
||||
}
|
||||
Foo other = (Foo) obj;
|
||||
return ObjectUtils.nullSafeEquals(this.foo, other.foo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Bar {
|
||||
|
||||
String bar;
|
||||
|
||||
public Bar(String bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
|
||||
public String getBar() {
|
||||
return bar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.bar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Bar)) {
|
||||
return false;
|
||||
}
|
||||
Bar other = (Bar) obj;
|
||||
return ObjectUtils.nullSafeEquals(this.bar, other.bar);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ClassWithStringId {
|
||||
|
||||
@Id String id;
|
||||
String value;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.id);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.value);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof ClassWithStringId)) {
|
||||
return false;
|
||||
}
|
||||
ClassWithStringId other = (ClassWithStringId) obj;
|
||||
if (!ObjectUtils.nullSafeEquals(this.id, other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(this.value, other.value)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ExplicitKeySpace(name = "aliased")
|
||||
static class ClassWithTypeAlias {
|
||||
|
||||
@Id String id;
|
||||
String name;
|
||||
|
||||
public ClassWithTypeAlias(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.id);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.name);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof ClassWithTypeAlias)) {
|
||||
return false;
|
||||
}
|
||||
ClassWithTypeAlias other = (ClassWithTypeAlias) obj;
|
||||
if (!ObjectUtils.nullSafeEquals(this.id, other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(this.name, other.name)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SubclassOfAliasedType extends ClassWithTypeAlias {
|
||||
|
||||
public SubclassOfAliasedType(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Persistent
|
||||
static class EntityWithPersistentAnnotation {
|
||||
|
||||
}
|
||||
|
||||
@TypeAlias("foo")
|
||||
static class AliasedEntity {
|
||||
|
||||
}
|
||||
|
||||
@KeySpace("rhaegar")
|
||||
static class ClassWithDirectKeySpaceAnnotation {
|
||||
|
||||
}
|
||||
|
||||
@Persistent
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
private static @interface ExplicitKeySpace {
|
||||
|
||||
@KeySpace
|
||||
String name() default "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright 2014 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.keyvalue.core;
|
||||
|
||||
import static java.lang.Integer.*;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.number.OrderingComparison.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SpelPropertyComparator}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SpelPropertyComperatorUnitTests {
|
||||
|
||||
private static final SpelExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
private static final SomeType ONE = new SomeType("one", Integer.valueOf(1), 1);
|
||||
private static final SomeType TWO = new SomeType("two", Integer.valueOf(2), 2);
|
||||
private static final WrapperType WRAPPER_ONE = new WrapperType("w-one", ONE);
|
||||
private static final WrapperType WRAPPER_TWO = new WrapperType("w-two", TWO);
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldCompareStringAscCorrectly() {
|
||||
|
||||
Comparator<SomeType> comparator = new SpelPropertyComparator<SomeType>("stringProperty", PARSER);
|
||||
assertThat(comparator.compare(ONE, TWO), is(ONE.getStringProperty().compareTo(TWO.getStringProperty())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldCompareStringDescCorrectly() {
|
||||
|
||||
Comparator<SomeType> comparator = new SpelPropertyComparator<SomeType>("stringProperty", PARSER).desc();
|
||||
assertThat(comparator.compare(ONE, TWO), is(TWO.getStringProperty().compareTo(ONE.getStringProperty())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldCompareIntegerAscCorrectly() {
|
||||
|
||||
Comparator<SomeType> comparator = new SpelPropertyComparator<SomeType>("integerProperty", PARSER);
|
||||
assertThat(comparator.compare(ONE, TWO), is(ONE.getIntegerProperty().compareTo(TWO.getIntegerProperty())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldCompareIntegerDescCorrectly() {
|
||||
|
||||
Comparator<SomeType> comparator = new SpelPropertyComparator<SomeType>("integerProperty", PARSER).desc();
|
||||
assertThat(comparator.compare(ONE, TWO), is(TWO.getIntegerProperty().compareTo(ONE.getIntegerProperty())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldComparePrimitiveIntegerAscCorrectly() {
|
||||
|
||||
Comparator<SomeType> comparator = new SpelPropertyComparator<SomeType>("primitiveProperty", PARSER);
|
||||
assertThat(comparator.compare(ONE, TWO),
|
||||
is(valueOf(ONE.getPrimitiveProperty()).compareTo(valueOf(TWO.getPrimitiveProperty()))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldNotFailOnNullValues() {
|
||||
|
||||
Comparator<SomeType> comparator = new SpelPropertyComparator<SomeType>("stringProperty", PARSER);
|
||||
assertThat(comparator.compare(ONE, new SomeType(null, null, 2)), is(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldComparePrimitiveIntegerDescCorrectly() {
|
||||
|
||||
Comparator<SomeType> comparator = new SpelPropertyComparator<SomeType>("primitiveProperty", PARSER).desc();
|
||||
assertThat(comparator.compare(ONE, TWO),
|
||||
is(valueOf(TWO.getPrimitiveProperty()).compareTo(valueOf(ONE.getPrimitiveProperty()))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldSortNullsFirstCorrectly() {
|
||||
Comparator<SomeType> comparator = new SpelPropertyComparator<SomeType>("stringProperty", PARSER).nullsFirst();
|
||||
assertThat(comparator.compare(ONE, new SomeType(null, null, 2)), equalTo(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldSortNullsLastCorrectly() {
|
||||
|
||||
Comparator<SomeType> comparator = new SpelPropertyComparator<SomeType>("stringProperty", PARSER).nullsLast();
|
||||
assertThat(comparator.compare(ONE, new SomeType(null, null, 2)), equalTo(-1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldCompareNestedTypesCorrectly() {
|
||||
|
||||
Comparator<WrapperType> comparator = new SpelPropertyComparator<WrapperType>("nestedType.stringProperty", PARSER);
|
||||
assertThat(comparator.compare(WRAPPER_ONE, WRAPPER_TWO), is(WRAPPER_ONE.getNestedType().getStringProperty()
|
||||
.compareTo(WRAPPER_TWO.getNestedType().getStringProperty())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldCompareNestedTypesCorrectlyWhenOneOfThemHasNullValue() {
|
||||
|
||||
SpelPropertyComparator<WrapperType> comparator = new SpelPropertyComparator<WrapperType>(
|
||||
"nestedType.stringProperty", PARSER);
|
||||
assertThat(comparator.compare(WRAPPER_ONE, new WrapperType("two", null)), is(greaterThanOrEqualTo(1)));
|
||||
}
|
||||
|
||||
static class WrapperType {
|
||||
|
||||
private String stringPropertyWrapper;
|
||||
private SomeType nestedType;
|
||||
|
||||
public WrapperType(String stringPropertyWrapper, SomeType nestedType) {
|
||||
this.stringPropertyWrapper = stringPropertyWrapper;
|
||||
this.nestedType = nestedType;
|
||||
}
|
||||
|
||||
public String getStringPropertyWrapper() {
|
||||
return stringPropertyWrapper;
|
||||
}
|
||||
|
||||
public void setStringPropertyWrapper(String stringPropertyWrapper) {
|
||||
this.stringPropertyWrapper = stringPropertyWrapper;
|
||||
}
|
||||
|
||||
public SomeType getNestedType() {
|
||||
return nestedType;
|
||||
}
|
||||
|
||||
public void setNestedType(SomeType nestedType) {
|
||||
this.nestedType = nestedType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SomeType {
|
||||
|
||||
public SomeType() {
|
||||
|
||||
}
|
||||
|
||||
public SomeType(String stringProperty, Integer integerProperty, int primitiveProperty) {
|
||||
this.stringProperty = stringProperty;
|
||||
this.integerProperty = integerProperty;
|
||||
this.primitiveProperty = primitiveProperty;
|
||||
}
|
||||
|
||||
String stringProperty;
|
||||
Integer integerProperty;
|
||||
int primitiveProperty;
|
||||
|
||||
public String getStringProperty() {
|
||||
return stringProperty;
|
||||
}
|
||||
|
||||
public void setStringProperty(String stringProperty) {
|
||||
this.stringProperty = stringProperty;
|
||||
}
|
||||
|
||||
public Integer getIntegerProperty() {
|
||||
return integerProperty;
|
||||
}
|
||||
|
||||
public void setIntegerProperty(Integer integerProperty) {
|
||||
this.integerProperty = integerProperty;
|
||||
}
|
||||
|
||||
public int getPrimitiveProperty() {
|
||||
return primitiveProperty;
|
||||
}
|
||||
|
||||
public void setPrimitiveProperty(int primitiveProperty) {
|
||||
this.primitiveProperty = primitiveProperty;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2014 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.keyvalue.repository;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.keyvalue.core.KeyValueOperations;
|
||||
import org.springframework.data.keyvalue.repository.support.SimpleKeyValueRepository;
|
||||
import org.springframework.data.repository.core.support.ReflectionEntityInformation;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SimpleKeyValueRepositoryUnitTests {
|
||||
|
||||
private SimpleKeyValueRepository<Foo, String> repo;
|
||||
private @Mock KeyValueOperations opsMock;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
ReflectionEntityInformation<Foo, String> ei = new ReflectionEntityInformation<Foo, String>(Foo.class);
|
||||
repo = new SimpleKeyValueRepository<Foo, String>(ei, opsMock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void saveNewWithNumericId() {
|
||||
|
||||
ReflectionEntityInformation<WithNumericId, Integer> ei = new ReflectionEntityInformation<WithNumericId, Integer>(
|
||||
WithNumericId.class);
|
||||
SimpleKeyValueRepository<WithNumericId, Integer> temp = new SimpleKeyValueRepository<WithNumericId, Integer>(ei,
|
||||
opsMock);
|
||||
|
||||
WithNumericId withNumericId = new WithNumericId();
|
||||
temp.save(withNumericId);
|
||||
|
||||
verify(opsMock, times(1)).insert(eq(withNumericId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void testDoubleSave() {
|
||||
|
||||
Foo foo = new Foo("one");
|
||||
|
||||
repo.save(foo);
|
||||
|
||||
foo.id = "1";
|
||||
repo.save(foo);
|
||||
verify(opsMock, times(1)).insert(eq(foo));
|
||||
verify(opsMock, times(1)).update(eq(foo.getId()), eq(foo));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void multipleSave() {
|
||||
|
||||
Foo one = new Foo("one");
|
||||
Foo two = new Foo("one");
|
||||
|
||||
repo.save(Arrays.asList(one, two));
|
||||
verify(opsMock, times(1)).insert(eq(one));
|
||||
verify(opsMock, times(1)).insert(eq(two));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void deleteEntity() {
|
||||
|
||||
Foo one = repo.save(new Foo("one"));
|
||||
repo.delete(one);
|
||||
|
||||
verify(opsMock, times(1)).delete(eq(one.getId()), eq(Foo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void deleteById() {
|
||||
|
||||
repo.delete("one");
|
||||
|
||||
verify(opsMock, times(1)).delete(eq("one"), eq(Foo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void deleteAll() {
|
||||
|
||||
repo.deleteAll();
|
||||
|
||||
verify(opsMock, times(1)).delete(eq(Foo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findAllIds() {
|
||||
|
||||
repo.findAll(Arrays.asList("one", "two", "three"));
|
||||
|
||||
verify(opsMock, times(3)).findById(anyString(), eq(Foo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findAllWithPageableShouldDelegateToOperationsCorrectlyWhenPageableDoesNotContainSort() {
|
||||
|
||||
repo.findAll(new PageRequest(10, 15));
|
||||
|
||||
verify(opsMock, times(1)).findInRange(eq(150), eq(15), isNull(Sort.class), eq(Foo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findAllWithPageableShouldDelegateToOperationsCorrectlyWhenPageableContainsSort() {
|
||||
|
||||
Sort sort = new Sort("for", "bar");
|
||||
repo.findAll(new PageRequest(10, 15, sort));
|
||||
|
||||
verify(opsMock, times(1)).findInRange(eq(150), eq(15), eq(sort), eq(Foo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findAllShouldFallbackToFindAllOfWhenGivenNullPageable() {
|
||||
|
||||
repo.findAll((Pageable) null);
|
||||
|
||||
verify(opsMock, times(1)).findAll(eq(Foo.class));
|
||||
}
|
||||
|
||||
static class Foo {
|
||||
|
||||
private @Id String id;
|
||||
private Long longValue;
|
||||
private String name;
|
||||
private Bar bar;
|
||||
|
||||
public Foo() {
|
||||
|
||||
}
|
||||
|
||||
public Foo(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getLongValue() {
|
||||
return longValue;
|
||||
}
|
||||
|
||||
public void setLongValue(Long longValue) {
|
||||
this.longValue = longValue;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Bar getBar() {
|
||||
return bar;
|
||||
}
|
||||
|
||||
public void setBar(Bar bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Bar {
|
||||
|
||||
private String bar;
|
||||
|
||||
public String getBar() {
|
||||
return bar;
|
||||
}
|
||||
|
||||
public void setBar(String bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
}
|
||||
|
||||
@Persistent
|
||||
static class WithNumericId {
|
||||
|
||||
@Id Integer id;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2014 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.keyvalue.repository.config;
|
||||
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.keyvalue.core.KeyValueOperations;
|
||||
import org.springframework.data.keyvalue.core.KeyValueTemplate;
|
||||
import org.springframework.data.map.MapKeyValueAdapter;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class KeyValueRepositoryRegistrarIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@EnableKeyValueRepositories(considerNestedRepositories = true)
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public KeyValueOperations keyValueTemplate() {
|
||||
return new KeyValueTemplate(new MapKeyValueAdapter());
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired PersonRepository repo;
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldEnableKeyValueRepositoryCorrectly() {
|
||||
assertThat(repo, notNullValue());
|
||||
}
|
||||
|
||||
static class Person {
|
||||
|
||||
@Id String id;
|
||||
String firstname;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public void setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static interface PersonRepository extends CrudRepository<Person, String> {
|
||||
|
||||
List<Person> findByFirstname(String firstname);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,566 @@
|
||||
/*
|
||||
* Copyright 2014 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.keyvalue.repository.query;
|
||||
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SpelQueryCreatorUnitTests {
|
||||
|
||||
static final DateTimeFormatter FORMATTER = ISODateTimeFormat.dateTimeNoMillis().withZoneUTC();
|
||||
|
||||
static final Person RICKON = new Person("rickon", 4);
|
||||
static final Person BRAN = new Person("bran", 9)//
|
||||
.skinChanger(true)//
|
||||
.bornAt(FORMATTER.parseDateTime("2013-01-31T06:00:00Z").toDate());
|
||||
static final Person ARYA = new Person("arya", 13);
|
||||
static final Person ROBB = new Person("robb", 16)//
|
||||
.named("stark")//
|
||||
.bornAt(FORMATTER.parseDateTime("2010-09-20T06:00:00Z").toDate());
|
||||
static final Person JON = new Person("jon", 17).named("snow");
|
||||
|
||||
@Mock RepositoryMetadata metadataMock;
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void equalsReturnsTrueWhenMatching() throws Exception {
|
||||
assertThat(evaluate("findByFirstname", BRAN.firstname).against(BRAN), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void equalsReturnsFalseWhenNotMatching() throws Exception {
|
||||
assertThat(evaluate("findByFirstname", BRAN.firstname).against(RICKON), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void isTrueAssertedPropertlyWhenTrue() throws Exception {
|
||||
assertThat(evaluate("findBySkinChangerIsTrue").against(BRAN), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void isTrueAssertedPropertlyWhenFalse() throws Exception {
|
||||
assertThat(evaluate("findBySkinChangerIsTrue").against(RICKON), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void isFalseAssertedPropertlyWhenTrue() throws Exception {
|
||||
assertThat(evaluate("findBySkinChangerIsFalse").against(BRAN), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void isFalseAssertedPropertlyWhenFalse() throws Exception {
|
||||
assertThat(evaluate("findBySkinChangerIsFalse").against(RICKON), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void isNullAssertedPropertlyWhenAttributeIsNull() throws Exception {
|
||||
assertThat(evaluate("findByLastnameIsNull").against(BRAN), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void isNullAssertedPropertlyWhenAttributeIsNotNull() throws Exception {
|
||||
assertThat(evaluate("findByLastnameIsNull").against(ROBB), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void isNotNullFalseTrueWhenAttributeIsNull() throws Exception {
|
||||
assertThat(evaluate("findByLastnameIsNotNull").against(BRAN), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void isNotNullReturnsTrueAttributeIsNotNull() throws Exception {
|
||||
assertThat(evaluate("findByLastnameIsNotNull").against(ROBB), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void startsWithReturnsTrueWhenMatching() throws Exception {
|
||||
assertThat(evaluate("findByFirstnameStartingWith", "r").against(ROBB), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void startsWithReturnsFalseWhenNotMatching() throws Exception {
|
||||
assertThat(evaluate("findByFirstnameStartingWith", "r").against(BRAN), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void likeReturnsTrueWhenMatching() throws Exception {
|
||||
assertThat(evaluate("findByFirstnameLike", "ob").against(ROBB), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void likeReturnsFalseWhenNotMatching() throws Exception {
|
||||
assertThat(evaluate("findByFirstnameLike", "ra").against(ROBB), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void endsWithReturnsTrueWhenMatching() throws Exception {
|
||||
assertThat(evaluate("findByFirstnameEndingWith", "bb").against(ROBB), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void endsWithReturnsFalseWhenNotMatching() throws Exception {
|
||||
assertThat(evaluate("findByFirstnameEndingWith", "an").against(ROBB), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class)
|
||||
public void startsWithIgnoreCaseReturnsTrueWhenMatching() throws Exception {
|
||||
assertThat(evaluate("findByFirstnameIgnoreCase", "R").against(ROBB), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void greaterThanReturnsTrueForHigherValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeGreaterThan", BRAN.age).against(ROBB), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void greaterThanReturnsFalseForLowerValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeGreaterThan", BRAN.age).against(RICKON), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void afterReturnsTrueForHigherValues() throws Exception {
|
||||
assertThat(evaluate("findByBirthdayAfter", ROBB.birthday).against(BRAN), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void afterReturnsFalseForLowerValues() throws Exception {
|
||||
assertThat(evaluate("findByBirthdayAfter", BRAN.birthday).against(ROBB), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void greaterThanEaualsReturnsTrueForHigherValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeGreaterThanEqual", BRAN.age).against(ROBB), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void greaterThanEaualsReturnsTrueForEqualValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeGreaterThanEqual", BRAN.age).against(BRAN), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void greaterThanEqualsReturnsFalseForLowerValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeGreaterThanEqual", BRAN.age).against(RICKON), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void lessThanReturnsTrueForHigherValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeLessThan", BRAN.age).against(ROBB), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void lessThanReturnsFalseForLowerValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeLessThan", BRAN.age).against(RICKON), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void beforeReturnsTrueForLowerValues() throws Exception {
|
||||
assertThat(evaluate("findByBirthdayBefore", BRAN.birthday).against(ROBB), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void beforeReturnsFalseForHigherValues() throws Exception {
|
||||
assertThat(evaluate("findByBirthdayBefore", ROBB.birthday).against(BRAN), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void lessThanEaualsReturnsTrueForHigherValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeLessThanEqual", BRAN.age).against(ROBB), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void lessThanEaualsReturnsTrueForEqualValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeLessThanEqual", BRAN.age).against(BRAN), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void lessThanEqualsReturnsFalseForLowerValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeLessThanEqual", BRAN.age).against(RICKON), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void betweenEqualsReturnsTrueForValuesInBetween() throws Exception {
|
||||
assertThat(evaluate("findByAgeBetween", BRAN.age, ROBB.age).against(ARYA), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void betweenEqualsReturnsFalseForHigherValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeBetween", BRAN.age, ROBB.age).against(JON), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void betweenEqualsReturnsFalseForLowerValues() throws Exception {
|
||||
assertThat(evaluate("findByAgeBetween", BRAN.age, ROBB.age).against(RICKON), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void connectByAndReturnsTrueWhenAllPropertiesMatching() throws Exception {
|
||||
assertThat(evaluate("findByAgeGreaterThanAndLastname", BRAN.age, JON.lastname).against(JON), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void connectByAndReturnsFalseWhenOnlyFewPropertiesMatch() throws Exception {
|
||||
assertThat(evaluate("findByAgeGreaterThanAndLastname", BRAN.age, JON.lastname).against(ROBB), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void connectByOrReturnsTrueWhenOnlyFewPropertiesMatch() throws Exception {
|
||||
assertThat(evaluate("findByAgeGreaterThanOrLastname", BRAN.age, JON.lastname).against(ROBB), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void connectByOrReturnsTrueWhenAllPropertiesMatch() throws Exception {
|
||||
assertThat(evaluate("findByAgeGreaterThanOrLastname", BRAN.age, JON.lastname).against(JON), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void regexReturnsTrueWhenMatching() throws Exception {
|
||||
assertThat(evaluate("findByLastnameMatches", "^s.*w$").against(JON), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void regexReturnsFalseWhenNotMatching() throws Exception {
|
||||
assertThat(evaluate("findByLastnameMatches", "^s.*w$").against(ROBB), is(false));
|
||||
}
|
||||
|
||||
private Evaluation evaluate(String methodName, Object... args) throws Exception {
|
||||
return new Evaluation((SpelExpression) createQueryForMethodWithArgs(methodName, args).getCritieria());
|
||||
}
|
||||
|
||||
private KeyValueQuery<SpelExpression> createQueryForMethodWithArgs(String methodName, Object... args)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Class<?>[] argTypes = new Class<?>[args.length];
|
||||
if (!ObjectUtils.isEmpty(args)) {
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
argTypes[i] = args[i].getClass();
|
||||
}
|
||||
}
|
||||
|
||||
Method method = PersonRepository.class.getMethod(methodName, argTypes);
|
||||
|
||||
PartTree partTree = new PartTree(method.getName(), method.getReturnType());
|
||||
SpelQueryCreator creator = new SpelQueryCreator(partTree, new ParametersParameterAccessor(new QueryMethod(method,
|
||||
metadataMock).getParameters(), args));
|
||||
|
||||
KeyValueQuery<SpelExpression> q = creator.createQuery();
|
||||
q.getCritieria().setEvaluationContext(new StandardEvaluationContext(args));
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
static interface PersonRepository {
|
||||
|
||||
// Type.SIMPLE_PROPERTY
|
||||
Person findByFirstname(String firstname);
|
||||
|
||||
// Type.TRUE
|
||||
Person findBySkinChangerIsTrue();
|
||||
|
||||
// Type.FALSE
|
||||
Person findBySkinChangerIsFalse();
|
||||
|
||||
// Type.IS_NULL
|
||||
Person findByLastnameIsNull();
|
||||
|
||||
// Type.IS_NOT_NULL
|
||||
Person findByLastnameIsNotNull();
|
||||
|
||||
// Type.STARTING_WITH
|
||||
Person findByFirstnameStartingWith(String firstanme);
|
||||
|
||||
Person findByFirstnameIgnoreCase(String firstanme);
|
||||
|
||||
// Type.AFTER
|
||||
Person findByBirthdayAfter(Date date);
|
||||
|
||||
// Type.GREATHER_THAN
|
||||
Person findByAgeGreaterThan(Integer age);
|
||||
|
||||
// Type.GREATER_THAN_EQUAL
|
||||
Person findByAgeGreaterThanEqual(Integer age);
|
||||
|
||||
// Type.BEFORE
|
||||
Person findByBirthdayBefore(Date date);
|
||||
|
||||
// Type.LESS_THAN
|
||||
Person findByAgeLessThan(Integer age);
|
||||
|
||||
// Type.LESS_THAN_EQUAL
|
||||
Person findByAgeLessThanEqual(Integer age);
|
||||
|
||||
// Type.BETWEEN
|
||||
Person findByAgeBetween(Integer low, Integer high);
|
||||
|
||||
// Type.LIKE
|
||||
Person findByFirstnameLike(String firstname);
|
||||
|
||||
// Type.ENDING_WITH
|
||||
Person findByFirstnameEndingWith(String firstname);
|
||||
|
||||
Person findByAgeGreaterThanAndLastname(Integer age, String lastname);
|
||||
|
||||
Person findByAgeGreaterThanOrLastname(Integer age, String lastname);
|
||||
|
||||
// Type.REGEX
|
||||
Person findByLastnameMatches(String lastname);
|
||||
|
||||
}
|
||||
|
||||
static class Evaluation {
|
||||
|
||||
SpelExpression expression;
|
||||
Object candidate;
|
||||
|
||||
public Evaluation(SpelExpression expresison) {
|
||||
this.expression = expresison;
|
||||
}
|
||||
|
||||
public Boolean against(Object candidate) {
|
||||
this.candidate = candidate;
|
||||
return evaluate();
|
||||
}
|
||||
|
||||
private boolean evaluate() {
|
||||
expression.getEvaluationContext().setVariable("it", candidate);
|
||||
return expression.getValue(Boolean.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Person {
|
||||
|
||||
private @Id String id;
|
||||
private String firstname, lastname;
|
||||
private int age;
|
||||
private boolean isSkinChanger = false;
|
||||
private Date birthday;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(String firstname, int age) {
|
||||
super();
|
||||
this.firstname = firstname;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public void setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
public void setLastname(String lastname) {
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public Date getBirthday() {
|
||||
return birthday;
|
||||
}
|
||||
|
||||
public void setBirthday(Date birthday) {
|
||||
this.birthday = birthday;
|
||||
}
|
||||
|
||||
public boolean isSkinChanger() {
|
||||
return isSkinChanger;
|
||||
}
|
||||
|
||||
public void setSkinChanger(boolean isSkinChanger) {
|
||||
this.isSkinChanger = isSkinChanger;
|
||||
}
|
||||
|
||||
public Person skinChanger(boolean isSkinChanger) {
|
||||
this.isSkinChanger = isSkinChanger;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Person named(String lastname) {
|
||||
this.lastname = lastname;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Person bornAt(Date date) {
|
||||
this.birthday = date;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2014 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.keyvalue.repository.support;
|
||||
|
||||
import static org.hamcrest.collection.IsArrayWithSize.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.keyvalue.repository.support.KeyValueQueryDslUtils.*;
|
||||
|
||||
import org.hamcrest.collection.IsArrayContainingInOrder;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.NullHandling;
|
||||
import org.springframework.data.keyvalue.Person;
|
||||
import org.springframework.data.keyvalue.QPerson;
|
||||
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
||||
|
||||
import com.mysema.query.types.EntityPath;
|
||||
import com.mysema.query.types.OrderSpecifier;
|
||||
import com.mysema.query.types.path.PathBuilder;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public class QueryDslUtilsUnitTests {
|
||||
|
||||
private EntityPath<Person> path;
|
||||
private PathBuilder<Person> builder;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.path = SimpleEntityPathResolver.INSTANCE.createPath(Person.class);
|
||||
this.builder = new PathBuilder<Person>(path.getType(), path.getMetadata());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void toOrderSpecifierThrowsExceptioOnNullPathBuilder() {
|
||||
toOrderSpecifier(new Sort("firstname"), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void toOrderSpecifierReturnsEmptyArrayWhenSortIsNull() {
|
||||
assertThat(toOrderSpecifier(null, builder), arrayWithSize(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void toOrderSpecifierConvertsSimpleAscSortCorrectly() {
|
||||
|
||||
Sort sort = new Sort(Direction.ASC, "firstname");
|
||||
|
||||
OrderSpecifier<?>[] specifiers = toOrderSpecifier(sort, builder);
|
||||
|
||||
assertThat(specifiers, IsArrayContainingInOrder.<OrderSpecifier<?>> arrayContaining(QPerson.person.firstname.asc()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void toOrderSpecifierConvertsSimpleDescSortCorrectly() {
|
||||
|
||||
Sort sort = new Sort(Direction.DESC, "firstname");
|
||||
|
||||
OrderSpecifier<?>[] specifiers = toOrderSpecifier(sort, builder);
|
||||
|
||||
assertThat(specifiers,
|
||||
IsArrayContainingInOrder.<OrderSpecifier<?>> arrayContaining(QPerson.person.firstname.desc()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void toOrderSpecifierConvertsSortCorrectlyAndRetainsArgumentOrder() {
|
||||
|
||||
Sort sort = new Sort(Direction.DESC, "firstname").and(new Sort(Direction.ASC, "age"));
|
||||
|
||||
OrderSpecifier<?>[] specifiers = toOrderSpecifier(sort, builder);
|
||||
|
||||
assertThat(specifiers, IsArrayContainingInOrder.<OrderSpecifier<?>> arrayContaining(
|
||||
QPerson.person.firstname.desc(), QPerson.person.age.asc()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void toOrderSpecifierConvertsSortWithNullHandlingCorrectly() {
|
||||
|
||||
Sort sort = new Sort(new Sort.Order(Direction.DESC, "firstname", NullHandling.NULLS_LAST));
|
||||
|
||||
OrderSpecifier<?>[] specifiers = toOrderSpecifier(sort, builder);
|
||||
|
||||
assertThat(specifiers,
|
||||
IsArrayContainingInOrder.<OrderSpecifier<?>> arrayContaining(QPerson.person.firstname.desc().nullsLast()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2014 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.map;
|
||||
|
||||
import static org.hamcrest.core.IsEqual.*;
|
||||
import static org.hamcrest.core.IsInstanceOf.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MapKeyValueAdapterFactoryUnitTests {
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldDefaultToConcurrentHashMapWhenTypeIsNull() {
|
||||
|
||||
assertThat(new MapKeyValueAdapterFactory(null).getAdapter().getKeySpaceMap("foo"),
|
||||
instanceOf(ConcurrentHashMap.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldDefaultToCollecitonUtilsDefaultForInterfaceTypes() {
|
||||
|
||||
assertThat(new MapKeyValueAdapterFactory(Map.class).getAdapter().getKeySpaceMap("foo"),
|
||||
instanceOf(CollectionFactory.createMap(Map.class, 0).getClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldUseConcreteMapTypeWhenInstantiable() {
|
||||
|
||||
assertThat(new MapKeyValueAdapterFactory(ConcurrentSkipListMap.class).getAdapter().getKeySpaceMap("foo"),
|
||||
instanceOf(CollectionFactory.createMap(ConcurrentSkipListMap.class, 0).getClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void shouldPopulateAdapterWithValues() {
|
||||
|
||||
MapKeyValueAdapterFactory factory = new MapKeyValueAdapterFactory();
|
||||
factory.setInitialValuesForKeyspace("foo", Collections.singletonMap("1", "STANIS"));
|
||||
factory.setInitialValuesForKeyspace("bar", Collections.singletonMap("1", "ROBERT"));
|
||||
|
||||
assertThat((String) factory.getAdapter().get("1", "foo"), equalTo("STANIS"));
|
||||
assertThat((String) factory.getAdapter().get("1", "bar"), equalTo("ROBERT"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenSettingValuesForNullKeySpace() {
|
||||
new MapKeyValueAdapterFactory().setInitialValuesForKeyspace(null, Collections.<Serializable, Object> emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenSettingNullValuesForKeySpace() {
|
||||
new MapKeyValueAdapterFactory().setInitialValuesForKeyspace("foo", null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2014 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.map;
|
||||
|
||||
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.*;
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.hamcrest.core.IsEqual.*;
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.map.MapKeyValueAdapter;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MapKeyValueAdapterUnitTests {
|
||||
|
||||
private static final String COLLECTION_1 = "collection-1";
|
||||
private static final String COLLECTION_2 = "collection-2";
|
||||
private static final String STRING_1 = new String("1");
|
||||
|
||||
private Object object1 = new SimpleObject("one");
|
||||
private Object object2 = new SimpleObject("two");
|
||||
|
||||
private MapKeyValueAdapter adapter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.adapter = new MapKeyValueAdapter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void putShouldThrowExceptionWhenAddingNullId() {
|
||||
adapter.put(null, object1, COLLECTION_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void putShouldThrowExceptionWhenCollectionIsNullValue() {
|
||||
adapter.put("1", object1, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void putReturnsNullWhenNoObjectForIdPresent() {
|
||||
assertThat(adapter.put("1", object1, COLLECTION_1), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void putShouldReturnPreviousObjectForIdWhenAddingNewOneWithSameIdPresent() {
|
||||
|
||||
adapter.put("1", object1, COLLECTION_1);
|
||||
assertThat(adapter.put("1", object2, COLLECTION_1), equalTo(object1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void containsShouldThrowExceptionWhenIdIsNull() {
|
||||
adapter.contains(null, COLLECTION_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void containsShouldThrowExceptionWhenTypeIsNull() {
|
||||
adapter.contains("", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void containsShouldReturnFalseWhenNoElementsPresent() {
|
||||
assertThat(adapter.contains("1", COLLECTION_1), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void containShouldReturnTrueWhenElementWithIdPresent() {
|
||||
|
||||
adapter.put("1", object1, COLLECTION_1);
|
||||
assertThat(adapter.contains("1", COLLECTION_1), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void getShouldReturnNullWhenNoElementWithIdPresent() {
|
||||
assertThat(adapter.get("1", COLLECTION_1), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void getShouldReturnElementWhenMatchingIdPresent() {
|
||||
|
||||
adapter.put("1", object1, COLLECTION_1);
|
||||
assertThat(adapter.get("1", COLLECTION_1), is(object1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void getShouldThrowExceptionWhenIdIsNull() {
|
||||
adapter.get(null, COLLECTION_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void getShouldThrowExceptionWhenTypeIsNull() {
|
||||
adapter.get("1", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void getAllOfShouldReturnAllValuesOfGivenCollection() {
|
||||
|
||||
adapter.put("1", object1, COLLECTION_1);
|
||||
adapter.put("2", object2, COLLECTION_1);
|
||||
adapter.put("3", STRING_1, COLLECTION_2);
|
||||
|
||||
assertThat(adapter.getAllOf(COLLECTION_1), containsInAnyOrder(object1, object2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void getAllOfShouldThrowExceptionWhenTypeIsNull() {
|
||||
adapter.getAllOf(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void deleteShouldReturnNullWhenGivenIdThatDoesNotExist() {
|
||||
assertThat(adapter.delete("1", COLLECTION_1), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void deleteShouldReturnDeletedObject() {
|
||||
|
||||
adapter.put("1", object1, COLLECTION_1);
|
||||
assertThat(adapter.delete("1", COLLECTION_1), is(object1));
|
||||
}
|
||||
|
||||
static class SimpleObject {
|
||||
|
||||
protected String stringValue;
|
||||
|
||||
public SimpleObject() {}
|
||||
|
||||
SimpleObject(String value) {
|
||||
this.stringValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * ObjectUtils.nullSafeHashCode(this.stringValue);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof SimpleObject)) {
|
||||
return false;
|
||||
}
|
||||
SimpleObject that = (SimpleObject) obj;
|
||||
return ObjectUtils.nullSafeEquals(this.stringValue, that.stringValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2014 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.map;
|
||||
|
||||
import static org.hamcrest.collection.IsCollectionWithSize.*;
|
||||
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.*;
|
||||
import static org.hamcrest.collection.IsIterableContainingInOrder.*;
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.keyvalue.Person;
|
||||
import org.springframework.data.keyvalue.QPerson;
|
||||
import org.springframework.data.querydsl.QSort;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class QueryDslMapRepositoryUnitTests extends SimpleKeyValueRepositoryUnitTests {
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findOneIsExecutedCorrectly() {
|
||||
|
||||
repository.save(LENNISTERS);
|
||||
|
||||
Person result = getQPersonRepo().findOne(QPerson.person.firstname.eq(CERSEI.getFirstname()));
|
||||
assertThat(result, is(CERSEI));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findAllIsExecutedCorrectly() {
|
||||
|
||||
repository.save(LENNISTERS);
|
||||
|
||||
Iterable<Person> result = getQPersonRepo().findAll(QPerson.person.age.eq(CERSEI.getAge()));
|
||||
assertThat(result, containsInAnyOrder(CERSEI, JAIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findWithPaginationWorksCorrectly() {
|
||||
|
||||
repository.save(LENNISTERS);
|
||||
Page<Person> page1 = getQPersonRepo().findAll(QPerson.person.age.eq(CERSEI.getAge()), new PageRequest(0, 1));
|
||||
|
||||
assertThat(page1.getTotalElements(), is(2L));
|
||||
assertThat(page1.getContent(), hasSize(1));
|
||||
assertThat(page1.hasNext(), is(true));
|
||||
|
||||
Page<Person> page2 = ((QPersonRepository) repository).findAll(QPerson.person.age.eq(CERSEI.getAge()),
|
||||
page1.nextPageable());
|
||||
|
||||
assertThat(page2.getTotalElements(), is(2L));
|
||||
assertThat(page2.getContent(), hasSize(1));
|
||||
assertThat(page2.hasNext(), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findAllUsingOrderSpecifierWorksCorrectly() {
|
||||
|
||||
repository.save(LENNISTERS);
|
||||
|
||||
Iterable<Person> result = getQPersonRepo().findAll(QPerson.person.age.eq(CERSEI.getAge()),
|
||||
QPerson.person.firstname.desc());
|
||||
|
||||
assertThat(result, contains(JAIME, CERSEI));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findAllUsingPageableWithSortWorksCorrectly() {
|
||||
|
||||
repository.save(LENNISTERS);
|
||||
|
||||
Iterable<Person> result = getQPersonRepo().findAll(QPerson.person.age.eq(CERSEI.getAge()),
|
||||
new PageRequest(0, 10, Direction.DESC, "firstname"));
|
||||
|
||||
assertThat(result, contains(JAIME, CERSEI));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findAllUsingPagableWithQSortWorksCorrectly() {
|
||||
|
||||
repository.save(LENNISTERS);
|
||||
|
||||
Iterable<Person> result = getQPersonRepo().findAll(QPerson.person.age.eq(CERSEI.getAge()),
|
||||
new PageRequest(0, 10, new QSort(QPerson.person.firstname.desc())));
|
||||
|
||||
assertThat(result, contains(JAIME, CERSEI));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends PersonRepository> getRepositoryClass() {
|
||||
return QPersonRepository.class;
|
||||
}
|
||||
|
||||
QPersonRepository getQPersonRepo() {
|
||||
return ((QPersonRepository) repository);
|
||||
}
|
||||
|
||||
static interface QPersonRepository extends PersonRepository, QueryDslPredicateExecutor<Person> {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright 2014 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.map;
|
||||
|
||||
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.*;
|
||||
import static org.hamcrest.collection.IsIterableContainingInOrder.*;
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.collection.IsCollectionWithSize;
|
||||
import org.hamcrest.collection.IsIterableContainingInOrder;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.keyvalue.Person;
|
||||
import org.springframework.data.keyvalue.core.KeyValueTemplate;
|
||||
import org.springframework.data.keyvalue.repository.KeyValueRepository;
|
||||
import org.springframework.data.keyvalue.repository.support.KeyValueRepositoryFactory;
|
||||
import org.springframework.data.map.MapKeyValueAdapter;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class SimpleKeyValueRepositoryUnitTests {
|
||||
|
||||
protected static final Person CERSEI = new Person("cersei", 19);
|
||||
protected static final Person JAIME = new Person("jaime", 19);
|
||||
protected static final Person TYRION = new Person("tyrion", 17);
|
||||
|
||||
protected static List<Person> LENNISTERS = Arrays.asList(CERSEI, JAIME, TYRION);
|
||||
|
||||
protected PersonRepository repository;
|
||||
protected KeyValueTemplate template = new KeyValueTemplate(new MapKeyValueAdapter());
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.repository = new KeyValueRepositoryFactory(template).getRepository(getRepositoryClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findBy() {
|
||||
|
||||
this.repository.save(LENNISTERS);
|
||||
assertThat(this.repository.findByAge(19), containsInAnyOrder(CERSEI, JAIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void combindedFindUsingAnd() {
|
||||
|
||||
this.repository.save(LENNISTERS);
|
||||
|
||||
assertThat(this.repository.findByFirstnameAndAge(JAIME.getFirstname(), 19), containsInAnyOrder(JAIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findPage() {
|
||||
|
||||
this.repository.save(LENNISTERS);
|
||||
|
||||
Page<Person> page = this.repository.findByAge(19, new PageRequest(0, 1));
|
||||
assertThat(page.hasNext(), is(true));
|
||||
assertThat(page.getTotalElements(), is(2L));
|
||||
assertThat(page.getContent(), IsCollectionWithSize.hasSize(1));
|
||||
|
||||
Page<Person> next = this.repository.findByAge(19, page.nextPageable());
|
||||
assertThat(next.hasNext(), is(false));
|
||||
assertThat(next.getTotalElements(), is(2L));
|
||||
assertThat(next.getContent(), IsCollectionWithSize.hasSize(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findByConnectingOr() {
|
||||
|
||||
this.repository.save(LENNISTERS);
|
||||
|
||||
assertThat(this.repository.findByAgeOrFirstname(19, TYRION.getFirstname()),
|
||||
containsInAnyOrder(CERSEI, JAIME, TYRION));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void singleEntityExecution() {
|
||||
|
||||
this.repository.save(LENNISTERS);
|
||||
|
||||
assertThat(this.repository.findByAgeAndFirstname(TYRION.getAge(), TYRION.getFirstname()), is(TYRION));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void findAllShouldRespectSort() {
|
||||
|
||||
this.repository.save(LENNISTERS);
|
||||
|
||||
assertThat(this.repository.findAll(new Sort(new Sort.Order(Direction.ASC, "age"), new Sort.Order(Direction.DESC,
|
||||
"firstname"))), IsIterableContainingInOrder.contains(TYRION, JAIME, CERSEI));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-525
|
||||
*/
|
||||
@Test
|
||||
public void derivedFinderShouldRespectSort() {
|
||||
|
||||
repository.save(LENNISTERS);
|
||||
|
||||
List<Person> result = repository.findByAgeGreaterThanOrderByAgeAscFirstnameDesc(2);
|
||||
|
||||
assertThat(result, contains(TYRION, JAIME, CERSEI));
|
||||
}
|
||||
|
||||
protected Class<? extends PersonRepository> getRepositoryClass() {
|
||||
return PersonRepository.class;
|
||||
}
|
||||
|
||||
public static interface PersonRepository extends CrudRepository<Person, String>, KeyValueRepository<Person, String> {
|
||||
|
||||
List<Person> findByAge(int age);
|
||||
|
||||
List<Person> findByFirstname(String firstname);
|
||||
|
||||
List<Person> findByFirstnameAndAge(String firstname, int age);
|
||||
|
||||
Page<Person> findByAge(int age, Pageable page);
|
||||
|
||||
List<Person> findByAgeOrFirstname(int age, String firstname);
|
||||
|
||||
Person findByAgeAndFirstname(int age, String firstname);
|
||||
|
||||
List<Person> findByAgeGreaterThanOrderByAgeAscFirstnameDesc(int age);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user