#289 - Add support for Criteria composition.
We now support composition of Criteria objects to create a Criteria from one or more top-level criteria and to compose nested AND/OR Criteria objects:
Criteria.where("name").is("Foo")).and(Criteria.where("name").is("Bar").or("age")
.lessThan(49).or(Criteria.where("name").not("Bar").and("age").greaterThan(49))
Original pull request: #307.
This commit is contained in:
committed by
Jens Schauder
parent
b3d00022d5
commit
0e5a584277
@@ -88,7 +88,7 @@ class DefaultStatementMapper implements StatementMapper {
|
||||
BindMarkers bindMarkers = this.dialect.getBindMarkersFactory().create();
|
||||
Bindings bindings = Bindings.empty();
|
||||
|
||||
if (selectSpec.getCriteria() != null) {
|
||||
if (!selectSpec.getCriteria().isEmpty()) {
|
||||
|
||||
BoundCondition mappedObject = this.updateMapper.getMappedObject(bindMarkers, selectSpec.getCriteria(), table,
|
||||
entity);
|
||||
@@ -203,7 +203,7 @@ class DefaultStatementMapper implements StatementMapper {
|
||||
|
||||
Update update;
|
||||
|
||||
if (updateSpec.getCriteria() != null) {
|
||||
if (!updateSpec.getCriteria().isEmpty()) {
|
||||
|
||||
BoundCondition boundCondition = this.updateMapper.getMappedObject(bindMarkers, updateSpec.getCriteria(), table,
|
||||
entity);
|
||||
@@ -237,7 +237,7 @@ class DefaultStatementMapper implements StatementMapper {
|
||||
Bindings bindings = Bindings.empty();
|
||||
|
||||
Delete delete;
|
||||
if (deleteSpec.getCriteria() != null) {
|
||||
if (!deleteSpec.getCriteria().isEmpty()) {
|
||||
|
||||
BoundCondition boundCondition = this.updateMapper.getMappedObject(bindMarkers, deleteSpec.getCriteria(), table,
|
||||
entity);
|
||||
|
||||
@@ -185,7 +185,7 @@ public interface StatementMapper {
|
||||
private final Table table;
|
||||
private final List<String> projectedFields;
|
||||
private final List<Expression> selectList;
|
||||
private final @Nullable Criteria criteria;
|
||||
private final Criteria criteria;
|
||||
private final Sort sort;
|
||||
private final long offset;
|
||||
private final int limit;
|
||||
@@ -219,7 +219,7 @@ public interface StatementMapper {
|
||||
* @since 1.1
|
||||
*/
|
||||
public static SelectSpec create(SqlIdentifier table) {
|
||||
return new SelectSpec(Table.create(table), Collections.emptyList(), Collections.emptyList(), null,
|
||||
return new SelectSpec(Table.create(table), Collections.emptyList(), Collections.emptyList(), Criteria.empty(),
|
||||
Sort.unsorted(), -1, -1);
|
||||
}
|
||||
|
||||
@@ -463,9 +463,9 @@ public interface StatementMapper {
|
||||
@Nullable
|
||||
private final Update update;
|
||||
|
||||
private final @Nullable Criteria criteria;
|
||||
private final Criteria criteria;
|
||||
|
||||
protected UpdateSpec(SqlIdentifier table, @Nullable Update update, @Nullable Criteria criteria) {
|
||||
protected UpdateSpec(SqlIdentifier table, @Nullable Update update, Criteria criteria) {
|
||||
|
||||
this.table = table;
|
||||
this.update = update;
|
||||
@@ -490,7 +490,7 @@ public interface StatementMapper {
|
||||
* @since 1.1
|
||||
*/
|
||||
public static UpdateSpec create(SqlIdentifier table, Update update) {
|
||||
return new UpdateSpec(table, update, null);
|
||||
return new UpdateSpec(table, update, Criteria.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -512,7 +512,6 @@ public interface StatementMapper {
|
||||
return this.update;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Criteria getCriteria() {
|
||||
return this.criteria;
|
||||
}
|
||||
@@ -525,9 +524,9 @@ public interface StatementMapper {
|
||||
|
||||
private final SqlIdentifier table;
|
||||
|
||||
private final @Nullable Criteria criteria;
|
||||
private final Criteria criteria;
|
||||
|
||||
protected DeleteSpec(SqlIdentifier table, @Nullable Criteria criteria) {
|
||||
protected DeleteSpec(SqlIdentifier table, Criteria criteria) {
|
||||
this.table = table;
|
||||
this.criteria = criteria;
|
||||
}
|
||||
@@ -550,7 +549,7 @@ public interface StatementMapper {
|
||||
* @since 1.1
|
||||
*/
|
||||
public static DeleteSpec create(SqlIdentifier table) {
|
||||
return new DeleteSpec(table, null);
|
||||
return new DeleteSpec(table, Criteria.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -567,7 +566,6 @@ public interface StatementMapper {
|
||||
return this.table;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Criteria getCriteria() {
|
||||
return this.criteria;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ package org.springframework.data.r2dbc.query;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
@@ -27,33 +29,106 @@ import org.springframework.util.Assert;
|
||||
* Central class for creating queries. It follows a fluent API style so that you can easily chain together multiple
|
||||
* criteria. Static import of the {@code Criteria.property(…)} method will improve readability as in
|
||||
* {@code where(property(…).is(…)}.
|
||||
* <p>
|
||||
* The Criteria API supports composition with a {@link #empty() NULL object} and a {@link #from(List) static factory
|
||||
* method}. Example usage:
|
||||
*
|
||||
* <pre class="code">
|
||||
* Criteria.from(Criteria.where("name").is("Foo"), Criteria.from(Criteria.where("age").greaterThan(42)));
|
||||
* </pre>
|
||||
*
|
||||
* rendering:
|
||||
*
|
||||
* <pre class="code">
|
||||
* WHERE name = 'Foo' AND age > 42
|
||||
* </pre>
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
public class Criteria {
|
||||
|
||||
private static final Criteria EMPTY = new Criteria(SqlIdentifier.EMPTY, Comparator.INITIAL, null);
|
||||
|
||||
private final @Nullable Criteria previous;
|
||||
private final Combinator combinator;
|
||||
private final List<Criteria> group;
|
||||
|
||||
private final SqlIdentifier column;
|
||||
private final Comparator comparator;
|
||||
private final @Nullable SqlIdentifier column;
|
||||
private final @Nullable Comparator comparator;
|
||||
private final @Nullable Object value;
|
||||
|
||||
private Criteria(SqlIdentifier column, Comparator comparator, @Nullable Object value) {
|
||||
this(null, Combinator.INITIAL, column, comparator, value);
|
||||
this(null, Combinator.INITIAL, Collections.emptyList(), column, comparator, value);
|
||||
}
|
||||
|
||||
private Criteria(@Nullable Criteria previous, Combinator combinator, SqlIdentifier column, Comparator comparator,
|
||||
@Nullable Object value) {
|
||||
private Criteria(@Nullable Criteria previous, Combinator combinator, List<Criteria> group,
|
||||
@Nullable SqlIdentifier column, @Nullable Comparator comparator, @Nullable Object value) {
|
||||
|
||||
this.previous = previous;
|
||||
this.combinator = combinator;
|
||||
this.combinator = previous != null && previous.isEmpty() ? Combinator.INITIAL : combinator;
|
||||
this.group = group;
|
||||
this.column = column;
|
||||
this.comparator = comparator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private Criteria(@Nullable Criteria previous, Combinator combinator, List<Criteria> group) {
|
||||
|
||||
this.previous = previous;
|
||||
this.combinator = previous != null && previous.isEmpty() ? Combinator.INITIAL : combinator;
|
||||
this.group = group;
|
||||
this.column = null;
|
||||
this.comparator = null;
|
||||
this.value = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method to create an empty Criteria.
|
||||
*
|
||||
* @return an empty {@link Criteria}.
|
||||
* @since 1.1
|
||||
*/
|
||||
public static Criteria empty() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Criteria} and combine it as group with {@code AND} using the provided {@link List Criterias}.
|
||||
*
|
||||
* @return new {@link Criteria}.
|
||||
* @since 1.1
|
||||
*/
|
||||
public static Criteria from(Criteria... criteria) {
|
||||
|
||||
Assert.notNull(criteria, "Criteria must not be null");
|
||||
Assert.noNullElements(criteria, "Criteria must not contain null elements");
|
||||
|
||||
return from(Arrays.asList(criteria));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Criteria} and combine it as group with {@code AND} using the provided {@link List Criterias}.
|
||||
*
|
||||
* @return new {@link Criteria}.
|
||||
* @since 1.1
|
||||
*/
|
||||
public static Criteria from(List<Criteria> criteria) {
|
||||
|
||||
Assert.notNull(criteria, "Criteria must not be null");
|
||||
Assert.noNullElements(criteria, "Criteria must not contain null elements");
|
||||
|
||||
if (criteria.isEmpty()) {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
if (criteria.size() == 1) {
|
||||
return criteria.get(0);
|
||||
}
|
||||
|
||||
return EMPTY.and(criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method to create a Criteria using the provided {@code column} name.
|
||||
*
|
||||
@@ -77,14 +152,43 @@ public class Criteria {
|
||||
|
||||
Assert.hasText(column, "Column name must not be null or empty!");
|
||||
|
||||
return new DefaultCriteriaStep(SqlIdentifier.unquoted(column)) {
|
||||
SqlIdentifier identifier = SqlIdentifier.unquoted(column);
|
||||
return new DefaultCriteriaStep(identifier) {
|
||||
@Override
|
||||
protected Criteria createCriteria(Comparator comparator, Object value) {
|
||||
return new Criteria(Criteria.this, Combinator.AND, SqlIdentifier.unquoted(column), comparator, value);
|
||||
return new Criteria(Criteria.this, Combinator.AND, Collections.emptyList(), identifier, comparator, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Criteria} and combine it as group with {@code AND} using the provided {@link Criteria} group.
|
||||
*
|
||||
* @param criteria criteria object.
|
||||
* @return a new {@link Criteria} object.
|
||||
* @since 1.1
|
||||
*/
|
||||
public Criteria and(Criteria criteria) {
|
||||
|
||||
Assert.notNull(criteria, "Criteria must not be null!");
|
||||
|
||||
return and(Collections.singletonList(criteria));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Criteria} and combine it as group with {@code AND} using the provided {@link Criteria} group.
|
||||
*
|
||||
* @param criteria criteria objects.
|
||||
* @return a new {@link Criteria} object.
|
||||
* @since 1.1
|
||||
*/
|
||||
public Criteria and(List<Criteria> criteria) {
|
||||
|
||||
Assert.notNull(criteria, "Criteria must not be null!");
|
||||
|
||||
return new Criteria(Criteria.this, Combinator.AND, criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Criteria} and combine it with {@code OR} using the provided {@code column} name.
|
||||
*
|
||||
@@ -95,14 +199,43 @@ public class Criteria {
|
||||
|
||||
Assert.hasText(column, "Column name must not be null or empty!");
|
||||
|
||||
return new DefaultCriteriaStep(SqlIdentifier.unquoted(column)) {
|
||||
SqlIdentifier identifier = SqlIdentifier.unquoted(column);
|
||||
return new DefaultCriteriaStep(identifier) {
|
||||
@Override
|
||||
protected Criteria createCriteria(Comparator comparator, Object value) {
|
||||
return new Criteria(Criteria.this, Combinator.OR, SqlIdentifier.unquoted(column), comparator, value);
|
||||
return new Criteria(Criteria.this, Combinator.OR, Collections.emptyList(), identifier, comparator, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Criteria} and combine it as group with {@code OR} using the provided {@link Criteria} group.
|
||||
*
|
||||
* @param criteria criteria object.
|
||||
* @return a new {@link Criteria} object.
|
||||
* @since 1.1
|
||||
*/
|
||||
public Criteria or(Criteria criteria) {
|
||||
|
||||
Assert.notNull(criteria, "Criteria must not be null!");
|
||||
|
||||
return or(Collections.singletonList(criteria));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Criteria} and combine it as group with {@code OR} using the provided {@link Criteria} group.
|
||||
*
|
||||
* @param criteria criteria object.
|
||||
* @return a new {@link Criteria} object.
|
||||
* @since 1.1
|
||||
*/
|
||||
public Criteria or(List<Criteria> criteria) {
|
||||
|
||||
Assert.notNull(criteria, "Criteria must not be null!");
|
||||
|
||||
return new Criteria(Criteria.this, Combinator.OR, criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the previous {@link Criteria} object. Can be {@literal null} if there is no previous {@link Criteria}.
|
||||
* @see #hasPrevious()
|
||||
@@ -119,6 +252,56 @@ public class Criteria {
|
||||
return previous != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if this {@link Criteria} is empty.
|
||||
* @since 1.1
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
|
||||
if (!doIsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Criteria parent = this.previous;
|
||||
|
||||
while (parent != null) {
|
||||
|
||||
if (!parent.doIsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
parent = parent.previous;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean doIsEmpty() {
|
||||
|
||||
if (this.comparator == Comparator.INITIAL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.column != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Criteria criteria : group) {
|
||||
if (!criteria.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if this {@link Criteria} is empty.
|
||||
*/
|
||||
boolean isGroup() {
|
||||
return !this.group.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link Combinator} to combine this criteria with a previous one.
|
||||
*/
|
||||
@@ -126,9 +309,14 @@ public class Criteria {
|
||||
return combinator;
|
||||
}
|
||||
|
||||
List<Criteria> getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the column/property name.
|
||||
*/
|
||||
@Nullable
|
||||
SqlIdentifier getColumn() {
|
||||
return column;
|
||||
}
|
||||
@@ -136,6 +324,7 @@ public class Criteria {
|
||||
/**
|
||||
* @return {@link Comparator}.
|
||||
*/
|
||||
@Nullable
|
||||
Comparator getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
@@ -149,7 +338,7 @@ public class Criteria {
|
||||
}
|
||||
|
||||
enum Comparator {
|
||||
EQ, NEQ, LT, LTE, GT, GTE, IS_NULL, IS_NOT_NULL, LIKE, NOT_IN, IN,
|
||||
INITIAL, EQ, NEQ, LT, LTE, GT, GTE, IS_NULL, IS_NOT_NULL, LIKE, NOT_IN, IN,
|
||||
}
|
||||
|
||||
enum Combinator {
|
||||
@@ -240,13 +429,11 @@ public class Criteria {
|
||||
|
||||
/**
|
||||
* Creates a {@link Criteria} using {@code IS NULL}.
|
||||
*
|
||||
*/
|
||||
Criteria isNull();
|
||||
|
||||
/**
|
||||
* Creates a {@link Criteria} using {@code IS NOT NULL}.
|
||||
*
|
||||
*/
|
||||
Criteria isNotNull();
|
||||
}
|
||||
|
||||
@@ -195,9 +195,22 @@ public class QueryMapper {
|
||||
Assert.notNull(criteria, "Criteria must not be null!");
|
||||
Assert.notNull(table, "Table must not be null!");
|
||||
|
||||
Criteria current = criteria;
|
||||
MutableBindings bindings = new MutableBindings(markers);
|
||||
|
||||
if (criteria.isEmpty()) {
|
||||
throw new IllegalArgumentException("Cannot map empty Criteria");
|
||||
}
|
||||
|
||||
Condition mapped = unroll(criteria, table, entity, bindings);
|
||||
|
||||
return new BoundCondition(bindings, mapped);
|
||||
}
|
||||
|
||||
private Condition unroll(Criteria criteria, Table table, @Nullable RelationalPersistentEntity<?> entity,
|
||||
MutableBindings bindings) {
|
||||
|
||||
Criteria current = criteria;
|
||||
|
||||
// reverse unroll criteria chain
|
||||
Map<Criteria, Criteria> forwardChain = new HashMap<>();
|
||||
|
||||
@@ -210,25 +223,83 @@ public class QueryMapper {
|
||||
Condition mapped = getCondition(current, bindings, table, entity);
|
||||
while (forwardChain.containsKey(current)) {
|
||||
|
||||
Criteria nextCriteria = forwardChain.get(current);
|
||||
Criteria criterion = forwardChain.get(current);
|
||||
Condition result = null;
|
||||
|
||||
if (nextCriteria.getCombinator() == Combinator.AND) {
|
||||
mapped = mapped.and(getCondition(nextCriteria, bindings, table, entity));
|
||||
Condition condition = getCondition(criterion, bindings, table, entity);
|
||||
if (condition != null) {
|
||||
result = combine(criterion, mapped, criterion.getCombinator(), condition);
|
||||
}
|
||||
|
||||
if (nextCriteria.getCombinator() == Combinator.OR) {
|
||||
mapped = mapped.or(getCondition(nextCriteria, bindings, table, entity));
|
||||
if (result != null) {
|
||||
mapped = result;
|
||||
}
|
||||
|
||||
current = nextCriteria;
|
||||
current = criterion;
|
||||
}
|
||||
|
||||
return new BoundCondition(bindings, mapped);
|
||||
if (mapped == null) {
|
||||
throw new IllegalStateException("Cannot map empty Criteria");
|
||||
}
|
||||
|
||||
return mapped;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Condition unrollGroup(List<Criteria> criteria, Table table, Combinator combinator,
|
||||
@Nullable RelationalPersistentEntity<?> entity, MutableBindings bindings) {
|
||||
|
||||
Condition mapped = null;
|
||||
for (Criteria criterion : criteria) {
|
||||
|
||||
if (criterion.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Condition condition = unroll(criterion, table, entity, bindings);
|
||||
|
||||
mapped = combine(criterion, mapped, combinator, condition);
|
||||
}
|
||||
|
||||
return mapped;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Condition getCondition(Criteria criteria, MutableBindings bindings, Table table,
|
||||
@Nullable RelationalPersistentEntity<?> entity) {
|
||||
|
||||
if (criteria.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (criteria.isGroup()) {
|
||||
|
||||
Condition condition = unrollGroup(criteria.getGroup(), table, criteria.getCombinator(), entity, bindings);
|
||||
|
||||
return condition == null ? null : Conditions.nest(condition);
|
||||
}
|
||||
|
||||
return mapCondition(criteria, bindings, table, entity);
|
||||
}
|
||||
|
||||
private Condition combine(Criteria criteria, @Nullable Condition currentCondition, Combinator combinator,
|
||||
Condition nextCondition) {
|
||||
|
||||
if (currentCondition == null) {
|
||||
currentCondition = nextCondition;
|
||||
} else if (combinator == Combinator.AND) {
|
||||
currentCondition = currentCondition.and(nextCondition);
|
||||
} else if (combinator == Combinator.OR) {
|
||||
currentCondition = currentCondition.or(nextCondition);
|
||||
} else {
|
||||
throw new IllegalStateException("Combinator " + criteria.getCombinator() + " not supported");
|
||||
}
|
||||
|
||||
return currentCondition;
|
||||
}
|
||||
|
||||
private Condition mapCondition(Criteria criteria, MutableBindings bindings, Table table,
|
||||
@Nullable RelationalPersistentEntity<?> entity) {
|
||||
|
||||
Field propertyField = createPropertyField(entity, criteria.getColumn(), this.mappingContext);
|
||||
Column column = table.column(propertyField.getMappedColumnName());
|
||||
TypeInformation<?> actualType = propertyField.getTypeHint().getRequiredActualType();
|
||||
|
||||
@@ -32,6 +32,27 @@ import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
*/
|
||||
public class CriteriaUnitTests {
|
||||
|
||||
@Test // gh-289
|
||||
public void fromCriteria() {
|
||||
|
||||
Criteria nested1 = where("foo").isNotNull();
|
||||
Criteria nested2 = where("foo").isNull();
|
||||
Criteria criteria = Criteria.from(nested1, nested2);
|
||||
|
||||
assertThat(criteria.isGroup()).isTrue();
|
||||
assertThat(criteria.getGroup()).containsExactly(nested1, nested2);
|
||||
assertThat(criteria.getPrevious()).isEqualTo(Criteria.empty());
|
||||
}
|
||||
|
||||
@Test // gh-289
|
||||
public void fromCriteriaOptimized() {
|
||||
|
||||
Criteria nested = where("foo").is("bar").and("baz").isNotNull();
|
||||
Criteria criteria = Criteria.from(nested);
|
||||
|
||||
assertThat(criteria).isSameAs(nested);
|
||||
}
|
||||
|
||||
@Test // gh-64
|
||||
public void andChainedCriteria() {
|
||||
|
||||
@@ -50,6 +71,23 @@ public class CriteriaUnitTests {
|
||||
assertThat(criteria.getValue()).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test // gh-289
|
||||
public void andGroupedCriteria() {
|
||||
|
||||
Criteria criteria = where("foo").is("bar").and(where("foo").is("baz"));
|
||||
|
||||
assertThat(criteria.isGroup()).isTrue();
|
||||
assertThat(criteria.getGroup()).hasSize(1);
|
||||
assertThat(criteria.getGroup().get(0).getColumn()).isEqualTo(SqlIdentifier.unquoted("foo"));
|
||||
assertThat(criteria.getCombinator()).isEqualTo(Combinator.AND);
|
||||
|
||||
criteria = criteria.getPrevious();
|
||||
|
||||
assertThat(criteria.getColumn()).isEqualTo(SqlIdentifier.unquoted("foo"));
|
||||
assertThat(criteria.getComparator()).isEqualTo(Comparator.EQ);
|
||||
assertThat(criteria.getValue()).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test // gh-64
|
||||
public void orChainedCriteria() {
|
||||
|
||||
@@ -64,6 +102,23 @@ public class CriteriaUnitTests {
|
||||
assertThat(criteria.getValue()).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test // gh-289
|
||||
public void orGroupedCriteria() {
|
||||
|
||||
Criteria criteria = where("foo").is("bar").or(where("foo").is("baz"));
|
||||
|
||||
assertThat(criteria.isGroup()).isTrue();
|
||||
assertThat(criteria.getGroup()).hasSize(1);
|
||||
assertThat(criteria.getGroup().get(0).getColumn()).isEqualTo(SqlIdentifier.unquoted("foo"));
|
||||
assertThat(criteria.getCombinator()).isEqualTo(Combinator.OR);
|
||||
|
||||
criteria = criteria.getPrevious();
|
||||
|
||||
assertThat(criteria.getColumn()).isEqualTo(SqlIdentifier.unquoted("foo"));
|
||||
assertThat(criteria.getComparator()).isEqualTo(Comparator.EQ);
|
||||
assertThat(criteria.getValue()).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test // gh-64
|
||||
public void shouldBuildEqualsCriteria() {
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.domain.Sort.Order.*;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -45,6 +47,74 @@ public class QueryMapperUnitTests {
|
||||
QueryMapper mapper = new QueryMapper(PostgresDialect.INSTANCE, converter);
|
||||
BindTarget bindTarget = mock(BindTarget.class);
|
||||
|
||||
@Test // gh-289
|
||||
public void shouldNotMapEmptyCriteria() {
|
||||
|
||||
Criteria criteria = Criteria.empty();
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> map(criteria));
|
||||
}
|
||||
|
||||
@Test // gh-289
|
||||
public void shouldNotMapEmptyAndCriteria() {
|
||||
|
||||
Criteria criteria = Criteria.empty().and(Collections.emptyList());
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> map(criteria));
|
||||
}
|
||||
|
||||
@Test // gh-289
|
||||
public void shouldNotMapEmptyNestedCriteria() {
|
||||
|
||||
Criteria criteria = Criteria.empty().and(Collections.emptyList()).and(Criteria.empty().and(Criteria.empty()));
|
||||
|
||||
assertThat(criteria.isEmpty()).isTrue();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> map(criteria));
|
||||
}
|
||||
|
||||
@Test // gh-289
|
||||
public void shouldMapSomeNestedCriteria() {
|
||||
|
||||
Criteria criteria = Criteria.empty().and(Collections.emptyList())
|
||||
.and(Criteria.empty().and(Criteria.where("name").is("Hank")));
|
||||
|
||||
assertThat(criteria.isEmpty()).isFalse();
|
||||
|
||||
BoundCondition bindings = map(criteria);
|
||||
|
||||
assertThat(bindings.getCondition().toString()).isEqualTo("((person.name = ?[$1]))");
|
||||
}
|
||||
|
||||
@Test // gh-289
|
||||
public void shouldMapNestedGroup() {
|
||||
|
||||
Criteria initial = Criteria.empty();
|
||||
|
||||
Criteria criteria = initial.and(Criteria.where("name").is("Foo")).and(Criteria.where("name").is("Bar").or("age")
|
||||
.lessThan(49).or(Criteria.where("name").not("Bar").and("age").greaterThan(49)));
|
||||
|
||||
assertThat(criteria.isEmpty()).isFalse();
|
||||
|
||||
BoundCondition bindings = map(criteria);
|
||||
|
||||
assertThat(bindings.getCondition().toString()).isEqualTo(
|
||||
"(person.name = ?[$1]) AND (person.name = ?[$2] OR person.age < ?[$3] OR (person.name != ?[$4] AND person.age > ?[$5]))");
|
||||
}
|
||||
|
||||
@Test // gh-289
|
||||
public void shouldMapFrom() {
|
||||
|
||||
Criteria criteria = Criteria.from(Criteria.where("name").is("Foo"))
|
||||
.and(Criteria.where("name").is("Bar").or("age").lessThan(49));
|
||||
|
||||
assertThat(criteria.isEmpty()).isFalse();
|
||||
|
||||
BoundCondition bindings = map(criteria);
|
||||
|
||||
assertThat(bindings.getCondition().toString())
|
||||
.isEqualTo("person.name = ?[$1] AND (person.name = ?[$2] OR person.age < ?[$3])");
|
||||
}
|
||||
|
||||
@Test // gh-64
|
||||
public void shouldMapSimpleCriteria() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user