Skip to content

Commit

Permalink
Merge pull request #13 from itsallcode/convert-legacy-data-types
Browse files Browse the repository at this point in the history
Allow converting legacy types Timestamp & Date
  • Loading branch information
kaklakariada authored Nov 26, 2023
2 parents 16d15ec + 1a64977 commit 89afc36
Show file tree
Hide file tree
Showing 25 changed files with 644 additions and 96 deletions.
19 changes: 14 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ on:
branches: [ main ]

jobs:
build:
matrix-build:
name: Build and test with Java ${{ matrix.java }}
strategy:
matrix:
java: [11, 17, 21]
java: ['17', '21']
env:
DEFAULT_JAVA: 17
DEFAULT_JAVA: '17'
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.java }}
Expand All @@ -39,8 +40,8 @@ jobs:
java-version: ${{ matrix.java }}
cache: 'gradle'

- name: Build with Gradle
run: ./gradlew clean build
- name: Build with Java ${{ matrix.java }}
run: ./gradlew clean build --info -PjavaVersion=${{matrix.java}}

- name: Publish Test Report
uses: scacap/action-surefire-report@v1
Expand All @@ -55,3 +56,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

build:
name: Build and test with all Java versions
needs: matrix-build
runs-on: ubuntu-latest
continue-on-error: false
steps:
- run: echo Build successful
1 change: 1 addition & 0 deletions .settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=ignore
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.source=17
Expand Down
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
"java.saveActions.organizeImports": true,
"java.sources.organizeImports.starThreshold": 3,
"java.sources.organizeImports.staticStarThreshold": 3,
"java.test.config": {
"vmArgs": [
"-Djava.util.logging.config.file=src/main/resources/logging.properties"
]
},
"sonarlint.connectedMode.project": {
"connectionId": "itsallcode",
"projectKey": "org.itsallcode:simple-jdbc"
Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.5.0] - unreleased
## [0.6.0] - unreleased

## [0.5.0] - 2023-11-26

- [PR #13](https://github.com/itsallcode/simple-jdbc/pull/13): Allow converting legacy types Timestamp, Time & Date

## [0.4.0] - 2023-10-21

Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ Wrapper to simplify working with JDBC.

## Usage

This project requires Java 17 or later.

Add dependency to your gradle project:

```gradle
```groovy
dependencies {
implementation 'org.itsallcode:simple-jdbc:0.4.0'
implementation 'org.itsallcode:simple-jdbc:0.5.0'
}
```

Expand Down Expand Up @@ -55,6 +57,7 @@ try (SimpleConnection connection = connectionFactory.create("jdbc:h2:mem:", "use
### Building

Install to local maven repository:

```sh
./gradlew clean publishToMavenLocal
```
Expand Down
72 changes: 55 additions & 17 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
plugins {
id 'java-library'
id 'jvm-test-suite'
id 'jacoco'
id 'jacoco-report-aggregation'
id 'signing'
id 'maven-publish'
id 'org.sonarqube' version '4.4.1.3373'
id "io.github.gradle-nexus.publish-plugin" version "1.3.0"
id 'com.github.ben-manes.versions' version '0.49.0'
}

repositories {
mavenCentral()
id 'com.github.ben-manes.versions' version '0.50.0'
}

group 'org.itsallcode'
version = '0.4.0'
version = '0.5.0'

dependencies {
testImplementation 'org.assertj:assertj-core:3.24.2'
testRuntimeOnly 'com.h2database:h2:2.2.224'
}

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
languageVersion = JavaLanguageVersion.of(getPropertyWithDefault('javaVersion', '17'))
}
withJavadocJar()
withSourcesJar()
Expand All @@ -36,23 +32,55 @@ javadoc {

tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:all'
options.compilerArgs << '-Werror'
options.encoding = 'UTF-8'
}

testing {
suites {
configureEach {
useJUnitJupiter('5.10.1')
dependencies {
implementation project()
implementation libs.assertj
runtimeOnly libs.slf4jLogger
}
targets {
all {
testTask.configure {
if(logger.infoEnabled) {
testLogging.showStandardStreams = true
}
jvmArgs '-enableassertions'
systemProperty 'java.util.logging.config.file', file('src/test/resources/logging.properties')
}
}
}
}
test {
useJUnitJupiter('5.10.0')
dependencies {
implementation libs.h2
}
}
integrationTest(JvmTestSuite) {
testType = TestSuiteType.INTEGRATION_TEST
dependencies {
implementation libs.exasolTestcontainers
runtimeOnly libs.exasolJdbc
}
targets {
all {
testTask.configure {
shouldRunAfter(test)
}
}
}
}
}
}

test {
if(logger.infoEnabled) {
testLogging.showStandardStreams = true
}
jvmArgs '-XX:+HeapDumpOnOutOfMemoryError', '-enableassertions'
systemProperty 'java.util.logging.config.file', file('src/test/resources/logging.properties')
tasks.named('check') {
dependsOn(testing.suites.integrationTest)
}

jacocoTestReport {
Expand All @@ -68,7 +96,17 @@ sonar {
}
}

rootProject.tasks['sonarqube'].dependsOn(tasks['jacocoTestReport'])
rootProject.tasks['sonarqube'].dependsOn(tasks['testCodeCoverageReport'], tasks['integrationTestCodeCoverageReport'])

def getPropertyWithDefault(String name, String defaultValue) {
if(project.hasProperty(name)) {
def value = project.property(name)
logger.info("Found value '${value}' for project property '${name}'")
return value
}
logger.info("Project property '${name}' not defined, using default '${defaultValue}'")
return defaultValue
}

def getOptionalProperty(String name) {
if(project.hasProperty(name)) {
Expand Down
22 changes: 22 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1,23 @@
rootProject.name = 'simple-jdbc'


dependencyResolutionManagement {
repositories {
mavenCentral()
}
versionCatalogs {
libs {
library('assertj', 'org.assertj:assertj-core:3.24.2')
library('h2', 'com.h2database:h2:2.2.224')
library('junitPioneer', 'org.junit-pioneer:junit-pioneer:2.2.0')
library('equalsverifier', 'nl.jqno.equalsverifier:equalsverifier:3.15.3')
library('tostringverifier', 'com.jparams:to-string-verifier:1.4.8')
library('hamcrest', 'org.hamcrest:hamcrest-all:1.3')
library('hamcrestResultSetMatcher', 'com.exasol:hamcrest-resultset-matcher:1.6.3')
library('mockito', 'org.mockito:mockito-core:5.7.0')
library('slf4jLogger', 'org.slf4j:slf4j-jdk14:2.0.9')
library('exasolJdbc', 'com.exasol:exasol-jdbc:7.1.20')
library('exasolTestcontainers', 'com.exasol:exasol-testcontainers:7.0.0')
}
}
}
87 changes: 87 additions & 0 deletions src/integrationTest/java/org/itsallcode/jdbc/LegacyTypeTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.itsallcode.jdbc;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.util.stream.Stream;

import org.itsallcode.jdbc.resultset.Row;
import org.itsallcode.jdbc.resultset.SimpleResultSet;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import com.exasol.containers.ExasolContainer;
import com.exasol.containers.ExasolService;

class LegacyTypeITest {

private static final ExasolContainer<?> container = new ExasolContainer<>("8.23.1")
.withRequiredServices(ExasolService.JDBC).withReuse(true);

@BeforeAll
static void startDb() {
container.start();
}

@AfterAll
static void stopDb() {
container.stop();
}

SimpleConnection connect() {
return ConnectionFactory.create(Context.builder().useModernTypes(true).build()).create(container.getJdbcUrl(),
container.getUsername(), container.getPassword());
}

@ParameterizedTest
@MethodSource("testTypes")
void type(final TypeTest test) {
try (SimpleResultSet<Row> result = connect()
.query("select cast('" + test.value() + "' as " + test.type() + ")")) {
final Object value = result.toList().get(0).getColumnValue(0).getValue();
assertAll(
() -> assertThat(value.getClass()).isEqualTo(test.expectedValue().getClass()),
() -> assertThat(value).isEqualTo(test.expectedValue()));
}
}

@ParameterizedTest
@MethodSource("testTypes")
void nullValue(final TypeTest test) {
try (SimpleResultSet<Row> result = connect()
.query("select cast(NULL as " + test.type() + ")")) {
assertThat(result.toList().get(0).getColumnValue(0).getValue())
.isNull();
}
}

static Stream<Arguments> testTypes() {
return Stream.of(
typeTest("2023-11-25 16:18:46", "timestamp", Instant.parse("2023-11-25T16:18:46.0Z")),
typeTest("2023-11-25", "date", LocalDate.parse("2023-11-25")),
typeTest("5-3", "INTERVAL YEAR TO MONTH", "+05-03"),
typeTest("2 12:50:10.123", "INTERVAL DAY TO SECOND", "+02 12:50:10.123"),
typeTest("POINT(1 2)", "GEOMETRY", "POINT (1 2)"),
typeTest("550e8400-e29b-11d4-a716-446655440000", "HASHTYPE", "550e8400e29b11d4a716446655440000"),
typeTest("text", "VARCHAR(10)", "text"),
typeTest("text", "CHAR(10)", "text "),
typeTest("123.456", "DECIMAL", 123L),
typeTest("123.457", "DECIMAL(6,3)", BigDecimal.valueOf(123.457d)),
typeTest("123.458", "DOUBLE PRECISION", 123.458d),
typeTest("true", "BOOLEAN", true));
}

private static Arguments typeTest(final String value, final String type, final Object expectedValue) {
return Arguments.of(new TypeTest(value, type, expectedValue));
}

record TypeTest(String value, String type, Object expectedValue) {

}
}
37 changes: 35 additions & 2 deletions src/main/java/org/itsallcode/jdbc/ConnectionFactory.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package org.itsallcode.jdbc;

import java.sql.*;
import java.util.List;
import java.util.Properties;

import org.itsallcode.jdbc.resultset.Row;
import org.itsallcode.jdbc.resultset.RowMapper;

/**
* This class connects to a database and returns new {@link SimpleConnection}s.
*/
Expand All @@ -14,12 +18,22 @@ private ConnectionFactory(final Context context) {
}

/**
* Create a new connection factory.
* Create a new connection factory with a default context.
*
* @return a new instance
*/
public static ConnectionFactory create() {
return new ConnectionFactory(new Context());
return create(Context.builder().build());
}

/**
* Create a new connection factory with a custom context.
*
* @param context a custom context
* @return a new instance
*/
public static ConnectionFactory create(final Context context) {
return new ConnectionFactory(context);
}

/**
Expand Down Expand Up @@ -65,4 +79,23 @@ private Connection createConnection(final String url, final Properties info) {
throw new UncheckedSQLException("Error connecting to '" + url + "'", e);
}
}

/**
* Create a {@link RowMapper} that creates generic {@link Row} objects.
*
* @return a new row mapper
*/
public RowMapper<Row> createGenericRowMapper() {
return RowMapper.createGenericRowMapper(context);
}

/**
* Create a {@link RowMapper} that creates {@link List}s of simple column
* objects.
*
* @return a new row mapper
*/
public RowMapper<List<Object>> createListRowMapper() {
return RowMapper.createListRowMapper(context);
}
}
Loading

0 comments on commit 89afc36

Please sign in to comment.