Skip to content

Commit

Permalink
Refactor parameter setting
Browse files Browse the repository at this point in the history
  • Loading branch information
kaklakariada committed Oct 20, 2024
1 parent 3d8f2f7 commit 1ce68ad
Show file tree
Hide file tree
Showing 16 changed files with 179 additions and 153 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
/.classpath
/bin/
/.settings/org.eclipse.buildship.core.prefs
/.idea/
10 changes: 0 additions & 10 deletions src/main/java/org/itsallcode/jdbc/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,6 @@ public final class Context {
private Context() {
}

/**
* Get the configured {@link ParameterMapper}.
*
* @return parameter mapper
*/
@SuppressWarnings("java:S2325") // Not-static by intention
public ParameterMapper getParameterMapper() {
return ParameterMapper.create();
}

/**
* Create a new builder for {@link Context} objects.
*
Expand Down
78 changes: 0 additions & 78 deletions src/main/java/org/itsallcode/jdbc/ParameterMapper.java

This file was deleted.

5 changes: 4 additions & 1 deletion src/main/java/org/itsallcode/jdbc/SimpleConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.itsallcode.jdbc.resultset.*;
import org.itsallcode.jdbc.resultset.generic.Row;
import org.itsallcode.jdbc.statement.ConvertingPreparedStatement;
import org.itsallcode.jdbc.statement.ParamSetterProvider;

/**
* A simplified version of a JDBC {@link Connection}. Create new connections
Expand All @@ -22,11 +23,13 @@ public class SimpleConnection implements AutoCloseable {
private final Connection connection;
private final Context context;
private final DbDialect dialect;
private final ParamSetterProvider paramSetterProvider;

SimpleConnection(final Connection connection, final Context context, final DbDialect dialect) {
this.connection = Objects.requireNonNull(connection, "connection");
this.context = Objects.requireNonNull(context, "context");
this.dialect = Objects.requireNonNull(dialect, "dialect");
this.paramSetterProvider = new ParamSetterProvider(dialect);
}

/**
Expand Down Expand Up @@ -102,7 +105,7 @@ SimplePreparedStatement prepareStatement(final String sql) {
}

private PreparedStatement wrap(final PreparedStatement preparedStatement) {
return new ConvertingPreparedStatement(preparedStatement, context.getParameterMapper());
return new ConvertingPreparedStatement(preparedStatement, paramSetterProvider);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.itsallcode.jdbc.dialect;

import java.sql.PreparedStatement;
import java.sql.SQLException;

public interface ColumnValueSetter<T> {

void setObject(PreparedStatement stmt, int parameterIndex, T object) throws SQLException;
}
2 changes: 2 additions & 0 deletions src/main/java/org/itsallcode/jdbc/dialect/DbDialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ public interface DbDialect {
* @return extractor
*/
ColumnValueExtractor createExtractor(final ColumnMetaData column);

<T> ColumnValueSetter<T> createSetter(Class<T> type);
}
20 changes: 20 additions & 0 deletions src/main/java/org/itsallcode/jdbc/dialect/ExasolDialect.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package org.itsallcode.jdbc.dialect;

import java.time.*;
import java.time.format.DateTimeFormatter;

import org.itsallcode.jdbc.resultset.generic.ColumnMetaData;

/**
* Dialect for the Exasol database.
*/
public class ExasolDialect extends AbstractDbDialect {
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
private static final ZoneId UTC_ZONE = ZoneId.of("UTC");

/**
* Create a new instance.
Expand All @@ -24,4 +29,19 @@ public ColumnValueExtractor createExtractor(final ColumnMetaData column) {
default -> Extractors.generic();
};
}

@SuppressWarnings("unchecked")
@Override
public <T> ColumnValueSetter<T> createSetter(final Class<T> type) {
if (type == LocalDate.class) {
return (ColumnValueSetter<T>) Setters.localDateToString();
}
if (type == Instant.class) {
return (ColumnValueSetter<T>) Setters.instantToString(DATE_TIME_FORMATTER, UTC_ZONE);
}
if (type == LocalDateTime.class) {
return (ColumnValueSetter<T>) Setters.localDateTimeToString(DATE_TIME_FORMATTER);
}
return Setters.generic();
}
}
14 changes: 5 additions & 9 deletions src/main/java/org/itsallcode/jdbc/dialect/Extractors.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,22 @@

final class Extractors {

@SuppressWarnings("java:S2143") // Need to use calendar api
private final static Calendar UTC_CALENDAR = Calendar.getInstance(TimeZone.getTimeZone("UTC"));

private Extractors() {
}

static ColumnValueExtractor timestampToUTCInstant() {
final Calendar utcCalendar = createUtcCalendar();
return nonNull((resultSet, columnIndex) -> resultSet.getTimestamp(columnIndex, utcCalendar).toInstant());
return nonNull((resultSet, columnIndex) -> resultSet.getTimestamp(columnIndex, UTC_CALENDAR).toInstant());
}

public static ColumnValueExtractor timestampToInstant() {
return nonNull((resultSet, columnIndex) -> resultSet.getTimestamp(columnIndex).toInstant());
}

static ColumnValueExtractor dateToLocalDate() {
final Calendar utcCalendar = createUtcCalendar();
return nonNull((resultSet, columnIndex) -> resultSet.getDate(columnIndex, utcCalendar).toLocalDate());
}

@SuppressWarnings("java:S2143") // Need to use calendar api
private static Calendar createUtcCalendar() {
return Calendar.getInstance(TimeZone.getTimeZone("UTC"));
return nonNull((resultSet, columnIndex) -> resultSet.getDate(columnIndex, UTC_CALENDAR).toLocalDate());
}

private static ColumnValueExtractor nonNull(final ColumnValueExtractor extractor) {
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/itsallcode/jdbc/dialect/H2Dialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ public ColumnValueExtractor createExtractor(final ColumnMetaData column) {
default -> Extractors.generic();
};
}

@Override
public <T> ColumnValueSetter<T> createSetter(final Class<T> type) {
return Setters.generic();
}
}
30 changes: 30 additions & 0 deletions src/main/java/org/itsallcode/jdbc/dialect/Setters.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.itsallcode.jdbc.dialect;

import java.sql.PreparedStatement;
import java.time.*;
import java.time.format.DateTimeFormatter;

public final class Setters {
private Setters() {
}

public static <T> ColumnValueSetter<T> generic() {
return PreparedStatement::setObject;
}

static ColumnValueSetter<LocalDate> localDateToString() {
return (final PreparedStatement stmt, final int parameterIndex, final LocalDate date) -> stmt
.setString(parameterIndex, date.toString());
}

public static ColumnValueSetter<Instant> instantToString(final DateTimeFormatter dateTimeFormatter,
final ZoneId timeZone) {
return (final PreparedStatement stmt, final int parameterIndex, final Instant instant) -> stmt
.setString(parameterIndex, dateTimeFormatter.format(LocalDateTime.ofInstant(instant, timeZone)));
}

public static ColumnValueSetter<LocalDateTime> localDateTimeToString(final DateTimeFormatter dateTimeFormatter) {
return (final PreparedStatement stmt, final int parameterIndex, final LocalDateTime localDateTime) -> stmt
.setString(parameterIndex, dateTimeFormatter.format(localDateTime));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,31 @@
import java.sql.PreparedStatement;
import java.sql.SQLException;

import org.itsallcode.jdbc.ParameterMapper;

/**
* A {@link PreparedStatement} that delegates all methods and converts parameter
* value of {@link #convert(Object)} using a {@link ParameterMapper}.
*/
public class ConvertingPreparedStatement extends DelegatingPreparedStatement {

private final ParameterMapper parameterMapper;
private final PreparedStatement originalDelegate;
private final ParamSetterProvider paramSetterProvider;

/**
* Create a new instance.
*
* @param delegate delegate
* @param parameterMapper parameter mapper
* @param delegate delegate
* @param paramSetterProvider parameter setter provider
*/
public ConvertingPreparedStatement(final PreparedStatement delegate, final ParameterMapper parameterMapper) {
public ConvertingPreparedStatement(final PreparedStatement delegate,
final ParamSetterProvider paramSetterProvider) {
super(delegate);
this.parameterMapper = parameterMapper;
this.originalDelegate = delegate;
this.paramSetterProvider = paramSetterProvider;
}

@Override
public void setObject(final int parameterIndex, final Object x) throws SQLException {
super.setObject(parameterIndex, convert(x));
}

private Object convert(final Object object) {
return parameterMapper.map(object);
paramSetterProvider.findSetter(x)
.setObject(originalDelegate, parameterIndex, x);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.itsallcode.jdbc.statement;

import java.util.HashMap;
import java.util.Map;

import org.itsallcode.jdbc.dialect.*;

public class ParamSetterProvider {
private static final ColumnValueSetter<Object> GENERIC_SETTER = Setters.generic();
private final DbDialect dialect;
private final Map<Class<?>, ColumnValueSetter<Object>> setters = new HashMap<>();

public ParamSetterProvider(final DbDialect dialect) {
this.dialect = dialect;
}

@SuppressWarnings("unchecked")
ColumnValueSetter<Object> findSetter(final Object object) {
if (object == null) {
return GENERIC_SETTER;
}
return setters.computeIfAbsent(object.getClass(),
type -> (ColumnValueSetter<Object>) dialect.createSetter(type));
}
}
6 changes: 2 additions & 4 deletions src/test/java/org/itsallcode/jdbc/H2TypeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,8 @@ void preparedStatementSetParameter(final TypeTest test) {
try (final SimpleConnection connection = H2TestFixture.createMemConnection();
final SimpleResultSet<Object> result = connection
.query("select ?",
preparedStatement -> preparedStatement.setObject(1,
value),
(resultSet, rowNum) -> resultSet
.getObject(1, value.getClass()))) {
stmt -> stmt.setObject(1, value),
(rs, rowNum) -> rs.getObject(1, value.getClass()))) {
assertThat(result.toList()).containsExactly(value);
}
}
Expand Down
32 changes: 0 additions & 32 deletions src/test/java/org/itsallcode/jdbc/ParameterMapperTest.java

This file was deleted.

Loading

0 comments on commit 1ce68ad

Please sign in to comment.