-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add utility classes for database object creation (#12445)
* Add utility classes for database object creation * Remove unused variable
- Loading branch information
1 parent
915573e
commit de70351
Showing
9 changed files
with
555 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
airbyte-db/lib/src/main/java/io/airbyte/db/factory/DSLContextFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright (c) 2021 Airbyte, Inc., all rights reserved. | ||
*/ | ||
|
||
package io.airbyte.db.factory; | ||
|
||
import javax.sql.DataSource; | ||
import org.jooq.DSLContext; | ||
import org.jooq.SQLDialect; | ||
import org.jooq.impl.DSL; | ||
|
||
/** | ||
* Temporary factory class that provides convenience methods for creating a {@link DSLContext} | ||
* instances. This class will be removed once the project has been converted to leverage an | ||
* application framework to manage the creation and injection of {@link DSLContext} objects. | ||
* | ||
* This class replaces direct calls to {@link io.airbyte.db.Databases}. | ||
*/ | ||
public class DSLContextFactory { | ||
|
||
/** | ||
* Constructs a configured {@link DSLContext} instance using the provided configuration. | ||
* | ||
* @param dataSource The {@link DataSource} used to connect to the database. | ||
* @param dialect The SQL dialect to use with objects created from this context. | ||
* @return The configured {@link DSLContext}. | ||
*/ | ||
public static DSLContext create(final DataSource dataSource, final SQLDialect dialect) { | ||
return DSL.using(dataSource, dialect); | ||
} | ||
|
||
} |
251 changes: 251 additions & 0 deletions
251
airbyte-db/lib/src/main/java/io/airbyte/db/factory/DataSourceFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
/* | ||
* Copyright (c) 2021 Airbyte, Inc., all rights reserved. | ||
*/ | ||
|
||
package io.airbyte.db.factory; | ||
|
||
import com.zaxxer.hikari.HikariConfig; | ||
import com.zaxxer.hikari.HikariDataSource; | ||
import java.util.Map; | ||
import javax.sql.DataSource; | ||
|
||
/** | ||
* Temporary factory class that provides convenience methods for creating a {@link DataSource} | ||
* instance. This class will be removed once the project has been converted to leverage an | ||
* application framework to manage the creation and injection of {@link DataSource} objects. | ||
* | ||
* This class replaces direct calls to {@link io.airbyte.db.Databases}. | ||
*/ | ||
public class DataSourceFactory { | ||
|
||
/** | ||
* Constructs a new {@link DataSource} using the provided configuration. | ||
* | ||
* @param username The username of the database user. | ||
* @param password The password of the database user. | ||
* @param driverClassName The fully qualified name of the JDBC driver class. | ||
* @param jdbcConnectionString The JDBC connection string. | ||
* @return The configured {@link DataSource}. | ||
*/ | ||
public static DataSource create(final String username, | ||
final String password, | ||
final String driverClassName, | ||
final String jdbcConnectionString) { | ||
return new DataSourceBuilder() | ||
.withDriverClassName(driverClassName) | ||
.withJdbcUrl(jdbcConnectionString) | ||
.withPassword(password) | ||
.withUsername(username) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Constructs a new {@link DataSource} using the provided configuration. | ||
* | ||
* @param username The username of the database user. | ||
* @param password The password of the database user. | ||
* @param driverClassName The fully qualified name of the JDBC driver class. | ||
* @param jdbcConnectionString The JDBC connection string. | ||
* @param connectionProperties Additional configuration properties for the underlying driver. | ||
* @return The configured {@link DataSource}. | ||
*/ | ||
public static DataSource create(final String username, | ||
final String password, | ||
final String driverClassName, | ||
final String jdbcConnectionString, | ||
final Map<String, String> connectionProperties) { | ||
return new DataSourceBuilder() | ||
.withConnectionProperties(connectionProperties) | ||
.withDriverClassName(driverClassName) | ||
.withJdbcUrl(jdbcConnectionString) | ||
.withPassword(password) | ||
.withUsername(username) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Constructs a new {@link DataSource} using the provided configuration. | ||
* | ||
* @param username The username of the database user. | ||
* @param password The password of the database user. | ||
* @param host The host address of the database. | ||
* @param port The port of the database. | ||
* @param database The name of the database. | ||
* @param driverClassName The fully qualified name of the JDBC driver class. | ||
* @return The configured {@link DataSource}. | ||
*/ | ||
public static DataSource create(final String username, | ||
final String password, | ||
final String host, | ||
final int port, | ||
final String database, | ||
final String driverClassName) { | ||
return new DataSourceBuilder() | ||
.withDatabase(database) | ||
.withDriverClassName(driverClassName) | ||
.withHost(host) | ||
.withPort(port) | ||
.withPassword(password) | ||
.withUsername(username) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Constructs a new {@link DataSource} using the provided configuration. | ||
* | ||
* @param username The username of the database user. | ||
* @param password The password of the database user. | ||
* @param host The host address of the database. | ||
* @param port The port of the database. | ||
* @param database The name of the database. | ||
* @param driverClassName The fully qualified name of the JDBC driver class. | ||
* @param connectionProperties Additional configuration properties for the underlying driver. | ||
* @return The configured {@link DataSource}. | ||
*/ | ||
public static DataSource create(final String username, | ||
final String password, | ||
final String host, | ||
final int port, | ||
final String database, | ||
final String driverClassName, | ||
final Map<String, String> connectionProperties) { | ||
return new DataSourceBuilder() | ||
.withConnectionProperties(connectionProperties) | ||
.withDatabase(database) | ||
.withDriverClassName(driverClassName) | ||
.withHost(host) | ||
.withPort(port) | ||
.withPassword(password) | ||
.withUsername(username) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Convenience method that constructs a new {@link DataSource} for a PostgreSQL database using the | ||
* provided configuration. | ||
* | ||
* @param username The username of the database user. | ||
* @param password The password of the database user. | ||
* @param host The host address of the database. | ||
* @param port The port of the database. | ||
* @param database The name of the database. | ||
* @return The configured {@link DataSource}. | ||
*/ | ||
public static DataSource createPostgres(final String username, | ||
final String password, | ||
final String host, | ||
final int port, | ||
final String database) { | ||
return new DataSourceBuilder() | ||
.withDatabase(database) | ||
.withDriverClassName("org.postgresql.Driver") | ||
.withHost(host) | ||
.withPort(port) | ||
.withPassword(password) | ||
.withUsername(username) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Builder class used to configure and construct {@link DataSource} instances. | ||
*/ | ||
private static class DataSourceBuilder { | ||
|
||
private static final Map<String, String> JDBC_URL_FORMATS = Map.of("org.postgresql.Driver", "jdbc:postgresql://%s:%d/%s", | ||
"com.amazon.redshift.jdbc.Driver", "jdbc:redshift://%s:%d/%s", | ||
"com.mysql.cj.jdbc.Driver", "jdbc:mysql://%s:%d/%s", | ||
"com.microsoft.sqlserver.jdbc.SQLServerDriver", "jdbc:sqlserver://%s:%d/%s", | ||
"oracle.jdbc.OracleDriver", "jdbc:oracle:thin:@%s:%d:%s", | ||
"ru.yandex.clickhouse.ClickHouseDriver", "jdbc:ch://%s:%d/%s", | ||
"org.mariadb.jdbc.Driver", "jdbc:mariadb://%s:%d/%s"); | ||
|
||
private Map<String, String> connectionProperties = Map.of(); | ||
private String database; | ||
private String driverClassName = "org.postgresql.Driver"; | ||
private String host; | ||
private String jdbcUrl; | ||
private Integer maximumPoolSize = 5; | ||
private Integer minimumPoolSize = 0; | ||
private String password; | ||
private Integer port = 5432; | ||
private String username; | ||
|
||
private DataSourceBuilder() {} | ||
|
||
public DataSourceBuilder withConnectionProperties(final Map<String, String> connectionProperties) { | ||
if (connectionProperties != null) { | ||
this.connectionProperties = connectionProperties; | ||
} | ||
return this; | ||
} | ||
|
||
public DataSourceBuilder withDatabase(final String database) { | ||
this.database = database; | ||
return this; | ||
} | ||
|
||
public DataSourceBuilder withDriverClassName(final String driverClassName) { | ||
this.driverClassName = driverClassName; | ||
return this; | ||
} | ||
|
||
public DataSourceBuilder withHost(final String host) { | ||
this.host = host; | ||
return this; | ||
} | ||
|
||
public DataSourceBuilder withJdbcUrl(final String jdbcUrl) { | ||
this.jdbcUrl = jdbcUrl; | ||
return this; | ||
} | ||
|
||
public DataSourceBuilder withMaximumPoolSize(final Integer maximumPoolSize) { | ||
if (maximumPoolSize != null) { | ||
this.maximumPoolSize = maximumPoolSize; | ||
} | ||
return this; | ||
} | ||
|
||
public DataSourceBuilder withMinimumPoolSize(final Integer minimumPoolSize) { | ||
if (minimumPoolSize != null) { | ||
this.minimumPoolSize = minimumPoolSize; | ||
} | ||
return this; | ||
} | ||
|
||
public DataSourceBuilder withPassword(final String password) { | ||
this.password = password; | ||
return this; | ||
} | ||
|
||
public DataSourceBuilder withPort(final Integer port) { | ||
if (port != null) { | ||
this.port = port; | ||
} | ||
return this; | ||
} | ||
|
||
public DataSourceBuilder withUsername(final String username) { | ||
this.username = username; | ||
return this; | ||
} | ||
|
||
public DataSource build() { | ||
final HikariConfig config = new HikariConfig(); | ||
config.setDriverClassName(driverClassName); | ||
config.setJdbcUrl(jdbcUrl != null ? jdbcUrl : String.format(JDBC_URL_FORMATS.getOrDefault(driverClassName, ""), host, port, database)); | ||
config.setMaximumPoolSize(maximumPoolSize); | ||
config.setMinimumIdle(minimumPoolSize); | ||
config.setPassword(password); | ||
config.setUsername(username); | ||
|
||
connectionProperties.forEach(config::addDataSourceProperty); | ||
|
||
final HikariDataSource dataSource = new HikariDataSource(config); | ||
dataSource.validate(); | ||
return dataSource; | ||
} | ||
|
||
} | ||
|
||
} |
53 changes: 53 additions & 0 deletions
53
airbyte-db/lib/src/main/java/io/airbyte/db/factory/FlywayFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* Copyright (c) 2021 Airbyte, Inc., all rights reserved. | ||
*/ | ||
|
||
package io.airbyte.db.factory; | ||
|
||
import javax.sql.DataSource; | ||
import org.flywaydb.core.Flyway; | ||
|
||
/** | ||
* Temporary factory class that provides convenience methods for creating a {@link Flyway} | ||
* instances. This class will be removed once the project has been converted to leverage an | ||
* application framework to manage the creation and injection of {@link Flyway} objects. | ||
* | ||
* This class replaces direct calls to {@link io.airbyte.db.Databases}. | ||
*/ | ||
public class FlywayFactory { | ||
|
||
static final String MIGRATION_TABLE_FORMAT = "airbyte_%s_migrations"; | ||
|
||
// Constants for Flyway baseline. See here for details: | ||
// https://flywaydb.org/documentation/command/baseline | ||
static final String BASELINE_VERSION = "0.29.0.001"; | ||
static final String BASELINE_DESCRIPTION = "Baseline from file-based migration v1"; | ||
static final boolean BASELINE_ON_MIGRATION = true; | ||
|
||
/** | ||
* Constructs a configured {@link Flyway} instance using the provided configuration. | ||
* | ||
* @param dataSource The {@link DataSource} used to connect to the database. | ||
* @param installedBy The name of the module performing the migration. | ||
* @param dbIdentifier The name of the database to be migrated. This is used to name the table to | ||
* hold the migration history for the database. | ||
* @param migrationFileLocations The array of migration files to be used. | ||
* @return The configured {@link Flyway} instance. | ||
*/ | ||
public static Flyway create(final DataSource dataSource, | ||
final String installedBy, | ||
final String dbIdentifier, | ||
final String... migrationFileLocations) { | ||
return Flyway.configure() | ||
.dataSource(dataSource) | ||
.baselineVersion(BASELINE_VERSION) | ||
.baselineDescription(BASELINE_DESCRIPTION) | ||
.baselineOnMigrate(BASELINE_ON_MIGRATION) | ||
.installedBy(installedBy) | ||
.table(String.format(MIGRATION_TABLE_FORMAT, dbIdentifier)) | ||
.locations(migrationFileLocations) | ||
.load(); | ||
|
||
} | ||
|
||
} |
34 changes: 34 additions & 0 deletions
34
airbyte-db/lib/src/test/java/io/airbyte/db/factory/AbstractFactoryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* Copyright (c) 2021 Airbyte, Inc., all rights reserved. | ||
*/ | ||
|
||
package io.airbyte.db.factory; | ||
|
||
import org.junit.jupiter.api.AfterAll; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.testcontainers.containers.PostgreSQLContainer; | ||
|
||
/** | ||
* Common test suite for the classes found in the {@code io.airbyte.db.factory} package. | ||
*/ | ||
public abstract class AbstractFactoryTest { | ||
|
||
private static final String DATABASE_NAME = "airbyte_test_database"; | ||
|
||
protected static PostgreSQLContainer<?> container; | ||
|
||
@BeforeAll | ||
public static void dbSetup() { | ||
container = new PostgreSQLContainer<>("postgres:13-alpine") | ||
.withDatabaseName(DATABASE_NAME) | ||
.withUsername("docker") | ||
.withPassword("docker"); | ||
container.start(); | ||
} | ||
|
||
@AfterAll | ||
public static void dbDown() { | ||
container.close(); | ||
} | ||
|
||
} |
Oops, something went wrong.