DATACMNS-669 - Moved some types for better code structure.

Introduced dedicated querydsl.bindings package to contain all non-web projects to make sure domain types and repositories don't have to depend on types in a web package.

Updated Sonargraph architecture description accordingly.

Original pull request: #132.
This commit is contained in:
Oliver Gierke
2015-07-17 23:30:02 +02:00
parent 0330cdc3d3
commit c5e5244162
13 changed files with 92 additions and 63 deletions

View File

@@ -0,0 +1,254 @@
/*
* Copyright 2015 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.querydsl.binding;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.querydsl.QUser;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
import org.springframework.data.querydsl.User;
import org.springframework.data.querydsl.binding.MultiValueBinding;
import org.springframework.data.querydsl.binding.QuerydslBindings;
import org.springframework.data.querydsl.binding.QuerydslPredicateBuilder;
import org.springframework.data.querydsl.binding.SingleValueBinding;
import org.springframework.test.util.ReflectionTestUtils;
import com.mysema.query.types.Path;
import com.mysema.query.types.Predicate;
import com.mysema.query.types.path.StringPath;
/**
* Unit tests for {@link QuerydslBindings}.
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
public class QuerydslBindingsUnitTests {
QuerydslPredicateBuilder builder;
QuerydslBindings bindings;
static final SingleValueBinding<StringPath, String> CONTAINS_BINDING = new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.contains(value);
}
};
@Before
public void setUp() {
this.builder = new QuerydslPredicateBuilder(new DefaultConversionService(), SimpleEntityPathResolver.INSTANCE);
this.bindings = new QuerydslBindings();
}
/**
* @see DATACMNS-669
*/
@Test(expected = IllegalArgumentException.class)
public void rejectsNullPath() {
bindings.getBindingForPath(null);
}
/**
* @see DATACMNS-669
*/
@Test
public void returnsNullIfNoBindingRegisteredForPath() {
assertThat(bindings.getBindingForPath(PropertyPath.from("lastname", User.class)), nullValue());
}
/**
* @see DATACMNS-669
*/
@Test
public void returnsRegisteredBindingForSimplePath() {
bindings.bind(QUser.user.firstname).first(CONTAINS_BINDING);
assertAdapterWithTargetBinding(bindings.getBindingForPath(PropertyPath.from("firstname", User.class)),
CONTAINS_BINDING);
}
/**
* @see DATACMNS-669
*/
@Test
public void getBindingForPathShouldReturnSpeficicBindingForNestedElementsWhenAvailable() {
bindings.bind(QUser.user.address.street).first(CONTAINS_BINDING);
assertAdapterWithTargetBinding(bindings.getBindingForPath(PropertyPath.from("address.street", User.class)),
CONTAINS_BINDING);
}
/**
* @see DATACMNS-669
*/
@Test
public void getBindingForPathShouldReturnSpeficicBindingForTypes() {
bindings.bind(String.class).first(CONTAINS_BINDING);
assertAdapterWithTargetBinding(bindings.getBindingForPath(PropertyPath.from("address.street", User.class)),
CONTAINS_BINDING);
}
/**
* @see DATACMNS-669
*/
@Test
public void propertyNotExplicitlyIncludedAndWithoutTypeBindingIsInvisible() {
bindings.bind(String.class).first(CONTAINS_BINDING);
assertThat(bindings.getBindingForPath(PropertyPath.from("inceptionYear", User.class)), nullValue());
}
/**
* @see DATACMNS-669
*/
@Test
public void pathIsVisibleIfTypeBasedBindingWasRegistered() {
bindings.bind(String.class).first(CONTAINS_BINDING);
assertThat(bindings.isPathVisible(PropertyPath.from("inceptionYear", User.class)), is(true));
}
/**
* @see DATACMNS-669
*/
@Test
public void explicitlyIncludedPathIsVisible() {
bindings.including(QUser.user.inceptionYear);
assertThat(bindings.isPathVisible(PropertyPath.from("inceptionYear", User.class)), is(true));
}
/**
* @see DATACMNS-669
*/
@Test
public void notExplicitlyIncludedPathIsInvisible() {
bindings.including(QUser.user.inceptionYear);
assertThat(bindings.isPathVisible(PropertyPath.from("firstname", User.class)), is(false));
}
/**
* @see DATACMNS-669
*/
@Test
public void excludedPathIsInvisible() {
bindings.excluding(QUser.user.inceptionYear);
assertThat(bindings.isPathVisible(PropertyPath.from("inceptionYear", User.class)), is(false));
}
/**
* @see DATACMNS-669
*/
@Test
public void pathIsVisibleIfNotExplicitlyExcluded() {
bindings.excluding(QUser.user.inceptionYear);
assertThat(bindings.isPathVisible(PropertyPath.from("firstname", User.class)), is(true));
}
/**
* @see DATACMNS-669
*/
@Test
public void pathIsVisibleIfItsBothBlackAndWhitelisted() {
bindings.excluding(QUser.user.firstname);
bindings.including(QUser.user.firstname);
assertThat(bindings.isPathVisible(PropertyPath.from("firstname", User.class)), is(true));
}
/**
* @see DATACMNS-669
*/
@Test
public void nestedPathIsInvisibleIfAParanetPathWasExcluded() {
bindings.excluding(QUser.user.address);
assertThat(bindings.isPathVisible(PropertyPath.from("address.city", User.class)), is(false));
}
/**
* @see DATACMNS-669
*/
@Test
public void pathIsVisibleIfConcretePathIsVisibleButParentExcluded() {
bindings.excluding(QUser.user.address);
bindings.including(QUser.user.address.city);
assertThat(bindings.isPathVisible(PropertyPath.from("address.city", User.class)), is(true));
}
/**
* @see DATACMNS-669
*/
@Test
public void isPathVisibleShouldReturnFalseWhenPartialPathContainedInExcludingAndConcretePathToDifferentPropertyIsIncluded() {
bindings.excluding(QUser.user.address);
bindings.including(QUser.user.address.city);
assertThat(bindings.isPathVisible(PropertyPath.from("address.street", User.class)), is(false));
}
/**
* @see DATACMNS-669
*/
@Test
public void testname() {
PropertyPath firstname = PropertyPath.from("firstname", User.class);
PropertyPath lastname = PropertyPath.from("lastname", User.class);
PropertyPath city = PropertyPath.from("address.city", User.class);
PropertyPath street = PropertyPath.from("address.street", User.class);
bindings.including(QUser.user.firstname, QUser.user.address.street);
assertThat(bindings.isPathVisible(firstname), is(true));
assertThat(bindings.isPathVisible(street), is(true));
assertThat(bindings.isPathVisible(lastname), is(false));
assertThat(bindings.isPathVisible(city), is(false));
}
private static <P extends Path<S>, S> void assertAdapterWithTargetBinding(MultiValueBinding<P, S> binding,
SingleValueBinding<? extends Path<?>, ?> expected) {
assertThat(binding, is(instanceOf(QuerydslBindings.MultiValueBindingAdapter.class)));
assertThat(ReflectionTestUtils.getField(binding, "delegate"), is((Object) expected));
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright 2015 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.querydsl.binding;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collections;
import org.hamcrest.Matcher;
import org.hamcrest.core.Is;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.querydsl.QUser;
import org.springframework.data.querydsl.binding.QuerydslDefaultBinding;
import com.mysema.query.types.Expression;
import com.mysema.query.types.Predicate;
/**
* @author Christoph Strobl
* @author Oliver Gierke
*/
public class QuerydslDefaultBindingUnitTests {
QuerydslDefaultBinding binding;
@Before
public void setUp() {
binding = new QuerydslDefaultBinding();
}
/**
* @see DATACMNS-669
*/
@Test
public void shouldCreatePredicateCorrectlyWhenPropertyIsInRoot() {
Predicate predicate = binding.bind(QUser.user.firstname, Collections.singleton("tam"));
assertPredicate(predicate, is(QUser.user.firstname.eq("tam")));
}
/**
* @see DATACMNS-669
*/
@Test
public void shouldCreatePredicateCorrectlyWhenPropertyIsInNestedElement() {
Predicate predicate = binding.bind(QUser.user.address.city, Collections.singleton("two rivers"));
Assert.assertThat(predicate.toString(), is(QUser.user.address.city.eq("two rivers").toString()));
}
/**
* @see DATACMNS-669
*/
@Test
public void shouldCreatePredicateWithContainingWhenPropertyIsCollectionLikeAndValueIsObject() {
Predicate predicate = binding.bind(QUser.user.nickNames, Collections.singleton("dragon reborn"));
assertPredicate(predicate, is(QUser.user.nickNames.contains("dragon reborn")));
}
/**
* @see DATACMNS-669
*/
@Test
public void shouldCreatePredicateWithInWhenPropertyIsAnObjectAndValueIsACollection() {
Predicate predicate = binding.bind(QUser.user.firstname, Arrays.asList("dragon reborn", "shadowkiller"));
assertPredicate(predicate, is(QUser.user.firstname.in(Arrays.asList("dragon reborn", "shadowkiller"))));
}
@Test
public void testname() {
assertThat(binding.bind(QUser.user.lastname, Collections.emptySet()), is(nullValue()));
}
/*
* just to satisfy generic type boundaries o_O
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private void assertPredicate(Predicate predicate, Matcher<? extends Expression> matcher) {
Assert.assertThat((Expression) predicate, Is.<Expression> is((Matcher<Expression>) matcher));
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright 2015 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.querydsl.binding;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.querydsl.QUser;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
import org.springframework.data.querydsl.User;
import org.springframework.data.querydsl.Users;
import org.springframework.data.querydsl.binding.QuerydslBindings;
import org.springframework.data.querydsl.binding.QuerydslPredicateBuilder;
import org.springframework.data.querydsl.binding.SingleValueBinding;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import com.mysema.query.collections.CollQueryFactory;
import com.mysema.query.types.Predicate;
import com.mysema.query.types.path.StringPath;
/**
* Unit tests for {@link QuerydslPredicateBuilder}.
*
* @author Christoph Strobl
* @author Oliver Gierke
*/
public class QuerydslPredicateBuilderUnitTests {
static final ClassTypeInformation<User> USER_TYPE = ClassTypeInformation.from(User.class);
static final QuerydslBindings DEFAULT_BINDINGS = new QuerydslBindings();
QuerydslPredicateBuilder builder;
MultiValueMap<String, String> values;
@Before
public void setUp() {
this.builder = new QuerydslPredicateBuilder(new DefaultConversionService(), SimpleEntityPathResolver.INSTANCE);
this.values = new LinkedMultiValueMap<String, String>();
}
/**
* @see DATACMNS-669
*/
@Test(expected = IllegalArgumentException.class)
public void rejectsNullConversionService() {
new QuerydslPredicateBuilder(null, SimpleEntityPathResolver.INSTANCE);
}
/**
* @see DATACMNS-669
*/
@Test(expected = IllegalArgumentException.class)
public void getPredicateShouldThrowErrorWhenBindingContextIsNull() {
builder.getPredicate(null, values, null);
}
/**
* @see DATACMNS-669
*/
@Test
public void getPredicateShouldReturnEmptyPredicateWhenPropertiesAreEmpty() {
assertThat(builder.getPredicate(ClassTypeInformation.OBJECT, values, DEFAULT_BINDINGS), is(nullValue()));
}
/**
* @see DATACMNS-669
*/
@Test
public void resolveArgumentShouldCreateSingleStringParameterPredicateCorrectly() throws Exception {
values.add("firstname", "Oliver");
Predicate predicate = builder.getPredicate(USER_TYPE, values, DEFAULT_BINDINGS);
assertThat(predicate, is((Predicate) QUser.user.firstname.eq("Oliver")));
List<User> result = CollQueryFactory.from(QUser.user, Users.USERS).where(predicate).list(QUser.user);
assertThat(result, hasSize(1));
assertThat(result, hasItem(Users.OLIVER));
}
/**
* @see DATACMNS-669
*/
@Test
public void resolveArgumentShouldCreateNestedStringParameterPredicateCorrectly() throws Exception {
values.add("address.city", "Linz");
Predicate predicate = builder.getPredicate(USER_TYPE, values, DEFAULT_BINDINGS);
assertThat(predicate, is((Predicate) QUser.user.address.city.eq("Linz")));
List<User> result = CollQueryFactory.from(QUser.user, Users.USERS).where(predicate).list(QUser.user);
assertThat(result, hasSize(1));
assertThat(result, hasItem(Users.CHRISTOPH));
}
/**
* @see DATACMNS-669
*/
@Test
public void ignoresNonDomainTypeProperties() {
values.add("firstname", "rand");
values.add("lastname".toUpperCase(), "al'thor");
Predicate predicate = builder.getPredicate(USER_TYPE, values, DEFAULT_BINDINGS);
assertThat(predicate, is((Predicate) QUser.user.firstname.eq("rand")));
}
/**
* @see DATACMNS-669
*/
@Test
public void forwardsNullForEmptyParameterToSingleValueBinder() {
values.add("lastname", null);
QuerydslBindings bindings = new QuerydslBindings();
bindings.bind(QUser.user.lastname).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return value == null ? null : path.contains(value);
}
});
builder.getPredicate(USER_TYPE, values, bindings);
}
}