InternalUtils.java

/*
 * Copyright 2025-present 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
 *
 * https://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 io.github.simplejdbcmapper.core;

import java.sql.Types;
import java.util.Locale;

import org.springframework.jdbc.core.StatementCreatorUtils;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.support.SqlBinaryValue;
import org.springframework.jdbc.core.support.SqlCharacterValue;
import org.springframework.util.StringUtils;

import io.github.simplejdbcmapper.exception.MapperException;

/**
 * Utility methods used by mapper.
 *
 * @author Antony Joseph
 */
class InternalUtils {
	public static Integer javaTypeToSqlParameterType(Class<?> type) {
		if (type.isEnum()) {
			return Types.VARCHAR;
		} else {
			// use springs default mappings.
			return StatementCreatorUtils.javaTypeToSqlParameterType(type);
		}
	}

	public static void assignBlobMapSqlParameterSource(MapSqlParameterSource mapSqlParameterSource, Object val,
			String paramName, Integer columnSqlType) {
		if (val == null) {
			mapSqlParameterSource.addValue(paramName, null, columnSqlType);
		} else if (val instanceof byte[] byteArray) {
			mapSqlParameterSource.addValue(paramName, new SqlBinaryValue(byteArray), columnSqlType);
		} else {
			throw new MapperException(val.getClass().getSimpleName() + " " + paramName
					+ " : java type has to be byte[] for a BLOB mapping. No other type is supported.");
		}
	}

	public static void assignClobMapSqlParameterSource(MapSqlParameterSource mapSqlParameterSource, Object val,
			String paramName, Integer columnSqlType) {
		if (val == null) {
			mapSqlParameterSource.addValue(paramName, null, columnSqlType);
		} else if (val instanceof String str) {
			mapSqlParameterSource.addValue(paramName, new SqlCharacterValue(str), columnSqlType);
		} else {
			throw new MapperException(val.getClass().getSimpleName() + "." + paramName
					+ " : java type has to be String for a CLOB mapping. No other type is supported");
		}
	}

	/**
	 * Converts camel case to underscore case. Ex: userLastName gets converted to
	 * user_last_name. Copy of code from Spring BeanPropertyRowMapper
	 *
	 * @param str camel case string
	 * @return the underscore case string
	 */
	public static String toUnderscoreName(String str) {
		if (!StringUtils.hasText(str)) {
			return "";
		}
		StringBuilder result = new StringBuilder();
		result.append(Character.toLowerCase(str.charAt(0)));
		for (int i = 1; i < str.length(); i++) {
			char c = str.charAt(i);
			if (Character.isUpperCase(c)) {
				result.append('_').append(Character.toLowerCase(c));
			} else {
				result.append(c);
			}
		}
		return result.toString();
	}

	public static String toLowerCase(String str) {
		if (!StringUtils.hasLength(str)) {
			return "";
		}
		return str.toLowerCase(Locale.US);
	}

	public static boolean isAlphanumericPlusUnderscore(String str) {
		return str != null && str.matches("^[a-zA-Z0-9_]*$");
	}

	public static void validateTableAlias(String tableAlias) {
		if (!StringUtils.hasText(tableAlias)) {
			throw new IllegalArgumentException("tableAlias has no value");
		}
		if (isAlphanumericPlusUnderscore(tableAlias)) {
			if (!Character.isLetter(tableAlias.charAt(0)) && tableAlias.charAt(0) != '_') {
				throw new IllegalArgumentException("tableAlias should start with an alphabet or underscore.");
			}
		} else {
			throw new IllegalArgumentException("tableAlias should be alphanumberic and can include underscore.");
		}
	}

	private InternalUtils() {
	}
}