package squill.db;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.lang.reflect.Method;
import squill.query.Declaration;
import squill.query.select.Column;
import squill.util.BeanUtil;
import squill.util.ReflectUtils;
import static java.lang.String.format;
/**
* Data conversion helper methods.
*
* @author Juhan Aasaru
* @author Rein Raudjärv
*/
public class DataTypeUtil {
// Writing JDBC statement
/**
* Add arguments (represented as "?" in query) to prepared statement.
*
* @param stmt
* Statement.
* @param params
* @param ctx
*/
public static void setStatementParams(PreparedStatement stmt, List params, final Map<String, ? extends Object> ctx) throws SQLException {
if (params==null || params.isEmpty()) return;
int i = 0;
for (Object param : params) {
i++;
if (param instanceof Declaration) {
param=((Declaration)param).resolve(ctx);
}
setStatementParam(stmt, i, param);
}
}
private static void setStatementParam(PreparedStatement stmt, int i, Object param) throws SQLException {
if (param instanceof BigDecimal) {
stmt.setBigDecimal(i, (BigDecimal) param);
} else if (param instanceof Long) {
stmt.setLong(i, (Long) param);
} else if (param instanceof Integer) {
stmt.setInt(i, (Integer) param);
} else if (param instanceof Date) {
stmt.setDate(i, new java.sql.Date(((Date) param).getTime()));
} else if (param instanceof String) {
stmt.setString(i, param.toString());
} else {
stmt.setObject(i, param);
}
}
// Reading the result set
/**
* Change the datatype to reflect expected format.
*
* @param valueFromDb Value to convert
* @param expectedType Expected type
* @return Value converted into expected datatype
*/
public static <T> T convertIntoExpectedType(Object valueFromDb, Class<T> expectedType) {
if (valueFromDb == null || expectedType.isAssignableFrom(valueFromDb.getClass())) {
return expectedType.cast(valueFromDb);
}
if (Long.class.equals(expectedType) && valueFromDb instanceof Number) {
return expectedType.cast( ((Number) valueFromDb).longValue());
}
if (Integer.class.equals(expectedType) && valueFromDb instanceof Number) {
return expectedType.cast(((Number) valueFromDb).intValue());
}
if (Date.class.equals(expectedType) && valueFromDb instanceof java.sql.Date) {
return expectedType.cast( new Date(((Date) valueFromDb).getTime()));
}
if (String.class.equals(expectedType)) {
return expectedType.cast(valueFromDb.toString());
}
System.out.printf("Warning! Could not convert from %s into %s.",valueFromDb.getClass().getName(),expectedType.getClass().getName());
return expectedType.cast(valueFromDb);
}
/**
* Reads the corresponding value from the result set.
* <p>
* The value could be read from any number of result set columns.
*
* @param rs JDBC result set.
* @return value read from the result set.
*/
public static <T> T readFromResultSet(ResultSet rs, final String columnName, final Class<T> expectedType) throws SQLException {
Object result = rs.getObject(columnName);
if (result == null || expectedType.isInstance(result)) {
return expectedType.cast(result);
}
return convertIntoExpectedType(result, expectedType);
}
/**
* Reads the corresponding value from the result set.
* <p>
* The value could be read from any number of result set columns.
*
* @param rset JDBC result set.
* @return value read from the result set.
*/
@SuppressWarnings({"unchecked"})
public static <T> T readFromResultSet(ResultSet rset, List<Column<?, T>> columns, Class<T> type) throws SQLException {
Map<String, Method> setMethods = BeanUtil.getSetters(type);
Object result = ReflectUtils.typeInstance(type);
for (Column column : columns) {
final Class tableType = column.getTableType();
final Object value = readFromResultSet(rset, column.getAlias(), tableType);
column.set(value);
final String setterName = column.getModelSetterName();
Method setter = setMethods.get(setterName);
if (setter == null) {
throw new SQLException(format("Column %s setter '%s' not found!!!",column,setterName));
} else {
ReflectUtils.setValue(result, setter, value);
}
}
return type.cast(result);
}
}