DATAJDBC-513 - Polishing.

Add Criteria.toString and Update.toString.
This commit is contained in:
Mark Paluch
2020-03-30 09:51:46 +02:00
parent 15f868120a
commit 6a1ef7d69c
5 changed files with 200 additions and 4 deletions

View File

@@ -18,9 +18,13 @@ package org.springframework.data.relational.core.query;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.data.util.Pair;
import org.springframework.lang.Nullable;
@@ -370,6 +374,128 @@ public class Criteria implements CriteriaDefinition {
return ignoreCase;
}
@Override
public String toString() {
if (isEmpty()) {
return "";
}
StringBuilder builder = new StringBuilder();
unroll(this, builder);
return builder.toString();
}
private void unroll(CriteriaDefinition criteria, StringBuilder stringBuilder) {
CriteriaDefinition current = criteria;
// reverse unroll criteria chain
Map<CriteriaDefinition, CriteriaDefinition> forwardChain = new HashMap<>();
while (current.hasPrevious()) {
forwardChain.put(current.getPrevious(), current);
current = current.getPrevious();
}
// perform the actual mapping
render(current, stringBuilder);
while (forwardChain.containsKey(current)) {
CriteriaDefinition criterion = forwardChain.get(current);
if (criterion.getCombinator() != Combinator.INITIAL) {
stringBuilder.append(' ').append(criterion.getCombinator().name()).append(' ');
}
render(criterion, stringBuilder);
current = criterion;
}
}
private void unrollGroup(List<? extends CriteriaDefinition> criteria, StringBuilder stringBuilder) {
stringBuilder.append("(");
boolean first = true;
for (CriteriaDefinition criterion : criteria) {
if (criterion.isEmpty()) {
continue;
}
if (!first) {
Combinator combinator = criterion.getCombinator() == Combinator.INITIAL ? Combinator.AND
: criterion.getCombinator();
stringBuilder.append(' ').append(combinator.name()).append(' ');
}
unroll(criterion, stringBuilder);
first = false;
}
stringBuilder.append(")");
}
private void render(CriteriaDefinition criteria, StringBuilder stringBuilder) {
if (criteria.isEmpty()) {
return;
}
if (criteria.isGroup()) {
unrollGroup(criteria.getGroup(), stringBuilder);
return;
}
stringBuilder.append(criteria.getColumn().toSql(IdentifierProcessing.NONE)).append(' ')
.append(criteria.getComparator().getComparator());
switch (criteria.getComparator()) {
case BETWEEN:
case NOT_BETWEEN:
Pair<Object, Object> pair = (Pair<Object, Object>) criteria.getValue();
stringBuilder.append(' ').append(pair.getFirst()).append(" AND ").append(pair.getSecond());
break;
case IS_NULL:
case IS_NOT_NULL:
case IS_TRUE:
case IS_FALSE:
break;
case IN:
case NOT_IN:
stringBuilder.append(" (").append(renderValue(criteria.getValue())).append(')');
break;
default:
stringBuilder.append(' ').append(renderValue(criteria.getValue()));
}
}
private static String renderValue(@Nullable Object value) {
if (value instanceof Number) {
return value.toString();
}
if (value instanceof Collection) {
StringJoiner joiner = new StringJoiner(", ");
((Collection<?>) value).forEach(o -> joiner.add(renderValue(o)));
return joiner.toString();
}
if (value != null) {
return String.format("'%s'", value);
}
return "null";
}
/**
* Interface declaring terminal builder methods to build a {@link Criteria}.
*/

View File

@@ -135,6 +135,18 @@ public interface CriteriaDefinition {
}
enum Comparator {
INITIAL, EQ, NEQ, BETWEEN, NOT_BETWEEN, LT, LTE, GT, GTE, IS_NULL, IS_NOT_NULL, LIKE, NOT_LIKE, NOT_IN, IN, IS_TRUE, IS_FALSE
INITIAL(""), EQ("="), NEQ("!="), BETWEEN("BETWEEN"), NOT_BETWEEN("NOT BETWEEN"), LT("<"), LTE("<="), GT(">"), GTE(
">="), IS_NULL("IS NULL"), IS_NOT_NULL("IS NOT NULL"), LIKE(
"LIKE"), NOT_LIKE("NOT LIKE"), NOT_IN("NOT IN"), IN("IN"), IS_TRUE("IS TRUE"), IS_FALSE("IS FALSE");
private final String comparator;
Comparator(String comparator) {
this.comparator = comparator;
}
public String getComparator() {
return comparator;
}
}
}

View File

@@ -18,7 +18,9 @@ package org.springframework.data.relational.core.query;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.StringJoiner;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -105,4 +107,21 @@ public class Update {
return new Update(updates);
}
@Override
public String toString() {
if (getAssignments().isEmpty()) {
return "";
}
StringJoiner joiner = new StringJoiner(", ");
getAssignments().forEach((column, o) -> {
joiner.add(
String.format("%s = %s", column.toSql(IdentifierProcessing.NONE), o instanceof Number ? o : "'" + o + "'"));
});
return "SET " + joiner.toString();
}
}

View File

@@ -44,6 +44,7 @@ public class CriteriaUnitTests {
assertThat(criteria.isGroup()).isTrue();
assertThat(criteria.getGroup()).containsExactly(nested1, nested2);
assertThat(criteria.getPrevious()).isEqualTo(Criteria.empty());
assertThat(criteria).hasToString("(foo IS NOT NULL AND foo IS NULL)");
}
@Test // DATAJDBC-513
@@ -52,7 +53,7 @@ public class CriteriaUnitTests {
Criteria nested = where("foo").is("bar").and("baz").isNotNull();
Criteria criteria = Criteria.from(nested);
assertThat(criteria).isSameAs(nested);
assertThat(criteria).isSameAs(nested).hasToString("foo = 'bar' AND baz IS NOT NULL");
}
@Test // DATAJDBC-513
@@ -98,11 +99,12 @@ public class CriteriaUnitTests {
@Test // DATAJDBC-513
public void andGroupedCriteria() {
Criteria criteria = where("foo").is("bar").and(where("foo").is("baz"));
Criteria grouped = where("foo").is("bar").and(where("foo").is("baz").or("bar").isNotNull());
Criteria criteria = grouped;
assertThat(criteria.isGroup()).isTrue();
assertThat(criteria.getGroup()).hasSize(1);
assertThat(criteria.getGroup().get(0).getColumn()).isEqualTo(SqlIdentifier.unquoted("foo"));
assertThat(criteria.getGroup().get(0).getColumn()).isEqualTo(SqlIdentifier.unquoted("bar"));
assertThat(criteria.getCombinator()).isEqualTo(Criteria.Combinator.AND);
criteria = criteria.getPrevious();
@@ -111,6 +113,8 @@ public class CriteriaUnitTests {
assertThat(criteria.getColumn()).isEqualTo(SqlIdentifier.unquoted("foo"));
assertThat(criteria.getComparator()).isEqualTo(CriteriaDefinition.Comparator.EQ);
assertThat(criteria.getValue()).isEqualTo("bar");
assertThat(grouped).hasToString("foo = 'bar' AND (foo = 'baz' OR bar IS NOT NULL)");
}
@Test // DATAJDBC-513
@@ -184,6 +188,7 @@ public class CriteriaUnitTests {
assertThat(criteria.getColumn()).isEqualTo(SqlIdentifier.unquoted("foo"));
assertThat(criteria.getComparator()).isEqualTo(CriteriaDefinition.Comparator.IN);
assertThat(criteria.getValue()).isEqualTo(Arrays.asList("bar", "baz"));
assertThat(criteria).hasToString("foo IN ('bar', 'baz')");
}
@Test // DATAJDBC-513

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2020 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
*
* https://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.relational.core.query;
import org.junit.Test;
import static org.assertj.core.api.Assertions.*;
/**
* Unit tests for {@link Update}.
*
* @author Mark Paluch
*/
public class UpdateUnitTests {
@Test // DATAJDBC-513
public void shouldRenderUpdateToString() {
assertThat(Update.update("foo", "baz").set("bar", 42)).hasToString("SET foo = 'baz', bar = 42");
}
}