package org.springframework.data.simpledb.query; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import org.junit.Ignore; import org.junit.Test; import org.mockito.Mockito; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameters; import org.springframework.data.simpledb.attributeutil.SimpleDBAttributeConverter; /** * @author cclaudiu */ public class QueryUtilsIndexByQueryTest { private static final String BIND_QUERY = "select * from customer_all WHERE age = ? and email = ? and balance = ?"; @Test public void bindIndexPositionParameters_should_construct_correct_query_with_converted_parameter_values() { final int age = 23; final String email = "asd@g.c"; final float balance = 12.1f; final String convertedAge = SimpleDBAttributeConverter.encode(age); final String convertedBalance = SimpleDBAttributeConverter.encode(balance); String expectedQuery = "select * from customer_all WHERE age = '" + convertedAge + "' and email = '" + email + "' and balance = '" + convertedBalance + "'"; final Parameters parameters = getMockParameters(new String[]{"?","?","?"}, new Class[]{int.class, String.class, float.class}); String resultedQuery = QueryUtils.buildQuery(BIND_QUERY, parameters, age, email, balance); assertThat(resultedQuery, is(expectedQuery)); } @Test public void bindIndexPositionParameters_should_construct_correct_query_for_Date_parameter() { final String bindQueryWithDate = "select * from customer_all WHERE date = ?"; final Date date = new Date(); final String convertedDate = SimpleDBAttributeConverter.encode(date); String expectedQuery = "select * from customer_all WHERE date = '" + convertedDate + "'"; final Parameters parameters = getMockParameters(new String[]{"?"}, new Class[]{Date.class}); String resultedQuery = QueryUtils.buildQuery(bindQueryWithDate, parameters, date); assertThat(resultedQuery, is(expectedQuery)); } @Test public void bindIndexPositionParameters_should_construct_correct_query_for_primitive_array_parameter() { final String bindQueryWithDate = "select * from customer_all WHERE byte_array = ?"; final byte[] byteArray = new byte[] { 1, 2, 5 }; final String convertedByteArray = SimpleDBAttributeConverter.encode(byteArray); String expectedQuery = "select * from customer_all WHERE byte_array = '" + convertedByteArray + "'"; final Parameters parameters = getMockParameters(new String[]{"?"}, new Class[]{byte[].class}); String resultedQuery = QueryUtils.buildQuery(bindQueryWithDate, parameters, byteArray); assertThat(resultedQuery, is(expectedQuery)); } @Test public void bindIndexPositionParameters() { final String bindQueryWithDate = "select * from customer_all WHERE byte_array = ? and c = 4"; int intValue = 5; final String convertedInt = SimpleDBAttributeConverter.encode(intValue); String expectedQuery = "select * from customer_all WHERE byte_array = '" + convertedInt + "' and c = 4"; final Parameters parameters = getMockParameters(new String[]{"?"}, new Class[]{int.class}); String resultedQuery = QueryUtils.buildQuery(bindQueryWithDate, parameters, intValue); assertThat(resultedQuery, is(expectedQuery)); } @Test public void buildQueryConditionsWithParameters_should_construct_correct_bind_query_for_in_operator() { final String bind_query = "select * from customer_all WHERE age in ?"; final long firstAge = 23; final long secondAge = 25; final String convertedFirstAge = SimpleDBAttributeConverter.encode(firstAge); final String convertedSecondAge = SimpleDBAttributeConverter.encode(secondAge); String expectedQuery = "select * from customer_all WHERE age in ('" + convertedFirstAge + "','" + convertedSecondAge + "')"; final Parameters parameters = getMockParameters(new String[] { "?" }, new Class[] { long[].class }); String resultedQuery = QueryUtils.buildQuery(bind_query, parameters, new long[] { firstAge, secondAge }); assertThat(resultedQuery, is(expectedQuery)); } @Test public void buildQueryConditionsWithParameters_should_construct_tricky_query_for_in_operator() { final String bind_query = "select * from customer_all WHERE age in ('1','2') and age=?"; final long firstAge = 23; final String convertedFirstAge = SimpleDBAttributeConverter.encode(firstAge); String expectedQuery = "select * from customer_all WHERE age in ('1','2') and age='" + convertedFirstAge + "'"; final Parameters parameters = getMockParameters(new String[]{"?"}, new Class[]{long.class}); String resultedQuery = QueryUtils.buildQuery(bind_query, parameters, firstAge); assertThat(resultedQuery, is(expectedQuery)); } /** * This test shows that if there is a String containing a '?' character, this character will be recognised as a * index parameter */ @Ignore @Test(expected = MappingException.class) public void buildQueryConditionsWithParameters_should_fail_for_wrong_string() { final String bind_query = "select * from customer_all WHERE name = 'where?' and age=?"; final Parameters parameters = getMockParameters("?"); System.out.println(QueryUtils.buildQuery(bind_query, parameters, 23)); } /** * This test shows that a index parameter should not be in quotes * * @Test(expected = MappingException.class) */ public void buildQueryConditionsWithParameters_should_double_quote_for_already_quoted_parameter() { final String bind_query = "select * from customer_all WHERE name = '?'"; final Parameters parameters = getMockParameters("?"); QueryUtils.buildQuery(bind_query, parameters, 23); } /** * This test shows that if a named param or an index param is used to replace a field name, this will generate an * invalid query because quotes are added surrounding the field name */ @Ignore @Test public void buildQueryConditionsWithParameters_should_construct_The_trickiest_query_for_in_operator() { final String bind_query = "select * from customer_all WHERE ?=?"; final long firstAge = 23; final String convertedFirstAge = SimpleDBAttributeConverter.encode(firstAge); String expectedQuery = "select * from customer_all WHERE name = '" + convertedFirstAge + "'"; final Parameters parameters = getMockParameters("?", "?"); String resultedQuery = QueryUtils.buildQuery(bind_query, parameters, "name", firstAge); assertThat(resultedQuery, is(expectedQuery)); } @Test public void replaceOneParameterInQuery_should_parse_positional_parameters() { final String paramPlaceholder = "\\?"; final String rawQuery = "a = ? AND (`b.c` = ? OR d IN ?) ORDER BY x"; String replacedQuery = QueryUtils.replaceOneParameterInQuery(rawQuery, paramPlaceholder, 0.01F); replacedQuery = QueryUtils.replaceOneParameterInQuery(replacedQuery, paramPlaceholder, "baz"); replacedQuery = QueryUtils.replaceOneParameterInQuery( replacedQuery, paramPlaceholder, new String[] {"foo", "bar"}); assertEquals("a = '" + SimpleDBAttributeConverter.encode(0.01F) + "' AND (`b.c` = 'baz' OR d IN ('foo','bar')) ORDER BY x", replacedQuery); } static final List<Class<?>> TYPES = Arrays.<Class<?>>asList(Pageable.class, Sort.class); @SuppressWarnings({ "rawtypes", "unchecked" }) private Parameter getMockParameter(String placeHolder, Integer idx, Class clazz) { Parameter mockParameter = Mockito.mock(Parameter.class); Mockito.when(mockParameter.getPlaceholder()).thenReturn(placeHolder); Mockito.when(mockParameter.isNamedParameter()).thenReturn(Boolean.FALSE); Mockito.when(mockParameter.getIndex()).thenReturn(idx); Mockito.when(mockParameter.getType()).thenReturn(clazz); Mockito.when(mockParameter.getType()).thenReturn(clazz); Mockito.when(mockParameter.isSpecialParameter()).thenReturn(TYPES.contains(clazz)); return mockParameter; } private Parameters getMockParameters(String... placeHolders) { return getMockParameters(placeHolders, new Class[placeHolders.length]); } @SuppressWarnings({ "rawtypes" }) private Parameters getMockParameters(String[] placeHolders, Class[] clazzes) { Parameters mockParameters = Mockito.mock(Parameters.class); List<Parameter> parameters = new ArrayList<Parameter>(placeHolders.length); for(int idx = 0; idx < placeHolders.length; ++idx) { parameters.add(getMockParameter(placeHolders[idx], idx, clazzes[idx])); } Mockito.when(mockParameters.iterator()).thenReturn(parameters.iterator()); Mockito.when(mockParameters.getNumberOfParameters()).thenReturn(parameters.size()); return mockParameters; } }