Skip to content

Commit

Permalink
Add generic DB dialect (#44)
Browse files Browse the repository at this point in the history
* Add generic DB Dialect

* Use generic dialect as fallback

---------

Co-authored-by: kaklakariada <[email protected]>
Co-authored-by: kaklakariada <[email protected]>
  • Loading branch information
3 people authored Jan 4, 2025
1 parent c9b7f8d commit f00bce7
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [PR #41](https://github.com/itsallcode/simple-jdbc/pull/41): Allow direct access to `PreparedStatement` for batch insert
- [PR #42](https://github.com/itsallcode/simple-jdbc/pull/42): Allow direct access to `Connection`
- [PR #43](https://github.com/itsallcode/simple-jdbc/pull/43): Allow direct access to `Connection` from `DbOperations`
- [PR #44](https://github.com/itsallcode/simple-jdbc/pull/44): Add `GenericDialect` for unsupported databases

## [0.9.0] - 2024-12-23

Expand Down
10 changes: 9 additions & 1 deletion src/main/java/org/itsallcode/jdbc/DbDialectFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@

import java.util.ServiceLoader;
import java.util.ServiceLoader.Provider;
import java.util.logging.Logger;

import org.itsallcode.jdbc.dialect.DbDialect;
import org.itsallcode.jdbc.dialect.GenericDialect;

class DbDialectFactory {

private static final Logger LOG = Logger.getLogger(DbDialectFactory.class.getName());

public DbDialect createDialect(final String url) {
final ServiceLoader<DbDialect> serviceLoader = ServiceLoader.load(DbDialect.class,
Thread.currentThread().getContextClassLoader());
return serviceLoader.stream()
.map(Provider::get)
.filter(dialect -> dialect.supportsUrl(url))
.findAny()
.orElseThrow(() -> new IllegalStateException("No DB dialect registered for JDBC URL '" + url + "'"));
.orElseGet(() -> {
LOG.warning(() -> "No dialect found for URL '%s', using generic dialect.".formatted(url));
return GenericDialect.INSTANCE;
});
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/itsallcode/jdbc/DbOperations.java
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ <T> SimpleResultSet<T> query(final String sql, final PreparedStatementSetter pre
*
* @return original wrapped connection
*/
public Connection getOriginalConnection();
Connection getOriginalConnection();

@Override
void close();
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/org/itsallcode/jdbc/dialect/GenericDialect.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.itsallcode.jdbc.dialect;

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

/**
* A generic {@link DbDialect} without any special handling.
*/
public final class GenericDialect implements DbDialect {
/** Singleton instance of the generic DB dialect. */
public static final DbDialect INSTANCE = new GenericDialect();

private GenericDialect() {
// Nothing to do
}

@Override
public boolean supportsUrl(final String jdbcUrl) {
return true;
}

@Override
public ColumnValueExtractor createExtractor(final ColumnMetaData column) {
return Extractors.generic();
}

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

import static org.assertj.core.api.Assertions.assertThat;

import org.itsallcode.jdbc.dialect.*;
import org.junit.jupiter.api.Test;

class DbDialectFactoryTest {
@Test
void exasolDialect() {
assertThat(new DbDialectFactory().createDialect("jdbc:exa:localhost:8563;schema=SCHEMA"))
.isInstanceOf(ExasolDialect.class);
}

@Test
void h2Dialect() {
assertThat(new DbDialectFactory().createDialect("jdbc:h2:mem:"))
.isInstanceOf(H2Dialect.class);
}

@Test
void genericDialect() {
assertThat(new DbDialectFactory().createDialect("jdbc:unknown:localhost:8563;schema=SCHEMA"))
.isInstanceOf(GenericDialect.class);
}
}
46 changes: 46 additions & 0 deletions src/test/java/org/itsallcode/jdbc/dialect/GenericDialectITest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.itsallcode.jdbc.dialect;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;
import java.util.stream.Stream;

import org.h2.jdbcx.JdbcDataSource;
import org.itsallcode.jdbc.*;
import org.itsallcode.jdbc.resultset.ContextRowMapper;
import org.itsallcode.jdbc.resultset.generic.Row;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

class GenericDialectITest {

static Stream<Arguments> types() {
return Stream.of(
Arguments.of(1),
Arguments.of("a"),
Arguments.of(1.0),
Arguments.of(true),
Arguments.of((Object) null));
}

@ParameterizedTest
@MethodSource("types")
void setGet(final Object value) {
try (SimpleConnection connection = genericDialectConnection()) {
final List<Row> result = connection
.query("select ?", asList(value), ContextRowMapper.generic(GenericDialect.INSTANCE)).toList();
assertThat(result)
.hasSize(1)
.first().extracting(row -> row.get(0).getValue())
.isEqualTo(value);
}
}

private SimpleConnection genericDialectConnection() {
final JdbcDataSource dataSource = new JdbcDataSource();
dataSource.setURL(H2TestFixture.H2_MEM_JDBC_URL);
return DataSourceConnectionFactory.create(GenericDialect.INSTANCE, dataSource).getConnection();
}
}
2 changes: 1 addition & 1 deletion src/test/resources/logging.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ handlers=java.util.logging.ConsoleHandler
.level=INFO
java.util.logging.ConsoleHandler.level=ALL
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=%1$tF %1$tT.%1$tL [%4$-7s] %5$s %n
java.util.logging.SimpleFormatter.format=%1$tF %1$tT.%1$tL [%4$-7s] %2$s %5$s %n
org.itsallcode.level=ALL

0 comments on commit f00bce7

Please sign in to comment.