DATACMNS-1258 - Polishing.

Moved newly introduced types into the ….data.repository.query package as the parser one contains types that parses queries from method names. Simplified the API surface by hiding SpelExtractor completely and making the API on SpelQueryContext more convenient to directly create a SpelEvaluator.
This commit is contained in:
Oliver Gierke
2018-05-14 16:46:50 +02:00
parent 1fdf77aed7
commit 495b1f30bb
8 changed files with 528 additions and 414 deletions

View File

@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.repository.query.parser;
package org.springframework.data.repository.query;
import static org.assertj.core.api.Assertions.*;
import org.assertj.core.api.SoftAssertions;
import org.junit.Test;
import org.springframework.data.repository.query.SpelQueryContext.QuotationMap;
/**
* Unit tests for {@link QuotationMap}.
@@ -41,7 +42,9 @@ public class QuotationMapUnitTests {
@Test // DATAJPA-1235
public void simpleStringDoesNotContainQuotes() {
String query = "something";
isNotQuoted(query, "simple String", -1, 0, query.length() - 1, query.length(), query.length() + 1);
}
@@ -49,6 +52,7 @@ public class QuotationMapUnitTests {
public void fullySingleQuotedStringDoesContainQuotes() {
String query = "'something'";
isNotQuoted(query, "quoted String", -1, query.length());
isQuoted(query, "quoted String", 0, 1, 5, query.length() - 1);
}
@@ -57,6 +61,7 @@ public class QuotationMapUnitTests {
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);
}
@@ -65,6 +70,7 @@ public class QuotationMapUnitTests {
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);
}
@@ -73,6 +79,7 @@ public class QuotationMapUnitTests {
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);
}
@@ -81,6 +88,7 @@ public class QuotationMapUnitTests {
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);
}
@@ -95,11 +103,10 @@ public class QuotationMapUnitTests {
@Test // DATAJPA-1235
public void openEndedQuoteThrowsException() {
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> new QuotationMap("a'b"));
}
private void isNotQuoted(String query, Object label, int... indexes) {
private static void isNotQuoted(String query, Object label, int... indexes) {
QuotationMap quotationMap = new QuotationMap(query);
@@ -111,14 +118,15 @@ public class QuotationMapUnitTests {
}
}
private void isQuoted(String query, Object label, int... indexes) {
private static 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();
.describedAs(String.format("(%s) %s does contain a quote at %s", label, query, index)) //
.isTrue();
}
}
}

View File

@@ -0,0 +1,116 @@
/*
* 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.repository.query;
import static org.assertj.core.api.Assertions.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import org.assertj.core.api.SoftAssertions;
import org.assertj.core.groups.Tuple;
import org.junit.Test;
import org.springframework.data.repository.query.SpelQueryContext.SpelExtractor;
/**
* Unit tests for {@link SpelExtractor}.
*
* @author Jens Schauder
* @author Oliver Gierke
*/
public class SpelExtractorUnitTests {
static final BiFunction<Integer, String, String> PARAMETER_NAME_SOURCE = (index, spel) -> "EPP" + index;
static final BiFunction<String, String, String> REPLACEMENT_SOURCE = (prefix, name) -> prefix + name;
final SoftAssertions softly = new SoftAssertions();
@Test // DATACMNS-1258
public void nullQueryThrowsException() {
SpelQueryContext context = SpelQueryContext.of(PARAMETER_NAME_SOURCE, REPLACEMENT_SOURCE);
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> context.parse(null));
}
@Test // DATACMNS-1258
public void emptyStringGetsParsedCorrectly() {
SpelQueryContext context = SpelQueryContext.of(PARAMETER_NAME_SOURCE, REPLACEMENT_SOURCE);
SpelExtractor extractor = context.parse("");
softly.assertThat(extractor.getQueryString()).isEqualTo("");
softly.assertThat(extractor.getParameterMap()).isEmpty();
softly.assertAll();
}
@Test // DATACMNS-1258
public void findsAndReplacesExpressions() {
SpelQueryContext context = SpelQueryContext.of(PARAMETER_NAME_SOURCE, REPLACEMENT_SOURCE);
SpelExtractor extractor = context.parse(":#{one} ?#{two}");
softly.assertThat(extractor.getQueryString()).isEqualTo(":EPP0 ?EPP1");
softly.assertThat(extractor.getParameterMap().entrySet()) //
.extracting(Map.Entry::getKey, Map.Entry::getValue) //
.containsExactlyInAnyOrder( //
Tuple.tuple("EPP0", "one"), //
Tuple.tuple("EPP1", "two") //
);
softly.assertAll();
}
@Test // DATACMNS-1258
public void keepsStringWhenNoMatchIsFound() {
SpelQueryContext context = SpelQueryContext.of(PARAMETER_NAME_SOURCE, REPLACEMENT_SOURCE);
SpelExtractor extractor = context.parse("abcdef");
softly.assertThat(extractor.getQueryString()).isEqualTo("abcdef");
softly.assertThat(extractor.getParameterMap()).isEmpty();
softly.assertAll();
}
@Test // DATACMNS-1258
public void spelsInQuotesGetIgnored() {
List<String> queries = Arrays.asList(//
"a'b:#{one}cd'ef", //
"a'b:#{o'ne}cdef", //
"ab':#{one}'cdef", //
"ab:'#{one}cd'ef", //
"ab:#'{one}cd'ef", //
"a'b:#{o'ne}cdef");
queries.forEach(this::checkNoSpelIsFound);
softly.assertAll();
}
private void checkNoSpelIsFound(String query) {
SpelQueryContext context = SpelQueryContext.of(PARAMETER_NAME_SOURCE, REPLACEMENT_SOURCE);
SpelExtractor extractor = context.parse(query);
softly.assertThat(extractor.getQueryString()).describedAs(query).isEqualTo(query);
softly.assertThat(extractor.getParameterMap()).describedAs(query).isEmpty();
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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.repository.query;
import static org.assertj.core.api.Assertions.*;
import java.util.function.BiFunction;
import org.junit.Test;
/**
* Unit tests for {@link SpelQueryContext}.
*
* @author Oliver Gierke
* @author Jens Schauder
*/
public class SpelQueryContextUnitTests {
static final QueryMethodEvaluationContextProvider EVALUATION_CONTEXT_PROVIDER = QueryMethodEvaluationContextProvider.DEFAULT;
static final BiFunction<Integer, String, String> PARAMETER_NAME_SOURCE = (index, spel) -> "EPP" + index;
static final BiFunction<String, String, String> REPLACEMENT_SOURCE = (prefix, name) -> prefix + name;
@Test // DATACMNS-1258
public void nullParameterNameSourceThrowsException() {
assertThatExceptionOfType(IllegalArgumentException.class) //
.isThrownBy(() -> SpelQueryContext.of(null, REPLACEMENT_SOURCE));
}
@Test // DATACMNS-1258
public void nullReplacementSourceThrowsException() {
assertThatExceptionOfType(IllegalArgumentException.class) //
.isThrownBy(() -> SpelQueryContext.of(PARAMETER_NAME_SOURCE, null));
}
@Test // DATACMNS-1258
public void rejectsNullEvaluationContextProvider() {
SpelQueryContext context = SpelQueryContext.of(PARAMETER_NAME_SOURCE, REPLACEMENT_SOURCE);
assertThatExceptionOfType(IllegalArgumentException.class) //
.isThrownBy(() -> context.withEvaluationContextProvider(null));
}
@Test // DATACMNS-1258
public void createsEvaluatingContextUsingProvider() {
SpelQueryContext context = SpelQueryContext.of(PARAMETER_NAME_SOURCE, REPLACEMENT_SOURCE);
assertThat(context.withEvaluationContextProvider(EVALUATION_CONTEXT_PROVIDER)).isNotNull();
}
}

View File

@@ -1,145 +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.repository.query.parser;
import static org.assertj.core.api.Assertions.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import org.assertj.core.api.SoftAssertions;
import org.assertj.core.groups.Tuple;
import org.junit.Test;
/**
* Unit tests for {@link SpelQueryContext} and
* {@link org.springframework.data.repository.query.parser.SpelQueryContext.SpelExtractor}
*
* @author Jens Schauder
*/
public class SpelExtractorUnitTests {
static final String EXPRESSION_PARAMETER_PREFIX = "EPP";
static final BiFunction<Integer, String, String> PARAMETER_NAME_SOURCE = (index, spel) -> EXPRESSION_PARAMETER_PREFIX + index;
static final BiFunction<String, String, String> REPLACEMENT_SOURCE = (prefix, name) -> prefix + name;
final SoftAssertions softly = new SoftAssertions();
@Test // DATACMNS-1258
public void nullQueryThrowsException() {
assertThatExceptionOfType(IllegalArgumentException.class) //
.isThrownBy(() -> new SpelQueryContext( //
PARAMETER_NAME_SOURCE, //
REPLACEMENT_SOURCE) //
.parse(null) //
);
}
@Test // DATACMNS-1258
public void nullParameterNameSourceThrowsException() {
assertThatExceptionOfType(IllegalArgumentException.class) //
.isThrownBy(() -> new SpelQueryContext( //
null, //
REPLACEMENT_SOURCE) //
);
}
@Test // DATACMNS-1258
public void nullReplacementSourceThrowsException() {
assertThatExceptionOfType(IllegalArgumentException.class) //
.isThrownBy( //
() -> new SpelQueryContext( //
PARAMETER_NAME_SOURCE, //
null) //
);
}
@Test // DATACMNS-1258
public void emptyStringGetsParsedCorrectly() {
SpelQueryContext.SpelExtractor extractor = new SpelQueryContext( //
PARAMETER_NAME_SOURCE, //
REPLACEMENT_SOURCE //
).parse("");
softly.assertThat(extractor.query()).isEqualTo("");
softly.assertThat(extractor.parameterNameToSpelMap()).isEmpty();
softly.assertAll();
}
@Test // DATACMNS-1258
public void findsAndReplacesExpressions() {
SpelQueryContext.SpelExtractor extractor = new SpelQueryContext( //
PARAMETER_NAME_SOURCE, //
REPLACEMENT_SOURCE //
).parse(":#{one} ?#{two}");
softly.assertThat(extractor.query()).isEqualTo(":EPP0 ?EPP1");
softly.assertThat(extractor.parameterNameToSpelMap().entrySet()) //
.extracting(Map.Entry::getKey, Map.Entry::getValue) //
.containsExactlyInAnyOrder( //
Tuple.tuple("EPP0", "one"), //
Tuple.tuple("EPP1", "two") //
);
softly.assertAll();
}
@Test // DATACMNS-1258
public void keepsStringWhenNoMatchIsFound() {
SpelQueryContext.SpelExtractor extractor = new SpelQueryContext( //
PARAMETER_NAME_SOURCE, //
REPLACEMENT_SOURCE //
).parse("abcdef");
softly.assertThat(extractor.query()).isEqualTo("abcdef");
softly.assertThat(extractor.parameterNameToSpelMap()).isEmpty();
softly.assertAll();
}
@Test // DATACMNS-1258
public void spelsInQuotesGetIgnored() {
List<String> queries = Arrays.asList("a'b:#{one}cd'ef", "a'b:#{o'ne}cdef", "ab':#{one}'cdef", "ab:'#{one}cd'ef",
"ab:#'{one}cd'ef", "a'b:#{o'ne}cdef");
for (String query : queries) {
checkNoSpelIsFound(query);
}
softly.assertAll();
}
private void checkNoSpelIsFound(String query) {
SpelQueryContext.SpelExtractor extractor = new SpelQueryContext( //
PARAMETER_NAME_SOURCE, //
REPLACEMENT_SOURCE //
).parse(query);
softly.assertThat(extractor.query()).describedAs(query).isEqualTo(query);
softly.assertThat(extractor.parameterNameToSpelMap()).describedAs(query).isEmpty();
}
}