--- a/app/src/androidTest/java/com/geekorum/ttrss/data/migrations/ArticlesDatabaseMigrationTest.kt Mon Dec 03 12:27:52 2018 -0800
+++ b/app/src/androidTest/java/com/geekorum/ttrss/data/migrations/ArticlesDatabaseMigrationTest.kt Mon Dec 03 12:54:02 2018 -0800
@@ -55,7 +55,7 @@
// Re-open the database with version 2 and provide
// MIGRATION_1_2 as the migration process.
- helper.runMigrationsAndValidate(TEST_DB, 2, true, MIGRATION_1_2).use {
+ helper.runMigrationsAndValidate(TEST_DB, 2, true, MigrationFrom1To2).use {
// MigrationTestHelper automatically verifies the schema changes,
// but you need to validate that the data was migrated properly.
assertMigration1To2DataIntegrity(it)
@@ -136,7 +136,7 @@
}
helper.runMigrationsAndValidate(TEST_DB, 3, true,
- MIGRATION_1_2, MigrationFrom2To3).use {
+ MigrationFrom1To2, MigrationFrom2To3).use {
// MigrationTestHelper automatically verifies the schema changes,
// but you need to validate that the data was migrated properly.
assertMigration1To2DataIntegrity(it)
@@ -156,7 +156,7 @@
}
helper.runMigrationsAndValidate(TEST_DB, 4, true,
- MIGRATION_1_2, MigrationFrom2To3, MigrationFrom3To4).use {
+ MigrationFrom1To2, MigrationFrom2To3, MigrationFrom3To4).use {
// MigrationTestHelper automatically verifies the schema changes,
// but you need to validate that the data was migrated properly.
assertMigration1To2DataIntegrity(it)
@@ -164,8 +164,6 @@
}
companion object {
-
private val TEST_DB = "migration-test"
- private val MIGRATION_1_2 = ArticlesDatabaseFrom1To2()
}
}
--- a/app/src/main/java/com/geekorum/ttrss/data/ArticlesDatabaseModule.java Mon Dec 03 12:27:52 2018 -0800
+++ b/app/src/main/java/com/geekorum/ttrss/data/ArticlesDatabaseModule.java Mon Dec 03 12:54:02 2018 -0800
@@ -21,9 +21,9 @@
package com.geekorum.ttrss.data;
import android.app.Application;
+import androidx.room.Room;
import androidx.sqlite.db.SupportSQLiteOpenHelper;
-import androidx.room.Room;
-import com.geekorum.ttrss.data.migrations.ArticlesDatabaseFrom1To2;
+import com.geekorum.ttrss.data.migrations.MigrationFrom1To2;
import com.geekorum.ttrss.data.migrations.MigrationFrom2To3;
import com.geekorum.ttrss.data.migrations.MigrationFrom3To4;
import com.geekorum.ttrss.providers.ArticlesProvidersDao;
@@ -42,7 +42,7 @@
@Singleton
ArticlesDatabase providesAppDatabase(Application application) {
return Room.databaseBuilder(application, ArticlesDatabase.class, ArticlesDatabase.DATABASE_NAME)
- .addMigrations(new ArticlesDatabaseFrom1To2(),
+ .addMigrations(MigrationFrom1To2.INSTANCE,
MigrationFrom2To3.INSTANCE,
MigrationFrom3To4.INSTANCE)
.build();
--- a/app/src/main/java/com/geekorum/ttrss/data/migrations/ArticlesDatabase.kt Mon Dec 03 12:27:52 2018 -0800
+++ b/app/src/main/java/com/geekorum/ttrss/data/migrations/ArticlesDatabase.kt Mon Dec 03 12:54:02 2018 -0800
@@ -27,27 +27,130 @@
* Migrations for the ArticleDatabase
*/
+/**
+ * Architecture components alpha8 adds NOT NULL constraints for column with primitive types.
+ * This needs a schema migration.
+ * This works by creating a table with the new schema and copying all the previous data into it,
+ * then renaming the table to the original name.
+ */
+object MigrationFrom1To2 : Migration(1, 2) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ // Migrate primitive field to add not null constraint
+ database.runInTransaction {
+ migrateCategoriesTable(database)
+ migrateFeedsTable(database)
+ migrateTransactionTable(database)
+ migrateArticlesTable(database)
+ }
+ }
+
+ private fun migrateCategoriesTable(database: SupportSQLiteDatabase) {
+ with(database) {
+ execSQL("""CREATE TABLE `categories_new` (
+ |`_id` INTEGER NOT NULL,
+ |`title` TEXT,
+ |`unread_count` INTEGER NOT NULL,
+ | PRIMARY KEY(`_id`));""".trimMargin())
+
+ execSQL("INSERT INTO categories_new SELECT * FROM categories;")
+ execSQL("DROP TABLE categories;")
+ execSQL("ALTER TABLE categories_new RENAME TO categories;")
+ }
+ }
+
+ private fun migrateTransactionTable(database: SupportSQLiteDatabase) {
+ with(database) {
+ execSQL("""CREATE TABLE `transactions_new` (
+ |`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ |`article_id` INTEGER NOT NULL,
+ |`field` TEXT, `value` INTEGER NOT NULL,
+ |FOREIGN KEY(`article_id`) REFERENCES `articles`(`_id`)
+ |ON UPDATE NO ACTION ON DELETE NO ACTION );""".trimMargin())
+
+ execSQL("DROP INDEX IF EXISTS `index_transactions_article_id`;")
+ execSQL("CREATE INDEX `index_transactions_article_id` ON `transactions_new` (`article_id`);")
+
+ execSQL("INSERT INTO transactions_new SELECT * FROM transactions;")
+ execSQL("DROP TABLE transactions;")
+ execSQL("ALTER TABLE transactions_new RENAME TO transactions;")
+ }
+ }
+
+ private fun migrateFeedsTable(database: SupportSQLiteDatabase) {
+ with(database) {
+ execSQL("""CREATE TABLE `feeds_new` (
+ |`_id` INTEGER NOT NULL,
+ |`url` TEXT,
+ |`title` TEXT,
+ |`cat_id` INTEGER NOT NULL,
+ |`display_title` TEXT,
+ |`last_time_update` INTEGER NOT NULL,
+ |`unread_count` INTEGER NOT NULL,
+ |PRIMARY KEY(`_id`),
+ |FOREIGN KEY(`cat_id`) REFERENCES `categories`(`_id`)
+ |ON UPDATE NO ACTION ON DELETE NO ACTION )""".trimMargin())
+
+ execSQL("DROP INDEX IF EXISTS `index_feeds_cat_id`;")
+ execSQL("CREATE INDEX `index_feeds_cat_id` ON `feeds_new` (`cat_id`);")
+
+ execSQL("INSERT INTO feeds_new SELECT * FROM feeds;")
+ execSQL("DROP TABLE feeds;")
+ execSQL("ALTER TABLE feeds_new RENAME TO feeds;")
+ }
+ }
+
+ private fun migrateArticlesTable(database: SupportSQLiteDatabase) {
+ with(database) {
+ execSQL("CREATE TABLE `articles_new` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
+ + "`title` TEXT, "
+ + "`unread` INTEGER NOT NULL, "
+ + "`transiant_unread` INTEGER NOT NULL, "
+ + "`marked` INTEGER NOT NULL, "
+ + "`published` INTEGER NOT NULL, "
+ + "`score` INTEGER NOT NULL, "
+ + "`last_time_update` INTEGER NOT NULL, "
+ + "`is_updated` INTEGER NOT NULL, "
+ + "`link` TEXT, "
+ + "`feed_id` INTEGER NOT NULL, "
+ + "`tags` TEXT, "
+ + "`content` TEXT, "
+ + "`author` TEXT, "
+ + "`flavor_image_uri` TEXT, "
+ + "`content_excerpt` TEXT, "
+ + "FOREIGN KEY(`feed_id`) REFERENCES `feeds`(`_id`) "
+ + "ON UPDATE NO ACTION ON DELETE NO ACTION )")
+
+ execSQL("DROP INDEX IF EXISTS `index_articles_feed_id`;")
+ execSQL("CREATE INDEX `index_articles_feed_id` ON `articles_new` (`feed_id`);")
+
+ execSQL("INSERT INTO articles_new SELECT * FROM articles;")
+ execSQL("DROP TABLE articles;")
+ execSQL("ALTER TABLE articles_new RENAME TO articles;")
+ }
+ }
+}
+
+
/** This migration makes fields non nullable **/
object MigrationFrom2To3 : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
- database.beginTransaction()
- try {
+ database.runInTransaction {
migrateCategoriesTables(database)
migrateTransactionTable(database)
migrateFeedsTable(database)
migrateArticlesTable(database)
- database.setTransactionSuccessful()
- } finally {
- database.endTransaction()
+
}
}
private fun migrateCategoriesTables(database: SupportSQLiteDatabase) {
with(database) {
- execSQL("CREATE TABLE `categories_new` (`_id` INTEGER NOT NULL,"
- + "`title` TEXT NOT NULL, "
- + "`unread_count` INTEGER NOT NULL, "
- + "PRIMARY KEY(`_id`));")
+ execSQL("""CREATE TABLE `categories_new` (
+ |`_id` INTEGER NOT NULL,
+ |`title` TEXT NOT NULL,
+ |`unread_count` INTEGER NOT NULL,
+ |PRIMARY KEY(`_id`));""".trimMargin())
execSQL("INSERT INTO categories_new SELECT * FROM categories WHERE title is NOT NULL;")
execSQL("DROP TABLE categories;")
@@ -57,12 +160,13 @@
private fun migrateTransactionTable(database: SupportSQLiteDatabase) {
with(database) {
- execSQL("CREATE TABLE `transactions_new` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "`article_id` INTEGER NOT NULL, "
- + "`field` TEXT NOT NULL, "
- + "`value` INTEGER NOT NULL, "
- + "FOREIGN KEY(`article_id`) REFERENCES `articles`(`_id`) "
- + "ON UPDATE NO ACTION ON DELETE NO ACTION );")
+ execSQL("""CREATE TABLE `transactions_new` (
+ |`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ |`article_id` INTEGER NOT NULL,
+ |`field` TEXT NOT NULL,
+ |`value` INTEGER NOT NULL,
+ |FOREIGN KEY(`article_id`) REFERENCES `articles`(`_id`)
+ |ON UPDATE NO ACTION ON DELETE NO ACTION );""".trimMargin())
execSQL("DROP INDEX IF EXISTS `index_transactions_article_id`;")
execSQL("CREATE INDEX `index_transactions_article_id` ON `transactions_new` (`article_id`);")
@@ -75,21 +179,26 @@
private fun migrateFeedsTable(database: SupportSQLiteDatabase) {
with(database) {
- execSQL("CREATE TABLE `feeds_new` (`_id` INTEGER NOT NULL, "
- + "`url` TEXT NOT NULL, "
- + "`title` TEXT NOT NULL, "
- + "`cat_id` INTEGER NOT NULL, "
- + "`display_title` TEXT NOT NULL, "
- + "`last_time_update` INTEGER NOT NULL, "
- + "`unread_count` INTEGER NOT NULL, "
- + "PRIMARY KEY(`_id`), "
- + "FOREIGN KEY(`cat_id`) REFERENCES `categories`(`_id`) "
- + "ON UPDATE NO ACTION ON DELETE NO ACTION )")
+ execSQL("""CREATE TABLE `feeds_new` (
+ |`_id` INTEGER NOT NULL,
+ |`url` TEXT NOT NULL,
+ |`title` TEXT NOT NULL,
+ |`cat_id` INTEGER NOT NULL,
+ |`display_title` TEXT NOT NULL,
+ |`last_time_update` INTEGER NOT NULL,
+ |`unread_count` INTEGER NOT NULL,
+ |PRIMARY KEY(`_id`),
+ |FOREIGN KEY(`cat_id`) REFERENCES `categories`(`_id`)
+ |ON UPDATE NO ACTION ON DELETE NO ACTION )""".trimMargin())
execSQL("DROP INDEX IF EXISTS `index_feeds_cat_id`;")
execSQL("CREATE INDEX `index_feeds_cat_id` ON `feeds_new` (`cat_id`);")
- execSQL("INSERT INTO feeds_new SELECT * FROM feeds WHERE url IS NOT NULL AND title IS NOT NULL AND display_title IS NOT NULL;")
+ execSQL("""INSERT INTO feeds_new
+ |SELECT * FROM feeds
+ |WHERE url IS NOT NULL
+ |AND title IS NOT NULL
+ |AND display_title IS NOT NULL;""".trimMargin())
execSQL("DROP TABLE feeds;")
execSQL("ALTER TABLE feeds_new RENAME TO feeds;")
}
@@ -97,32 +206,38 @@
private fun migrateArticlesTable(database: SupportSQLiteDatabase) {
with(database) {
- execSQL("CREATE TABLE `articles_new` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "`title` TEXT NOT NULL, "
- + "`unread` INTEGER NOT NULL, "
- + "`transiant_unread` INTEGER NOT NULL, "
- + "`marked` INTEGER NOT NULL, "
- + "`published` INTEGER NOT NULL, "
- + "`score` INTEGER NOT NULL, "
- + "`last_time_update` INTEGER NOT NULL, "
- + "`is_updated` INTEGER NOT NULL, "
- + "`link` TEXT NOT NULL, "
- + "`feed_id` INTEGER NOT NULL, "
- + "`tags` TEXT NOT NULL, "
- + "`content` TEXT NOT NULL, "
- + "`author` TEXT NOT NULL, "
- + "`flavor_image_uri` TEXT NOT NULL, "
- + "`content_excerpt` TEXT NOT NULL, "
- + "FOREIGN KEY(`feed_id`) REFERENCES `feeds`(`_id`) "
- + "ON UPDATE NO ACTION ON DELETE NO ACTION )")
+ execSQL("""CREATE TABLE `articles_new` (
+ |`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ |`title` TEXT NOT NULL,
+ |`unread` INTEGER NOT NULL,
+ |`transiant_unread` INTEGER NOT NULL,
+ |`marked` INTEGER NOT NULL,
+ |`published` INTEGER NOT NULL,
+ |`score` INTEGER NOT NULL,
+ |`last_time_update` INTEGER NOT NULL,
+ |`is_updated` INTEGER NOT NULL,
+ |`link` TEXT NOT NULL,
+ |`feed_id` INTEGER NOT NULL,
+ |`tags` TEXT NOT NULL,
+ |`content` TEXT NOT NULL,
+ |`author` TEXT NOT NULL,
+ |`flavor_image_uri` TEXT NOT NULL,
+ |`content_excerpt` TEXT NOT NULL,
+ |FOREIGN KEY(`feed_id`) REFERENCES `feeds`(`_id`)
+ |ON UPDATE NO ACTION ON DELETE NO ACTION )""".trimMargin())
execSQL("DROP INDEX IF EXISTS `index_articles_feed_id`;")
execSQL("CREATE INDEX `index_articles_feed_id` ON `articles_new` (`feed_id`);")
-
- execSQL("INSERT INTO articles_new SELECT * FROM articles WHERE title IS NOT NULL AND link IS NOT NULL "
- + "AND tags IS NOT NULL AND content IS NOT NULL AND author IS NOT NULL "
- + "AND flavor_image_uri is NOT NULL AND content_excerpt IS NOT NULL;")
+ execSQL("""INSERT INTO articles_new
+ |SELECT * FROM articles
+ |WHERE title IS NOT NULL
+ |AND link IS NOT NULL
+ |AND tags IS NOT NULL
+ |AND content IS NOT NULL
+ |AND author IS NOT NULL
+ |AND flavor_image_uri is NOT NULL
+ |AND content_excerpt IS NOT NULL;""".trimMargin())
execSQL("DROP TABLE articles;")
execSQL("ALTER TABLE articles_new RENAME TO articles;")
}
@@ -131,27 +246,23 @@
}
-
/** This migration add some cascade on delete constraints **/
object MigrationFrom3To4 : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
- database.beginTransaction()
- try {
+ database.runInTransaction {
migrateTransactionTable(database)
- database.setTransactionSuccessful()
- } finally {
- database.endTransaction()
}
}
private fun migrateTransactionTable(database: SupportSQLiteDatabase) {
with(database) {
- execSQL("CREATE TABLE `transactions_new` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "`article_id` INTEGER NOT NULL, "
- + "`field` TEXT NOT NULL, "
- + "`value` INTEGER NOT NULL, "
- + "FOREIGN KEY(`article_id`) REFERENCES `articles`(`_id`)"
- + "ON UPDATE NO ACTION ON DELETE CASCADE );")
+ execSQL("""CREATE TABLE `transactions_new` (
+ |`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ |`article_id` INTEGER NOT NULL,
+ |`field` TEXT NOT NULL,
+ |`value` INTEGER NOT NULL,
+ |FOREIGN KEY(`article_id`) REFERENCES `articles`(`_id`)
+ |ON UPDATE NO ACTION ON DELETE CASCADE );""".trimMargin())
execSQL("DROP INDEX IF EXISTS `index_transactions_article_id`;")
execSQL("CREATE INDEX `index_transactions_article_id` ON `transactions_new` (`article_id`);")
@@ -161,5 +272,21 @@
execSQL("ALTER TABLE transactions_new RENAME TO transactions;")
}
}
+}
+
+private fun <V> SupportSQLiteDatabase.runInTransaction(body: () -> V): V {
+ beginTransaction()
+ try {
+ val result = body()
+ setTransactionSuccessful()
+ return result
+ } catch (e: RuntimeException) {
+ throw e
+ } catch (e: Exception) {
+ throw RuntimeException("Exception in transaction", e)
+ } finally {
+ endTransaction()
+ }
}
+
--- a/app/src/main/java/com/geekorum/ttrss/data/migrations/ArticlesDatabaseFrom1To2.java Mon Dec 03 12:27:52 2018 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/**
- * Geekttrss is a RSS feed reader application on the Android Platform.
- *
- * Copyright (C) 2017-2018 by Frederic-Charles Barthelery.
- *
- * This file is part of Geekttrss.
- *
- * Geekttrss is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Geekttrss is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Geekttrss. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.geekorum.ttrss.data.migrations;
-
-import androidx.sqlite.db.SupportSQLiteDatabase;
-import androidx.room.migration.Migration;
-
-/**
- * Architecture components alpha8 adds NOT NULL constraints for column with primitive types.
- * This needs a schema migration.
- * This works by creating a table with the new schema and copying all the previous data into it,
- * then renaming the table to the original name.
- */
-public class ArticlesDatabaseFrom1To2 extends Migration {
-
- /**
- * Creates the {@link ArticlesDatabaseFrom1To2} migration.
- */
- public ArticlesDatabaseFrom1To2() {
- super(1, 2);
- }
-
- @Override
- public void migrate(SupportSQLiteDatabase database) {
- // Migrate primitive field to add not null constraint
- database.beginTransaction();
- try {
- migrateCategoriesTable(database);
- migrateFeedsTable(database);
- migrateTransactionTable(database);
- migrateArticlesTable(database);
- database.setTransactionSuccessful();
- } finally {
- database.endTransaction();
- }
- }
-
- private void migrateCategoriesTable(SupportSQLiteDatabase database) {
- database.execSQL("CREATE TABLE `categories_new` (`_id` INTEGER NOT NULL,"
- + "`title` TEXT, "
- + "`unread_count` INTEGER NOT NULL, "
- + "PRIMARY KEY(`_id`));");
-
- database.execSQL("INSERT INTO categories_new SELECT * FROM categories;");
- database.execSQL("DROP TABLE categories;");
- database.execSQL("ALTER TABLE categories_new RENAME TO categories;");
- }
-
- private void migrateTransactionTable(SupportSQLiteDatabase database) {
- database.execSQL("CREATE TABLE `transactions_new` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "`article_id` INTEGER NOT NULL, "
- + "`field` TEXT, "
- + "`value` INTEGER NOT NULL, "
- + "FOREIGN KEY(`article_id`) REFERENCES `articles`(`_id`) "
- + "ON UPDATE NO ACTION ON DELETE NO ACTION );");
-
- database.execSQL("DROP INDEX IF EXISTS `index_transactions_article_id`;");
- database.execSQL("CREATE INDEX `index_transactions_article_id` ON `transactions_new` (`article_id`);");
-
- database.execSQL("INSERT INTO transactions_new SELECT * FROM transactions;");
- database.execSQL("DROP TABLE transactions;");
- database.execSQL("ALTER TABLE transactions_new RENAME TO transactions;");
- }
-
- private void migrateFeedsTable(SupportSQLiteDatabase database) {
- database.execSQL("CREATE TABLE `feeds_new` (`_id` INTEGER NOT NULL, "
- + "`url` TEXT, "
- + "`title` TEXT, "
- + "`cat_id` INTEGER NOT NULL, "
- + "`display_title` TEXT, "
- + "`last_time_update` INTEGER NOT NULL, "
- + "`unread_count` INTEGER NOT NULL, "
- + "PRIMARY KEY(`_id`), "
- + "FOREIGN KEY(`cat_id`) REFERENCES `categories`(`_id`) "
- + "ON UPDATE NO ACTION ON DELETE NO ACTION )");
-
- database.execSQL("DROP INDEX IF EXISTS `index_feeds_cat_id`;");
- database.execSQL("CREATE INDEX `index_feeds_cat_id` ON `feeds_new` (`cat_id`);");
-
- database.execSQL("INSERT INTO feeds_new SELECT * FROM feeds;");
- database.execSQL("DROP TABLE feeds;");
- database.execSQL("ALTER TABLE feeds_new RENAME TO feeds;");
- }
-
- private void migrateArticlesTable(SupportSQLiteDatabase database) {
- database.execSQL("CREATE TABLE `articles_new` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "`title` TEXT, "
- + "`unread` INTEGER NOT NULL, "
- + "`transiant_unread` INTEGER NOT NULL, "
- + "`marked` INTEGER NOT NULL, "
- + "`published` INTEGER NOT NULL, "
- + "`score` INTEGER NOT NULL, "
- + "`last_time_update` INTEGER NOT NULL, "
- + "`is_updated` INTEGER NOT NULL, "
- + "`link` TEXT, "
- + "`feed_id` INTEGER NOT NULL, "
- + "`tags` TEXT, "
- + "`content` TEXT, "
- + "`author` TEXT, "
- + "`flavor_image_uri` TEXT, "
- + "`content_excerpt` TEXT, "
- + "FOREIGN KEY(`feed_id`) REFERENCES `feeds`(`_id`) "
- + "ON UPDATE NO ACTION ON DELETE NO ACTION )");
-
- database.execSQL("DROP INDEX IF EXISTS `index_articles_feed_id`;");
- database.execSQL("CREATE INDEX `index_articles_feed_id` ON `articles_new` (`feed_id`);");
-
- database.execSQL("INSERT INTO articles_new SELECT * FROM articles;");
- database.execSQL("DROP TABLE articles;");
- database.execSQL("ALTER TABLE articles_new RENAME TO articles;");
- }
-
-}