de.chojo.sadu.mapper.DefaultMapper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sadu-mapper Show documentation
Show all versions of sadu-mapper Show documentation
SADU module to map values received from a database to java objects using the queries module.
The newest version!
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* Copyright (C) RainbowDashLabs and Contributor
*/
package de.chojo.sadu.mapper;
import de.chojo.sadu.core.exceptions.ThrowingBiFunction;
import de.chojo.sadu.core.types.SqlType;
import de.chojo.sadu.mapper.rowmapper.RowMapper;
import de.chojo.sadu.mapper.util.Results;
import de.chojo.sadu.mapper.wrapper.Row;
import java.math.BigDecimal;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import static de.chojo.sadu.mapper.reader.StandardReader.UUID_FROM_BYTES;
import static de.chojo.sadu.mapper.reader.StandardReader.UUID_FROM_STRING;
public final class DefaultMapper {
private DefaultMapper() {
throw new UnsupportedOperationException("This is a utility class.");
}
public static RowMapper createShort(List types) {
return create(Short.class, Row::getShort, types);
}
public static RowMapper createInteger(List types) {
return create(Integer.class, Row::getInt, types);
}
public static RowMapper createLong(List types) {
return create(Long.class, Row::getLong, types);
}
public static RowMapper createFloat(List types) {
return create(Float.class, Row::getFloat, types);
}
public static RowMapper createDouble(List types) {
return create(Double.class, Row::getDouble, types);
}
public static RowMapper createBigDecimal(List types) {
return create(BigDecimal.class, Row::getBigDecimal, types);
}
public static RowMapper createString(List types) {
return create(String.class, Row::getString, types);
}
public static RowMapper createBoolean(List types) {
return create(Boolean.class, Row::getBoolean, types);
}
public static RowMapper createBytes(List types) {
return create(Byte[].class, (row, columnIndex) -> convertByteArray(row.getBytes(columnIndex)), types);
}
public static RowMapper createUuid(List textTypes, List byteTypes) {
return RowMapper.forClass(java.util.UUID.class)
.mapper(row -> {
var meta = row.getMetaData();
var columnIndexOfType = Results.getFirstColumnIndexOfType(meta, textTypes);
if (columnIndexOfType.isPresent()) {
return row.get(columnIndexOfType.get(), UUID_FROM_STRING);
}
columnIndexOfType = Results.getFirstColumnIndexOfType(meta, byteTypes);
var index = columnIndexOfType.orElseThrow(() -> {
List sqlTypes = new ArrayList<>(textTypes);
sqlTypes.addAll(byteTypes);
return createException(sqlTypes, meta);
});
return row.get(index, UUID_FROM_BYTES);
})
.build();
}
public static RowMapper create(Class clazz, ThrowingBiFunction mapper, List types) {
return RowMapper.forClass(clazz)
.mapper(row -> {
var meta = row.getMetaData();
var columnIndexOfType = Results.getFirstColumnIndexOfType(meta, types);
var index = columnIndexOfType.orElseThrow(() -> createException(types, meta));
return mapper.apply(row, index);
}).build();
}
private static SQLException createException(List types, ResultSetMetaData meta) {
var type = types.stream()
.map(SqlType::descr)
.collect(Collectors.joining(", "));
var available = "error";
try {
available = getColumnTypes(meta).entrySet().stream()
.map(e -> "%s : %s".formatted(e.getKey(), e.getValue()))
.collect(Collectors.joining(", "));
} catch (SQLException e) {
// ignore
}
return new SQLException("No column of type %s present. Available: %s".formatted(type, available));
}
private static Map getColumnTypes(ResultSetMetaData meta) throws SQLException {
Map columns = new LinkedHashMap<>();
for (var i = 1; i <= meta.getColumnCount(); i++) {
columns.put(
"%s | %s".formatted(i, meta.getColumnLabel(i)),
"%s (%s)".formatted(meta.getColumnTypeName(i), meta.getColumnType(i)));
}
return columns;
}
private static Byte[] convertByteArray(byte[] primBytes) {
var bytes = new Byte[primBytes.length];
Arrays.setAll(bytes, n -> primBytes[n]);
return bytes;
}
}