From 43d789df7098a80a1e72e8c1eba257afacecd826 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 16:31:58 -0600 Subject: [PATCH 01/16] Remove obsolete DB migration SQL constants and version history for v48-51 Co-Authored-By: Claude Sonnet 4.6 --- .../org/keynote/godtools/android/db/Contract.kt | 15 --------------- .../godtools/android/db/GodToolsDatabase.kt | 16 ---------------- 2 files changed, 31 deletions(-) diff --git a/library/db/src/main/kotlin/org/keynote/godtools/android/db/Contract.kt b/library/db/src/main/kotlin/org/keynote/godtools/android/db/Contract.kt index 3282636e24..306d93afe6 100644 --- a/library/db/src/main/kotlin/org/keynote/godtools/android/db/Contract.kt +++ b/library/db/src/main/kotlin/org/keynote/godtools/android/db/Contract.kt @@ -85,22 +85,7 @@ internal object Contract : BaseContract() { COLUMN_SPOTLIGHT ) - private const val SQL_COLUMN_DETAILS_BANNER_ANIMATION = "$COLUMN_DETAILS_BANNER_ANIMATION INTEGER" - private const val SQL_COLUMN_META_TOOL = "$COLUMN_META_TOOL TEXT" - private const val SQL_COLUMN_DEFAULT_VARIANT = "$COLUMN_DEFAULT_VARIANT TEXT" - private const val SQL_COLUMN_SPOTLIGHT = "$COLUMN_SPOTLIGHT INTEGER" - internal val SQL_DELETE_TABLE = drop(TABLE_NAME) - - // region DB migrations - internal const val SQL_V48_CREATE_SPOTLIGHT = "ALTER TABLE $TABLE_NAME ADD COLUMN $SQL_COLUMN_SPOTLIGHT" - internal const val SQL_V48_POPULATE_SPOTLIGHT = "UPDATE $TABLE_NAME SET $COLUMN_SPOTLIGHT = 0" - internal const val SQL_V49_ALTER_DETAILS_BANNER_ANIMATION = - "ALTER TABLE $TABLE_NAME ADD COLUMN $SQL_COLUMN_DETAILS_BANNER_ANIMATION" - internal const val SQL_V50_ALTER_META_TOOL = "ALTER TABLE $TABLE_NAME ADD COLUMN $SQL_COLUMN_META_TOOL" - internal const val SQL_V51_ALTER_DEFAULT_VARIANT = - "ALTER TABLE $TABLE_NAME ADD COLUMN $SQL_COLUMN_DEFAULT_VARIANT" - // endregion DB migrations } internal object TranslationTable : BaseTable() { diff --git a/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt b/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt index b80b2b785a..707db1add1 100644 --- a/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt +++ b/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt @@ -46,11 +46,6 @@ private const val DATABASE_VERSION = 63 /* * Version history * - * v5.7.0 - * 48: 2022-02-14 - * 49: 2022-04-08 - * 50: 2022-04-29 - * 51: 2022-05-02 * v6.0.0 - v6.0.1 * 52: 2022-09-22 * 53: 2022-09-23 @@ -77,17 +72,6 @@ internal class GodToolsDatabase(private val context: Context, private val roomDb var upgradeTo = oldVersion + 1 while (upgradeTo <= newVersion) { when (upgradeTo) { - 48 -> { - db.execSQL(ToolTable.SQL_V48_CREATE_SPOTLIGHT) - db.execSQL(ToolTable.SQL_V48_POPULATE_SPOTLIGHT) - } - - 49 -> db.execSQL(ToolTable.SQL_V49_ALTER_DETAILS_BANNER_ANIMATION) - - 50 -> db.execSQL(ToolTable.SQL_V50_ALTER_META_TOOL) - - 51 -> db.execSQL(ToolTable.SQL_V51_ALTER_DEFAULT_VARIANT) - 52 -> { db.query( UserCounterTable.TABLE_NAME, From d083989ca1fd3ef9488ae35be03b1ca04542c7fa Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 16:35:00 -0600 Subject: [PATCH 02/16] Remove obsolete DB migration SQL constants and handlers for v52-57 Co-Authored-By: Claude Sonnet 4.6 --- .../keynote/godtools/android/db/Contract.kt | 38 ---- .../godtools/android/db/GodToolsDatabase.kt | 176 ------------------ 2 files changed, 214 deletions(-) diff --git a/library/db/src/main/kotlin/org/keynote/godtools/android/db/Contract.kt b/library/db/src/main/kotlin/org/keynote/godtools/android/db/Contract.kt index 306d93afe6..b571c6661a 100644 --- a/library/db/src/main/kotlin/org/keynote/godtools/android/db/Contract.kt +++ b/library/db/src/main/kotlin/org/keynote/godtools/android/db/Contract.kt @@ -32,10 +32,6 @@ internal object Contract : BaseContract() { internal object LanguageTable : BaseTable() { internal const val TABLE_NAME = "languages" - const val COLUMN_ID = BaseTable.COLUMN_ID - const val COLUMN_CODE = "code" - const val COLUMN_NAME = "name" - internal val SQL_DELETE_TABLE = drop(TABLE_NAME) } @@ -120,20 +116,7 @@ internal object Contract : BaseContract() { COLUMN_DOWNLOADED, ) - private const val SQL_COLUMN_DETAILS_OUTLINE = "$COLUMN_DETAILS_OUTLINE TEXT" - private const val SQL_COLUMN_DETAILS_BIBLE_REFERENCES = "$COLUMN_DETAILS_BIBLE_REFERENCES TEXT" - private const val SQL_COLUMN_DETAILS_CONVERSATION_STARTERS = "$COLUMN_DETAILS_CONVERSATION_STARTERS TEXT" - internal val SQL_DELETE_TABLE = drop(TABLE_NAME) - - // region DB migrations - internal const val SQL_V57_ALTER_DETAILS_OUTLINE = - "ALTER TABLE $TABLE_NAME ADD COLUMN $SQL_COLUMN_DETAILS_OUTLINE" - internal const val SQL_V57_ALTER_DETAILS_BIBLE_REFERENCES = - "ALTER TABLE $TABLE_NAME ADD COLUMN $SQL_COLUMN_DETAILS_BIBLE_REFERENCES" - internal const val SQL_V57_ALTER_DETAILS_CONVERSATION_STARTERS = - "ALTER TABLE $TABLE_NAME ADD COLUMN $SQL_COLUMN_DETAILS_CONVERSATION_STARTERS" - // endregion DB migrations } internal object AttachmentTable : BaseTable() { @@ -170,45 +153,24 @@ internal object Contract : BaseContract() { internal object FollowupTable : BaseTable() { const val TABLE_NAME = "followups" - const val COLUMN_NAME = "name" - const val COLUMN_EMAIL = "email" - const val COLUMN_DESTINATION = "destination" - const val COLUMN_LANGUAGE = "language" - const val COLUMN_CREATE_TIME = "created_at" - val SQL_DELETE_TABLE = drop(TABLE_NAME) } internal object GlobalActivityAnalyticsTable : BaseTable() { internal const val TABLE_NAME = "global_activity_analytics" - internal const val COLUMN_USERS = "users" - internal const val COLUMN_COUNTRIES = "countries" - internal const val COLUMN_LAUNCHES = "launches" - internal const val COLUMN_GOSPEL_PRESENTATIONS = "gospel_presentations" - internal val SQL_DELETE_TABLE = drop(TABLE_NAME) } internal object TrainingTipTable : Base { internal const val TABLE_NAME = "training_tips" - internal const val COLUMN_TOOL = ToolCode.COLUMN_TOOL - internal const val COLUMN_LANGUAGE = LanguageCode.COLUMN_LANGUAGE - internal const val COLUMN_TIP_ID = "tipId" - const val COLUMN_IS_COMPLETED = "isCompleted" - internal val SQL_DELETE_TABLE = drop(TABLE_NAME) } internal object UserCounterTable : Base { internal const val TABLE_NAME = "user_counters" - internal const val COLUMN_COUNTER_ID = "counter_id" - const val COLUMN_COUNT = "count" - const val COLUMN_DECAYED_COUNT = "decayed_count" - internal const val COLUMN_DELTA = "delta" - internal val SQL_DELETE_TABLE = drop(TABLE_NAME) } } diff --git a/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt b/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt index 707db1add1..4b9a480be1 100644 --- a/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt +++ b/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt @@ -5,28 +5,18 @@ import android.database.SQLException import android.database.sqlite.SQLiteConstraintException import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteException -import java.time.Instant import org.ccci.gto.android.common.db.CommonTables.LastSyncTable import org.ccci.gto.android.common.db.WalSQLiteOpenHelper -import org.ccci.gto.android.common.db.util.CursorUtils.getBool import org.ccci.gto.android.common.util.content.isApplicationDebuggable import org.ccci.gto.android.common.util.database.forEach -import org.ccci.gto.android.common.util.database.getDouble -import org.ccci.gto.android.common.util.database.getInt -import org.ccci.gto.android.common.util.database.getLocale -import org.ccci.gto.android.common.util.database.getLong import org.ccci.gto.android.common.util.database.getString import org.ccci.gto.android.common.util.database.map import org.cru.godtools.db.room.GodToolsRoomDatabase import org.cru.godtools.db.room.entity.AttachmentEntity import org.cru.godtools.db.room.entity.DownloadedFileEntity import org.cru.godtools.db.room.entity.DownloadedTranslationFileEntity.Companion.toEntity -import org.cru.godtools.db.room.entity.FollowupEntity -import org.cru.godtools.db.room.entity.LanguageEntity import org.cru.godtools.db.room.entity.ToolEntity -import org.cru.godtools.db.room.entity.TrainingTipEntity import org.cru.godtools.db.room.entity.TranslationEntity -import org.cru.godtools.db.room.entity.partial.MigrationGlobalActivity import org.keynote.godtools.android.db.Contract.AttachmentTable import org.keynote.godtools.android.db.Contract.DownloadedFileTable import org.keynote.godtools.android.db.Contract.FollowupTable @@ -46,13 +36,6 @@ private const val DATABASE_VERSION = 63 /* * Version history * - * v6.0.0 - v6.0.1 - * 52: 2022-09-22 - * 53: 2022-09-23 - * 54: 2022-11-04 - * 55: 2022-11-22 - * 56: 2022-12-06 - * 57: 2022-12-06 * v6.1.0 - v6.2.0 * 58: 2023-01-25 * 59: 2023-05-15 @@ -72,165 +55,6 @@ internal class GodToolsDatabase(private val context: Context, private val roomDb var upgradeTo = oldVersion + 1 while (upgradeTo <= newVersion) { when (upgradeTo) { - 52 -> { - db.query( - UserCounterTable.TABLE_NAME, - arrayOf( - UserCounterTable.COLUMN_COUNTER_ID, - UserCounterTable.COLUMN_COUNT, - UserCounterTable.COLUMN_DECAYED_COUNT, - UserCounterTable.COLUMN_DELTA - ), - null, - emptyArray(), - null, - null, - null - ).use { - while (it.moveToNext()) { - roomDb.userCountersRepository.migrateCounter( - it.getString(UserCounterTable.COLUMN_COUNTER_ID) ?: continue, - it.getInt(UserCounterTable.COLUMN_COUNT, 0), - it.getDouble(UserCounterTable.COLUMN_DECAYED_COUNT, 0.0), - it.getInt(UserCounterTable.COLUMN_DELTA, 0), - ) - } - } - - db.execSQL(UserCounterTable.SQL_DELETE_TABLE) - } - - 53 -> { - db.query( - GlobalActivityAnalyticsTable.TABLE_NAME, - arrayOf( - GlobalActivityAnalyticsTable.COLUMN_USERS, - GlobalActivityAnalyticsTable.COLUMN_COUNTRIES, - GlobalActivityAnalyticsTable.COLUMN_LAUNCHES, - GlobalActivityAnalyticsTable.COLUMN_GOSPEL_PRESENTATIONS - ), - null, - emptyArray(), - null, - null, - null - ).use { - if (it.moveToFirst()) { - roomDb.globalActivityDao.insertOrIgnore( - MigrationGlobalActivity( - it.getInt(GlobalActivityAnalyticsTable.COLUMN_USERS, 0), - it.getInt(GlobalActivityAnalyticsTable.COLUMN_COUNTRIES, 0), - it.getInt(GlobalActivityAnalyticsTable.COLUMN_LAUNCHES, 0), - it.getInt(GlobalActivityAnalyticsTable.COLUMN_GOSPEL_PRESENTATIONS, 0), - ) - ) - } - } - - db.execSQL(GlobalActivityAnalyticsTable.SQL_DELETE_TABLE) - } - - 54 -> { - db.query( - TrainingTipTable.TABLE_NAME, - arrayOf( - TrainingTipTable.COLUMN_TOOL, - TrainingTipTable.COLUMN_LANGUAGE, - TrainingTipTable.COLUMN_TIP_ID, - TrainingTipTable.COLUMN_IS_COMPLETED - ), - null, - emptyArray(), - null, - null, - null - ).use { - while (it.moveToNext()) { - roomDb.trainingTipDao.insertOrIgnoreBlocking( - TrainingTipEntity( - TrainingTipEntity.Key( - tool = it.getString(TrainingTipTable.COLUMN_TOOL) ?: continue, - locale = it.getLocale(TrainingTipTable.COLUMN_LANGUAGE) ?: continue, - tipId = it.getString(TrainingTipTable.COLUMN_TIP_ID) ?: continue, - ) - ).apply { - isCompleted = getBool(it, TrainingTipTable.COLUMN_IS_COMPLETED, false) - isNew = true - } - ) - } - } - - db.execSQL(TrainingTipTable.SQL_DELETE_TABLE) - } - - 55 -> { - db.query( - FollowupTable.TABLE_NAME, - arrayOf( - FollowupTable.COLUMN_NAME, - FollowupTable.COLUMN_EMAIL, - FollowupTable.COLUMN_LANGUAGE, - FollowupTable.COLUMN_DESTINATION, - FollowupTable.COLUMN_CREATE_TIME - ), - null, - emptyArray(), - null, - null, - null - ).use { - while (it.moveToNext()) { - roomDb.followupsDao.insertBlocking( - FollowupEntity( - name = it.getString(FollowupTable.COLUMN_NAME), - email = it.getString(FollowupTable.COLUMN_EMAIL) ?: continue, - language = it.getLocale(FollowupTable.COLUMN_LANGUAGE) ?: continue, - destination = it.getLong(FollowupTable.COLUMN_DESTINATION) ?: continue, - createdAt = it.getLong(FollowupTable.COLUMN_CREATE_TIME) - ?.let { Instant.ofEpochMilli(it) } ?: Instant.now() - ) - ) - } - } - - db.execSQL(FollowupTable.SQL_DELETE_TABLE) - } - - 56 -> { - db.query( - LanguageTable.TABLE_NAME, - arrayOf( - LanguageTable.COLUMN_ID, - LanguageTable.COLUMN_CODE, - LanguageTable.COLUMN_NAME - ), - null, - emptyArray(), - null, - null, - null - ).use { - roomDb.languagesDao.insertOrIgnoreLanguages( - it.map { - LanguageEntity( - code = it.getLocale(LanguageTable.COLUMN_CODE) ?: return@map null, - name = it.getString(LanguageTable.COLUMN_NAME), - apiId = it.getLong(LanguageTable.COLUMN_ID), - ) - }.filterNotNull() - ) - } - - db.execSQL(LanguageTable.SQL_DELETE_TABLE) - } - - 57 -> { - db.execSQL(TranslationTable.SQL_V57_ALTER_DETAILS_OUTLINE) - db.execSQL(TranslationTable.SQL_V57_ALTER_DETAILS_BIBLE_REFERENCES) - db.execSQL(TranslationTable.SQL_V57_ALTER_DETAILS_CONVERSATION_STARTERS) - } - 58 -> { db.query( DownloadedFileTable.TABLE_NAME, From 7726ba4bb475995296f90803c169a482ef48e441 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 16:36:45 -0600 Subject: [PATCH 03/16] Add v6.3.0 label to DB version history Co-Authored-By: Claude Sonnet 4.6 --- .../kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt b/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt index 4b9a480be1..5782b1a6ae 100644 --- a/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt +++ b/library/db/src/main/kotlin/org/keynote/godtools/android/db/GodToolsDatabase.kt @@ -43,6 +43,7 @@ private const val DATABASE_VERSION = 63 * 61: 2023-06-07 * 62: 2024-01-17 * 63: 2024-01-17 + * v6.3.0 */ internal class GodToolsDatabase(private val context: Context, private val roomDb: GodToolsRoomDatabase) : From e51ebff530fe0dd4ea46eb820a23e90b1bde9315 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 16:42:39 -0600 Subject: [PATCH 04/16] Remove obsolete Room auto-migration and schema dump for v6.0.1 (version 6) Co-Authored-By: Claude Sonnet 4.6 --- .../6.json | 283 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 3 - .../room/GodToolsRoomDatabaseMigrationIT.kt | 30 -- 3 files changed, 316 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/6.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/6.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/6.json deleted file mode 100644 index 969762e539..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/6.json +++ /dev/null @@ -1,283 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 6, - "identityHash": "546f68fb4f7b431d1e0c2512029ba5fd", - "entities": [ - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "code" - ], - "autoGenerate": false - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": false - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "tool", - "locale", - "tipId" - ], - "autoGenerate": false - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `createdAt` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": false - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "columnNames": [ - "name" - ], - "autoGenerate": false - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": false - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '546f68fb4f7b431d1e0c2512029ba5fd')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index 5413d5637e..4773c3b284 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -63,7 +63,6 @@ import org.cru.godtools.db.room.repository.UserRoomRepository LastSyncTimeEntity::class, ], autoMigrations = [ - AutoMigration(from = 6, to = 7), AutoMigration(from = 7, to = 8), AutoMigration(from = 8, to = 9), AutoMigration(from = 9, to = 10), @@ -124,8 +123,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { /* * Version history * - * v6.0.1 - * 6: 2022-12-05 * v6.1.0-v6.1.1 * 7: 2023-03-27 * v6.2.0 diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index 0030a36fb3..83a9f75666 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -13,10 +13,8 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse -import kotlin.test.assertNotEquals import kotlin.test.assertNull import kotlin.test.assertTrue -import org.ccci.gto.android.common.util.database.getString import org.ccci.gto.android.common.util.database.map import org.cru.godtools.model.Tool import org.junit.Rule @@ -31,34 +29,6 @@ class GodToolsRoomDatabaseMigrationIT { @get:Rule val helper = MigrationTestHelper(InstrumentationRegistry.getInstrumentation(), GodToolsRoomDatabase::class.java) - @Test - fun testMigrate6To7() { - val guid = UUID.randomUUID().toString() - val usersQuery = "SELECT * FROM users" - - // create v6 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 6).use { db -> - db.execSQL("INSERT INTO users (id, ssoGuid) VALUES (?, ?)", arrayOf("user1", guid)) - db.query(usersQuery).use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals("user1", it.getString("id")) - assertEquals(guid, it.getString("ssoGuid")) - } - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 7, true, *MIGRATIONS).use { db -> - db.query(usersQuery).use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals("user1", it.getString("id")) - assertEquals(guid, it.getString("ssoGuid")) - assertNotEquals(-1, it.getColumnIndex("name")) - } - } - } - @Test fun testMigrate7To8() { val filesQuery = "SELECT * FROM downloadedFiles" From 18f7485e5410909ba17940fa075fcc61190a1e10 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 16:58:48 -0600 Subject: [PATCH 05/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=208?= =?UTF-8?q?=E2=86=929=20and=209=E2=86=9210=20into=20a=20single=208?= =?UTF-8?q?=E2=86=9210=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../9.json | 446 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 4 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 25 +- 3 files changed, 4 insertions(+), 471 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/9.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/9.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/9.json deleted file mode 100644 index 3ef408e141..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/9.json +++ /dev/null @@ -1,446 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 9, - "identityHash": "128676e0b58be0450281eda29dee40ff", - "entities": [ - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL, `defaultOrder` INTEGER NOT NULL, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL, `isSpotlight` INTEGER NOT NULL, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `createdAt` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '128676e0b58be0450281eda29dee40ff')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index 4773c3b284..6c761e1851 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -64,8 +64,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository ], autoMigrations = [ AutoMigration(from = 7, to = 8), - AutoMigration(from = 8, to = 9), - AutoMigration(from = 9, to = 10), + AutoMigration(from = 8, to = 10), AutoMigration(from = 10, to = 11), AutoMigration(from = 11, to = 12), AutoMigration(from = 12, to = 13), @@ -127,7 +126,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * 7: 2023-03-27 * v6.2.0 * 8: 2023-01-24 - * 9: 2023-05-09 * 10: 2023-05-08 * 11: 2023-05-15 * 12: 2023-06-08 diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index 83a9f75666..c23617ed82 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -52,34 +52,14 @@ class GodToolsRoomDatabaseMigrationIT { } @Test - fun testMigrate8To9() { + fun testMigrate8To10() { val toolsQuery = "SELECT * FROM tools" + val attachmentsQuery = "SELECT * FROM attachments" // create v8 database helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 8).use { db -> db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("sync_time", "1234")) assertFailsWith { db.query(toolsQuery) } - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 9, true, *MIGRATIONS).use { db -> - db.query("SELECT id, time FROM last_sync_times").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals("sync_time", it.getStringOrNull(0)) - assertEquals(1234, it.getIntOrNull(1)) - } - db.query(toolsQuery).close() - } - } - - @Test - fun testMigrate9To10() { - val attachmentsQuery = "SELECT * FROM attachments" - - // create v9 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 9).use { db -> - db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("sync_time", "1234")) assertFailsWith { db.query(attachmentsQuery) } } @@ -91,6 +71,7 @@ class GodToolsRoomDatabaseMigrationIT { assertEquals("sync_time", it.getStringOrNull(0)) assertEquals(1234, it.getIntOrNull(1)) } + db.query(toolsQuery).close() db.query(attachmentsQuery).close() } } From e24ab3341b76d14bbdbddd6add583308e12447aa Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:07:32 -0600 Subject: [PATCH 06/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=208?= =?UTF-8?q?=E2=86=9210=20and=2010=E2=86=9211=20into=20a=20single=208?= =?UTF-8?q?=E2=86=9211=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../10.json | 513 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 4 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 27 +- 3 files changed, 5 insertions(+), 539 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/10.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/10.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/10.json deleted file mode 100644 index f8366e1e6c..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/10.json +++ /dev/null @@ -1,513 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 10, - "identityHash": "2b7afab8cf565ea868c33c68cabf81f0", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL, `defaultOrder` INTEGER NOT NULL, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL, `isSpotlight` INTEGER NOT NULL, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `createdAt` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2b7afab8cf565ea868c33c68cabf81f0')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index 6c761e1851..ee3fea448e 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -64,8 +64,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository ], autoMigrations = [ AutoMigration(from = 7, to = 8), - AutoMigration(from = 8, to = 10), - AutoMigration(from = 10, to = 11), + AutoMigration(from = 8, to = 11), AutoMigration(from = 11, to = 12), AutoMigration(from = 12, to = 13), AutoMigration(from = 13, to = 14, spec = Migration14::class), @@ -126,7 +125,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * 7: 2023-03-27 * v6.2.0 * 8: 2023-01-24 - * 10: 2023-05-08 * 11: 2023-05-15 * 12: 2023-06-08 * 13: 2023-09-18 diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index c23617ed82..0856a34208 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -52,37 +52,16 @@ class GodToolsRoomDatabaseMigrationIT { } @Test - fun testMigrate8To10() { + fun testMigrate8To11() { val toolsQuery = "SELECT * FROM tools" val attachmentsQuery = "SELECT * FROM attachments" + val translationsQuery = "SELECT * FROM translations" // create v8 database helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 8).use { db -> db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("sync_time", "1234")) assertFailsWith { db.query(toolsQuery) } assertFailsWith { db.query(attachmentsQuery) } - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 10, true, *MIGRATIONS).use { db -> - db.query("SELECT id, time FROM last_sync_times").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals("sync_time", it.getStringOrNull(0)) - assertEquals(1234, it.getIntOrNull(1)) - } - db.query(toolsQuery).close() - db.query(attachmentsQuery).close() - } - } - - @Test - fun testMigrate10To11() { - val translationsQuery = "SELECT * FROM translations" - - // create v10 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 10).use { db -> - db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("sync_time", "1234")) assertFailsWith { db.query(translationsQuery) } } @@ -94,6 +73,8 @@ class GodToolsRoomDatabaseMigrationIT { assertEquals("sync_time", it.getStringOrNull(0)) assertEquals(1234, it.getIntOrNull(1)) } + db.query(toolsQuery).close() + db.query(attachmentsQuery).close() db.query(translationsQuery).close() } } From dfc38d7a10fa9ee11871002eeeae30945d03563a Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:12:37 -0600 Subject: [PATCH 07/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=208?= =?UTF-8?q?=E2=86=9211=20and=2011=E2=86=9212=20into=20a=20single=208?= =?UTF-8?q?=E2=86=9212=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../11.json | 649 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 4 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 31 +- 3 files changed, 11 insertions(+), 673 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/11.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/11.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/11.json deleted file mode 100644 index 88b4465ac3..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/11.json +++ /dev/null @@ -1,649 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 11, - "identityHash": "0c7f603011ef1c8cf73c54377464a52f", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL, `defaultOrder` INTEGER NOT NULL, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL, `isSpotlight` INTEGER NOT NULL, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `createdAt` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '0c7f603011ef1c8cf73c54377464a52f')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index ee3fea448e..14db87ef64 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -64,8 +64,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository ], autoMigrations = [ AutoMigration(from = 7, to = 8), - AutoMigration(from = 8, to = 11), - AutoMigration(from = 11, to = 12), + AutoMigration(from = 8, to = 12), AutoMigration(from = 12, to = 13), AutoMigration(from = 13, to = 14, spec = Migration14::class), AutoMigration(from = 14, to = 15), @@ -125,7 +124,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * 7: 2023-03-27 * v6.2.0 * 8: 2023-01-24 - * 11: 2023-05-15 * 12: 2023-06-08 * 13: 2023-09-18 * 14: 2023-09-18 diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index 0856a34208..fa245883d9 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -52,13 +52,14 @@ class GodToolsRoomDatabaseMigrationIT { } @Test - fun testMigrate8To11() { + fun testMigrate8To12() { val toolsQuery = "SELECT * FROM tools" val attachmentsQuery = "SELECT * FROM attachments" val translationsQuery = "SELECT * FROM translations" // create v8 database helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 8).use { db -> + db.execSQL("INSERT INTO languages (id, code) VALUES (1, ?)", arrayOf("en")) db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("sync_time", "1234")) assertFailsWith { db.query(toolsQuery) } assertFailsWith { db.query(attachmentsQuery) } @@ -66,7 +67,14 @@ class GodToolsRoomDatabaseMigrationIT { } // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 11, true, *MIGRATIONS).use { db -> + helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 12, true, *MIGRATIONS).use { db -> + db.query("SELECT id, code, isAdded FROM languages").use { + assertEquals(1, it.count) + it.moveToFirst() + assertEquals(1, it.getIntOrNull(0)) + assertEquals("en", it.getStringOrNull(1)) + assertEquals(0, it.getIntOrNull(2)) + } db.query("SELECT id, time FROM last_sync_times").use { assertEquals(1, it.count) it.moveToFirst() @@ -79,25 +87,6 @@ class GodToolsRoomDatabaseMigrationIT { } } - @Test - fun testMigrate11To12() { - // create v11 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 11).use { db -> - db.execSQL("INSERT INTO languages (id, code) VALUES (1, ?)", arrayOf("en")) - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 12, true, *MIGRATIONS).use { db -> - db.query("SELECT id, code, isAdded FROM languages").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals(1, it.getIntOrNull(0)) - assertEquals("en", it.getStringOrNull(1)) - assertEquals(0, it.getIntOrNull(2)) - } - } - } - @Test fun testMigrate12To13() { // create v12 database From 82d7eb0cd5b1a1e0bac5944412763a96d734661f Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:16:16 -0600 Subject: [PATCH 08/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=208?= =?UTF-8?q?=E2=86=9212=20and=2012=E2=86=9213=20into=20a=20single=208?= =?UTF-8?q?=E2=86=9213=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../12.json | 656 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 4 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 13 +- 3 files changed, 3 insertions(+), 670 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/12.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/12.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/12.json deleted file mode 100644 index 332faf6006..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/12.json +++ /dev/null @@ -1,656 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 12, - "identityHash": "9f36dbda310b82c3adbbb969d2c20c9e", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL, `defaultOrder` INTEGER NOT NULL, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL, `isSpotlight` INTEGER NOT NULL, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `createdAt` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9f36dbda310b82c3adbbb969d2c20c9e')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index 14db87ef64..a575edeb48 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -64,8 +64,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository ], autoMigrations = [ AutoMigration(from = 7, to = 8), - AutoMigration(from = 8, to = 12), - AutoMigration(from = 12, to = 13), + AutoMigration(from = 8, to = 13), AutoMigration(from = 13, to = 14, spec = Migration14::class), AutoMigration(from = 14, to = 15), AutoMigration(from = 15, to = 16, spec = ResetUserSyncMigration::class), @@ -124,7 +123,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * 7: 2023-03-27 * v6.2.0 * 8: 2023-01-24 - * 12: 2023-06-08 * 13: 2023-09-18 * 14: 2023-09-18 * 15: 2023-09-18 diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index fa245883d9..f0a6ee7345 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -52,7 +52,7 @@ class GodToolsRoomDatabaseMigrationIT { } @Test - fun testMigrate8To12() { + fun testMigrate8To13() { val toolsQuery = "SELECT * FROM tools" val attachmentsQuery = "SELECT * FROM attachments" val translationsQuery = "SELECT * FROM translations" @@ -67,7 +67,7 @@ class GodToolsRoomDatabaseMigrationIT { } // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 12, true, *MIGRATIONS).use { db -> + helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 13, true, *MIGRATIONS).use { db -> db.query("SELECT id, code, isAdded FROM languages").use { assertEquals(1, it.count) it.moveToFirst() @@ -87,15 +87,6 @@ class GodToolsRoomDatabaseMigrationIT { } } - @Test - fun testMigrate12To13() { - // create v12 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 12).use {} - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 13, true, *MIGRATIONS).use {} - } - @Test fun testMigrate13To14() { // create v13 database From ef3f410917c5b3ed31660f1b403bba02363a053f Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:23:16 -0600 Subject: [PATCH 09/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=208?= =?UTF-8?q?=E2=86=9213=20and=2013=E2=86=9214=20into=20a=20single=208?= =?UTF-8?q?=E2=86=9214=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../13.json | 661 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 7 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 25 +- 3 files changed, 4 insertions(+), 689 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/13.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/13.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/13.json deleted file mode 100644 index 3da6df3be0..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/13.json +++ /dev/null @@ -1,661 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 13, - "identityHash": "c2eafd68c417479ddde50785d422f013", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL DEFAULT 0, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL DEFAULT false, `defaultOrder` INTEGER NOT NULL DEFAULT 0, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL DEFAULT false, `isSpotlight` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `createdAt` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c2eafd68c417479ddde50785d422f013')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index a575edeb48..ccbc60f4d8 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -64,8 +64,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository ], autoMigrations = [ AutoMigration(from = 7, to = 8), - AutoMigration(from = 8, to = 13), - AutoMigration(from = 13, to = 14, spec = Migration14::class), + AutoMigration(from = 8, to = 14), AutoMigration(from = 14, to = 15), AutoMigration(from = 15, to = 16, spec = ResetUserSyncMigration::class), AutoMigration(from = 16, to = 17), @@ -123,7 +122,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * 7: 2023-03-27 * v6.2.0 * 8: 2023-01-24 - * 13: 2023-09-18 * 14: 2023-09-18 * 15: 2023-09-18 * 16: 2023-09-19 @@ -152,9 +150,6 @@ internal class ResetUserSyncMigration : AutoMigrationSpec { } } -@RenameColumn(tableName = "tools", fromColumnName = "isAdded", toColumnName = "isFavorite") -internal class Migration14 : AutoMigrationSpec - @RenameColumn(tableName = "languages", fromColumnName = "id", toColumnName = "apiId") internal class Migration18 : AutoMigrationSpec diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index f0a6ee7345..43542462a2 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -52,7 +52,7 @@ class GodToolsRoomDatabaseMigrationIT { } @Test - fun testMigrate8To13() { + fun testMigrate8To14() { val toolsQuery = "SELECT * FROM tools" val attachmentsQuery = "SELECT * FROM attachments" val translationsQuery = "SELECT * FROM translations" @@ -67,7 +67,7 @@ class GodToolsRoomDatabaseMigrationIT { } // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 13, true, *MIGRATIONS).use { db -> + helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 14, true, *MIGRATIONS).use { db -> db.query("SELECT id, code, isAdded FROM languages").use { assertEquals(1, it.count) it.moveToFirst() @@ -81,31 +81,12 @@ class GodToolsRoomDatabaseMigrationIT { assertEquals("sync_time", it.getStringOrNull(0)) assertEquals(1234, it.getIntOrNull(1)) } - db.query(toolsQuery).close() + db.query("SELECT code, isFavorite FROM tools").use { assertEquals(0, it.count) } db.query(attachmentsQuery).close() db.query(translationsQuery).close() } } - @Test - fun testMigrate13To14() { - // create v13 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 13).use { db -> - db.execSQL("""INSERT INTO tools (id, code, type, isAdded) VALUES (1, "a", "TRACT", 1)""") - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 14, true, *MIGRATIONS).use { db -> - db.query("SELECT id, code, isFavorite FROM tools").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals(1, it.getIntOrNull(0)) - assertEquals("a", it.getStringOrNull(1)) - assertEquals(1, it.getIntOrNull(2)) - } - } - } - @Test fun testMigrate14To15() { // create v14 database From bb3c953cbe2e6627b6f53d2d21a02f32334178f6 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:27:44 -0600 Subject: [PATCH 10/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=208?= =?UTF-8?q?=E2=86=9214=20and=2014=E2=86=9215=20into=20a=20single=208?= =?UTF-8?q?=E2=86=9215=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../14.json | 661 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 4 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 25 +- 3 files changed, 8 insertions(+), 682 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/14.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/14.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/14.json deleted file mode 100644 index 29bc95f55c..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/14.json +++ /dev/null @@ -1,661 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 14, - "identityHash": "61b9f620ca5749cf1e85d2e93b08fdcf", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL DEFAULT 0, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL DEFAULT false, `defaultOrder` INTEGER NOT NULL DEFAULT 0, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isFavorite` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL DEFAULT false, `isSpotlight` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isFavorite", - "columnName": "isFavorite", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `createdAt` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '61b9f620ca5749cf1e85d2e93b08fdcf')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index ccbc60f4d8..f930785ee5 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -64,8 +64,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository ], autoMigrations = [ AutoMigration(from = 7, to = 8), - AutoMigration(from = 8, to = 14), - AutoMigration(from = 14, to = 15), + AutoMigration(from = 8, to = 15), AutoMigration(from = 15, to = 16, spec = ResetUserSyncMigration::class), AutoMigration(from = 16, to = 17), AutoMigration(from = 17, to = 18, spec = Migration18::class), @@ -122,7 +121,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * 7: 2023-03-27 * v6.2.0 * 8: 2023-01-24 - * 14: 2023-09-18 * 15: 2023-09-18 * 16: 2023-09-19 * 17: 2023-09-25 diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index 43542462a2..8275bfbe7f 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -52,7 +52,7 @@ class GodToolsRoomDatabaseMigrationIT { } @Test - fun testMigrate8To14() { + fun testMigrate8To15() { val toolsQuery = "SELECT * FROM tools" val attachmentsQuery = "SELECT * FROM attachments" val translationsQuery = "SELECT * FROM translations" @@ -67,7 +67,7 @@ class GodToolsRoomDatabaseMigrationIT { } // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 14, true, *MIGRATIONS).use { db -> + helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 15, true, *MIGRATIONS).use { db -> db.query("SELECT id, code, isAdded FROM languages").use { assertEquals(1, it.count) it.moveToFirst() @@ -81,28 +81,17 @@ class GodToolsRoomDatabaseMigrationIT { assertEquals("sync_time", it.getStringOrNull(0)) assertEquals(1234, it.getIntOrNull(1)) } - db.query("SELECT code, isFavorite FROM tools").use { assertEquals(0, it.count) } - db.query(attachmentsQuery).close() - db.query(translationsQuery).close() - } - } - - @Test - fun testMigrate14To15() { - // create v14 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 14).use { db -> db.execSQL("""INSERT INTO tools (id, code, type) VALUES (1, "a", "TRACT")""") - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 15, true, *MIGRATIONS).use { db -> - db.query("SELECT id, code, changedFields FROM tools").use { + db.query("SELECT id, code, isFavorite, changedFields FROM tools").use { assertEquals(1, it.count) it.moveToFirst() assertEquals(1, it.getIntOrNull(0)) assertEquals("a", it.getStringOrNull(1)) - assertEquals("", it.getStringOrNull(2)) + assertEquals(0, it.getIntOrNull(2)) + assertEquals("", it.getStringOrNull(3)) } + db.query(attachmentsQuery).close() + db.query(translationsQuery).close() } } From de6f416d34b028148eb5c57d88cfb9cee6f36b3c Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:31:27 -0600 Subject: [PATCH 11/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=207?= =?UTF-8?q?=E2=86=928=20and=208=E2=86=9215=20into=20a=20single=207?= =?UTF-8?q?=E2=86=9215=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../8.json | 309 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 4 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 29 +- 3 files changed, 6 insertions(+), 336 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/8.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/8.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/8.json deleted file mode 100644 index 2477e63c53..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/8.json +++ /dev/null @@ -1,309 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 8, - "identityHash": "377066d3767333d86e67ece932003acf", - "entities": [ - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `createdAt` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '377066d3767333d86e67ece932003acf')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index f930785ee5..34769500bf 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -63,8 +63,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository LastSyncTimeEntity::class, ], autoMigrations = [ - AutoMigration(from = 7, to = 8), - AutoMigration(from = 8, to = 15), + AutoMigration(from = 7, to = 15), AutoMigration(from = 15, to = 16, spec = ResetUserSyncMigration::class), AutoMigration(from = 16, to = 17), AutoMigration(from = 17, to = 18, spec = Migration18::class), @@ -120,7 +119,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * v6.1.0-v6.1.1 * 7: 2023-03-27 * v6.2.0 - * 8: 2023-01-24 * 15: 2023-09-18 * 16: 2023-09-19 * 17: 2023-09-25 diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index 8275bfbe7f..ae4671612e 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -30,37 +30,17 @@ class GodToolsRoomDatabaseMigrationIT { val helper = MigrationTestHelper(InstrumentationRegistry.getInstrumentation(), GodToolsRoomDatabase::class.java) @Test - fun testMigrate7To8() { + fun testMigrate7To15() { val filesQuery = "SELECT * FROM downloadedFiles" - - // create v7 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 7).use { db -> - db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("sync_time", "1234")) - assertFailsWith { db.query(filesQuery) } - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 8, true, *MIGRATIONS).use { db -> - db.query("SELECT id, time FROM last_sync_times").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals("sync_time", it.getStringOrNull(0)) - assertEquals(1234, it.getIntOrNull(1)) - } - db.query(filesQuery).close() - } - } - - @Test - fun testMigrate8To15() { val toolsQuery = "SELECT * FROM tools" val attachmentsQuery = "SELECT * FROM attachments" val translationsQuery = "SELECT * FROM translations" - // create v8 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 8).use { db -> + // create v7 database + helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 7).use { db -> db.execSQL("INSERT INTO languages (id, code) VALUES (1, ?)", arrayOf("en")) db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("sync_time", "1234")) + assertFailsWith { db.query(filesQuery) } assertFailsWith { db.query(toolsQuery) } assertFailsWith { db.query(attachmentsQuery) } assertFailsWith { db.query(translationsQuery) } @@ -90,6 +70,7 @@ class GodToolsRoomDatabaseMigrationIT { assertEquals(0, it.getIntOrNull(2)) assertEquals("", it.getStringOrNull(3)) } + db.query(filesQuery).close() db.query(attachmentsQuery).close() db.query(translationsQuery).close() } From 8fd6196d5779d5051cb1848f310b398b5c607b84 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:40:13 -0600 Subject: [PATCH 12/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=207?= =?UTF-8?q?=E2=86=9215=20and=2015=E2=86=9216=20into=20a=20single=207?= =?UTF-8?q?=E2=86=9216=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../15.json | 668 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 4 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 52 +- 3 files changed, 18 insertions(+), 706 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/15.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/15.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/15.json deleted file mode 100644 index 07d793482e..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/15.json +++ /dev/null @@ -1,668 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 15, - "identityHash": "9334f5fbc202b319d6b690c3c809c1ca", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL DEFAULT 0, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL DEFAULT false, `defaultOrder` INTEGER NOT NULL DEFAULT 0, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isFavorite` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL DEFAULT false, `isSpotlight` INTEGER NOT NULL DEFAULT false, `changedFields` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isFavorite", - "columnName": "isFavorite", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "changedFields", - "columnName": "changedFields", - "affinity": "TEXT", - "notNull": true, - "defaultValue": "''" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `createdAt` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9334f5fbc202b319d6b690c3c809c1ca')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index 34769500bf..612bcbc7d5 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -63,8 +63,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository LastSyncTimeEntity::class, ], autoMigrations = [ - AutoMigration(from = 7, to = 15), - AutoMigration(from = 15, to = 16, spec = ResetUserSyncMigration::class), + AutoMigration(from = 7, to = 16, spec = ResetUserSyncMigration::class), AutoMigration(from = 16, to = 17), AutoMigration(from = 17, to = 18, spec = Migration18::class), AutoMigration(from = 18, to = 19, spec = Migration19::class), @@ -119,7 +118,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * v6.1.0-v6.1.1 * 7: 2023-03-27 * v6.2.0 - * 15: 2023-09-18 * 16: 2023-09-19 * 17: 2023-09-25 * 18: 2023-11-21 diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index ae4671612e..538caa2569 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -8,18 +8,20 @@ import androidx.room.testing.MigrationTestHelper import androidx.sqlite.db.SupportSQLiteDatabase import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry -import java.util.UUID import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse import kotlin.test.assertNull import kotlin.test.assertTrue +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid import org.ccci.gto.android.common.util.database.map import org.cru.godtools.model.Tool import org.junit.Rule import org.junit.runner.RunWith +@OptIn(ExperimentalUuidApi::class) @RunWith(AndroidJUnit4::class) class GodToolsRoomDatabaseMigrationIT { companion object { @@ -30,7 +32,8 @@ class GodToolsRoomDatabaseMigrationIT { val helper = MigrationTestHelper(InstrumentationRegistry.getInstrumentation(), GodToolsRoomDatabase::class.java) @Test - fun testMigrate7To15() { + fun testMigrate7To16() { + val name = Uuid.random().toString() val filesQuery = "SELECT * FROM downloadedFiles" val toolsQuery = "SELECT * FROM tools" val attachmentsQuery = "SELECT * FROM attachments" @@ -39,6 +42,8 @@ class GodToolsRoomDatabaseMigrationIT { // create v7 database helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 7).use { db -> db.execSQL("INSERT INTO languages (id, code) VALUES (1, ?)", arrayOf("en")) + db.execSQL("INSERT INTO users (id, name) VALUES (1, ?)", arrayOf(name)) + db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("last_synced.user:1", "1234")) db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("sync_time", "1234")) assertFailsWith { db.query(filesQuery) } assertFailsWith { db.query(toolsQuery) } @@ -47,7 +52,7 @@ class GodToolsRoomDatabaseMigrationIT { } // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 15, true, *MIGRATIONS).use { db -> + helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 16, true, *MIGRATIONS).use { db -> db.query("SELECT id, code, isAdded FROM languages").use { assertEquals(1, it.count) it.moveToFirst() @@ -55,6 +60,15 @@ class GodToolsRoomDatabaseMigrationIT { assertEquals("en", it.getStringOrNull(1)) assertEquals(0, it.getIntOrNull(2)) } + db.query("SELECT id, name, givenName, familyName, email FROM users").use { + assertEquals(1, it.count) + it.moveToFirst() + assertEquals(1, it.getIntOrNull(0)) + assertEquals(name, it.getStringOrNull(1)) + assertNull(it.getStringOrNull(2)) + assertNull(it.getStringOrNull(3)) + assertNull(it.getStringOrNull(4)) + } db.query("SELECT id, time FROM last_sync_times").use { assertEquals(1, it.count) it.moveToFirst() @@ -76,38 +90,6 @@ class GodToolsRoomDatabaseMigrationIT { } } - @Test - fun testMigrate15To16() { - val name = UUID.randomUUID().toString() - - // create v15 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 15).use { db -> - db.execSQL("INSERT INTO users (id, name) VALUES (1, ?)", arrayOf(name)) - db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("last_synced.user:1", "1234")) - db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("sync_time", "1234")) - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 16, true, *MIGRATIONS).use { db -> - db.query("SELECT id, name, givenName, familyName, email FROM users").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals(1, it.getIntOrNull(0)) - assertEquals(name, it.getStringOrNull(1)) - assertNull(it.getStringOrNull(2)) - assertNull(it.getStringOrNull(3)) - assertNull(it.getStringOrNull(4)) - } - - db.query("SELECT id, time FROM last_sync_times").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals("sync_time", it.getStringOrNull(0)) - assertEquals(1234, it.getIntOrNull(1)) - } - } - } - @Test fun testMigrate16To17() { // create v16 database From 7997eee4d5608768a7f728dda40b85f3202413e4 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:43:53 -0600 Subject: [PATCH 13/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=207?= =?UTF-8?q?=E2=86=9216=20and=2016=E2=86=9217=20into=20a=20single=207?= =?UTF-8?q?=E2=86=9217=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../16.json | 686 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 4 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 25 +- 3 files changed, 5 insertions(+), 710 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/16.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/16.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/16.json deleted file mode 100644 index 969b864bec..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/16.json +++ /dev/null @@ -1,686 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 16, - "identityHash": "24e9df6ade2763e59a618668caa26a9b", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL DEFAULT 0, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL DEFAULT false, `defaultOrder` INTEGER NOT NULL DEFAULT 0, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isFavorite` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL DEFAULT false, `isSpotlight` INTEGER NOT NULL DEFAULT false, `changedFields` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isFavorite", - "columnName": "isFavorite", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "changedFields", - "columnName": "changedFields", - "affinity": "TEXT", - "notNull": true, - "defaultValue": "''" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `givenName` TEXT, `familyName` TEXT, `email` TEXT, `createdAt` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "givenName", - "columnName": "givenName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "familyName", - "columnName": "familyName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '24e9df6ade2763e59a618668caa26a9b')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index 612bcbc7d5..7178f00178 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -63,8 +63,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository LastSyncTimeEntity::class, ], autoMigrations = [ - AutoMigration(from = 7, to = 16, spec = ResetUserSyncMigration::class), - AutoMigration(from = 16, to = 17), + AutoMigration(from = 7, to = 17, spec = ResetUserSyncMigration::class), AutoMigration(from = 17, to = 18, spec = Migration18::class), AutoMigration(from = 18, to = 19, spec = Migration19::class), AutoMigration(from = 19, to = 20), @@ -118,7 +117,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * v6.1.0-v6.1.1 * 7: 2023-03-27 * v6.2.0 - * 16: 2023-09-19 * 17: 2023-09-25 * 18: 2023-11-21 * 19: 2023-12-07 diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index 538caa2569..2427b012d3 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -32,7 +32,7 @@ class GodToolsRoomDatabaseMigrationIT { val helper = MigrationTestHelper(InstrumentationRegistry.getInstrumentation(), GodToolsRoomDatabase::class.java) @Test - fun testMigrate7To16() { + fun testMigrate7To17() { val name = Uuid.random().toString() val filesQuery = "SELECT * FROM downloadedFiles" val toolsQuery = "SELECT * FROM tools" @@ -52,7 +52,7 @@ class GodToolsRoomDatabaseMigrationIT { } // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 16, true, *MIGRATIONS).use { db -> + helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 17, true, *MIGRATIONS).use { db -> db.query("SELECT id, code, isAdded FROM languages").use { assertEquals(1, it.count) it.moveToFirst() @@ -60,7 +60,7 @@ class GodToolsRoomDatabaseMigrationIT { assertEquals("en", it.getStringOrNull(1)) assertEquals(0, it.getIntOrNull(2)) } - db.query("SELECT id, name, givenName, familyName, email FROM users").use { + db.query("SELECT id, name, givenName, familyName, email, isInitialFavoriteToolsSynced FROM users").use { assertEquals(1, it.count) it.moveToFirst() assertEquals(1, it.getIntOrNull(0)) @@ -68,6 +68,7 @@ class GodToolsRoomDatabaseMigrationIT { assertNull(it.getStringOrNull(2)) assertNull(it.getStringOrNull(3)) assertNull(it.getStringOrNull(4)) + assertEquals(0, it.getIntOrNull(5)) } db.query("SELECT id, time FROM last_sync_times").use { assertEquals(1, it.count) @@ -90,24 +91,6 @@ class GodToolsRoomDatabaseMigrationIT { } } - @Test - fun testMigrate16To17() { - // create v16 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 16).use { db -> - db.execSQL("""INSERT INTO users (id) VALUES (1)""") - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 17, true, *MIGRATIONS).use { db -> - db.query("SELECT id, isInitialFavoriteToolsSynced FROM users").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals(1, it.getIntOrNull(0)) - assertEquals(0, it.getIntOrNull(1)) - } - } - } - @Test fun testMigrate17To18() { // create v17 database From 80ffeedb508ab869ee2f6f004cc410f2ac41edca Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:47:33 -0600 Subject: [PATCH 14/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=207?= =?UTF-8?q?=E2=86=9217=20and=2017=E2=86=9218=20into=20a=20single=207?= =?UTF-8?q?=E2=86=9218=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../17.json | 693 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 10 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 24 +- 3 files changed, 6 insertions(+), 721 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/17.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/17.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/17.json deleted file mode 100644 index caecb089df..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/17.json +++ /dev/null @@ -1,693 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 17, - "identityHash": "288e0515f2cf370e063ab9462736a6af", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL DEFAULT 0, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL DEFAULT false, `defaultOrder` INTEGER NOT NULL DEFAULT 0, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isFavorite` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL DEFAULT false, `isSpotlight` INTEGER NOT NULL DEFAULT false, `changedFields` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isFavorite", - "columnName": "isFavorite", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "changedFields", - "columnName": "changedFields", - "affinity": "TEXT", - "notNull": true, - "defaultValue": "''" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `givenName` TEXT, `familyName` TEXT, `email` TEXT, `createdAt` INTEGER, `isInitialFavoriteToolsSynced` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "givenName", - "columnName": "givenName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "familyName", - "columnName": "familyName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "isInitialFavoriteToolsSynced", - "columnName": "isInitialFavoriteToolsSynced", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '288e0515f2cf370e063ab9462736a6af')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index 7178f00178..51ce3d9028 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -63,8 +63,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository LastSyncTimeEntity::class, ], autoMigrations = [ - AutoMigration(from = 7, to = 17, spec = ResetUserSyncMigration::class), - AutoMigration(from = 17, to = 18, spec = Migration18::class), + AutoMigration(from = 7, to = 18, spec = Migration7To18::class), AutoMigration(from = 18, to = 19, spec = Migration19::class), AutoMigration(from = 19, to = 20), AutoMigration(from = 20, to = 21), @@ -117,7 +116,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * v6.1.0-v6.1.1 * 7: 2023-03-27 * v6.2.0 - * 17: 2023-09-25 * 18: 2023-11-21 * 19: 2023-12-07 * 20: 2024-01-17 @@ -136,15 +134,13 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { internal fun RoomDatabase.Builder.enableMigrations() = fallbackToDestructiveMigration(dropAllTables = true) -internal class ResetUserSyncMigration : AutoMigrationSpec { +@RenameColumn(tableName = "languages", fromColumnName = "id", toColumnName = "apiId") +internal class Migration7To18 : AutoMigrationSpec { override fun onPostMigrate(db: SupportSQLiteDatabase) { db.execSQL("DELETE FROM last_sync_times WHERE id LIKE ?", arrayOf("last_synced.user%")) } } -@RenameColumn(tableName = "languages", fromColumnName = "id", toColumnName = "apiId") -internal class Migration18 : AutoMigrationSpec - @RenameColumn(tableName = "tools", fromColumnName = "id", toColumnName = "apiId") internal class Migration19 : AutoMigrationSpec // endregion Migrations diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index 2427b012d3..43c9655ce3 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -32,7 +32,7 @@ class GodToolsRoomDatabaseMigrationIT { val helper = MigrationTestHelper(InstrumentationRegistry.getInstrumentation(), GodToolsRoomDatabase::class.java) @Test - fun testMigrate7To17() { + fun testMigrate7To18() { val name = Uuid.random().toString() val filesQuery = "SELECT * FROM downloadedFiles" val toolsQuery = "SELECT * FROM tools" @@ -52,8 +52,8 @@ class GodToolsRoomDatabaseMigrationIT { } // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 17, true, *MIGRATIONS).use { db -> - db.query("SELECT id, code, isAdded FROM languages").use { + helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 18, true, *MIGRATIONS).use { db -> + db.query("SELECT apiId, code, isAdded FROM languages").use { assertEquals(1, it.count) it.moveToFirst() assertEquals(1, it.getIntOrNull(0)) @@ -91,24 +91,6 @@ class GodToolsRoomDatabaseMigrationIT { } } - @Test - fun testMigrate17To18() { - // create v17 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 17).use { db -> - db.execSQL("""INSERT INTO languages (id, code) VALUES (1, "en")""") - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 18, true, *MIGRATIONS).use { db -> - db.query("SELECT apiId, code FROM languages").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals(1, it.getIntOrNull(0)) - assertEquals("en", it.getStringOrNull(1)) - } - } - } - @Test fun testMigrate18To19() { // create v18 database From 8a49edaa46a9b8ad3bf4077d7d39bca55e9df8d1 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:51:17 -0600 Subject: [PATCH 15/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=207?= =?UTF-8?q?=E2=86=9218=20and=2018=E2=86=9219=20into=20a=20single=207?= =?UTF-8?q?=E2=86=9219=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../18.json | 693 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 9 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 27 +- 3 files changed, 6 insertions(+), 723 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/18.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/18.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/18.json deleted file mode 100644 index f0ecc7263d..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/18.json +++ /dev/null @@ -1,693 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 18, - "identityHash": "af6a0bc236a51dcc56b3473b0b9a322a", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `name` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, `apiId` INTEGER, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "apiId", - "columnName": "apiId", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL DEFAULT 0, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL DEFAULT false, `defaultOrder` INTEGER NOT NULL DEFAULT 0, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isFavorite` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL DEFAULT false, `isSpotlight` INTEGER NOT NULL DEFAULT false, `changedFields` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isFavorite", - "columnName": "isFavorite", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "changedFields", - "columnName": "changedFields", - "affinity": "TEXT", - "notNull": true, - "defaultValue": "''" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `givenName` TEXT, `familyName` TEXT, `email` TEXT, `createdAt` INTEGER, `isInitialFavoriteToolsSynced` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "givenName", - "columnName": "givenName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "familyName", - "columnName": "familyName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "isInitialFavoriteToolsSynced", - "columnName": "isInitialFavoriteToolsSynced", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'af6a0bc236a51dcc56b3473b0b9a322a')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index 51ce3d9028..f2236e5458 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -63,8 +63,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository LastSyncTimeEntity::class, ], autoMigrations = [ - AutoMigration(from = 7, to = 18, spec = Migration7To18::class), - AutoMigration(from = 18, to = 19, spec = Migration19::class), + AutoMigration(from = 7, to = 19, spec = Migration7To19::class), AutoMigration(from = 19, to = 20), AutoMigration(from = 20, to = 21), AutoMigration(from = 21, to = 22), @@ -116,7 +115,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * v6.1.0-v6.1.1 * 7: 2023-03-27 * v6.2.0 - * 18: 2023-11-21 * 19: 2023-12-07 * 20: 2024-01-17 * 21: 2024-01-26 @@ -135,12 +133,9 @@ internal fun RoomDatabase.Builder.enableMigrations() = fallbackToDestructiveMigration(dropAllTables = true) @RenameColumn(tableName = "languages", fromColumnName = "id", toColumnName = "apiId") -internal class Migration7To18 : AutoMigrationSpec { +internal class Migration7To19 : AutoMigrationSpec { override fun onPostMigrate(db: SupportSQLiteDatabase) { db.execSQL("DELETE FROM last_sync_times WHERE id LIKE ?", arrayOf("last_synced.user%")) } } - -@RenameColumn(tableName = "tools", fromColumnName = "id", toColumnName = "apiId") -internal class Migration19 : AutoMigrationSpec // endregion Migrations diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index 43c9655ce3..b35d01e824 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -32,7 +32,7 @@ class GodToolsRoomDatabaseMigrationIT { val helper = MigrationTestHelper(InstrumentationRegistry.getInstrumentation(), GodToolsRoomDatabase::class.java) @Test - fun testMigrate7To18() { + fun testMigrate7To19() { val name = Uuid.random().toString() val filesQuery = "SELECT * FROM downloadedFiles" val toolsQuery = "SELECT * FROM tools" @@ -52,7 +52,7 @@ class GodToolsRoomDatabaseMigrationIT { } // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 18, true, *MIGRATIONS).use { db -> + helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 19, true, *MIGRATIONS).use { db -> db.query("SELECT apiId, code, isAdded FROM languages").use { assertEquals(1, it.count) it.moveToFirst() @@ -76,8 +76,8 @@ class GodToolsRoomDatabaseMigrationIT { assertEquals("sync_time", it.getStringOrNull(0)) assertEquals(1234, it.getIntOrNull(1)) } - db.execSQL("""INSERT INTO tools (id, code, type) VALUES (1, "a", "TRACT")""") - db.query("SELECT id, code, isFavorite, changedFields FROM tools").use { + db.execSQL("""INSERT INTO tools (apiId, code, type) VALUES (1, "a", "TRACT")""") + db.query("SELECT apiId, code, isFavorite, changedFields FROM tools").use { assertEquals(1, it.count) it.moveToFirst() assertEquals(1, it.getIntOrNull(0)) @@ -91,25 +91,6 @@ class GodToolsRoomDatabaseMigrationIT { } } - @Test - fun testMigrate18To19() { - // create v18 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 18).use { db -> - db.execSQL("""INSERT INTO tools (id, code, type) VALUES (1, "a", "TRACT")""") - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 19, true, *MIGRATIONS).use { db -> - db.query("SELECT apiId, code, type FROM tools").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals(1, it.getIntOrNull(0)) - assertEquals("a", it.getStringOrNull(1)) - assertEquals("TRACT", it.getStringOrNull(2)) - } - } - } - @Test fun testMigrate19To20() { val filesQuery = "SELECT * FROM downloadedTranslationFiles" From 3cb69f81468157c9f17dd0fb85cef7ebc3c6cff7 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 4 May 2026 17:59:39 -0600 Subject: [PATCH 16/16] =?UTF-8?q?Collapse=20DB=20auto-migrations=207?= =?UTF-8?q?=E2=86=9219=20through=2021=E2=86=9222=20into=20a=20single=207?= =?UTF-8?q?=E2=86=9222=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../19.json | 693 ----------------- .../20.json | 720 ----------------- .../21.json | 727 ------------------ .../godtools/db/room/GodToolsRoomDatabase.kt | 10 +- .../room/GodToolsRoomDatabaseMigrationIT.kt | 68 +- 5 files changed, 10 insertions(+), 2208 deletions(-) delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/19.json delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/20.json delete mode 100644 library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/21.json diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/19.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/19.json deleted file mode 100644 index 77f4556808..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/19.json +++ /dev/null @@ -1,693 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 19, - "identityHash": "aa77202e5e638c6d8df2c6d370bc1cb3", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `name` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, `apiId` INTEGER, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "apiId", - "columnName": "apiId", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL DEFAULT 0, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL DEFAULT false, `defaultOrder` INTEGER NOT NULL DEFAULT 0, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isFavorite` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL DEFAULT false, `isSpotlight` INTEGER NOT NULL DEFAULT false, `changedFields` TEXT NOT NULL DEFAULT '', `apiId` INTEGER, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isFavorite", - "columnName": "isFavorite", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "changedFields", - "columnName": "changedFields", - "affinity": "TEXT", - "notNull": true, - "defaultValue": "''" - }, - { - "fieldPath": "apiId", - "columnName": "apiId", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `givenName` TEXT, `familyName` TEXT, `email` TEXT, `createdAt` INTEGER, `isInitialFavoriteToolsSynced` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "givenName", - "columnName": "givenName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "familyName", - "columnName": "familyName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "isInitialFavoriteToolsSynced", - "columnName": "isInitialFavoriteToolsSynced", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'aa77202e5e638c6d8df2c6d370bc1cb3')" - ] - } -} \ No newline at end of file diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/20.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/20.json deleted file mode 100644 index 21d34eefaa..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/20.json +++ /dev/null @@ -1,720 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 20, - "identityHash": "331b8aa77df342da38b633780f65b439", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `name` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, `apiId` INTEGER, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "apiId", - "columnName": "apiId", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedTranslationFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`translationId` INTEGER NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`translationId`, `filename`))", - "fields": [ - { - "fieldPath": "key.translationId", - "columnName": "translationId", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "translationId", - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL DEFAULT 0, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL DEFAULT false, `defaultOrder` INTEGER NOT NULL DEFAULT 0, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isFavorite` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL DEFAULT false, `isSpotlight` INTEGER NOT NULL DEFAULT false, `changedFields` TEXT NOT NULL DEFAULT '', `apiId` INTEGER, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isFavorite", - "columnName": "isFavorite", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "changedFields", - "columnName": "changedFields", - "affinity": "TEXT", - "notNull": true, - "defaultValue": "''" - }, - { - "fieldPath": "apiId", - "columnName": "apiId", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `givenName` TEXT, `familyName` TEXT, `email` TEXT, `createdAt` INTEGER, `isInitialFavoriteToolsSynced` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "givenName", - "columnName": "givenName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "familyName", - "columnName": "familyName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "isInitialFavoriteToolsSynced", - "columnName": "isInitialFavoriteToolsSynced", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '331b8aa77df342da38b633780f65b439')" - ] - } -} \ No newline at end of file diff --git a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/21.json b/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/21.json deleted file mode 100644 index 8af75bee70..0000000000 --- a/library/db/room-schemas/org.cru.godtools.db.room.GodToolsRoomDatabase/21.json +++ /dev/null @@ -1,727 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 21, - "identityHash": "bf3559488761d7b47a298aec41de8f56", - "entities": [ - { - "tableName": "attachments", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT, `filename` TEXT, `sha256` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sha256", - "columnName": "sha256", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_attachments_tool", - "unique": false, - "columnNames": [ - "tool" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_attachments_tool` ON `${TABLE_NAME}` (`tool`)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "languages", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `name` TEXT, `isAdded` INTEGER NOT NULL DEFAULT false, `apiId` INTEGER, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isAdded", - "columnName": "isAdded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "apiId", - "columnName": "apiId", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`filename` TEXT NOT NULL, PRIMARY KEY(`filename`))", - "fields": [ - { - "fieldPath": "filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "downloadedTranslationFiles", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`translationId` INTEGER NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`translationId`, `filename`))", - "fields": [ - { - "fieldPath": "key.translationId", - "columnName": "translationId", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.filename", - "columnName": "filename", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "translationId", - "filename" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "followups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `email` TEXT NOT NULL, `destination` INTEGER NOT NULL, `language` TEXT NOT NULL, `createdAt` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "destination", - "columnName": "destination", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "language", - "columnName": "language", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "global_activity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`users` INTEGER NOT NULL, `countries` INTEGER NOT NULL, `launches` INTEGER NOT NULL, `gospelPresentations` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "users", - "columnName": "users", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "countries", - "columnName": "countries", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "launches", - "columnName": "launches", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "gospelPresentations", - "columnName": "gospelPresentations", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tools", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`code` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `category` TEXT, `description` TEXT, `shares` INTEGER NOT NULL DEFAULT 0, `pendingShares` INTEGER NOT NULL DEFAULT 0, `bannerId` INTEGER, `detailsBannerId` INTEGER, `detailsBannerAnimationId` INTEGER, `detailsBannerYoutubeVideoId` TEXT, `isScreenShareDisabled` INTEGER NOT NULL DEFAULT false, `defaultLocale` TEXT NOT NULL DEFAULT 'en', `defaultOrder` INTEGER NOT NULL DEFAULT 0, `order` INTEGER NOT NULL DEFAULT 2147483647, `metatoolCode` TEXT, `defaultVariantCode` TEXT, `isFavorite` INTEGER NOT NULL DEFAULT false, `isHidden` INTEGER NOT NULL DEFAULT false, `isSpotlight` INTEGER NOT NULL DEFAULT false, `changedFields` TEXT NOT NULL DEFAULT '', `apiId` INTEGER, PRIMARY KEY(`code`))", - "fields": [ - { - "fieldPath": "code", - "columnName": "code", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "category", - "columnName": "category", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "shares", - "columnName": "shares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "pendingShares", - "columnName": "pendingShares", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "bannerId", - "columnName": "bannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerId", - "columnName": "detailsBannerId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerAnimationId", - "columnName": "detailsBannerAnimationId", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "detailsBannerYoutubeVideoId", - "columnName": "detailsBannerYoutubeVideoId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isScreenShareDisabled", - "columnName": "isScreenShareDisabled", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "defaultLocale", - "columnName": "defaultLocale", - "affinity": "TEXT", - "notNull": true, - "defaultValue": "'en'" - }, - { - "fieldPath": "defaultOrder", - "columnName": "defaultOrder", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "2147483647" - }, - { - "fieldPath": "metatoolCode", - "columnName": "metatoolCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "defaultVariantCode", - "columnName": "defaultVariantCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isFavorite", - "columnName": "isFavorite", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isHidden", - "columnName": "isHidden", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "isSpotlight", - "columnName": "isSpotlight", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - }, - { - "fieldPath": "changedFields", - "columnName": "changedFields", - "affinity": "TEXT", - "notNull": true, - "defaultValue": "''" - }, - { - "fieldPath": "apiId", - "columnName": "apiId", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "code" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "training_tips", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isCompleted` INTEGER NOT NULL, `isNew` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `tipId` TEXT NOT NULL, PRIMARY KEY(`tool`, `locale`, `tipId`))", - "fields": [ - { - "fieldPath": "isCompleted", - "columnName": "isCompleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isNew", - "columnName": "isNew", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "key.tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "key.tipId", - "columnName": "tipId", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tool", - "locale", - "tipId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "translations", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tool` TEXT NOT NULL, `locale` TEXT NOT NULL, `version` INTEGER NOT NULL, `name` TEXT, `description` TEXT, `tagline` TEXT, `toolDetailsConversationStarters` TEXT, `toolDetailsOutline` TEXT, `toolDetailsBibleReferences` TEXT, `manifestFileName` TEXT, `isDownloaded` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`tool`) REFERENCES `tools`(`code`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`locale`) REFERENCES `languages`(`code`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tool", - "columnName": "tool", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "locale", - "columnName": "locale", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "version", - "columnName": "version", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "description", - "columnName": "description", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "tagline", - "columnName": "tagline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsConversationStarters", - "columnName": "toolDetailsConversationStarters", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsOutline", - "columnName": "toolDetailsOutline", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "toolDetailsBibleReferences", - "columnName": "toolDetailsBibleReferences", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "manifestFileName", - "columnName": "manifestFileName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "isDownloaded", - "columnName": "isDownloaded", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_translations_tool_locale", - "unique": false, - "columnNames": [ - "tool", - "locale" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale` ON `${TABLE_NAME}` (`tool`, `locale`)" - }, - { - "name": "index_translations_tool_locale_version", - "unique": false, - "columnNames": [ - "tool", - "locale", - "version" - ], - "orders": [ - "ASC", - "ASC", - "DESC" - ], - "createSql": "CREATE INDEX IF NOT EXISTS `index_translations_tool_locale_version` ON `${TABLE_NAME}` (`tool` ASC, `locale` ASC, `version` DESC)" - } - ], - "foreignKeys": [ - { - "table": "tools", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tool" - ], - "referencedColumns": [ - "code" - ] - }, - { - "table": "languages", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "locale" - ], - "referencedColumns": [ - "code" - ] - } - ] - }, - { - "tableName": "users", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `ssoGuid` TEXT, `name` TEXT, `givenName` TEXT, `familyName` TEXT, `email` TEXT, `createdAt` INTEGER, `isInitialFavoriteToolsSynced` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "ssoGuid", - "columnName": "ssoGuid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "givenName", - "columnName": "givenName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "familyName", - "columnName": "familyName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "isInitialFavoriteToolsSynced", - "columnName": "isInitialFavoriteToolsSynced", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "false" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_counters", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `count` INTEGER NOT NULL, `decayedCount` REAL NOT NULL, `delta` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`name`))", - "fields": [ - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "count", - "columnName": "count", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "decayedCount", - "columnName": "decayedCount", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "delta", - "columnName": "delta", - "affinity": "INTEGER", - "notNull": true, - "defaultValue": "0" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "name" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "last_sync_times", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `time` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bf3559488761d7b47a298aec41de8f56')" - ] - } -} \ No newline at end of file diff --git a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt index f2236e5458..b9ed395419 100644 --- a/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt +++ b/library/db/src/main/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabase.kt @@ -63,10 +63,7 @@ import org.cru.godtools.db.room.repository.UserRoomRepository LastSyncTimeEntity::class, ], autoMigrations = [ - AutoMigration(from = 7, to = 19, spec = Migration7To19::class), - AutoMigration(from = 19, to = 20), - AutoMigration(from = 20, to = 21), - AutoMigration(from = 21, to = 22), + AutoMigration(from = 7, to = 22, spec = Migration7To22::class), AutoMigration(from = 22, to = 23), AutoMigration(from = 23, to = 24), AutoMigration(from = 24, to = 25), @@ -115,9 +112,6 @@ internal abstract class GodToolsRoomDatabase : RoomDatabase() { * v6.1.0-v6.1.1 * 7: 2023-03-27 * v6.2.0 - * 19: 2023-12-07 - * 20: 2024-01-17 - * 21: 2024-01-26 * 22: 2024-04-30 * v6.3.0 * 23: 2024-06-13 @@ -133,7 +127,7 @@ internal fun RoomDatabase.Builder.enableMigrations() = fallbackToDestructiveMigration(dropAllTables = true) @RenameColumn(tableName = "languages", fromColumnName = "id", toColumnName = "apiId") -internal class Migration7To19 : AutoMigrationSpec { +internal class Migration7To22 : AutoMigrationSpec { override fun onPostMigrate(db: SupportSQLiteDatabase) { db.execSQL("DELETE FROM last_sync_times WHERE id LIKE ?", arrayOf("last_synced.user%")) } diff --git a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt index b35d01e824..dcb662d832 100644 --- a/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt +++ b/library/db/src/test/kotlin/org/cru/godtools/db/room/GodToolsRoomDatabaseMigrationIT.kt @@ -11,7 +11,6 @@ import androidx.test.platform.app.InstrumentationRegistry import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith -import kotlin.test.assertFalse import kotlin.test.assertNull import kotlin.test.assertTrue import kotlin.uuid.ExperimentalUuidApi @@ -32,12 +31,13 @@ class GodToolsRoomDatabaseMigrationIT { val helper = MigrationTestHelper(InstrumentationRegistry.getInstrumentation(), GodToolsRoomDatabase::class.java) @Test - fun testMigrate7To19() { + fun testMigrate7To22() { val name = Uuid.random().toString() val filesQuery = "SELECT * FROM downloadedFiles" val toolsQuery = "SELECT * FROM tools" val attachmentsQuery = "SELECT * FROM attachments" val translationsQuery = "SELECT * FROM translations" + val translationFilesQuery = "SELECT * FROM downloadedTranslationFiles" // create v7 database helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 7).use { db -> @@ -49,10 +49,11 @@ class GodToolsRoomDatabaseMigrationIT { assertFailsWith { db.query(toolsQuery) } assertFailsWith { db.query(attachmentsQuery) } assertFailsWith { db.query(translationsQuery) } + assertFailsWith { db.query(translationFilesQuery) } } // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 19, true, *MIGRATIONS).use { db -> + helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 22, true, *MIGRATIONS).use { db -> db.query("SELECT apiId, code, isAdded FROM languages").use { assertEquals(1, it.count) it.moveToFirst() @@ -77,73 +78,20 @@ class GodToolsRoomDatabaseMigrationIT { assertEquals(1234, it.getIntOrNull(1)) } db.execSQL("""INSERT INTO tools (apiId, code, type) VALUES (1, "a", "TRACT")""") - db.query("SELECT apiId, code, isFavorite, changedFields FROM tools").use { + db.query("SELECT apiId, code, isFavorite, changedFields, defaultLocale FROM tools").use { assertEquals(1, it.count) it.moveToFirst() assertEquals(1, it.getIntOrNull(0)) assertEquals("a", it.getStringOrNull(1)) assertEquals(0, it.getIntOrNull(2)) assertEquals("", it.getStringOrNull(3)) + assertEquals("en", it.getStringOrNull(4)) } + assertTrue(db.dumpIndices("translations").values.any { it == setOf("locale") }) db.query(filesQuery).close() db.query(attachmentsQuery).close() db.query(translationsQuery).close() - } - } - - @Test - fun testMigrate19To20() { - val filesQuery = "SELECT * FROM downloadedTranslationFiles" - - // create v19 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 19).use { db -> - db.execSQL("INSERT INTO last_sync_times (id, time) VALUES (?, ?)", arrayOf("sync_time", "1234")) - assertFailsWith { db.query(filesQuery) } - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 20, true, *MIGRATIONS).use { db -> - db.query("SELECT id, time FROM last_sync_times").use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals("sync_time", it.getStringOrNull(0)) - assertEquals(1234, it.getIntOrNull(1)) - } - db.query(filesQuery).close() - } - } - - @Test - fun testMigrate20To21() { - val defaultLocaleQuery = "SELECT code, defaultLocale FROM tools WHERE code = 'kgp'" - - // create v20 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 20).use { db -> - db.execSQL("INSERT INTO tools (code, type) VALUES (?, ?)", arrayOf("kgp", Tool.Type.TRACT)) - assertFailsWith { db.query(defaultLocaleQuery) } - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 21, true, *MIGRATIONS).use { db -> - db.query(defaultLocaleQuery).use { - assertEquals(1, it.count) - it.moveToFirst() - assertEquals("kgp", it.getStringOrNull(0)) - assertEquals("en", it.getStringOrNull(1)) - } - } - } - - @Test - fun testMigrate21To22() { - // create v21 database - helper.createDatabase(GodToolsRoomDatabase.DATABASE_NAME, 21).use { db -> - assertFalse(db.dumpIndices("translations").values.any { it == setOf("locale") }) - } - - // run migration - helper.runMigrationsAndValidate(GodToolsRoomDatabase.DATABASE_NAME, 22, true, *MIGRATIONS).use { db -> - assertTrue(db.dumpIndices("translations").values.any { it == setOf("locale") }) + db.query(translationFilesQuery).close() } }