DATAJPA-1267 - Using SpEL infrastructure from commons.
With DATACMNS-1258 handling of SpEL expressions in queries was moved to SD-Commons. This change now uses that infrastructure and removes the parts no longer necessary in this repository. Original pull request: #250.
This commit is contained in:
committed by
Mark Paluch
parent
e51024e20a
commit
46afc8211c
@@ -22,14 +22,14 @@ import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.data.domain.Range;
|
||||
import org.springframework.data.repository.query.parser.Part.Type;
|
||||
import org.springframework.data.repository.query.parser.QuotationMap;
|
||||
import org.springframework.data.repository.query.parser.SpelQueryContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -54,7 +54,6 @@ class StringQuery implements DeclaredQuery {
|
||||
private final @Nullable String alias;
|
||||
private final boolean hasConstructorExpression;
|
||||
private final boolean containsPageableInSpel;
|
||||
private final boolean usesJdbcStyleParameters;
|
||||
|
||||
/**
|
||||
* Creates a new {@link StringQuery} from the given JPQL query.
|
||||
@@ -68,11 +67,9 @@ class StringQuery implements DeclaredQuery {
|
||||
|
||||
this.bindings = new ArrayList<>();
|
||||
this.containsPageableInSpel = query.contains("#pageable");
|
||||
Metadata queryMeta = new Metadata();
|
||||
this.query = ParameterBindingParser.INSTANCE.parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(query,
|
||||
this.bindings, queryMeta);
|
||||
this.bindings);
|
||||
|
||||
this.usesJdbcStyleParameters = queryMeta.usesJdbcStyleParameters;
|
||||
this.alias = QueryUtils.detectAlias(query);
|
||||
this.hasConstructorExpression = QueryUtils.hasConstructorExpression(query);
|
||||
}
|
||||
@@ -115,7 +112,7 @@ class StringQuery implements DeclaredQuery {
|
||||
*/
|
||||
@Override
|
||||
public boolean usesJdbcStyleParameters() {
|
||||
return usesJdbcStyleParameters;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -178,23 +175,18 @@ class StringQuery implements DeclaredQuery {
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public enum ParameterBindingParser {
|
||||
enum ParameterBindingParser {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__";
|
||||
public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![#\\w]))";
|
||||
// .....................................................................^ not followed by a hash or a letter.
|
||||
// .................................................................^ zero or more digits.
|
||||
// .............................................................^ start with a question mark.
|
||||
private static final Pattern PARAMETER_BINDING_BY_INDEX = Pattern.compile(POSITIONAL_OR_INDEXED_PARAMETER);
|
||||
private static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__";
|
||||
private static final Pattern PARAMETER_BINDING_BY_INDEX = Pattern.compile("\\?(\\d+)");
|
||||
private static final Pattern PARAMETER_BINDING_PATTERN;
|
||||
private static final String MESSAGE = "Already found parameter binding with same index / parameter name but differing binding type! "
|
||||
+ "Already have: %s, found %s! If you bind a parameter multiple times make sure they use the same binding.";
|
||||
public static final int INDEXED_PARAMETER_GROUP = 4;
|
||||
public static final int NAMED_PARAMETER_GROUP = 6;
|
||||
public static final int COMPARISION_TYPE_GROUP = 1;
|
||||
public static final int EXPRESSION_GROUP = 9;
|
||||
private static final int INDEXED_PARAMETER_GROUP = 4;
|
||||
private static final int NAMED_PARAMETER_GROUP = 6;
|
||||
private static final int COMPARISION_TYPE_GROUP = 1;
|
||||
|
||||
static {
|
||||
|
||||
@@ -213,13 +205,12 @@ class StringQuery implements DeclaredQuery {
|
||||
builder.append("(?: )?"); // some whitespace
|
||||
builder.append("\\(?"); // optional braces around parameters
|
||||
builder.append("(");
|
||||
builder.append("%?(" + POSITIONAL_OR_INDEXED_PARAMETER + ")%?"); // position parameter and parameter index
|
||||
builder.append("%?(\\?(\\d+))%?"); // position parameter and parameter index
|
||||
builder.append("|"); // or
|
||||
|
||||
// named parameter and the parameter name
|
||||
builder.append("%?(" + QueryUtils.COLON_NO_DOUBLE_COLON + QueryUtils.IDENTIFIER_GROUP + ")%?");
|
||||
builder.append("|"); // or
|
||||
builder.append("%?((:|\\?)#\\{([^}]+)\\})%?"); // expression parameter and expression
|
||||
|
||||
builder.append(")");
|
||||
builder.append("\\)?"); // optional braces around parameters
|
||||
|
||||
@@ -230,33 +221,17 @@ class StringQuery implements DeclaredQuery {
|
||||
* Parses {@link ParameterBinding} instances from the given query and adds them to the registered bindings. Returns
|
||||
* the cleaned up query.
|
||||
*/
|
||||
String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String query, List<ParameterBinding> bindings,
|
||||
Metadata queryMeta) {
|
||||
private String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String query,
|
||||
List<ParameterBinding> bindings) {
|
||||
|
||||
String result = query;
|
||||
Matcher matcher = PARAMETER_BINDING_PATTERN.matcher(query);
|
||||
SpelQueryContext.SpelExtractor spelExtractor = createSpelExtractor(query);
|
||||
|
||||
int greatestParameterIndex = tryFindGreatestParameterIndexIn(query);
|
||||
String resultingQuery = spelExtractor.query();
|
||||
|
||||
boolean parametersShouldBeAccessedByIndex = greatestParameterIndex != -1;
|
||||
Matcher matcher = PARAMETER_BINDING_PATTERN.matcher(spelExtractor.query());
|
||||
|
||||
/*
|
||||
* Prefer indexed access over named parameters if only SpEL Expression parameters are present.
|
||||
*/
|
||||
if (!parametersShouldBeAccessedByIndex && query.contains("?#{")) {
|
||||
parametersShouldBeAccessedByIndex = true;
|
||||
greatestParameterIndex = 0;
|
||||
}
|
||||
QuotationMap quotationMap = new QuotationMap(spelExtractor.query());
|
||||
|
||||
/*
|
||||
* If parameters need to be bound by index, we bind the synthetic expression parameters starting from position of the greatest discovered index parameter in order to
|
||||
* not mix-up with the actual parameter indices.
|
||||
*/
|
||||
int expressionParameterIndex = parametersShouldBeAccessedByIndex ? greatestParameterIndex : 0;
|
||||
|
||||
QuotationMap quotationMap = new QuotationMap(query);
|
||||
|
||||
boolean usesJpaStyleParameters = false;
|
||||
while (matcher.find()) {
|
||||
|
||||
if (quotationMap.isQuoted(matcher.start())) {
|
||||
@@ -265,51 +240,20 @@ class StringQuery implements DeclaredQuery {
|
||||
|
||||
String parameterIndexString = matcher.group(INDEXED_PARAMETER_GROUP);
|
||||
String parameterName = parameterIndexString != null ? null : matcher.group(NAMED_PARAMETER_GROUP);
|
||||
Integer parameterIndex = getParameterIndex(parameterIndexString);
|
||||
|
||||
Integer parameterIndex = parameterIndexString == null ? null : Integer.valueOf(parameterIndexString);
|
||||
String typeSource = matcher.group(COMPARISION_TYPE_GROUP);
|
||||
String expression = null;
|
||||
String expression = spelExtractor.parameterNameToSpelMap()
|
||||
.get(parameterName == null ? parameterIndexString : parameterName);
|
||||
String replacement = null;
|
||||
|
||||
if (parameterName == null && parameterIndex == null) {
|
||||
Assert.isTrue(parameterIndex != null || parameterName != null, "We need either a name or an index.");
|
||||
|
||||
expressionParameterIndex++;
|
||||
|
||||
if ("".equals(parameterIndexString)) {
|
||||
|
||||
parameterIndex = expressionParameterIndex;
|
||||
queryMeta.usesJdbcStyleParameters = true;
|
||||
} else {
|
||||
|
||||
usesJpaStyleParameters = true;
|
||||
|
||||
if (parametersShouldBeAccessedByIndex) {
|
||||
|
||||
parameterIndex = expressionParameterIndex;
|
||||
replacement = "?" + parameterIndex;
|
||||
} else {
|
||||
|
||||
parameterName = EXPRESSION_PARAMETER_PREFIX + expressionParameterIndex;
|
||||
replacement = ":" + parameterName;
|
||||
}
|
||||
}
|
||||
|
||||
expression = matcher.group(EXPRESSION_GROUP);
|
||||
} else {
|
||||
usesJpaStyleParameters = true;
|
||||
}
|
||||
|
||||
if (usesJpaStyleParameters && queryMeta.usesJdbcStyleParameters) {
|
||||
throw new IllegalArgumentException("Mixing of ? parameters and other forms like ?1 is not supported");
|
||||
}
|
||||
|
||||
String replacementTarget = matcher.group(2);
|
||||
switch (ParameterBindingType.of(typeSource)) {
|
||||
|
||||
case LIKE:
|
||||
|
||||
Type likeType = LikeParameterBinding.getLikeTypeFrom(replacementTarget);
|
||||
replacement = replacement != null ? replacement : matcher.group(3);
|
||||
Type likeType = LikeParameterBinding.getLikeTypeFrom(matcher.group(2));
|
||||
replacement = matcher.group(3);
|
||||
|
||||
if (parameterIndex != null) {
|
||||
checkAndRegister(new LikeParameterBinding(parameterIndex, likeType, expression), bindings);
|
||||
@@ -336,28 +280,48 @@ class StringQuery implements DeclaredQuery {
|
||||
|
||||
bindings.add(parameterIndex != null ? new ParameterBinding(null, parameterIndex, expression)
|
||||
: new ParameterBinding(parameterName, null, expression));
|
||||
|
||||
}
|
||||
|
||||
if (replacement != null) {
|
||||
result = replaceFirst(result, replacementTarget, replacement);
|
||||
resultingQuery = replaceFirst(resultingQuery, matcher.group(2), replacement);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
return resultingQuery;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Integer getParameterIndex(@Nullable String parameterIndexString) {
|
||||
private SpelQueryContext.SpelExtractor createSpelExtractor(String queryWithSpel) {
|
||||
int greatestParameterIndex = tryFindGreatestParameterIndexIn(queryWithSpel);
|
||||
|
||||
if (parameterIndexString == null || parameterIndexString.isEmpty()) {
|
||||
return null;
|
||||
boolean parametersShouldBeAccessedByIndex = greatestParameterIndex != -1;
|
||||
|
||||
/*
|
||||
* Prefer indexed access over named parameters if only SpEL Expression parameters are present.
|
||||
*/
|
||||
if (!parametersShouldBeAccessedByIndex && queryWithSpel.contains("?#{")) {
|
||||
parametersShouldBeAccessedByIndex = true;
|
||||
greatestParameterIndex = 0;
|
||||
}
|
||||
return Integer.valueOf(parameterIndexString);
|
||||
|
||||
/*
|
||||
* If parameters need to be bound by index, we bind the synthetic expression parameters starting from position of the greatest discovered index parameter in order to
|
||||
* not mix-up with the actual parameter indices.
|
||||
*/
|
||||
int expressionParameterIndex = parametersShouldBeAccessedByIndex ? greatestParameterIndex : 0;
|
||||
|
||||
BiFunction<Integer, String, String> indexToParameterName = parametersShouldBeAccessedByIndex
|
||||
? (index, expression) -> String.valueOf(index + expressionParameterIndex + 1)
|
||||
: (index, expression) -> EXPRESSION_PARAMETER_PREFIX + (index + 1);
|
||||
|
||||
String fixedPrefix = parametersShouldBeAccessedByIndex ? "?" : ":";
|
||||
|
||||
BiFunction<String, String, String> parameterNameToReplacement = (prefix, name) -> fixedPrefix + name;
|
||||
|
||||
return new SpelQueryContext(indexToParameterName, parameterNameToReplacement).parse(queryWithSpel);
|
||||
}
|
||||
|
||||
private static String replaceFirst(String text, String substring, String replacement) {
|
||||
private String replaceFirst(String text, String substring, String replacement) {
|
||||
|
||||
int index = text.indexOf(substring);
|
||||
if (index < 0) {
|
||||
@@ -373,18 +337,14 @@ class StringQuery implements DeclaredQuery {
|
||||
|
||||
int greatestParameterIndex = -1;
|
||||
while (parameterIndexMatcher.find()) {
|
||||
|
||||
String parameterIndexString = parameterIndexMatcher.group(1);
|
||||
Integer parameterIndex = getParameterIndex(parameterIndexString);
|
||||
if (parameterIndex != null) {
|
||||
greatestParameterIndex = Math.max(greatestParameterIndex, parameterIndex);
|
||||
}
|
||||
greatestParameterIndex = Math.max(greatestParameterIndex, Integer.parseInt(parameterIndexString));
|
||||
}
|
||||
|
||||
return greatestParameterIndex;
|
||||
}
|
||||
|
||||
private static void checkAndRegister(ParameterBinding binding, List<ParameterBinding> bindings) {
|
||||
private void checkAndRegister(ParameterBinding binding, List<ParameterBinding> bindings) {
|
||||
|
||||
for (ParameterBinding existing : bindings) {
|
||||
if (existing.hasName(binding.getName()) || existing.hasPosition(binding.getPosition())) {
|
||||
@@ -835,63 +795,4 @@ class StringQuery implements DeclaredQuery {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Value object to analyze a String to determine the parts of the String that are quoted and offers an API to query
|
||||
* that information.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 3.0.3
|
||||
*/
|
||||
static class QuotationMap {
|
||||
|
||||
private static final Set<Character> QUOTING_CHARACTERS = new HashSet<>(Arrays.asList('"', '\''));
|
||||
|
||||
private List<Range<Integer>> quotedRanges = new ArrayList<>();
|
||||
|
||||
QuotationMap(@Nullable String query) {
|
||||
|
||||
if (query == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Character inQuotation = null;
|
||||
int start = 0;
|
||||
|
||||
for (int i = 0; i < query.length(); i++) {
|
||||
|
||||
char currentChar = query.charAt(i);
|
||||
|
||||
if (QUOTING_CHARACTERS.contains(currentChar)) {
|
||||
|
||||
if (inQuotation == null) {
|
||||
|
||||
inQuotation = currentChar;
|
||||
start = i;
|
||||
|
||||
} else if (currentChar == inQuotation) {
|
||||
|
||||
inQuotation = null;
|
||||
quotedRanges.add(Range.of(Range.Bound.inclusive(start), Range.Bound.inclusive(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inQuotation != null) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("The string <%s> starts a quoted range at %d, but never ends it.", query, start));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index to check if it is part of a quoted range.
|
||||
* @return whether the query contains a quoted range at {@literal index}.
|
||||
*/
|
||||
public boolean isQuoted(int index) {
|
||||
return quotedRanges.stream().anyMatch(r -> r.contains(index));
|
||||
}
|
||||
}
|
||||
|
||||
static class Metadata {
|
||||
private boolean usesJdbcStyleParameters = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +69,9 @@ public class ParameterBindingParserUnitTests {
|
||||
|
||||
public void checkHasParameter(SoftAssertions softly, String query, boolean containsParameter, String label) {
|
||||
|
||||
List<ParameterBinding> bindings = new ArrayList<>();
|
||||
ParameterBindingParser.INSTANCE.parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(query, bindings,
|
||||
new StringQuery.Metadata());
|
||||
softly.assertThat(bindings.size()) //
|
||||
StringQuery stringQuery = new StringQuery(query);
|
||||
|
||||
softly.assertThat(stringQuery.getParameterBindings().size()) //
|
||||
.describedAs(String.format("<%s> (%s)", query, label)) //
|
||||
.isEqualTo(containsParameter ? 1 : 0);
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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.jpa.repository.query;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.jpa.repository.query.StringQuery.QuotationMap;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link QuotationMap}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public class QuotationMapUnitTests {
|
||||
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
public void emptyStringDoesNotContainQuotes() {
|
||||
isNotQuoted("", "empty String", -1, 0, 1);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
public void nullStringDoesNotContainQuotes() {
|
||||
isNotQuoted(null, "null String", -1, 0, 1);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
public void simpleStringDoesNotContainQuotes() {
|
||||
String query = "something";
|
||||
isNotQuoted(query, "simple String", -1, 0, query.length() - 1, query.length(), query.length() + 1);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
public void fullySingleQuotedStringDoesContainQuotes() {
|
||||
|
||||
String query = "'something'";
|
||||
isNotQuoted(query, "quoted String", -1, query.length());
|
||||
isQuoted(query, "quoted String", 0, 1, 5, query.length() - 1);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
public void fullyDoubleQuotedStringDoesContainQuotes() {
|
||||
|
||||
String query = "\"something\"";
|
||||
isNotQuoted(query, "double quoted String", -1, query.length());
|
||||
isQuoted(query, "double quoted String", 0, 1, 5, query.length() - 1);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
public void stringWithEmptyQuotes() {
|
||||
|
||||
String query = "abc''def";
|
||||
isNotQuoted(query, "zero length quote", -1, 0, 1, 2, 5, 6, 7);
|
||||
isQuoted(query, "zero length quote", 3, 4);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
public void doubleInSingleQuotes() {
|
||||
|
||||
String query = "abc'\"'def";
|
||||
isNotQuoted(query, "double inside single quote", -1, 0, 1, 2, 6, 7, 8);
|
||||
isQuoted(query, "double inside single quote", 3, 4, 5);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
public void singleQuotesInDoubleQuotes() {
|
||||
|
||||
String query = "abc\"'\"def";
|
||||
isNotQuoted(query, "single inside double quote", -1, 0, 1, 2, 6, 7, 8);
|
||||
isQuoted(query, "single inside double quote", 3, 4, 5);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
public void escapedQuotes() {
|
||||
|
||||
String query = "a'b''cd''e'f";
|
||||
isNotQuoted(query, "escaped quote", -1, 0, 11, 12);
|
||||
isQuoted(query, "escaped quote", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
public void openEndedQuoteThrowsException() {
|
||||
|
||||
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> new QuotationMap("a'b"));
|
||||
}
|
||||
|
||||
public void isNotQuoted(String query, Object label, int... indexes) {
|
||||
|
||||
QuotationMap quotationMap = new QuotationMap(query);
|
||||
|
||||
for (int index : indexes) {
|
||||
|
||||
assertThat(quotationMap.isQuoted(index))
|
||||
.describedAs(String.format("(%s) %s does not contain a quote at %s", label, query, index)) //
|
||||
.isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
public void isQuoted(String query, Object label, int... indexes) {
|
||||
|
||||
QuotationMap quotationMap = new QuotationMap(query);
|
||||
|
||||
for (int index : indexes) {
|
||||
|
||||
assertThat(quotationMap.isQuoted(index))
|
||||
.describedAs(String.format("(%s) %s does contain a quote at %s", label, query, index)).isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,8 @@ public class StringQueryUnitTests {
|
||||
|
||||
LikeParameterBinding binding = (LikeParameterBinding) bindings.get(0);
|
||||
assertThat(binding.getType()).isEqualTo(Type.LIKE);
|
||||
assertThat(binding.hasName("firstname")).isEqualTo(true);
|
||||
|
||||
assertThat(binding.hasName("firstname")).isTrue();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-292
|
||||
@@ -114,6 +115,8 @@ public class StringQueryUnitTests {
|
||||
assertThat(bindings).hasSize(1);
|
||||
|
||||
assertNamedBinding(InParameterBinding.class, "ids", bindings.get(0));
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-461
|
||||
@@ -131,6 +134,8 @@ public class StringQueryUnitTests {
|
||||
assertNamedBinding(InParameterBinding.class, "ids", bindings.get(0));
|
||||
assertNamedBinding(InParameterBinding.class, "names", bindings.get(1));
|
||||
assertNamedBinding(ParameterBinding.class, "bar", bindings.get(2));
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-461
|
||||
@@ -146,6 +151,8 @@ public class StringQueryUnitTests {
|
||||
assertThat(bindings).hasSize(1);
|
||||
|
||||
assertPositionalBinding(InParameterBinding.class, 1, bindings.get(0));
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-461
|
||||
@@ -163,6 +170,8 @@ public class StringQueryUnitTests {
|
||||
assertPositionalBinding(InParameterBinding.class, 1, bindings.get(0));
|
||||
assertPositionalBinding(InParameterBinding.class, 2, bindings.get(1));
|
||||
assertPositionalBinding(ParameterBinding.class, 3, bindings.get(2));
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-373
|
||||
@@ -183,6 +192,8 @@ public class StringQueryUnitTests {
|
||||
|
||||
assertThat(bindings).hasSize(1);
|
||||
assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0));
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-473
|
||||
@@ -196,8 +207,12 @@ public class StringQueryUnitTests {
|
||||
assertThat(bindings).hasSize(2);
|
||||
assertNamedBinding(LikeParameterBinding.class, "escapedWord", bindings.get(0));
|
||||
assertNamedBinding(ParameterBinding.class, "word", bindings.get(1));
|
||||
assertThat(query.getQueryString()).isEqualTo("SELECT a FROM Article a WHERE a.overview LIKE :escapedWord ESCAPE '~'"
|
||||
+ " OR a.content LIKE :escapedWord ESCAPE '~' OR a.title = :word ORDER BY a.articleId DESC");
|
||||
|
||||
softly.assertThat(query.getQueryString())
|
||||
.isEqualTo("SELECT a FROM Article a WHERE a.overview LIKE :escapedWord ESCAPE '~'"
|
||||
+ " OR a.content LIKE :escapedWord ESCAPE '~' OR a.title = :word ORDER BY a.articleId DESC");
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-483
|
||||
@@ -209,6 +224,8 @@ public class StringQueryUnitTests {
|
||||
|
||||
assertThat(bindings).hasSize(1);
|
||||
assertNamedBinding(InParameterBinding.class, "statuses", bindings.get(0));
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-545
|
||||
@@ -220,6 +237,8 @@ public class StringQueryUnitTests {
|
||||
|
||||
assertThat(bindings).hasSize(1);
|
||||
assertNamedBinding(InParameterBinding.class, "abonnés", bindings.get(0));
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-545
|
||||
@@ -231,6 +250,8 @@ public class StringQueryUnitTests {
|
||||
|
||||
assertThat(bindings).hasSize(1);
|
||||
assertNamedBinding(InParameterBinding.class, "øre", bindings.get(0));
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-545
|
||||
@@ -242,6 +263,8 @@ public class StringQueryUnitTests {
|
||||
|
||||
assertThat(bindings).hasSize(1);
|
||||
assertNamedBinding(InParameterBinding.class, "생일", bindings.get(0));
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-545
|
||||
@@ -253,6 +276,8 @@ public class StringQueryUnitTests {
|
||||
|
||||
assertThat(bindings).hasSize(1);
|
||||
assertNamedBinding(InParameterBinding.class, "ab1babc생일233", bindings.get(0));
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class) // DATAJPA-362
|
||||
@@ -275,15 +300,21 @@ public class StringQueryUnitTests {
|
||||
StringQuery query = new StringQuery("select a from A a where a.b in ?#{#bs} and a.c in ?#{#cs}");
|
||||
String queryString = query.getQueryString();
|
||||
|
||||
assertThat(queryString).isEqualTo("select a from A a where a.b in ?1 and a.c in ?2");
|
||||
softly.assertThat(queryString).isEqualTo("select a from A a where a.b in ?1 and a.c in ?2");
|
||||
softly.assertThat(query.getParameterBindings().get(0).getExpression()).isEqualTo("#bs");
|
||||
softly.assertThat(query.getParameterBindings().get(1).getExpression()).isEqualTo("#cs");
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-864
|
||||
public void detectsConstructorExpressions() {
|
||||
|
||||
assertThat(new StringQuery("select new Dto(a.foo, a.bar) from A a").hasConstructorExpression()).isTrue();
|
||||
assertThat(new StringQuery("select new Dto (a.foo, a.bar) from A a").hasConstructorExpression()).isTrue();
|
||||
assertThat(new StringQuery("select a from A a").hasConstructorExpression()).isFalse();
|
||||
softly.assertThat(new StringQuery("select new Dto(a.foo, a.bar) from A a").hasConstructorExpression()).isTrue();
|
||||
softly.assertThat(new StringQuery("select new Dto (a.foo, a.bar) from A a").hasConstructorExpression()).isTrue();
|
||||
softly.assertThat(new StringQuery("select a from A a").hasConstructorExpression()).isFalse();
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,8 +325,10 @@ public class StringQueryUnitTests {
|
||||
public void detectsConstructorExpressionForDefaultConstructor() {
|
||||
|
||||
// Parentheses required
|
||||
assertThat(new StringQuery("select new Dto() from A a").hasConstructorExpression()).isTrue();
|
||||
assertThat(new StringQuery("select new Dto from A a").hasConstructorExpression()).isFalse();
|
||||
softly.assertThat(new StringQuery("select new Dto() from A a").hasConstructorExpression()).isTrue();
|
||||
softly.assertThat(new StringQuery("select new Dto from A a").hasConstructorExpression()).isFalse();
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1179
|
||||
@@ -304,12 +337,15 @@ public class StringQueryUnitTests {
|
||||
StringQuery query = new StringQuery("select a from A a where a.first = :#{#exp} or a.second = :#{#exp}");
|
||||
|
||||
List<ParameterBinding> bindings = query.getParameterBindings();
|
||||
assertThat(bindings).isNotEmpty();
|
||||
softly.assertThat(bindings).isNotEmpty();
|
||||
|
||||
for (ParameterBinding binding : bindings) {
|
||||
assertThat(binding.getName()).isNotNull();
|
||||
assertThat(query.getQueryString()).containsSequence(binding.getName());
|
||||
softly.assertThat(binding.getName()).isNotNull();
|
||||
softly.assertThat(query.getQueryString()).contains(binding.getName());
|
||||
softly.assertThat(binding.getExpression()).isEqualTo("#exp");
|
||||
}
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1235
|
||||
@@ -526,16 +562,16 @@ public class StringQueryUnitTests {
|
||||
private void assertPositionalBinding(Class<? extends ParameterBinding> bindingType, Integer position,
|
||||
ParameterBinding expectedBinding) {
|
||||
|
||||
assertThat(bindingType.isInstance(expectedBinding)).isTrue();
|
||||
assertThat(expectedBinding).isNotNull();
|
||||
assertThat(expectedBinding.hasPosition(position)).isTrue();
|
||||
softly.assertThat(bindingType.isInstance(expectedBinding)).isTrue();
|
||||
softly.assertThat(expectedBinding).isNotNull();
|
||||
softly.assertThat(expectedBinding.hasPosition(position)).isTrue();
|
||||
}
|
||||
|
||||
private void assertNamedBinding(Class<? extends ParameterBinding> bindingType, String parameterName,
|
||||
ParameterBinding expectedBinding) {
|
||||
|
||||
assertThat(bindingType.isInstance(expectedBinding)).isTrue();
|
||||
assertThat(expectedBinding).isNotNull();
|
||||
assertThat(expectedBinding.hasName(parameterName)).isTrue();
|
||||
softly.assertThat(bindingType.isInstance(expectedBinding)).isTrue();
|
||||
softly.assertThat(expectedBinding).isNotNull();
|
||||
softly.assertThat(expectedBinding.hasName(parameterName)).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user