/* * Copyright 2013-2017 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.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.util.List; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.data.jpa.repository.query.StringQuery.InParameterBinding; import org.springframework.data.jpa.repository.query.StringQuery.LikeParameterBinding; import org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding; import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.parser.Part.Type; /** * Unit tests for {@link StringQuery}. * * @author Oliver Gierke * @author Thomas Darimont */ public class StringQueryUnitTests { public @Rule ExpectedException exception = ExpectedException.none(); @Test // DATAJPA-341 public void doesNotConsiderPlainLikeABinding() { String source = "select from User u where u.firstname like :firstname"; StringQuery query = new StringQuery(source); assertThat(query.hasParameterBindings(), is(true)); assertThat(query.getQueryString(), is(source)); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(1)); LikeParameterBinding binding = (LikeParameterBinding) bindings.get(0); assertThat(binding.getType(), is(Type.LIKE)); assertThat(binding.hasName("firstname"), is(true)); } @Test public void detectsPositionalLikeBindings() { StringQuery query = new StringQuery("select u from User u where u.firstname like %?1% or u.lastname like %?2"); assertThat(query.hasParameterBindings(), is(true)); assertThat(query.getQueryString(), is("select u from User u where u.firstname like ?1 or u.lastname like ?2")); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(2)); LikeParameterBinding binding = (LikeParameterBinding) bindings.get(0); assertThat(binding, is(notNullValue())); assertThat(binding.hasPosition(1), is(true)); assertThat(binding.getType(), is(Type.CONTAINING)); binding = (LikeParameterBinding) bindings.get(1); assertThat(binding, is(notNullValue())); assertThat(binding.hasPosition(2), is(true)); assertThat(binding.getType(), is(Type.ENDING_WITH)); } @Test public void detectsNamedLikeBindings() { StringQuery query = new StringQuery("select u from User u where u.firstname like %:firstname"); assertThat(query.hasParameterBindings(), is(true)); assertThat(query.getQueryString(), is("select u from User u where u.firstname like :firstname")); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(1)); LikeParameterBinding binding = (LikeParameterBinding) bindings.get(0); assertThat(binding, is(notNullValue())); assertThat(binding.hasName("firstname"), is(true)); assertThat(binding.getType(), is(Type.ENDING_WITH)); } @Test // DATAJPA-461 public void detectsNamedInParameterBindings() { String queryString = "select u from User u where u.id in :ids"; StringQuery query = new StringQuery(queryString); assertThat(query.hasParameterBindings(), is(true)); assertThat(query.getQueryString(), is(queryString)); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(1)); assertNamedBinding(InParameterBinding.class, "ids", bindings.get(0)); } @Test // DATAJPA-461 public void detectsMultipleNamedInParameterBindings() { String queryString = "select u from User u where u.id in :ids and u.name in :names and foo = :bar"; StringQuery query = new StringQuery(queryString); assertThat(query.hasParameterBindings(), is(true)); assertThat(query.getQueryString(), is(queryString)); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(3)); assertNamedBinding(InParameterBinding.class, "ids", bindings.get(0)); assertNamedBinding(InParameterBinding.class, "names", bindings.get(1)); assertNamedBinding(ParameterBinding.class, "bar", bindings.get(2)); } @Test // DATAJPA-461 public void detectsPositionalInParameterBindings() { String queryString = "select u from User u where u.id in ?1"; StringQuery query = new StringQuery(queryString); assertThat(query.hasParameterBindings(), is(true)); assertThat(query.getQueryString(), is(queryString)); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(1)); assertPositionalBinding(InParameterBinding.class, 1, bindings.get(0)); } @Test // DATAJPA-461 public void detectsMultiplePositionalInParameterBindings() { String queryString = "select u from User u where u.id in ?1 and u.names in ?2 and foo = ?3"; StringQuery query = new StringQuery(queryString); assertThat(query.hasParameterBindings(), is(true)); assertThat(query.getQueryString(), is(queryString)); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(3)); assertPositionalBinding(InParameterBinding.class, 1, bindings.get(0)); assertPositionalBinding(InParameterBinding.class, 2, bindings.get(1)); assertPositionalBinding(ParameterBinding.class, 3, bindings.get(2)); } @Test // DATAJPA-373 public void handlesMultipleNamedLikeBindingsCorrectly() { new StringQuery("select u from User u where u.firstname like %:firstname or foo like :bar"); } @Test(expected = IllegalArgumentException.class) // DATAJPA-292, DATAJPA-362 public void rejectsDifferentBindingsForRepeatedParameter() { new StringQuery("select u from User u where u.firstname like %?1 and u.lastname like ?1%"); } @Test // DATAJPA-461 public void treatsGreaterThanBindingAsSimpleBinding() { StringQuery query = new StringQuery("select u from User u where u.createdDate > ?1"); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(1)); assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0)); } @Test // DATAJPA-473 public void removesLikeBindingsFromQueryIfQueryContainsSimpleBinding() { StringQuery query = new StringQuery("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"); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(2)); assertNamedBinding(LikeParameterBinding.class, "escapedWord", bindings.get(0)); assertNamedBinding(ParameterBinding.class, "word", bindings.get(1)); assertThat(query.getQueryString(), is("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")); } @Test // DATAJPA-483 public void detectsInBindingWithParentheses() { StringQuery query = new StringQuery("select count(we) from MyEntity we where we.status in (:statuses)"); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(1)); assertNamedBinding(InParameterBinding.class, "statuses", bindings.get(0)); } @Test // DATAJPA-513 public void rejectsNullParameterNameHintingTowardsAtParamForNullParameterName() { StringQuery query = new StringQuery("select x from X"); exception.expect(IllegalArgumentException.class); exception.expectMessage(Param.class.getSimpleName()); query.getBindingFor(null); } @Test // DATAJPA-545 public void detectsInBindingWithSpecialFrenchCharactersInParentheses() { StringQuery query = new StringQuery("select * from MyEntity where abonnés in (:abonnés)"); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(1)); assertNamedBinding(InParameterBinding.class, "abonnés", bindings.get(0)); } @Test // DATAJPA-545 public void detectsInBindingWithSpecialCharactersInParentheses() { StringQuery query = new StringQuery("select * from MyEntity where øre in (:øre)"); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(1)); assertNamedBinding(InParameterBinding.class, "øre", bindings.get(0)); } @Test // DATAJPA-545 public void detectsInBindingWithSpecialAsianCharactersInParentheses() { StringQuery query = new StringQuery("select * from MyEntity where 생일 in (:생일)"); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(1)); assertNamedBinding(InParameterBinding.class, "생일", bindings.get(0)); } @Test // DATAJPA-545 public void detectsInBindingWithSpecialCharactersAndWordCharactersMixedInParentheses() { StringQuery query = new StringQuery("select * from MyEntity where foo in (:ab1babc생일233)"); List<ParameterBinding> bindings = query.getParameterBindings(); assertThat(bindings, hasSize(1)); assertNamedBinding(InParameterBinding.class, "ab1babc생일233", bindings.get(0)); } @Test(expected = IllegalArgumentException.class) // DATAJPA-362 public void rejectsDifferentBindingsForRepeatedParameter2() { new StringQuery("select u from User u where u.firstname like ?1 and u.lastname like %?1"); } @Test // DATAJPA-712 public void shouldReplaceAllNamedExpressionParametersWithInClause() { 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, is("select a from A a where a.b in :__$synthetic$__1 and a.c in :__$synthetic$__2")); } @Test // DATAJPA-712 public void shouldReplaceAllPositionExpressionParametersWithInClause() { 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, is("select a from A a where a.b in ?1 and a.c in ?2")); } @Test // DATAJPA-864 public void detectsConstructorExpressions() { assertThat(new StringQuery("select new Dto(a.foo, a.bar) from A a").hasConstructorExpression(), is(true)); assertThat(new StringQuery("select new Dto (a.foo, a.bar) from A a").hasConstructorExpression(), is(true)); assertThat(new StringQuery("select a from A a").hasConstructorExpression(), is(false)); } /** * @see <a href="download.oracle.com/otn-pub/jcp/persistence-2_1-fr-eval-spec/JavaPersistence.pdf">JPA 2.1 specification, section 4.8</a> */ @Test // DATAJPA-886 public void detectsConstructorExpressionForDefaultConstructor() { // Parentheses required assertThat(new StringQuery("select new Dto() from A a").hasConstructorExpression(), is(true)); assertThat(new StringQuery("select new Dto from A a").hasConstructorExpression(), is(false)); } private void assertPositionalBinding(Class<? extends ParameterBinding> bindingType, Integer position, ParameterBinding expectedBinding) { assertThat(bindingType.isInstance(expectedBinding), is(true)); assertThat(expectedBinding, is(notNullValue())); assertThat(expectedBinding.hasPosition(position), is(true)); } private void assertNamedBinding(Class<? extends ParameterBinding> bindingType, String parameterName, ParameterBinding expectedBinding) { assertThat(bindingType.isInstance(expectedBinding), is(true)); assertThat(expectedBinding, is(notNullValue())); assertThat(expectedBinding.hasName(parameterName), is(true)); } }