From 08122e927cb2b16146715e9cb9334433e9b4d1bd Mon Sep 17 00:00:00 2001 From: Mason Wheeler Date: Tue, 1 Jun 2021 11:46:16 -0700 Subject: [PATCH 1/7] Progressive checkin: initial WIP work on Postgres/DB config persistence --- airbyte-config/db-persistence/build.gradle | 9 ++ .../DatabaseConfigPersistence.java | 110 ++++++++++++++++++ .../PostgresConfigPersistence.java | 48 ++++++++ airbyte-db/build.gradle | 1 + .../java/io/airbyte/db/jdbc/JdbcDatabase.java | 22 ++++ 5 files changed, 190 insertions(+) create mode 100644 airbyte-config/db-persistence/build.gradle create mode 100644 airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/DatabaseConfigPersistence.java create mode 100644 airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java diff --git a/airbyte-config/db-persistence/build.gradle b/airbyte-config/db-persistence/build.gradle new file mode 100644 index 0000000000000..40af84c0bac54 --- /dev/null +++ b/airbyte-config/db-persistence/build.gradle @@ -0,0 +1,9 @@ +dependencies { + implementation group: 'commons-io', name: 'commons-io', version: '2.7' + + implementation project(':airbyte-db') + implementation project(':airbyte-commons') + implementation project(':airbyte-config:models') + implementation project(':airbyte-config:persistence') + implementation project(":airbyte-json-validation") +} diff --git a/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/DatabaseConfigPersistence.java b/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/DatabaseConfigPersistence.java new file mode 100644 index 0000000000000..25fe08ca81efc --- /dev/null +++ b/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/DatabaseConfigPersistence.java @@ -0,0 +1,110 @@ +/* + * MIT License + * + * Copyright (c) 2020 Airbyte + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package io.airbyte.config.dbPersistence; + +import com.fasterxml.jackson.databind.JsonNode; +import io.airbyte.commons.json.Jsons; +import io.airbyte.config.ConfigSchema; +import io.airbyte.config.persistence.ConfigNotFoundException; +import io.airbyte.config.persistence.ConfigPersistence; +import io.airbyte.db.jdbc.JdbcDatabase; +import io.airbyte.validation.json.JsonSchemaValidator; +import io.airbyte.validation.json.JsonValidationException; +import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public abstract class DatabaseConfigPersistence implements ConfigPersistence { + + private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseConfigPersistence.class) + + private final JdbcDatabase database; + private final JsonSchemaValidator jsonSchemaValidator; + + protected DatabaseConfigPersistence(JdbcDatabase db) { + this(db, new JsonSchemaValidator()); + } + + protected DatabaseConfigPersistence(JdbcDatabase db, JsonSchemaValidator validator) { + database = db; + jsonSchemaValidator = validator; + } + + @Override + public T getConfig(ConfigSchema configType, String configId, Class clazz) + throws ConfigNotFoundException, JsonValidationException, IOException { + Optional data = database.querySingle("SELECT CONFIG_DATA FROM CONFIG WHERE CONFIG_TYPE = ? AND CONFIG_ID = ?", + r -> r.getString("CONFIG_DATA"), configType.toString(), configId); + if (!data.isPresent()) { + throw new ConfigNotFoundException(configType, configId); + } + + final T config = Jsons.deserialize(data.get(), clazz); + validateJson(config, configType); + return config; + } + + @Override + public List listConfigs(ConfigSchema configType, Class clazz) throws JsonValidationException { + List results = database.query(c -> { + var stmt = c.prepareStatement("SELECT CONFIG_DATA FROM CONFIG WHERE CONFIG_TYPE = ?"); + stmt.setString(1, configType.toString()); + return stmt; + }, r -> r.getString("CONFIG_DATA")) + .map(s -> (T) Jsons.deserialize(s, clazz)) + .collect(Collectors.toList()); + return results; + } + + @Override + public void writeConfig(ConfigSchema configType, String configId, T config) throws JsonValidationException { + // validate config with schema + validateJson(Jsons.jsonNode(config), configType); + final String data = Jsons.serialize(config); + try { + database.execute(c -> writeConfigQuery(c, configType, configId, data).execute()); + } catch (SQLException e) + { + LOGGER.error("Error while writing config data,", e); + } + } + + // Made abstract because what we want for this is an upsert operation, which different databases + // handle with different syntax + // Overrides need to return a prepared statement with all 3 data elements added + protected abstract PreparedStatement writeConfigQuery(Connection conn, ConfigSchema configType, String configId, String data); + + private void validateJson(T config, ConfigSchema configType) throws JsonValidationException { + JsonNode schema = JsonSchemaValidator.getSchema(configType.getFile()); + jsonSchemaValidator.ensure(schema, Jsons.jsonNode(config)); + } +} diff --git a/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java b/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java new file mode 100644 index 0000000000000..32b4683530c5f --- /dev/null +++ b/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Copyright (c) 2020 Airbyte + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package io.airbyte.config.dbPersistence; + +import io.airbyte.db.jdbc.JdbcDatabase; +import io.airbyte.validation.json.JsonSchemaValidator; + +import java.sql.Connection; +import java.sql.PreparedStatement; + +public class PostgresConfigPersistence extends io.airbyte.config.dbPersistence.DatabaseConfigPersistence { + + protected PostgresConfigPersistence(JdbcDatabase db) { + super(db); + } + + protected DatabaseConfigPersistence(JdbcDatabase db, JsonSchemaValidator validator) { + super(db, validator); + } + + @Override + protected PreparedStatement writeConfigQuery(Connection conn, ConfigSchema configType, String configId, String data) + { + return conn.prepareStatement("INSERT INTO CONFIG (CONFIG_ID, CONFIG_TYPE, CONFIG_DATA) VALUES (?, ?, ?) ON CONFLICT (CONFIG_ID) DO UPDATE SET CONFIG_DATA = EXCLUDED.CONFIG_DATA", configId, configType.toString(), data); + } +} diff --git a/airbyte-db/build.gradle b/airbyte-db/build.gradle index 0205b835d1a23..a14853aa7c86c 100644 --- a/airbyte-db/build.gradle +++ b/airbyte-db/build.gradle @@ -9,6 +9,7 @@ dependencies { api 'org.postgresql:postgresql:42.2.18' implementation project(':airbyte-protocol:models') + implementation project(':airbyte-config') testImplementation project(':airbyte-test-utils') diff --git a/airbyte-db/src/main/java/io/airbyte/db/jdbc/JdbcDatabase.java b/airbyte-db/src/main/java/io/airbyte/db/jdbc/JdbcDatabase.java index 3f40bd384c23c..42104979b74fb 100644 --- a/airbyte-db/src/main/java/io/airbyte/db/jdbc/JdbcDatabase.java +++ b/airbyte-db/src/main/java/io/airbyte/db/jdbc/JdbcDatabase.java @@ -31,6 +31,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; +import java.util.Optional; import java.util.stream.Stream; /** @@ -50,6 +51,14 @@ default void execute(String sql) throws SQLException { execute(connection -> connection.createStatement().execute(sql)); } + default void executeParameterized (String sql, String... params) throws SQLException + { + execute(connection -> { + final PreparedStatement stmt = connection.prepareStatement(sql, params); + stmt.execute(); + }); + } + default void executeWithinTransaction(List queries) throws SQLException { execute(connection -> { connection.setAutoCommit(false); @@ -116,4 +125,17 @@ Stream query(CheckedFunction CheckedFunction recordTransform) throws SQLException; + default Optional querySingle(String sql, CheckedFunction recordTransform, String... params) + throws SQLException { + return query(c -> { + var stmt = c.prepareStatement(sql); + int i = 1; + for (String param : params) { + stmt.setString(i, param); + ++i; + } + return stmt; + }, recordTransform).findFirst(); + } + } From ffe739e023209410cb262b92b59df52fbfd9d94b Mon Sep 17 00:00:00 2001 From: Mason Wheeler Date: Wed, 2 Jun 2021 13:38:12 -0700 Subject: [PATCH 2/7] WIP, checking in to look at Gradle isses with team --- .../PostgresConfigPersistence.java | 4 +- .../PostgresConfigPersistenceTest.java | 104 ++++++++++++++++++ build.gradle | 1 - gradle/wrapper/gradle-wrapper.jar | Bin 58910 -> 59203 bytes gradlew | 2 +- gradlew.bat | 21 +--- settings.gradle | 2 +- 7 files changed, 111 insertions(+), 23 deletions(-) create mode 100644 airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java diff --git a/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java b/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java index 32b4683530c5f..edc656adad183 100644 --- a/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java +++ b/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java @@ -32,11 +32,11 @@ public class PostgresConfigPersistence extends io.airbyte.config.dbPersistence.DatabaseConfigPersistence { - protected PostgresConfigPersistence(JdbcDatabase db) { + public PostgresConfigPersistence(JdbcDatabase db) { super(db); } - protected DatabaseConfigPersistence(JdbcDatabase db, JsonSchemaValidator validator) { + public PostgresConfigPersistence(JdbcDatabase db, JsonSchemaValidator validator) { super(db, validator); } diff --git a/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java b/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java new file mode 100644 index 0000000000000..096b8724da372 --- /dev/null +++ b/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java @@ -0,0 +1,104 @@ +package io.airbyte.config.dbPersistence; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import com.google.common.collect.Sets; +import io.airbyte.config.ConfigSchema; +import io.airbyte.config.StandardSourceDefinition; +import io.airbyte.config.StandardSync; +import io.airbyte.validation.json.JsonSchemaValidator; +import io.airbyte.validation.json.JsonValidationException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class PostgresConfigPersistenceTest { + public static final UUID UUID_1 = new UUID(0, 1); + public static final StandardSourceDefinition SOURCE_1 = new StandardSourceDefinition(); + + static { + SOURCE_1.withSourceDefinitionId(UUID_1) + .withName("apache storm"); + } + + public static final UUID UUID_2 = new UUID(0, 2); + public static final StandardSourceDefinition SOURCE_2 = new StandardSourceDefinition(); + private static final Path TEST_ROOT = Path.of("/tmp/airbyte_tests"); + + static { + SOURCE_2.withSourceDefinitionId(UUID_2) + .withName("apache storm"); + } + + private Path rootPath; + private JsonSchemaValidator schemaValidator; + + private DefaultConfigPersistence configPersistence; + + @BeforeEach + void setUp() throws IOException { + schemaValidator = mock(JsonSchemaValidator.class); + rootPath = Files.createTempDirectory(Files.createDirectories(TEST_ROOT), DefaultConfigPersistenceTest.class.getName()); + + configPersistence = new DefaultConfigPersistence(rootPath, schemaValidator); + } + + @Test + void testReadWriteConfig() throws IOException, JsonValidationException, ConfigNotFoundException { + configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1.toString(), SOURCE_1); + + assertEquals( + SOURCE_1, + configPersistence.getConfig( + ConfigSchema.STANDARD_SOURCE_DEFINITION, + UUID_1.toString(), + StandardSourceDefinition.class)); + } + + @Test + void testListConfigs() throws JsonValidationException, IOException { + configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1.toString(), SOURCE_1); + configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_2.toString(), SOURCE_2); + + assertEquals( + Sets.newHashSet(SOURCE_1, SOURCE_2), + Sets.newHashSet(configPersistence.listConfigs(ConfigSchema.STANDARD_SOURCE_DEFINITION, StandardSourceDefinition.class))); + } + + @Test + void writeConfigWithJsonSchemaRef() throws JsonValidationException, IOException, ConfigNotFoundException { + final StandardSync standardSync = new StandardSync() + .withName("sync") + .withPrefix("sync") + .withConnectionId(UUID_1) + .withSourceId(UUID.randomUUID()) + .withDestinationId(UUID.randomUUID()) + .withOperationIds(List.of(UUID.randomUUID())); + + configPersistence.writeConfig(ConfigSchema.STANDARD_SYNC, UUID_1.toString(), standardSync); + + assertEquals( + standardSync, + configPersistence.getConfig(ConfigSchema.STANDARD_SYNC, UUID_1.toString(), StandardSync.class)); + } + + @Test + void writeConfigInvalidConfig() throws JsonValidationException { + StandardSourceDefinition standardSourceDefinition = SOURCE_1.withName(null); + + doThrow(new JsonValidationException("error")).when(schemaValidator).ensure(any(), any()); + + assertThrows(JsonValidationException.class, () -> configPersistence.writeConfig( + ConfigSchema.STANDARD_SOURCE_DEFINITION, + UUID_1.toString(), + standardSourceDefinition)); + } + +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 1f344bdba0646..7e844dd162100 100644 --- a/build.gradle +++ b/build.gradle @@ -118,7 +118,6 @@ allprojects { ":airbyte-migration", ":airbyte-scheduler:app", ":airbyte-server", - ":airbyte-webapp", ].toSet().asImmutable() if (project.getPath() in composeDeps) { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 62d4c053550b91381bbd28b1afc82d634bf73a8a..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch delta 6656 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 Yte!%o?r4GTrVtxD61Ym!|5fq-1K$0e!T1w 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 diff --git a/gradlew b/gradlew index fbd7c515832da..4f906e0c811fc 100755 --- a/gradlew +++ b/gradlew @@ -130,7 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index a9f778a7a964b..ac1b06f93825d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,21 +64,6 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line @@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle b/settings.gradle index f781d0d65417c..84dfaaeeed595 100644 --- a/settings.gradle +++ b/settings.gradle @@ -21,6 +21,7 @@ include ':airbyte-commons' include ':airbyte-config:models' include ':airbyte-config:init' include ':airbyte-config:persistence' +include ':airbyte-config:db-persistence' include ':airbyte-db' include ':airbyte-e2e-testing' include ':airbyte-integrations:bases:airbyte-protocol' @@ -45,7 +46,6 @@ include ':airbyte-scheduler:client' include ':airbyte-scheduler:models' include ':airbyte-scheduler:persistence' include ':airbyte-server' -include ':airbyte-webapp' include ':airbyte-workers' include ':airbyte-tests' include ':airbyte-test-utils' From f7031e6c361028e6611349035f5ef9a1d1cad03f Mon Sep 17 00:00:00 2001 From: Mason Wheeler Date: Thu, 3 Jun 2021 10:10:01 -0700 Subject: [PATCH 3/7] Working Postgres Config Persistence implementation! --- airbyte-config/db-persistence/build.gradle | 2 + .../DatabaseConfigPersistence.java | 68 +++--- .../PostgresConfigPersistence.java | 43 +++- .../PostgresConfigPersistenceTest.java | 203 ++++++++++-------- .../persistence/ConfigNotFoundException.java | 7 +- .../config/persistence/ConfigPersistence.java | 5 +- .../config/persistence/ConfigRepository.java | 32 +-- .../persistence/DefaultConfigPersistence.java | 15 +- .../persistence/ConfigRepositoryTest.java | 2 +- .../DefaultConfigPersistenceTest.java | 14 +- .../main/java/io/airbyte/db/Databases.java | 32 ++- .../java/io/airbyte/db/jdbc/JdbcDatabase.java | 16 +- .../postgres/PostgresDestination.java | 21 +- .../server/handlers/DestinationHandler.java | 2 +- .../server/handlers/OperationsHandler.java | 4 +- .../server/handlers/SourceHandler.java | 2 +- 16 files changed, 280 insertions(+), 188 deletions(-) diff --git a/airbyte-config/db-persistence/build.gradle b/airbyte-config/db-persistence/build.gradle index 40af84c0bac54..615e83c76bf96 100644 --- a/airbyte-config/db-persistence/build.gradle +++ b/airbyte-config/db-persistence/build.gradle @@ -6,4 +6,6 @@ dependencies { implementation project(':airbyte-config:models') implementation project(':airbyte-config:persistence') implementation project(":airbyte-json-validation") + + testImplementation "org.testcontainers:postgresql:1.15.1" } diff --git a/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/DatabaseConfigPersistence.java b/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/DatabaseConfigPersistence.java index 25fe08ca81efc..67b6c0c5ef941 100644 --- a/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/DatabaseConfigPersistence.java +++ b/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/DatabaseConfigPersistence.java @@ -38,73 +38,81 @@ import java.sql.SQLException; import java.util.List; import java.util.Optional; +import java.util.UUID; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - public abstract class DatabaseConfigPersistence implements ConfigPersistence { - private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseConfigPersistence.class) + private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseConfigPersistence.class); - private final JdbcDatabase database; + protected final JdbcDatabase database; private final JsonSchemaValidator jsonSchemaValidator; - protected DatabaseConfigPersistence(JdbcDatabase db) { - this(db, new JsonSchemaValidator()); - } - protected DatabaseConfigPersistence(JdbcDatabase db, JsonSchemaValidator validator) { database = db; jsonSchemaValidator = validator; } + // Create a table named CONFIG with three columns: CONFIG_ID (PK UUID/string), CONFIG_TYPE (string), + // CONFIG_DATA (JSON/string) + public abstract void Setup() throws SQLException; + @Override - public T getConfig(ConfigSchema configType, String configId, Class clazz) + public T getConfig(ConfigSchema configType, UUID configId, Class clazz) throws ConfigNotFoundException, JsonValidationException, IOException { - Optional data = database.querySingle("SELECT CONFIG_DATA FROM CONFIG WHERE CONFIG_TYPE = ? AND CONFIG_ID = ?", - r -> r.getString("CONFIG_DATA"), configType.toString(), configId); - if (!data.isPresent()) { - throw new ConfigNotFoundException(configType, configId); - } + try { + Optional data = database.querySingle("SELECT CONFIG_DATA FROM CONFIG WHERE CONFIG_TYPE = ? AND CONFIG_ID = ?", + r -> r.getString("CONFIG_DATA"), configType.toString(), configId); + if (!data.isPresent()) { + throw new ConfigNotFoundException(configType, configId); + } - final T config = Jsons.deserialize(data.get(), clazz); - validateJson(config, configType); - return config; + final T config = Jsons.deserialize(data.get(), clazz); + validateJson(config, configType); + return config; + } catch (SQLException e) { + throw new IOException(String.format("Failed to get config type %s item %s. Reason: %s", configType, configId, e.getMessage()), e); + } } @Override - public List listConfigs(ConfigSchema configType, Class clazz) throws JsonValidationException { - List results = database.query(c -> { - var stmt = c.prepareStatement("SELECT CONFIG_DATA FROM CONFIG WHERE CONFIG_TYPE = ?"); - stmt.setString(1, configType.toString()); - return stmt; - }, r -> r.getString("CONFIG_DATA")) - .map(s -> (T) Jsons.deserialize(s, clazz)) - .collect(Collectors.toList()); - return results; + public List listConfigs(ConfigSchema configType, Class clazz) throws JsonValidationException, IOException { + try { + List results = database.query(c -> { + var stmt = c.prepareStatement("SELECT CONFIG_DATA FROM CONFIG WHERE CONFIG_TYPE = ?"); + stmt.setString(1, configType.toString()); + return stmt; + }, r -> r.getString("CONFIG_DATA")) + .map(s -> (T) Jsons.deserialize(s, clazz)) + .collect(Collectors.toList()); + return results; + } catch (SQLException e) { + throw new IOException(String.format("Failed to get config type %s listing. Reason: %s", configType, e.getMessage()), e); + } } @Override - public void writeConfig(ConfigSchema configType, String configId, T config) throws JsonValidationException { + public void writeConfig(ConfigSchema configType, UUID configId, T config) throws JsonValidationException, IOException { // validate config with schema validateJson(Jsons.jsonNode(config), configType); final String data = Jsons.serialize(config); try { database.execute(c -> writeConfigQuery(c, configType, configId, data).execute()); - } catch (SQLException e) - { - LOGGER.error("Error while writing config data,", e); + } catch (SQLException e) { + throw new IOException(String.format("Failed to write config type %s item %s. Reason: %s", configType, configId, e.getMessage()), e); } } // Made abstract because what we want for this is an upsert operation, which different databases // handle with different syntax // Overrides need to return a prepared statement with all 3 data elements added - protected abstract PreparedStatement writeConfigQuery(Connection conn, ConfigSchema configType, String configId, String data); + protected abstract PreparedStatement writeConfigQuery(Connection conn, ConfigSchema configType, UUID configId, String data) throws SQLException; private void validateJson(T config, ConfigSchema configType) throws JsonValidationException { JsonNode schema = JsonSchemaValidator.getSchema(configType.getFile()); jsonSchemaValidator.ensure(schema, Jsons.jsonNode(config)); } + } diff --git a/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java b/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java index edc656adad183..114d5838ffc91 100644 --- a/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java +++ b/airbyte-config/db-persistence/src/main/java/io.airbyte.config.dbPersistence/PostgresConfigPersistence.java @@ -24,25 +24,48 @@ package io.airbyte.config.dbPersistence; -import io.airbyte.db.jdbc.JdbcDatabase; +import com.fasterxml.jackson.databind.JsonNode; +import io.airbyte.config.ConfigSchema; +import io.airbyte.db.Databases; import io.airbyte.validation.json.JsonSchemaValidator; - import java.sql.Connection; import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.UUID; + +public class PostgresConfigPersistence extends DatabaseConfigPersistence { -public class PostgresConfigPersistence extends io.airbyte.config.dbPersistence.DatabaseConfigPersistence { + public PostgresConfigPersistence(String username, String password, String connectionString) { + this(username, password, connectionString, new JsonSchemaValidator()); + } + + public PostgresConfigPersistence(JsonNode config) { + this(config, new JsonSchemaValidator()); + } - public PostgresConfigPersistence(JdbcDatabase db) { - super(db); + public PostgresConfigPersistence(JsonNode config, JsonSchemaValidator validator) { + this(config.get("username").asText(), config.get("password").asText(), Databases.getPostgresJdbcUrl(config), validator); } - public PostgresConfigPersistence(JdbcDatabase db, JsonSchemaValidator validator) { - super(db, validator); + public PostgresConfigPersistence(String username, String password, String connectionString, JsonSchemaValidator validator) { + super(Databases.createJdbcDatabase(username, password, connectionString, Databases.POSTGRES_DRIVER), validator); } @Override - protected PreparedStatement writeConfigQuery(Connection conn, ConfigSchema configType, String configId, String data) - { - return conn.prepareStatement("INSERT INTO CONFIG (CONFIG_ID, CONFIG_TYPE, CONFIG_DATA) VALUES (?, ?, ?) ON CONFLICT (CONFIG_ID) DO UPDATE SET CONFIG_DATA = EXCLUDED.CONFIG_DATA", configId, configType.toString(), data); + // Create a table named CONFIG with three columns: CONFIG_ID (PK UUID/string), CONFIG_TYPE (string), + // CONFIG_DATA (JSON/string) + public void Setup() throws SQLException { + database.execute("CREATE TABLE CONFIG (CONFIG_ID UUID PRIMARY KEY, CONFIG_TYPE VARCHAR(32) NOT NULL, CONFIG_DATA JSONB NOT NULL)"); } + + @Override + protected PreparedStatement writeConfigQuery(Connection conn, ConfigSchema configType, UUID configId, String data) throws SQLException { + var result = conn.prepareStatement( + "INSERT INTO CONFIG (CONFIG_ID, CONFIG_TYPE, CONFIG_DATA) VALUES (?, ?, CAST(? as jsonb)) ON CONFLICT (CONFIG_ID) DO UPDATE SET CONFIG_DATA = EXCLUDED.CONFIG_DATA"); + result.setObject(1, configId); + result.setString(2, configType.toString()); + result.setString(3, data); + return result; + } + } diff --git a/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java b/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java index 096b8724da372..8c1edc51b988e 100644 --- a/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java +++ b/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) 2020 Airbyte + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package io.airbyte.config.dbPersistence; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -9,96 +33,107 @@ import io.airbyte.config.ConfigSchema; import io.airbyte.config.StandardSourceDefinition; import io.airbyte.config.StandardSync; +import io.airbyte.config.persistence.ConfigNotFoundException; import io.airbyte.validation.json.JsonSchemaValidator; import io.airbyte.validation.json.JsonValidationException; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; +import java.sql.SQLException; import java.util.List; import java.util.UUID; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.testcontainers.containers.PostgreSQLContainer; public class PostgresConfigPersistenceTest { - public static final UUID UUID_1 = new UUID(0, 1); - public static final StandardSourceDefinition SOURCE_1 = new StandardSourceDefinition(); - - static { - SOURCE_1.withSourceDefinitionId(UUID_1) - .withName("apache storm"); - } - - public static final UUID UUID_2 = new UUID(0, 2); - public static final StandardSourceDefinition SOURCE_2 = new StandardSourceDefinition(); - private static final Path TEST_ROOT = Path.of("/tmp/airbyte_tests"); - - static { - SOURCE_2.withSourceDefinitionId(UUID_2) - .withName("apache storm"); - } - - private Path rootPath; - private JsonSchemaValidator schemaValidator; - - private DefaultConfigPersistence configPersistence; - - @BeforeEach - void setUp() throws IOException { - schemaValidator = mock(JsonSchemaValidator.class); - rootPath = Files.createTempDirectory(Files.createDirectories(TEST_ROOT), DefaultConfigPersistenceTest.class.getName()); - - configPersistence = new DefaultConfigPersistence(rootPath, schemaValidator); - } - - @Test - void testReadWriteConfig() throws IOException, JsonValidationException, ConfigNotFoundException { - configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1.toString(), SOURCE_1); - - assertEquals( - SOURCE_1, - configPersistence.getConfig( - ConfigSchema.STANDARD_SOURCE_DEFINITION, - UUID_1.toString(), - StandardSourceDefinition.class)); - } - - @Test - void testListConfigs() throws JsonValidationException, IOException { - configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1.toString(), SOURCE_1); - configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_2.toString(), SOURCE_2); - - assertEquals( - Sets.newHashSet(SOURCE_1, SOURCE_2), - Sets.newHashSet(configPersistence.listConfigs(ConfigSchema.STANDARD_SOURCE_DEFINITION, StandardSourceDefinition.class))); - } - - @Test - void writeConfigWithJsonSchemaRef() throws JsonValidationException, IOException, ConfigNotFoundException { - final StandardSync standardSync = new StandardSync() - .withName("sync") - .withPrefix("sync") - .withConnectionId(UUID_1) - .withSourceId(UUID.randomUUID()) - .withDestinationId(UUID.randomUUID()) - .withOperationIds(List.of(UUID.randomUUID())); - - configPersistence.writeConfig(ConfigSchema.STANDARD_SYNC, UUID_1.toString(), standardSync); - - assertEquals( - standardSync, - configPersistence.getConfig(ConfigSchema.STANDARD_SYNC, UUID_1.toString(), StandardSync.class)); - } - - @Test - void writeConfigInvalidConfig() throws JsonValidationException { - StandardSourceDefinition standardSourceDefinition = SOURCE_1.withName(null); - - doThrow(new JsonValidationException("error")).when(schemaValidator).ensure(any(), any()); - - assertThrows(JsonValidationException.class, () -> configPersistence.writeConfig( - ConfigSchema.STANDARD_SOURCE_DEFINITION, - UUID_1.toString(), - standardSourceDefinition)); - } - -} \ No newline at end of file + + public static final UUID UUID_1 = new UUID(0, 1); + public static final StandardSourceDefinition SOURCE_1 = new StandardSourceDefinition(); + + static { + SOURCE_1.withSourceDefinitionId(UUID_1) + .withName("apache storm"); + } + + public static final UUID UUID_2 = new UUID(0, 2); + public static final StandardSourceDefinition SOURCE_2 = new StandardSourceDefinition(); + + static { + SOURCE_2.withSourceDefinitionId(UUID_2) + .withName("apache storm"); + } + + private JsonSchemaValidator schemaValidator; + + private PostgresConfigPersistence configPersistence; + + private static final String IMAGE_NAME = "postgres:13-alpine"; + private PostgreSQLContainer db; + + @BeforeEach + void setUp() throws SQLException { + schemaValidator = mock(JsonSchemaValidator.class); + db = new PostgreSQLContainer<>(IMAGE_NAME); + db.start(); + configPersistence = new PostgresConfigPersistence(db.getUsername(), db.getPassword(), db.getJdbcUrl(), schemaValidator); + configPersistence.Setup(); + } + + @AfterEach + void tearDown() { + db.stop(); + db.close(); + } + + @Test + void testReadWriteConfig() throws IOException, JsonValidationException, ConfigNotFoundException { + configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1, SOURCE_1); + + assertEquals( + SOURCE_1, + configPersistence.getConfig( + ConfigSchema.STANDARD_SOURCE_DEFINITION, + UUID_1, + StandardSourceDefinition.class)); + } + + @Test + void testListConfigs() throws JsonValidationException, IOException { + configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1, SOURCE_1); + configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_2, SOURCE_2); + + assertEquals( + Sets.newHashSet(SOURCE_1, SOURCE_2), + Sets.newHashSet(configPersistence.listConfigs(ConfigSchema.STANDARD_SOURCE_DEFINITION, StandardSourceDefinition.class))); + } + + @Test + void writeConfigWithJsonSchemaRef() throws JsonValidationException, IOException, ConfigNotFoundException { + final StandardSync standardSync = new StandardSync() + .withName("sync") + .withPrefix("sync") + .withConnectionId(UUID_1) + .withSourceId(UUID.randomUUID()) + .withDestinationId(UUID.randomUUID()) + .withOperationIds(List.of(UUID.randomUUID())); + + configPersistence.writeConfig(ConfigSchema.STANDARD_SYNC, UUID_1, standardSync); + + assertEquals( + standardSync, + configPersistence.getConfig(ConfigSchema.STANDARD_SYNC, UUID_1, StandardSync.class)); + } + + @Test + void writeConfigInvalidConfig() throws JsonValidationException { + StandardSourceDefinition standardSourceDefinition = SOURCE_1.withName(null); + + doThrow(new JsonValidationException("error")).when(schemaValidator).ensure(any(), any()); + + assertThrows(JsonValidationException.class, () -> configPersistence.writeConfig( + ConfigSchema.STANDARD_SOURCE_DEFINITION, + UUID_1, + standardSourceDefinition)); + } + +} diff --git a/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigNotFoundException.java b/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigNotFoundException.java index a77e5176daba0..b37dad5497f2b 100644 --- a/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigNotFoundException.java +++ b/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigNotFoundException.java @@ -25,16 +25,17 @@ package io.airbyte.config.persistence; import io.airbyte.config.ConfigSchema; +import java.util.UUID; public class ConfigNotFoundException extends Exception { private ConfigSchema type; private final String configId; - public ConfigNotFoundException(ConfigSchema type, String configId) { - super(String.format("config type: %s id: %s", type, configId)); + public ConfigNotFoundException(ConfigSchema type, UUID configId) { + super(String.format("config type: %s id: %s", type, configId.toString())); this.type = type; - this.configId = configId; + this.configId = configId.toString(); } public ConfigSchema getType() { diff --git a/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigPersistence.java b/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigPersistence.java index 8ad20e5760042..dc82f0348b95f 100644 --- a/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigPersistence.java +++ b/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigPersistence.java @@ -28,13 +28,14 @@ import io.airbyte.validation.json.JsonValidationException; import java.io.IOException; import java.util.List; +import java.util.UUID; public interface ConfigPersistence { - T getConfig(ConfigSchema configType, String configId, Class clazz) throws ConfigNotFoundException, JsonValidationException, IOException; + T getConfig(ConfigSchema configType, UUID configId, Class clazz) throws ConfigNotFoundException, JsonValidationException, IOException; List listConfigs(ConfigSchema configType, Class clazz) throws JsonValidationException, IOException; - void writeConfig(ConfigSchema configType, String configId, T config) throws JsonValidationException, IOException; + void writeConfig(ConfigSchema configType, UUID configId, T config) throws JsonValidationException, IOException; } diff --git a/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigRepository.java b/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigRepository.java index f50cf5636327e..a6ca9250feeca 100644 --- a/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigRepository.java +++ b/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/ConfigRepository.java @@ -49,13 +49,13 @@ public ConfigRepository(ConfigPersistence persistence) { public StandardWorkspace getStandardWorkspace(final UUID workspaceId, boolean includeTombstone) throws JsonValidationException, IOException, ConfigNotFoundException { - StandardWorkspace workspace = persistence.getConfig(ConfigSchema.STANDARD_WORKSPACE, workspaceId.toString(), StandardWorkspace.class); + StandardWorkspace workspace = persistence.getConfig(ConfigSchema.STANDARD_WORKSPACE, workspaceId, StandardWorkspace.class); if (!MoreBooleans.isTruthy(workspace.getTombstone()) || includeTombstone) { return workspace; } - throw new ConfigNotFoundException(ConfigSchema.STANDARD_WORKSPACE, workspaceId.toString()); + throw new ConfigNotFoundException(ConfigSchema.STANDARD_WORKSPACE, workspaceId); } public StandardWorkspace getWorkspaceBySlug(String slug, boolean includeTombstone) @@ -66,7 +66,7 @@ public StandardWorkspace getWorkspaceBySlug(String slug, boolean includeTombston } } - throw new ConfigNotFoundException(ConfigSchema.STANDARD_WORKSPACE, slug); + throw new ConfigNotFoundException(ConfigSchema.STANDARD_WORKSPACE, UUID.fromString(slug)); } public List listStandardWorkspaces(boolean includeTombstone) @@ -84,12 +84,12 @@ public List listStandardWorkspaces(boolean includeTombstone) } public void writeStandardWorkspace(final StandardWorkspace workspace) throws JsonValidationException, IOException { - persistence.writeConfig(ConfigSchema.STANDARD_WORKSPACE, workspace.getWorkspaceId().toString(), workspace); + persistence.writeConfig(ConfigSchema.STANDARD_WORKSPACE, workspace.getWorkspaceId(), workspace); } public StandardSourceDefinition getStandardSourceDefinition(final UUID sourceDefinitionId) throws JsonValidationException, IOException, ConfigNotFoundException { - return persistence.getConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, sourceDefinitionId.toString(), StandardSourceDefinition.class); + return persistence.getConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, sourceDefinitionId, StandardSourceDefinition.class); } public StandardSourceDefinition getSourceDefinitionFromSource(UUID sourceId) { @@ -115,12 +115,12 @@ public List listStandardSources() throws JsonValidatio } public void writeStandardSource(final StandardSourceDefinition source) throws JsonValidationException, IOException { - persistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, source.getSourceDefinitionId().toString(), source); + persistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, source.getSourceDefinitionId(), source); } public StandardDestinationDefinition getStandardDestinationDefinition(final UUID destinationDefinitionId) throws JsonValidationException, IOException, ConfigNotFoundException { - return persistence.getConfig(ConfigSchema.STANDARD_DESTINATION_DEFINITION, destinationDefinitionId.toString(), + return persistence.getConfig(ConfigSchema.STANDARD_DESTINATION_DEFINITION, destinationDefinitionId, StandardDestinationDefinition.class); } @@ -150,16 +150,16 @@ public void writeStandardDestinationDefinition(final StandardDestinationDefiniti throws JsonValidationException, IOException { persistence.writeConfig( ConfigSchema.STANDARD_DESTINATION_DEFINITION, - destinationDefinition.getDestinationDefinitionId().toString(), + destinationDefinition.getDestinationDefinitionId(), destinationDefinition); } public SourceConnection getSourceConnection(final UUID sourceId) throws JsonValidationException, IOException, ConfigNotFoundException { - return persistence.getConfig(ConfigSchema.SOURCE_CONNECTION, sourceId.toString(), SourceConnection.class); + return persistence.getConfig(ConfigSchema.SOURCE_CONNECTION, sourceId, SourceConnection.class); } public void writeSourceConnection(final SourceConnection source) throws JsonValidationException, IOException { - persistence.writeConfig(ConfigSchema.SOURCE_CONNECTION, source.getSourceId().toString(), source); + persistence.writeConfig(ConfigSchema.SOURCE_CONNECTION, source.getSourceId(), source); } public List listSourceConnection() throws JsonValidationException, IOException { @@ -168,11 +168,11 @@ public List listSourceConnection() throws JsonValidationExcept public DestinationConnection getDestinationConnection(final UUID destinationId) throws JsonValidationException, IOException, ConfigNotFoundException { - return persistence.getConfig(ConfigSchema.DESTINATION_CONNECTION, destinationId.toString(), DestinationConnection.class); + return persistence.getConfig(ConfigSchema.DESTINATION_CONNECTION, destinationId, DestinationConnection.class); } public void writeDestinationConnection(DestinationConnection destinationConnection) throws JsonValidationException, IOException { - persistence.writeConfig(ConfigSchema.DESTINATION_CONNECTION, destinationConnection.getDestinationId().toString(), destinationConnection); + persistence.writeConfig(ConfigSchema.DESTINATION_CONNECTION, destinationConnection.getDestinationId(), destinationConnection); } public List listDestinationConnection() throws JsonValidationException, IOException { @@ -180,11 +180,11 @@ public List listDestinationConnection() throws JsonValida } public StandardSync getStandardSync(final UUID connectionId) throws JsonValidationException, IOException, ConfigNotFoundException { - return persistence.getConfig(ConfigSchema.STANDARD_SYNC, connectionId.toString(), StandardSync.class); + return persistence.getConfig(ConfigSchema.STANDARD_SYNC, connectionId, StandardSync.class); } public void writeStandardSync(final StandardSync standardSync) throws JsonValidationException, IOException { - persistence.writeConfig(ConfigSchema.STANDARD_SYNC, standardSync.getConnectionId().toString(), standardSync); + persistence.writeConfig(ConfigSchema.STANDARD_SYNC, standardSync.getConnectionId(), standardSync); } public List listStandardSyncs() throws ConfigNotFoundException, IOException, JsonValidationException { @@ -192,11 +192,11 @@ public List listStandardSyncs() throws ConfigNotFoundException, IO } public StandardSyncOperation getStandardSyncOperation(final UUID operationId) throws JsonValidationException, IOException, ConfigNotFoundException { - return persistence.getConfig(ConfigSchema.STANDARD_SYNC_OPERATION, operationId.toString(), StandardSyncOperation.class); + return persistence.getConfig(ConfigSchema.STANDARD_SYNC_OPERATION, operationId, StandardSyncOperation.class); } public void writeStandardSyncOperation(final StandardSyncOperation standardSyncOperation) throws JsonValidationException, IOException { - persistence.writeConfig(ConfigSchema.STANDARD_SYNC_OPERATION, standardSyncOperation.getOperationId().toString(), standardSyncOperation); + persistence.writeConfig(ConfigSchema.STANDARD_SYNC_OPERATION, standardSyncOperation.getOperationId(), standardSyncOperation); } public List listStandardSyncOperations() throws IOException, JsonValidationException { diff --git a/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/DefaultConfigPersistence.java b/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/DefaultConfigPersistence.java index 6841097e73322..984cdee958d2f 100644 --- a/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/DefaultConfigPersistence.java +++ b/airbyte-config/persistence/src/main/java/io/airbyte/config/persistence/DefaultConfigPersistence.java @@ -35,6 +35,7 @@ import java.nio.file.Path; import java.util.Collections; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -58,7 +59,7 @@ public DefaultConfigPersistence(final Path storageRoot, final JsonSchemaValidato } @Override - public T getConfig(final ConfigSchema configType, final String configId, final Class clazz) + public T getConfig(final ConfigSchema configType, final UUID configId, final Class clazz) throws ConfigNotFoundException, JsonValidationException, IOException { synchronized (lock) { return getConfigInternal(configType, configId, clazz); @@ -73,13 +74,13 @@ public List listConfigs(ConfigSchema configType, Class clazz) throws J } @Override - public void writeConfig(ConfigSchema configType, String configId, T config) throws JsonValidationException, IOException { + public void writeConfig(ConfigSchema configType, UUID configId, T config) throws JsonValidationException, IOException { synchronized (lock) { writeConfigInternal(configType, configId, config); } } - private T getConfigInternal(ConfigSchema configType, String configId, Class clazz) + private T getConfigInternal(ConfigSchema configType, UUID configId, Class clazz) throws ConfigNotFoundException, JsonValidationException, IOException { // validate file with schema final Path configPath = buildConfigPath(configType, configId); @@ -108,7 +109,7 @@ private List listConfigsInternal(ConfigSchema configType, Class clazz) final List configs = Lists.newArrayList(); for (String id : ids) { try { - configs.add(getConfig(configType, id, clazz)); + configs.add(getConfig(configType, UUID.fromString(id), clazz)); } catch (ConfigNotFoundException e) { // should not happen since we just read the ids from disk. throw new IOException(e); @@ -119,7 +120,7 @@ private List listConfigsInternal(ConfigSchema configType, Class clazz) } } - private void writeConfigInternal(ConfigSchema configType, String configId, T config) throws JsonValidationException, IOException { + private void writeConfigInternal(ConfigSchema configType, UUID configId, T config) throws JsonValidationException, IOException { // validate config with schema validateJson(Jsons.jsonNode(config), configType); @@ -129,8 +130,8 @@ private void writeConfigInternal(ConfigSchema configType, String configId, T Files.writeString(configPath, Jsons.serialize(config)); } - private Path buildConfigPath(ConfigSchema type, String configId) { - return buildTypePath(type).resolve(String.format("%s.json", configId)); + private Path buildConfigPath(ConfigSchema type, UUID configId) { + return buildTypePath(type).resolve(String.format("%s.json", configId.toString())); } private Path buildTypePath(ConfigSchema type) { diff --git a/airbyte-config/persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryTest.java b/airbyte-config/persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryTest.java index fb2be98d07bb9..3f28a59dd94bf 100644 --- a/airbyte-config/persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryTest.java +++ b/airbyte-config/persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryTest.java @@ -62,7 +62,7 @@ void testWorkspaceWithTrueTombstone() throws ConfigNotFoundException, IOExceptio } void assertReturnsWorkspace(StandardWorkspace workspace) throws ConfigNotFoundException, IOException, JsonValidationException { - when(configPersistence.getConfig(ConfigSchema.STANDARD_WORKSPACE, PersistenceConstants.DEFAULT_WORKSPACE_ID.toString(), StandardWorkspace.class)) + when(configPersistence.getConfig(ConfigSchema.STANDARD_WORKSPACE, PersistenceConstants.DEFAULT_WORKSPACE_ID, StandardWorkspace.class)) .thenReturn(workspace); assertEquals(workspace, configRepository.getStandardWorkspace(PersistenceConstants.DEFAULT_WORKSPACE_ID, true)); diff --git a/airbyte-config/persistence/src/test/java/io/airbyte/config/persistence/DefaultConfigPersistenceTest.java b/airbyte-config/persistence/src/test/java/io/airbyte/config/persistence/DefaultConfigPersistenceTest.java index b56a5899dcb82..118d06349b4db 100644 --- a/airbyte-config/persistence/src/test/java/io/airbyte/config/persistence/DefaultConfigPersistenceTest.java +++ b/airbyte-config/persistence/src/test/java/io/airbyte/config/persistence/DefaultConfigPersistenceTest.java @@ -77,20 +77,20 @@ void setUp() throws IOException { @Test void testReadWriteConfig() throws IOException, JsonValidationException, ConfigNotFoundException { - configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1.toString(), SOURCE_1); + configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1, SOURCE_1); assertEquals( SOURCE_1, configPersistence.getConfig( ConfigSchema.STANDARD_SOURCE_DEFINITION, - UUID_1.toString(), + UUID_1, StandardSourceDefinition.class)); } @Test void testListConfigs() throws JsonValidationException, IOException { - configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1.toString(), SOURCE_1); - configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_2.toString(), SOURCE_2); + configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1, SOURCE_1); + configPersistence.writeConfig(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_2, SOURCE_2); assertEquals( Sets.newHashSet(SOURCE_1, SOURCE_2), @@ -107,11 +107,11 @@ void writeConfigWithJsonSchemaRef() throws JsonValidationException, IOException, .withDestinationId(UUID.randomUUID()) .withOperationIds(List.of(UUID.randomUUID())); - configPersistence.writeConfig(ConfigSchema.STANDARD_SYNC, UUID_1.toString(), standardSync); + configPersistence.writeConfig(ConfigSchema.STANDARD_SYNC, UUID_1, standardSync); assertEquals( standardSync, - configPersistence.getConfig(ConfigSchema.STANDARD_SYNC, UUID_1.toString(), StandardSync.class)); + configPersistence.getConfig(ConfigSchema.STANDARD_SYNC, UUID_1, StandardSync.class)); } @Test @@ -122,7 +122,7 @@ void writeConfigInvalidConfig() throws JsonValidationException { assertThrows(JsonValidationException.class, () -> configPersistence.writeConfig( ConfigSchema.STANDARD_SOURCE_DEFINITION, - UUID_1.toString(), + UUID_1, standardSourceDefinition)); } diff --git a/airbyte-db/src/main/java/io/airbyte/db/Databases.java b/airbyte-db/src/main/java/io/airbyte/db/Databases.java index b38f2c47f2879..ffa052925642e 100644 --- a/airbyte-db/src/main/java/io/airbyte/db/Databases.java +++ b/airbyte-db/src/main/java/io/airbyte/db/Databases.java @@ -24,26 +24,33 @@ package io.airbyte.db; +import com.fasterxml.jackson.databind.JsonNode; import io.airbyte.db.jdbc.DefaultJdbcDatabase; import io.airbyte.db.jdbc.JdbcDatabase; import io.airbyte.db.jdbc.JdbcStreamingQueryConfiguration; import io.airbyte.db.jdbc.StreamingJdbcDatabase; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import org.apache.commons.dbcp2.BasicDataSource; import org.jooq.SQLDialect; public class Databases { + public static final String POSTGRES_DRIVER = "org.postgresql.Driver"; + public static final String REDSHIFT_DRIVER = "com.amazon.redshift.jdbc.Driver"; + public static final String MSSQL_DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; + public static Database createPostgresDatabase(String username, String password, String jdbcConnectionString) { - return createDatabase(username, password, jdbcConnectionString, "org.postgresql.Driver", SQLDialect.POSTGRES); + return createDatabase(username, password, jdbcConnectionString, POSTGRES_DRIVER, SQLDialect.POSTGRES); } public static JdbcDatabase createRedshiftDatabase(String username, String password, String jdbcConnectionString) { - return createJdbcDatabase(username, password, jdbcConnectionString, "com.amazon.redshift.jdbc.Driver"); + return createJdbcDatabase(username, password, jdbcConnectionString, REDSHIFT_DRIVER); } public static Database createSqlServerDatabase(String username, String password, String jdbcConnectionString) { - return createDatabase(username, password, jdbcConnectionString, "com.microsoft.sqlserver.jdbc.SQLServerDriver", SQLDialect.DEFAULT); + return createDatabase(username, password, jdbcConnectionString, MSSQL_DRIVER, SQLDialect.DEFAULT); } public static Database createDatabase(final String username, @@ -109,4 +116,23 @@ private static BasicDataSource createBasicDataSource(final String username, return connectionPool; } + public static String getPostgresJdbcUrl(JsonNode config) { + List additionalParameters = new ArrayList<>(); + + final StringBuilder jdbcUrl = new StringBuilder(String.format("jdbc:postgresql://%s:%s/%s?", + config.get("host").asText(), + config.get("port").asText(), + config.get("database").asText())); + + if (config.has("ssl") && config.get("ssl").asBoolean()) { + additionalParameters.add("ssl=true"); + additionalParameters.add("sslmode=require"); + } + + if (!additionalParameters.isEmpty()) { + additionalParameters.forEach(x -> jdbcUrl.append(x).append("&")); + } + return jdbcUrl.toString(); + } + } diff --git a/airbyte-db/src/main/java/io/airbyte/db/jdbc/JdbcDatabase.java b/airbyte-db/src/main/java/io/airbyte/db/jdbc/JdbcDatabase.java index 42104979b74fb..b15c8c94c628b 100644 --- a/airbyte-db/src/main/java/io/airbyte/db/jdbc/JdbcDatabase.java +++ b/airbyte-db/src/main/java/io/airbyte/db/jdbc/JdbcDatabase.java @@ -51,8 +51,7 @@ default void execute(String sql) throws SQLException { execute(connection -> connection.createStatement().execute(sql)); } - default void executeParameterized (String sql, String... params) throws SQLException - { + default void executeParameterized(String sql, String... params) throws SQLException { execute(connection -> { final PreparedStatement stmt = connection.prepareStatement(sql, params); stmt.execute(); @@ -138,4 +137,17 @@ default Optional querySingle(String sql, CheckedFunction Optional querySingle(String sql, CheckedFunction recordTransform, Object... params) + throws SQLException { + return query(c -> { + var stmt = c.prepareStatement(sql); + int i = 1; + for (Object param : params) { + stmt.setObject(i, param); + ++i; + } + return stmt; + }, recordTransform).findFirst(); + } + } diff --git a/airbyte-integrations/connectors/destination-postgres/src/main/java/io/airbyte/integrations/destination/postgres/PostgresDestination.java b/airbyte-integrations/connectors/destination-postgres/src/main/java/io/airbyte/integrations/destination/postgres/PostgresDestination.java index 296d976c1ff6f..1d9f865c98b21 100644 --- a/airbyte-integrations/connectors/destination-postgres/src/main/java/io/airbyte/integrations/destination/postgres/PostgresDestination.java +++ b/airbyte-integrations/connectors/destination-postgres/src/main/java/io/airbyte/integrations/destination/postgres/PostgresDestination.java @@ -27,12 +27,11 @@ import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableMap; import io.airbyte.commons.json.Jsons; +import io.airbyte.db.Databases; import io.airbyte.integrations.base.Destination; import io.airbyte.integrations.base.IntegrationRunner; import io.airbyte.integrations.destination.jdbc.AbstractJdbcDestination; import io.airbyte.integrations.destination.jdbc.DefaultSqlOperations; -import java.util.ArrayList; -import java.util.List; import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,25 +50,9 @@ public PostgresDestination() { public JsonNode toJdbcConfig(JsonNode config) { final String schema = Optional.ofNullable(config.get("schema")).map(JsonNode::asText).orElse("public"); - List additionalParameters = new ArrayList<>(); - - final StringBuilder jdbcUrl = new StringBuilder(String.format("jdbc:postgresql://%s:%s/%s?", - config.get("host").asText(), - config.get("port").asText(), - config.get("database").asText())); - - if (config.has("ssl") && config.get("ssl").asBoolean()) { - additionalParameters.add("ssl=true"); - additionalParameters.add("sslmode=require"); - } - - if (!additionalParameters.isEmpty()) { - additionalParameters.forEach(x -> jdbcUrl.append(x).append("&")); - } - final ImmutableMap.Builder configBuilder = ImmutableMap.builder() .put("username", config.get("username").asText()) - .put("jdbc_url", jdbcUrl.toString()) + .put("jdbc_url", Databases.getPostgresJdbcUrl(config)) .put("schema", schema); if (config.has("password")) { diff --git a/airbyte-server/src/main/java/io/airbyte/server/handlers/DestinationHandler.java b/airbyte-server/src/main/java/io/airbyte/server/handlers/DestinationHandler.java index 3af7889e84aaa..94a1740b98b39 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/handlers/DestinationHandler.java +++ b/airbyte-server/src/main/java/io/airbyte/server/handlers/DestinationHandler.java @@ -172,7 +172,7 @@ public DestinationRead getDestination(DestinationIdRequestBody destinationIdRequ final DestinationConnection dci = configRepository.getDestinationConnection(destinationId); if (dci.getTombstone()) { - throw new ConfigNotFoundException(ConfigSchema.DESTINATION_CONNECTION, destinationId.toString()); + throw new ConfigNotFoundException(ConfigSchema.DESTINATION_CONNECTION, destinationId); } return buildDestinationRead(destinationIdRequestBody.getDestinationId()); diff --git a/airbyte-server/src/main/java/io/airbyte/server/handlers/OperationsHandler.java b/airbyte-server/src/main/java/io/airbyte/server/handlers/OperationsHandler.java index ddf3135137af9..c74cd41831636 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/handlers/OperationsHandler.java +++ b/airbyte-server/src/main/java/io/airbyte/server/handlers/OperationsHandler.java @@ -158,7 +158,7 @@ public void deleteOperation(OperationIdRequestBody operationIdRequestBody) standardSyncOperation.withTombstone(true); configRepository.writeStandardSyncOperation(standardSyncOperation); } else { - throw new ConfigNotFoundException(ConfigSchema.STANDARD_SYNC_OPERATION, operationId.toString()); + throw new ConfigNotFoundException(ConfigSchema.STANDARD_SYNC_OPERATION, operationId); } } @@ -168,7 +168,7 @@ private OperationRead buildOperationRead(UUID operationId) if (standardSyncOperation != null) { return buildOperationRead(standardSyncOperation); } else { - throw new ConfigNotFoundException(ConfigSchema.STANDARD_SYNC_OPERATION, operationId.toString()); + throw new ConfigNotFoundException(ConfigSchema.STANDARD_SYNC_OPERATION, operationId); } } diff --git a/airbyte-server/src/main/java/io/airbyte/server/handlers/SourceHandler.java b/airbyte-server/src/main/java/io/airbyte/server/handlers/SourceHandler.java index d2a4be90f74ec..52aa25cec4a35 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/handlers/SourceHandler.java +++ b/airbyte-server/src/main/java/io/airbyte/server/handlers/SourceHandler.java @@ -132,7 +132,7 @@ public SourceRead getSource(SourceIdRequestBody sourceIdRequestBody) throws Json final SourceConnection sourceConnection = configRepository.getSourceConnection(sourceId); if (sourceConnection.getTombstone()) { - throw new ConfigNotFoundException(ConfigSchema.SOURCE_CONNECTION, sourceId.toString()); + throw new ConfigNotFoundException(ConfigSchema.SOURCE_CONNECTION, sourceId); } return buildSourceRead(sourceId); From 184254874799cc21d3c34e7a0bc1f8d50be06734 Mon Sep 17 00:00:00 2001 From: Mason Wheeler Date: Thu, 3 Jun 2021 10:29:14 -0700 Subject: [PATCH 4/7] Rolling back a few unnecessary changes --- airbyte-db/build.gradle | 1 - build.gradle | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 58910 bytes gradlew | 2 +- gradlew.bat | 21 ++++++++++++++++++--- settings.gradle | 1 + 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/airbyte-db/build.gradle b/airbyte-db/build.gradle index a14853aa7c86c..0205b835d1a23 100644 --- a/airbyte-db/build.gradle +++ b/airbyte-db/build.gradle @@ -9,7 +9,6 @@ dependencies { api 'org.postgresql:postgresql:42.2.18' implementation project(':airbyte-protocol:models') - implementation project(':airbyte-config') testImplementation project(':airbyte-test-utils') diff --git a/build.gradle b/build.gradle index 7e844dd162100..1f344bdba0646 100644 --- a/build.gradle +++ b/build.gradle @@ -118,6 +118,7 @@ allprojects { ":airbyte-migration", ":airbyte-scheduler:app", ":airbyte-server", + ":airbyte-webapp", ].toSet().asImmutable() if (project.getPath() in composeDeps) { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..62d4c053550b91381bbd28b1afc82d634bf73a8a 100644 GIT binary patch delta 6475 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 delta 6656 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 Yte!%o?r4GTrVtxD61Ym!|5fq-1K$0e!TNUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto execute +if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,6 +64,21 @@ echo location of your Java installation. goto fail +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + :execute @rem Setup the command line @@ -71,7 +86,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle b/settings.gradle index 84dfaaeeed595..5715bb253df7c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -46,6 +46,7 @@ include ':airbyte-scheduler:client' include ':airbyte-scheduler:models' include ':airbyte-scheduler:persistence' include ':airbyte-server' +include ':airbyte-webapp' include ':airbyte-workers' include ':airbyte-tests' include ':airbyte-test-utils' From a57b26e17ef34acf0595028986c7666903d7a24f Mon Sep 17 00:00:00 2001 From: masonwheeler Date: Thu, 3 Jun 2021 16:59:00 -0600 Subject: [PATCH 5/7] Update airbyte-config/db-persistence/build.gradle Co-authored-by: Charles --- airbyte-config/db-persistence/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airbyte-config/db-persistence/build.gradle b/airbyte-config/db-persistence/build.gradle index 615e83c76bf96..9686f2dcc41ef 100644 --- a/airbyte-config/db-persistence/build.gradle +++ b/airbyte-config/db-persistence/build.gradle @@ -1,5 +1,5 @@ dependencies { - implementation group: 'commons-io', name: 'commons-io', version: '2.7' + implementation 'commons-io:commons-io:2.7' implementation project(':airbyte-db') implementation project(':airbyte-commons') From c6fba44cc6558036b298c536effc0aaa1f562330 Mon Sep 17 00:00:00 2001 From: Mason Wheeler Date: Fri, 4 Jun 2021 08:06:12 -0700 Subject: [PATCH 6/7] Responding to review feedback --- .../config/dbPersistence/PostgresConfigPersistenceTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java b/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java index 8c1edc51b988e..7d61b039bbc0e 100644 --- a/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java +++ b/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java @@ -27,7 +27,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.doThrow; import com.google.common.collect.Sets; import io.airbyte.config.ConfigSchema; From 98a1133ac5faaa8addacb745d9fbb4c0ec9ffb22 Mon Sep 17 00:00:00 2001 From: Mason Wheeler Date: Fri, 4 Jun 2021 09:38:57 -0700 Subject: [PATCH 7/7] Fixing formatting --- .../config/dbPersistence/PostgresConfigPersistenceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java b/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java index 7d61b039bbc0e..7eb7abb741740 100644 --- a/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java +++ b/airbyte-config/db-persistence/src/test/java/io/airbyte/config/dbPersistence/PostgresConfigPersistenceTest.java @@ -27,8 +27,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; import com.google.common.collect.Sets; import io.airbyte.config.ConfigSchema;