Skip to content

Commit

Permalink
Correct migration callback AfterVersion range filter
Browse files Browse the repository at this point in the history
Introduced in 1.5.0, SQLDelight had an off-by-one error
for determining when to invoke an AfterMigration callback.
This commit corrects the version range for which callbacks
are invoked.

Closes #2393.
  • Loading branch information
Kevin Cianfarini committed May 12, 2021
1 parent 8858261 commit dcb7aa1
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 143 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ fun SqlDriver.Schema.migrateWithCallbacks(
) {
var lastVersion = oldVersion

// For each callback within the oldVersion..newVersion range, alternate between migrating
// For each callback within the [oldVersion..newVersion) range, alternate between migrating
// the schema and invoking each callback.
callbacks.filter { it.afterVersion in (oldVersion + 1) until newVersion }
callbacks.filter { it.afterVersion in oldVersion until newVersion }
.sortedBy { it.afterVersion }
.forEach { callback ->
migrate(driver, oldVersion = lastVersion, newVersion = callback.afterVersion + 1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.squareup.sqldelight.logs

import com.squareup.sqldelight.db.AfterVersion
import com.squareup.sqldelight.db.SqlDriver
import com.squareup.sqldelight.db.migrateWithCallbacks
import kotlin.test.Test
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class SqlDriverMigrationCallbackTest {

@Test fun migrationCallbackInvokedOnCorrectVersion() {
val schema = fakeSchema()

var callbackInvoked = false

schema.migrateWithCallbacks(
driver = FakeSqlDriver(),
oldVersion = 1,
newVersion = 2,
AfterVersion(1) { callbackInvoked = true }
)

assertTrue(callbackInvoked)
}

@Test fun migrationCallbacks() {
val schema = fakeSchema()

var callback1Invoked = false
var callback2Invoked = false
var callback3Invoked = false

schema.migrateWithCallbacks(
driver = FakeSqlDriver(),
oldVersion = 0,
newVersion = 4,
AfterVersion(1) { callback1Invoked = true },
AfterVersion(2) { callback2Invoked = true },
AfterVersion(3) { callback3Invoked = true },
)

assertTrue(callback1Invoked)
assertTrue(callback2Invoked)
assertTrue(callback3Invoked)
}

@Test fun migrationCallbackLessThanOldVersionNotCalled() {
val schema = fakeSchema()

var callback1Invoked = false
var callback2Invoked = false
var callback3Invoked = false

schema.migrateWithCallbacks(
driver = FakeSqlDriver(),
oldVersion = 2,
newVersion = 4,
AfterVersion(1) { callback1Invoked = true },
AfterVersion(2) { callback2Invoked = true },
AfterVersion(3) { callback3Invoked = true },
)

assertFalse(callback1Invoked)
assertTrue(callback2Invoked)
assertTrue(callback3Invoked)
}

@Test fun migrationCallbackGreaterThanNewVersionNotCalled() {
val schema = fakeSchema()

var callback1Invoked = false
var callback2Invoked = false
var callback3Invoked = false
var callback4Invoked = false

schema.migrateWithCallbacks(
driver = FakeSqlDriver(),
oldVersion = 0,
newVersion = 4,
AfterVersion(1) { callback1Invoked = true },
AfterVersion(2) { callback2Invoked = true },
AfterVersion(3) { callback3Invoked = true },
AfterVersion(4) { callback4Invoked = true },
)

assertTrue(callback1Invoked)
assertTrue(callback2Invoked)
assertTrue(callback3Invoked)
assertFalse(callback4Invoked)
}

private fun fakeSchema() = object : SqlDriver.Schema {
override val version: Int = 1
override fun create(driver: SqlDriver) = Unit
override fun migrate(driver: SqlDriver, oldVersion: Int, newVersion: Int) = Unit
}
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,6 @@ class IntegrationTest {
assertThat(result.output).contains("BUILD SUCCESSFUL")
}

@Test fun migrationCallbackIntegrationTests() {
val integrationRoot = File("src/test/integration-migration-callbacks")
val gradleRoot = File(integrationRoot, "gradle").apply {
mkdir()
}
File("../gradle/wrapper").copyRecursively(File(gradleRoot, "wrapper"), true)

val runner = GradleRunner.create()
.withProjectDir(integrationRoot)
.withArguments("clean", "check", "--stacktrace")

val result = runner.build()
assertThat(result.output).contains("BUILD SUCCESSFUL")
}

@Test fun `sqldelight output is cacheable`() {
val fixtureRoot = File("src/test/integration")
fixtureRoot.resolve("build").deleteRecursively()
Expand Down

0 comments on commit dcb7aa1

Please sign in to comment.