diff --git a/CHANGELOG.md b/CHANGELOG.md index 7252e37c3..a2a167f1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This log will detail notable changes to MyBatis Dynamic SQL. Full details are av ### Added - Added a new sort specification that is useful in selects with joins ([#269](https://github.com/mybatis/mybatis-dynamic-sql/pull/269)) +- Added the capability to generate a camel cased alias for a column ([#272](https://github.com/mybatis/mybatis-dynamic-sql/issues/272)) ## Release 1.2.1 - September 29, 2020 diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java b/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java index 4fab312c1..0c8cf5de5 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.render.TableAliasCalculator; +import org.mybatis.dynamic.sql.util.StringUtilities; public class SqlColumn implements BindableColumn, SortSpecification { @@ -85,6 +86,22 @@ public SqlColumn as(String alias) { return b.withAlias(alias).build(); } + /** + * Set an alias with a camel cased string based on the column name. The can be useful for queries using + * the {@link org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper} where the columns are placed into + * a map based on the column name returned from the database. + * + *

A camel case string is mixed case, and most databases do not support unquoted mixed case strings + * as identifiers. Therefore the generated alias will be surrounded by double quotes thereby making it a + * quoted identifier. Most databases will respect quoted mixed case identifiers. + * + * @return a new column aliased with a camel case version of the column name + */ + public SqlColumn asCamelCase() { + Builder b = copy(); + return b.withAlias("\"" + StringUtilities.toCamelCase(name) + "\"").build(); //$NON-NLS-1$ //$NON-NLS-2$ + } + @Override public boolean isDescending() { return isDescending; diff --git a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java index d86925855..00f6fea83 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java @@ -40,4 +40,28 @@ static String spaceBefore(String in) { static String safelyUpperCase(String s) { return s == null ? null : s.toUpperCase(); } + + static String toCamelCase(String inputString) { + StringBuilder sb = new StringBuilder(); + + boolean nextUpperCase = false; + + for (int i = 0; i < inputString.length(); i++) { + char c = inputString.charAt(i); + if (Character.isLetterOrDigit(c)) { + if (nextUpperCase) { + sb.append(Character.toUpperCase(c)); + nextUpperCase = false; + } else { + sb.append(Character.toLowerCase(c)); + } + } else { + if (sb.length() > 0) { + nextUpperCase = true; + } + } + } + + return sb.toString(); + } } diff --git a/src/test/java/examples/animal/data/CommonSelectMapperTest.java b/src/test/java/examples/animal/data/CommonSelectMapperTest.java index ca3250a4e..75c60f0d1 100644 --- a/src/test/java/examples/animal/data/CommonSelectMapperTest.java +++ b/src/test/java/examples/animal/data/CommonSelectMapperTest.java @@ -81,15 +81,15 @@ void setup() throws Exception { void testGeneralSelectOne() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { CommonSelectMapper mapper = sqlSession.getMapper(CommonSelectMapper.class); - SelectStatementProvider selectStatement = select(id, animalName) + SelectStatementProvider selectStatement = select(id.asCamelCase(), animalName.asCamelCase()) .from(animalData) .where(id, isEqualTo(1)) .build() .render(RenderingStrategies.MYBATIS3); Map row = mapper.selectOneMappedRow(selectStatement); - assertThat(row).containsEntry("ID", 1); - assertThat(row).containsEntry("ANIMAL_NAME", "Lesser short-tailed shrew"); + assertThat(row).containsEntry("id", 1); + assertThat(row).containsEntry("animalName", "Lesser short-tailed shrew"); } } diff --git a/src/test/java/org/mybatis/dynamic/sql/util/StringUtilitiesTest.java b/src/test/java/org/mybatis/dynamic/sql/util/StringUtilitiesTest.java new file mode 100644 index 000000000..435a82a78 --- /dev/null +++ b/src/test/java/org/mybatis/dynamic/sql/util/StringUtilitiesTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016-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 + * + * 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.mybatis.dynamic.sql.util; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class StringUtilitiesTest { + + @Test + void testInitialUnderscore() { + String input = "_USER"; + assertThat(StringUtilities.toCamelCase(input)).isEqualTo("user"); + } + + @Test + void testSpace() { + String input = "USER NAME"; + assertThat(StringUtilities.toCamelCase(input)).isEqualTo("userName"); + } + + @Test + void testNumeric() { + String input = "USER%NAME%3"; + assertThat(StringUtilities.toCamelCase(input)).isEqualTo("userName3"); + } +}