From 0acbd562a4d7808c146b5374927d439106554a7d Mon Sep 17 00:00:00 2001 From: Adam Jordens Date: Mon, 17 Jun 2019 22:47:09 -0700 Subject: [PATCH] fix(sql): Ensure that the columns are kept in sync with `body` This covers the `application`, `name`, etc. normalized columns that are also represented within the json `body` blob. --- front50-sql/front50-sql.gradle | 5 +-- .../front50/model/SqlStorageService.kt | 1 + .../front50/model/sql/TableDefinitions.kt | 33 +++++++++++++++++++ .../front50/model/SqlStorageServiceTests.kt | 11 +++++++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/front50-sql/front50-sql.gradle b/front50-sql/front50-sql.gradle index c03883783..a3a21311a 100644 --- a/front50-sql/front50-sql.gradle +++ b/front50-sql/front50-sql.gradle @@ -3,20 +3,17 @@ apply from: "$rootDir/gradle/kotlin.gradle" dependencies { implementation project(":front50-sql-mariadb") - implementation "com.netflix.spinnaker.front50:front50-core:${front50Version}" + implementation "com.netflix.spinnaker.front50:front50-core" implementation "com.netflix.spinnaker.kork:kork-sql" implementation "com.netflix.spinnaker.kork:kork-exceptions" -// implementation "org.jooq:jooq:3.11.11" implementation "io.strikt:strikt-core" implementation "com.netflix.hystrix:hystrix-core" implementation "io.github.resilience4j:resilience4j-retry" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core" - // runtimeOnly "mysql:mysql-connector-java" - testImplementation "io.mockk:mockk" testImplementation "mysql:mysql-connector-java" testImplementation "dev.minutest:minutest" diff --git a/front50-sql/src/main/kotlin/com/netflix/spinnaker/front50/model/SqlStorageService.kt b/front50-sql/src/main/kotlin/com/netflix/spinnaker/front50/model/SqlStorageService.kt index 79e03997e..f89e182a6 100644 --- a/front50-sql/src/main/kotlin/com/netflix/spinnaker/front50/model/SqlStorageService.kt +++ b/front50-sql/src/main/kotlin/com/netflix/spinnaker/front50/model/SqlStorageService.kt @@ -154,6 +154,7 @@ class SqlStorageService( .set(field("last_modified_at"), MySQLDSL.values(field("last_modified_at")) as Any) .set(field("last_modified_by"), MySQLDSL.values(field("last_modified_by")) as Any) .set(field("is_deleted"), MySQLDSL.values(field("is_deleted")) as Any) + .apply(definitionsByType[objectType]!!.onDuplicateKeyUpdate()) } insert.execute() diff --git a/front50-sql/src/main/kotlin/com/netflix/spinnaker/front50/model/sql/TableDefinitions.kt b/front50-sql/src/main/kotlin/com/netflix/spinnaker/front50/model/sql/TableDefinitions.kt index 6ae6d4e83..fa25ad16e 100644 --- a/front50-sql/src/main/kotlin/com/netflix/spinnaker/front50/model/sql/TableDefinitions.kt +++ b/front50-sql/src/main/kotlin/com/netflix/spinnaker/front50/model/sql/TableDefinitions.kt @@ -24,7 +24,10 @@ import com.netflix.spinnaker.front50.model.delivery.Delivery import com.netflix.spinnaker.front50.model.pipeline.Pipeline import com.netflix.spinnaker.front50.model.project.Project import org.jooq.Field +import org.jooq.InsertOnDuplicateSetMoreStep +import org.jooq.Record import org.jooq.impl.DSL +import org.jooq.util.mysql.MySQLDSL import java.nio.charset.StandardCharsets.UTF_8 import java.time.Clock @@ -76,6 +79,10 @@ open class DefaultTableDefinition( objectKey, objectAsString, signature, item.lastModified, clock.millis() ) } + + open fun onDuplicateKeyUpdate(): InsertOnDuplicateSetMoreStep.() -> Unit { + return {} + } } class DeliveryTableDefinition : DefaultTableDefinition(ObjectType.DELIVERY, "deliveries", true) { @@ -103,6 +110,12 @@ class DeliveryTableDefinition : DefaultTableDefinition(ObjectType.DELIVERY, "del false ) } + + override fun onDuplicateKeyUpdate(): InsertOnDuplicateSetMoreStep.() -> Unit { + return { + set(DSL.field("application"), MySQLDSL.values(DSL.field("application")) as Any) + } + } } class PipelineTableDefinition : DefaultTableDefinition(ObjectType.PIPELINE, "pipelines", true) { @@ -132,6 +145,13 @@ class PipelineTableDefinition : DefaultTableDefinition(ObjectType.PIPELINE, "pip false ) } + + override fun onDuplicateKeyUpdate(): InsertOnDuplicateSetMoreStep.() -> Unit { + return { + set(DSL.field("name"), MySQLDSL.values(DSL.field("name")) as Any) + set(DSL.field("application"), MySQLDSL.values(DSL.field("application")) as Any) + } + } } class PipelineStrategyTableDefinition : DefaultTableDefinition(ObjectType.STRATEGY, "pipeline_strategies", true) { @@ -161,6 +181,13 @@ class PipelineStrategyTableDefinition : DefaultTableDefinition(ObjectType.STRATE false ) } + + override fun onDuplicateKeyUpdate(): InsertOnDuplicateSetMoreStep.() -> Unit { + return { + set(DSL.field("name"), MySQLDSL.values(DSL.field("name")) as Any) + set(DSL.field("application"), MySQLDSL.values(DSL.field("application")) as Any) + } + } } class ProjectTableDefinition : DefaultTableDefinition(ObjectType.PROJECT, "projects", true) { @@ -188,4 +215,10 @@ class ProjectTableDefinition : DefaultTableDefinition(ObjectType.PROJECT, "proje false ) } + + override fun onDuplicateKeyUpdate(): InsertOnDuplicateSetMoreStep.() -> Unit { + return { + set(DSL.field("name"), MySQLDSL.values(DSL.field("name")) as Any) + } + } } diff --git a/front50-sql/src/test/kotlin/com/netflix/spinnaker/front50/model/SqlStorageServiceTests.kt b/front50-sql/src/test/kotlin/com/netflix/spinnaker/front50/model/SqlStorageServiceTests.kt index c208a5ca9..f36ea78ca 100644 --- a/front50-sql/src/test/kotlin/com/netflix/spinnaker/front50/model/SqlStorageServiceTests.kt +++ b/front50-sql/src/test/kotlin/com/netflix/spinnaker/front50/model/SqlStorageServiceTests.kt @@ -26,6 +26,7 @@ import com.netflix.spinnaker.kork.sql.config.SqlRetryProperties import dev.minutest.junit.JUnit5Minutests import dev.minutest.rootContext import org.jooq.SQLDialect +import org.jooq.impl.DSL import org.junit.jupiter.api.AfterAll import strikt.api.expectThat import strikt.api.expectThrows @@ -137,6 +138,16 @@ internal object SqlStorageServiceTests : JUnit5Minutests { pipeline = sqlStorageService.loadObject(ObjectType.PIPELINE, "id-pipeline001") expectThat(pipeline.name).isEqualTo("pipeline001_updated") + expectThat( + jooq + .select(DSL.field("id", String::class.java)) + .from("pipelines") + .where( + DSL.field("name", String::class.java).eq("pipeline001_updated") + ) + .fetchOne(DSL.field("id", String::class.java)) + ).isEqualTo("id-pipeline001") + // delete the pipeline sqlStorageService.deleteObject(ObjectType.PIPELINE, "id-pipeline001")