From 8326d06861e0fff586c5ba78325c6d3e7ca6fe9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Orzech?= Date: Fri, 20 Mar 2026 00:21:28 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20add=20DB=20migration=20v3=E2=86=92v4=20?= =?UTF-8?q?with=20new=20LocalPost=20columns=20for=20email,=20media,=20file?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../swoosh/microblog/data/db/AppDatabase.kt | 23 +++++++++++++++++-- .../swoosh/microblog/data/db/Converters.kt | 12 ++++++++-- .../microblog/data/model/GhostModels.kt | 14 ++++++++++- .../microblog/data/db/ConvertersTest.kt | 12 +++++----- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/swoosh/microblog/data/db/AppDatabase.kt b/app/src/main/java/com/swoosh/microblog/data/db/AppDatabase.kt index 1e21d15..aa729d1 100644 --- a/app/src/main/java/com/swoosh/microblog/data/db/AppDatabase.kt +++ b/app/src/main/java/com/swoosh/microblog/data/db/AppDatabase.kt @@ -9,7 +9,7 @@ import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase import com.swoosh.microblog.data.model.LocalPost -@Database(entities = [LocalPost::class], version = 3, exportSchema = false) +@Database(entities = [LocalPost::class], version = 4, exportSchema = false) @TypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { @@ -42,6 +42,25 @@ abstract class AppDatabase : RoomDatabase() { override fun migrate(db: SupportSQLiteDatabase) = addColumnsIfMissing(db) } + val MIGRATION_3_4 = object : Migration(3, 4) { + override fun migrate(db: SupportSQLiteDatabase) { + val columns = listOf( + "ALTER TABLE local_posts ADD COLUMN emailOnly INTEGER NOT NULL DEFAULT 0", + "ALTER TABLE local_posts ADD COLUMN newsletterSlug TEXT DEFAULT NULL", + "ALTER TABLE local_posts ADD COLUMN videoUri TEXT DEFAULT NULL", + "ALTER TABLE local_posts ADD COLUMN uploadedVideoUrl TEXT DEFAULT NULL", + "ALTER TABLE local_posts ADD COLUMN audioUri TEXT DEFAULT NULL", + "ALTER TABLE local_posts ADD COLUMN uploadedAudioUrl TEXT DEFAULT NULL", + "ALTER TABLE local_posts ADD COLUMN fileUri TEXT DEFAULT NULL", + "ALTER TABLE local_posts ADD COLUMN uploadedFileUrl TEXT DEFAULT NULL", + "ALTER TABLE local_posts ADD COLUMN fileName TEXT DEFAULT NULL" + ) + for (sql in columns) { + try { db.execSQL(sql) } catch (_: Exception) { } + } + } + } + fun getInstance(context: Context): AppDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( @@ -49,7 +68,7 @@ abstract class AppDatabase : RoomDatabase() { AppDatabase::class.java, "swoosh_database" ) - .addMigrations(MIGRATION_1_3, MIGRATION_2_3) + .addMigrations(MIGRATION_1_3, MIGRATION_2_3, MIGRATION_3_4) .fallbackToDestructiveMigration() .build() INSTANCE = instance diff --git a/app/src/main/java/com/swoosh/microblog/data/db/Converters.kt b/app/src/main/java/com/swoosh/microblog/data/db/Converters.kt index d5c5ad2..fa95220 100644 --- a/app/src/main/java/com/swoosh/microblog/data/db/Converters.kt +++ b/app/src/main/java/com/swoosh/microblog/data/db/Converters.kt @@ -11,13 +11,21 @@ class Converters { fun fromPostStatus(value: PostStatus): String = value.name @TypeConverter - fun toPostStatus(value: String): PostStatus = PostStatus.valueOf(value) + fun toPostStatus(value: String): PostStatus = try { + PostStatus.valueOf(value) + } catch (_: Exception) { + PostStatus.DRAFT + } @TypeConverter fun fromQueueStatus(value: QueueStatus): String = value.name @TypeConverter - fun toQueueStatus(value: String): QueueStatus = QueueStatus.valueOf(value) + fun toQueueStatus(value: String): QueueStatus = try { + QueueStatus.valueOf(value) + } catch (_: Exception) { + QueueStatus.NONE + } companion object { private val gson = Gson() diff --git a/app/src/main/java/com/swoosh/microblog/data/model/GhostModels.kt b/app/src/main/java/com/swoosh/microblog/data/model/GhostModels.kt index 243e47c..c99eef3 100644 --- a/app/src/main/java/com/swoosh/microblog/data/model/GhostModels.kt +++ b/app/src/main/java/com/swoosh/microblog/data/model/GhostModels.kt @@ -89,7 +89,19 @@ data class LocalPost( val tags: String = "[]", val createdAt: Long = System.currentTimeMillis(), val updatedAt: Long = System.currentTimeMillis(), - val queueStatus: QueueStatus = QueueStatus.NONE + val queueStatus: QueueStatus = QueueStatus.NONE, + // Phase 4b: email-only + val emailOnly: Boolean = false, + val newsletterSlug: String? = null, + // Phase 5: media + val videoUri: String? = null, + val uploadedVideoUrl: String? = null, + val audioUri: String? = null, + val uploadedAudioUrl: String? = null, + // Phase 6: file + val fileUri: String? = null, + val uploadedFileUrl: String? = null, + val fileName: String? = null ) enum class PostStatus { diff --git a/app/src/test/java/com/swoosh/microblog/data/db/ConvertersTest.kt b/app/src/test/java/com/swoosh/microblog/data/db/ConvertersTest.kt index 9eaea79..68d5f1b 100644 --- a/app/src/test/java/com/swoosh/microblog/data/db/ConvertersTest.kt +++ b/app/src/test/java/com/swoosh/microblog/data/db/ConvertersTest.kt @@ -56,9 +56,9 @@ class ConvertersTest { } } - @Test(expected = IllegalArgumentException::class) - fun `toPostStatus throws on invalid string`() { - converters.toPostStatus("INVALID") + @Test + fun `toPostStatus returns DRAFT fallback on invalid string`() { + assertEquals(PostStatus.DRAFT, converters.toPostStatus("INVALID")) } // --- QueueStatus conversions --- @@ -112,9 +112,9 @@ class ConvertersTest { } } - @Test(expected = IllegalArgumentException::class) - fun `toQueueStatus throws on invalid string`() { - converters.toQueueStatus("NONEXISTENT") + @Test + fun `toQueueStatus returns NONE fallback on invalid string`() { + assertEquals(QueueStatus.NONE, converters.toQueueStatus("NONEXISTENT")) } // --- String list JSON serialization ---