#831 Migrate from SQLiteOpenHelper to Room

Safe old migration steps
This commit is contained in:
Stefan Niedermann 2020-10-07 12:05:34 +02:00
parent 457a90b8c9
commit f6adc6ad3a
19 changed files with 266 additions and 74 deletions

View file

@ -51,6 +51,22 @@ import it.niedermann.owncloud.notes.persistence.entity.LocalAccount;
import it.niedermann.owncloud.notes.persistence.entity.Note; import it.niedermann.owncloud.notes.persistence.entity.Note;
import it.niedermann.owncloud.notes.persistence.entity.NotesListWidgetData; import it.niedermann.owncloud.notes.persistence.entity.NotesListWidgetData;
import it.niedermann.owncloud.notes.persistence.entity.SingleNoteWidgetData; import it.niedermann.owncloud.notes.persistence.entity.SingleNoteWidgetData;
import it.niedermann.owncloud.notes.persistence.migration.Migration_10_11;
import it.niedermann.owncloud.notes.persistence.migration.Migration_11_12;
import it.niedermann.owncloud.notes.persistence.migration.Migration_12_13;
import it.niedermann.owncloud.notes.persistence.migration.Migration_13_14;
import it.niedermann.owncloud.notes.persistence.migration.Migration_14_15;
import it.niedermann.owncloud.notes.persistence.migration.Migration_15_16;
import it.niedermann.owncloud.notes.persistence.migration.Migration_16_17;
import it.niedermann.owncloud.notes.persistence.migration.Migration_17_18;
import it.niedermann.owncloud.notes.persistence.migration.Migration_18_19;
import it.niedermann.owncloud.notes.persistence.migration.Migration_19_20;
import it.niedermann.owncloud.notes.persistence.migration.Migration_4_5;
import it.niedermann.owncloud.notes.persistence.migration.Migration_5_6;
import it.niedermann.owncloud.notes.persistence.migration.Migration_6_7;
import it.niedermann.owncloud.notes.persistence.migration.Migration_7_8;
import it.niedermann.owncloud.notes.persistence.migration.Migration_8_9;
import it.niedermann.owncloud.notes.persistence.migration.Migration_9_10;
import it.niedermann.owncloud.notes.shared.model.ApiVersion; import it.niedermann.owncloud.notes.shared.model.ApiVersion;
import it.niedermann.owncloud.notes.shared.model.Capabilities; import it.niedermann.owncloud.notes.shared.model.Capabilities;
import it.niedermann.owncloud.notes.shared.model.CategorySortingMethod; import it.niedermann.owncloud.notes.shared.model.CategorySortingMethod;
@ -72,7 +88,7 @@ import static it.niedermann.owncloud.notes.widget.singlenote.SingleNoteWidget.up
Category.class, Category.class,
SingleNoteWidgetData.class, SingleNoteWidgetData.class,
NotesListWidgetData.class NotesListWidgetData.class
}, version = 18 }, version = 20
) )
@TypeConverters({Converters.class}) @TypeConverters({Converters.class})
public abstract class NotesDatabase extends RoomDatabase { public abstract class NotesDatabase extends RoomDatabase {
@ -88,8 +104,25 @@ public abstract class NotesDatabase extends RoomDatabase {
context, context,
NotesDatabase.class, NotesDatabase.class,
NOTES_DB_NAME) NOTES_DB_NAME)
.addMigrations(OLD_STUFF) .addMigrations(
.fallbackToDestructiveMigration() new Migration_4_5(),
new Migration_5_6(),
new Migration_6_7(),
new Migration_7_8(),
new Migration_8_9(context, (supportSQLiteDatabase) -> { /* TODO */ }, () -> instance.notifyWidgets()),
new Migration_9_10(),
new Migration_10_11(context),
new Migration_11_12(context),
new Migration_12_13(context),
new Migration_13_14(context, () -> instance.notifyWidgets()),
new Migration_14_15(),
new Migration_15_16(context, () -> instance.notifyWidgets()),
new Migration_16_17(),
new Migration_17_18(),
new Migration_18_19(context),
new Migration_19_20()
)
// .fallbackToDestructiveMigration()
.addCallback(new RoomDatabase.Callback() { .addCallback(new RoomDatabase.Callback() {
@Override @Override
public void onCreate(@NonNull SupportSQLiteDatabase db) { public void onCreate(@NonNull SupportSQLiteDatabase db) {
@ -101,13 +134,6 @@ public abstract class NotesDatabase extends RoomDatabase {
.build(); .build();
} }
private static final Migration OLD_STUFF = new Migration(17, 18) {
@Override
public void migrate(SupportSQLiteDatabase database) {
}
};
public abstract LocalAccountDao getLocalAccountDao(); public abstract LocalAccountDao getLocalAccountDao();
public abstract CategoryDao getCategoryDao(); public abstract CategoryDao getCategoryDao();

View file

@ -25,11 +25,11 @@ import it.niedermann.owncloud.notes.shared.util.ColorUtil;
@Entity( @Entity(
tableName = "ACCOUNTS", tableName = "ACCOUNTS",
indices = { indices = {
@Index(name = "ACCOUNTS_ACCOUNT_NAME_idx", value = "ACCOUNT_NAME"),
@Index(name = "ACCOUNTS_ETAG_idx", value = "ETAG"),
@Index(name = "ACCOUNTS_MODIFIED_idx", value = "MODIFIED"), @Index(name = "ACCOUNTS_MODIFIED_idx", value = "MODIFIED"),
@Index(name = "ACCOUNTS_URL_idx", value = "URL"), @Index(name = "ACCOUNTS_URL_idx", value = "URL"),
@Index(name = "ACCOUNTS_USERNAME_idx", value = "USERNAME") @Index(name = "ACCOUNTS_USERNAME_idx", value = "USERNAME"),
@Index(name = "ACCOUNTS_ACCOUNT_NAME_idx", value = "ACCOUNT_NAME"),
@Index(name = "ACCOUNTS_ETAG_idx", value = "ETAG")
} }
) )
public class LocalAccount { public class LocalAccount {
@ -48,9 +48,9 @@ public class LocalAccount {
private Calendar modified; private Calendar modified;
@ColumnInfo(name = "API_VERSION") @ColumnInfo(name = "API_VERSION")
private String apiVersion; private String apiVersion;
@ColumnInfo(name = "COLOR") @ColumnInfo(name = "COLOR", defaultValue = "000000")
private String color; private String color;
@ColumnInfo(name = "TEXT_COLOR") @ColumnInfo(name = "TEXT_COLOR", defaultValue = "0082C9")
private String textColor; private String textColor;
@ColumnInfo(name = "CAPABILITIES_ETAG") @ColumnInfo(name = "CAPABILITIES_ETAG")
private String capabilitiesETag; private String capabilitiesETag;

View file

@ -5,16 +5,27 @@ import android.content.SharedPreferences;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import java.util.Map; import java.util.Map;
import it.niedermann.owncloud.notes.preferences.DarkModeSetting; import it.niedermann.owncloud.notes.preferences.DarkModeSetting;
public class Migration_10_11 { public class Migration_10_11 extends Migration {
@NonNull
private final Context context;
public Migration_10_11(@NonNull Context context) {
super(10, 11);
this.context = context;
}
/** /**
* Changes the boolean for light / dark mode to {@link DarkModeSetting} to also be able to represent system default value * Changes the boolean for light / dark mode to {@link DarkModeSetting} to also be able to represent system default value
*/ */
public Migration_10_11(@NonNull Context context) { @Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sharedPreferences.edit(); SharedPreferences.Editor editor = sharedPreferences.edit();
Map<String, ?> prefs = sharedPreferences.getAll(); Map<String, ?> prefs = sharedPreferences.getAll();

View file

@ -4,15 +4,26 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import it.niedermann.owncloud.notes.persistence.CapabilitiesWorker; import it.niedermann.owncloud.notes.persistence.CapabilitiesWorker;
import it.niedermann.owncloud.notes.shared.model.ApiVersion; import it.niedermann.owncloud.notes.shared.model.ApiVersion;
public class Migration_11_12 { public class Migration_11_12 extends Migration {
@NonNull
private final Context context;
public Migration_11_12(@NonNull Context context) {
super(11, 12);
this.context = context;
}
/** /**
* Adds columns to store the {@link ApiVersion} and the theme colors * Adds columns to store the {@link ApiVersion} and the theme colors
*/ */
public Migration_11_12(@NonNull SQLiteDatabase db, @NonNull Context context) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN API_VERSION TEXT"); db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN API_VERSION TEXT");
db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN COLOR VARCHAR(6) NOT NULL DEFAULT '000000'"); db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN COLOR VARCHAR(6) NOT NULL DEFAULT '000000'");
db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN TEXT_COLOR VARCHAR(6) NOT NULL DEFAULT '0082C9'"); db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN TEXT_COLOR VARCHAR(6) NOT NULL DEFAULT '0082C9'");

View file

@ -4,15 +4,26 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.work.WorkManager; import androidx.work.WorkManager;
import it.niedermann.owncloud.notes.shared.model.Capabilities; import it.niedermann.owncloud.notes.shared.model.Capabilities;
public class Migration_12_13 { public class Migration_12_13 extends Migration {
@NonNull
private final Context context;
public Migration_12_13(@NonNull Context context) {
super(12, 13);
this.context = context;
}
/** /**
* Adds a column to store the ETag of the server {@link Capabilities} * Adds a column to store the ETag of the server {@link Capabilities}
*/ */
public Migration_12_13(@NonNull SQLiteDatabase db, @NonNull Context context) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN CAPABILITIES_ETAG TEXT"); db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN CAPABILITIES_ETAG TEXT");
WorkManager.getInstance(context.getApplicationContext()).cancelUniqueWork("it.niedermann.owncloud.notes.persistence.SyncWorker"); WorkManager.getInstance(context.getApplicationContext()).cancelUniqueWork("it.niedermann.owncloud.notes.persistence.SyncWorker");
WorkManager.getInstance(context.getApplicationContext()).cancelUniqueWork("SyncWorker"); WorkManager.getInstance(context.getApplicationContext()).cancelUniqueWork("SyncWorker");

View file

@ -3,25 +3,38 @@ package it.niedermann.owncloud.notes.persistence.migration;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.room.OnConflictStrategy;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import java.util.Map; import java.util.Map;
import it.niedermann.owncloud.notes.preferences.DarkModeSetting; import it.niedermann.owncloud.notes.preferences.DarkModeSetting;
public class Migration_13_14 { public class Migration_13_14 extends Migration {
private static final String TAG = Migration_13_14.class.getSimpleName(); private static final String TAG = Migration_13_14.class.getSimpleName();
@NonNull
private final Context context;
@NonNull
private final Runnable notifyWidgets;
public Migration_13_14(@NonNull Context context, @NonNull Runnable notifyWidgets) {
super(13, 14);
this.context = context;
this.notifyWidgets = notifyWidgets;
}
/** /**
* Move single note widget preferences to database * Move single note widget preferences to database
* https://github.com/stefan-niedermann/nextcloud-notes/issues/754 * https://github.com/stefan-niedermann/nextcloud-notes/issues/754
*/ */
public Migration_13_14(@NonNull SQLiteDatabase db, @NonNull Context context, @NonNull Runnable notifyWidgets) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
db.execSQL("CREATE TABLE WIDGET_SINGLE_NOTES ( " + db.execSQL("CREATE TABLE WIDGET_SINGLE_NOTES ( " +
"ID INTEGER PRIMARY KEY, " + "ID INTEGER PRIMARY KEY, " +
"ACCOUNT_ID INTEGER, " + "ACCOUNT_ID INTEGER, " +
@ -60,7 +73,7 @@ public class Migration_13_14 {
migratedWidgetValues.put("ACCOUNT_ID", accountId); migratedWidgetValues.put("ACCOUNT_ID", accountId);
migratedWidgetValues.put("NOTE_ID", noteId); migratedWidgetValues.put("NOTE_ID", noteId);
migratedWidgetValues.put("THEME_MODE", themeMode); migratedWidgetValues.put("THEME_MODE", themeMode);
db.insert("WIDGET_SINGLE_NOTES", null, migratedWidgetValues); db.insert("WIDGET_SINGLE_NOTES", OnConflictStrategy.REPLACE, migratedWidgetValues);
} catch (Throwable t) { } catch (Throwable t) {
Log.e(TAG, "Could not migrate widget {widgetId: " + widgetId + ", accountId: " + accountId + ", noteId: " + noteId + ", themeMode: " + themeMode + "}"); Log.e(TAG, "Could not migrate widget {widgetId: " + widgetId + ", accountId: " + accountId + ", noteId: " + noteId + ", themeMode: " + themeMode + "}");
t.printStackTrace(); t.printStackTrace();

View file

@ -5,16 +5,27 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import androidx.room.OnConflictStrategy;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import java.util.Hashtable; import java.util.Hashtable;
import it.niedermann.owncloud.notes.shared.util.DatabaseIndexUtil; import it.niedermann.owncloud.notes.shared.util.DatabaseIndexUtil;
public class Migration_14_15 { public class Migration_14_15 extends Migration {
public Migration_14_15() {
super(14, 15);
}
/** /**
* Normalize database (move category from string field to own table) * Normalize database (move category from string field to own table)
* https://github.com/stefan-niedermann/nextcloud-notes/issues/814 * https://github.com/stefan-niedermann/nextcloud-notes/issues/814
*/ */
public Migration_14_15(SQLiteDatabase db) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
// Rename a tmp_NOTES table. // Rename a tmp_NOTES table.
String tmpTableNotes = String.format("tmp_%s", "NOTES"); String tmpTableNotes = String.format("tmp_%s", "NOTES");
db.execSQL("ALTER TABLE NOTES RENAME TO " + tmpTableNotes); db.execSQL("ALTER TABLE NOTES RENAME TO " + tmpTableNotes);
@ -44,7 +55,7 @@ public class Migration_14_15 {
// This is used to prevent too many searches in database // This is used to prevent too many searches in database
Hashtable<String, Integer> categoryTitleIdMap = new Hashtable<>(); Hashtable<String, Integer> categoryTitleIdMap = new Hashtable<>();
int id = 1; int id = 1;
Cursor tmpNotesCursor = db.rawQuery("SELECT * FROM " + tmpTableNotes, null); Cursor tmpNotesCursor = db.query("SELECT * FROM " + tmpTableNotes, null);
while (tmpNotesCursor.moveToNext()) { while (tmpNotesCursor.moveToNext()) {
String categoryTitle = tmpNotesCursor.getString(8); String categoryTitle = tmpNotesCursor.getString(8);
int accountId = tmpNotesCursor.getInt(2); int accountId = tmpNotesCursor.getInt(2);
@ -59,7 +70,7 @@ public class Migration_14_15 {
values.put("CATEGORY_ID", categoryId); values.put("CATEGORY_ID", categoryId);
values.put("CATEGORY_ACCOUNT_ID", accountId); values.put("CATEGORY_ACCOUNT_ID", accountId);
values.put("CATEGORY_TITLE", categoryTitle); values.put("CATEGORY_TITLE", categoryTitle);
db.insert("CATEGORIES", null, values); db.insert("CATEGORIES", OnConflictStrategy.REPLACE, values);
categoryTitleIdMap.put(categoryTitle, categoryId); categoryTitleIdMap.put(categoryTitle, categoryId);
} }
// Move the data in tmp_NOTES to NOTES // Move the data in tmp_NOTES to NOTES
@ -75,7 +86,7 @@ public class Migration_14_15 {
values.put("CATEGORY", categoryId); values.put("CATEGORY", categoryId);
values.put("ETAG", tmpNotesCursor.getString(9)); values.put("ETAG", tmpNotesCursor.getString(9));
values.put("EXCERPT", tmpNotesCursor.getString(10)); values.put("EXCERPT", tmpNotesCursor.getString(10));
db.insert("NOTES", null, values); db.insert("NOTES", OnConflictStrategy.REPLACE, values);
} }
tmpNotesCursor.close(); tmpNotesCursor.close();
db.execSQL("DROP TABLE IF EXISTS " + tmpTableNotes); db.execSQL("DROP TABLE IF EXISTS " + tmpTableNotes);

View file

@ -4,25 +4,38 @@ import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.room.OnConflictStrategy;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import java.util.Map; import java.util.Map;
import it.niedermann.owncloud.notes.preferences.DarkModeSetting; import it.niedermann.owncloud.notes.preferences.DarkModeSetting;
public class Migration_15_16 { public class Migration_15_16 extends Migration {
private static final String TAG = Migration_15_16.class.getSimpleName(); private static final String TAG = Migration_15_16.class.getSimpleName();
@NonNull
private final Context context;
@NonNull
private final Runnable notifyWidgets;
public Migration_15_16(@NonNull Context context, @NonNull Runnable notifyWidgets) {
super(15, 16);
this.context = context;
this.notifyWidgets = notifyWidgets;
}
/** /**
* Moves note list widget preferences from {@link SharedPreferences} to database * Moves note list widget preferences from {@link SharedPreferences} to database
* https://github.com/stefan-niedermann/nextcloud-notes/issues/832 * https://github.com/stefan-niedermann/nextcloud-notes/issues/832
*/ */
public Migration_15_16(SQLiteDatabase db, @NonNull Context context, @NonNull Runnable notifyWidgets) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
db.execSQL("CREATE TABLE WIDGET_NOTE_LISTS ( " + db.execSQL("CREATE TABLE WIDGET_NOTE_LISTS ( " +
"ID INTEGER PRIMARY KEY, " + "ID INTEGER PRIMARY KEY, " +
"ACCOUNT_ID INTEGER, " + "ACCOUNT_ID INTEGER, " +
@ -62,14 +75,7 @@ public class Migration_15_16 {
if (mode == 2) { if (mode == 2) {
final String categoryTitle = sharedPreferences.getString(SP_CATEGORY_KEY + widgetId, null); final String categoryTitle = sharedPreferences.getString(SP_CATEGORY_KEY + widgetId, null);
Cursor cursor = db.query( Cursor cursor = db.query("SELECT CATEGORY_ID FROM CATEGORIES WHERE CATEGORY_TITLE = ? AND CATEGORY_ACCOUNT_ID = ?", new String[]{categoryTitle, String.valueOf(accountId)});
"CATEGORIES",
new String[]{"CATEGORY_ID"},
"CATEGORY_TITLE = ? AND CATEGORY_ACCOUNT_ID = ? ",
new String[]{categoryTitle, String.valueOf(accountId)},
null,
null,
null);
if (cursor.moveToNext()) { if (cursor.moveToNext()) {
categoryId = cursor.getInt(0); categoryId = cursor.getInt(0);
} else { } else {
@ -84,7 +90,7 @@ public class Migration_15_16 {
migratedWidgetValues.put("CATEGORY_ID", categoryId); migratedWidgetValues.put("CATEGORY_ID", categoryId);
migratedWidgetValues.put("MODE", mode); migratedWidgetValues.put("MODE", mode);
migratedWidgetValues.put("THEME_MODE", themeMode); migratedWidgetValues.put("THEME_MODE", themeMode);
db.insert("WIDGET_NOTE_LISTS", null, migratedWidgetValues); db.insert("WIDGET_NOTE_LISTS", OnConflictStrategy.REPLACE, migratedWidgetValues);
} catch (Throwable t) { } catch (Throwable t) {
Log.e(TAG, "Could not migrate widget {widgetId: " + widgetId + ", accountId: " + accountId + ", mode: " + mode + ", categoryId: " + categoryId + ", themeMode: " + themeMode + "}"); Log.e(TAG, "Could not migrate widget {widgetId: " + widgetId + ", accountId: " + accountId + ", mode: " + mode + ", categoryId: " + categoryId + ", themeMode: " + themeMode + "}");
t.printStackTrace(); t.printStackTrace();

View file

@ -1,15 +1,21 @@
package it.niedermann.owncloud.notes.persistence.migration; package it.niedermann.owncloud.notes.persistence.migration;
import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
public class Migration_16_17 extends Migration {
public Migration_16_17() {
super(16, 17);
}
public class Migration_16_17 {
/** /**
* Adds a column to store the current scroll position per note * Adds a column to store the current scroll position per note
* https://github.com/stefan-niedermann/nextcloud-notes/issues/227 * https://github.com/stefan-niedermann/nextcloud-notes/issues/227
*/ */
public Migration_16_17(@NonNull SQLiteDatabase db) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
db.execSQL("ALTER TABLE NOTES ADD COLUMN SCROLL_Y INTEGER DEFAULT 0"); db.execSQL("ALTER TABLE NOTES ADD COLUMN SCROLL_Y INTEGER DEFAULT 0");
} }
} }

View file

@ -3,12 +3,20 @@ package it.niedermann.owncloud.notes.persistence.migration;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
public class Migration_17_18 extends Migration {
public Migration_17_18() {
super(17, 18);
}
public class Migration_17_18 {
/** /**
* Add a new column to store the sorting method for a category note list * Add a new column to store the sorting method for a category note list
*/ */
public Migration_17_18(@NonNull SQLiteDatabase db) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
db.execSQL("ALTER TABLE CATEGORIES ADD COLUMN CATEGORY_SORTING_METHOD INTEGER DEFAULT 0"); db.execSQL("ALTER TABLE CATEGORIES ADD COLUMN CATEGORY_SORTING_METHOD INTEGER DEFAULT 0");
} }
} }

View file

@ -4,19 +4,29 @@ import android.content.Context;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
public class Migration_18_19 { public class Migration_18_19 extends Migration {
private static final String TAG = Migration_18_19.class.getSimpleName(); private static final String TAG = Migration_18_19.class.getSimpleName();
@NonNull
private final Context context;
public Migration_18_19(@NonNull Context context) {
super(18, 19);
this.context = context;
}
/** /**
* Clears the {@link Glide} disk cache to fix wrong avatars in a multi user setup * Clears the {@link Glide} disk cache to fix wrong avatars in a multi user setup
* https://github.com/stefan-niedermann/nextcloud-deck/issues/531 * https://github.com/stefan-niedermann/nextcloud-deck/issues/531
*
* @param context {@link Context}
*/ */
public Migration_18_19(@NonNull Context context) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
new Thread(() -> { new Thread(() -> {
Log.i(TAG, "Clearing Glide disk cache"); Log.i(TAG, "Clearing Glide disk cache");
Glide.get(context.getApplicationContext()).clearDiskCache(); Glide.get(context.getApplicationContext()).clearDiskCache();

View file

@ -0,0 +1,24 @@
package it.niedermann.owncloud.notes.persistence.migration;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.NonNull;
import androidx.room.RoomDatabase;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
public class Migration_19_20 extends Migration {
public Migration_19_20() {
super(19, 20);
}
/**
* From {@link SQLiteOpenHelper} to {@link RoomDatabase}
* https://github.com/stefan-niedermann/nextcloud-deck/issues/531
*/
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
// Nothing to do...?
}
}

View file

@ -1,14 +1,20 @@
package it.niedermann.owncloud.notes.persistence.migration; package it.niedermann.owncloud.notes.persistence.migration;
import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
public class Migration_4_5 extends Migration {
public Migration_4_5() {
super(4, 5);
}
public class Migration_4_5 {
/** /**
* Differentiate between local id and remote id * Differentiate between local id and remote id
*/ */
public Migration_4_5(@NonNull SQLiteDatabase db) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
db.execSQL("ALTER TABLE NOTES ADD COLUMN REMOTEID INTEGER"); db.execSQL("ALTER TABLE NOTES ADD COLUMN REMOTEID INTEGER");
db.execSQL("UPDATE NOTES SET REMOTEID=ID WHERE (REMOTEID IS NULL OR REMOTEID=0) AND STATUS!=?", new String[]{"LOCAL_CREATED"}); db.execSQL("UPDATE NOTES SET REMOTEID=ID WHERE (REMOTEID IS NULL OR REMOTEID=0) AND STATUS!=?", new String[]{"LOCAL_CREATED"});
db.execSQL("UPDATE NOTES SET REMOTEID=0, STATUS=? WHERE STATUS=?", new String[]{"LOCAL_EDITED", "LOCAL_CREATED"}); db.execSQL("UPDATE NOTES SET REMOTEID=0, STATUS=? WHERE STATUS=?", new String[]{"LOCAL_EDITED", "LOCAL_CREATED"});

View file

@ -3,12 +3,20 @@ package it.niedermann.owncloud.notes.persistence.migration;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
public class Migration_5_6 extends Migration {
public Migration_5_6() {
super(5, 6);
}
public class Migration_5_6 {
/** /**
* Adds a column to support marking notes as favorite * Adds a column to support marking notes as favorite
*/ */
public Migration_5_6(@NonNull SQLiteDatabase db) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
db.execSQL("ALTER TABLE NOTES ADD COLUMN FAVORITE INTEGER DEFAULT 0"); db.execSQL("ALTER TABLE NOTES ADD COLUMN FAVORITE INTEGER DEFAULT 0");
} }
} }

View file

@ -3,14 +3,22 @@ package it.niedermann.owncloud.notes.persistence.migration;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import it.niedermann.owncloud.notes.shared.util.DatabaseIndexUtil; import it.niedermann.owncloud.notes.shared.util.DatabaseIndexUtil;
public class Migration_6_7 { public class Migration_6_7 extends Migration {
public Migration_6_7() {
super(6, 7);
}
/** /**
* Adds columns for category support and ETags * Adds columns for category support and ETags
*/ */
public Migration_6_7(@NonNull SQLiteDatabase db) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
DatabaseIndexUtil.dropIndexes(db); DatabaseIndexUtil.dropIndexes(db);
db.execSQL("ALTER TABLE NOTES ADD COLUMN CATEGORY TEXT NOT NULL DEFAULT ''"); db.execSQL("ALTER TABLE NOTES ADD COLUMN CATEGORY TEXT NOT NULL DEFAULT ''");
db.execSQL("ALTER TABLE NOTES ADD COLUMN ETAG TEXT"); db.execSQL("ALTER TABLE NOTES ADD COLUMN ETAG TEXT");

View file

@ -3,11 +3,19 @@ package it.niedermann.owncloud.notes.persistence.migration;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import it.niedermann.owncloud.notes.shared.util.DatabaseIndexUtil; import it.niedermann.owncloud.notes.shared.util.DatabaseIndexUtil;
public class Migration_7_8 { public class Migration_7_8 extends Migration {
public Migration_7_8(@NonNull SQLiteDatabase db) {
public Migration_7_8() {
super(7, 8);
}
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
final String table_temp = "NOTES_TEMP"; final String table_temp = "NOTES_TEMP";
db.execSQL("CREATE TABLE " + table_temp + " ( " + db.execSQL("CREATE TABLE " + table_temp + " ( " +
"ID INTEGER PRIMARY KEY AUTOINCREMENT, " + "ID INTEGER PRIMARY KEY AUTOINCREMENT, " +

View file

@ -11,6 +11,9 @@ import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.util.Consumer; import androidx.core.util.Consumer;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.room.OnConflictStrategy;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
@ -19,14 +22,26 @@ import it.niedermann.owncloud.notes.shared.util.DatabaseIndexUtil;
import it.niedermann.owncloud.notes.widget.notelist.NoteListWidget; import it.niedermann.owncloud.notes.widget.notelist.NoteListWidget;
import it.niedermann.owncloud.notes.widget.singlenote.SingleNoteWidget; import it.niedermann.owncloud.notes.widget.singlenote.SingleNoteWidget;
public class Migration_8_9 { public class Migration_8_9 extends Migration {
private static final String TAG = Migration_8_9.class.getSimpleName(); private static final String TAG = Migration_8_9.class.getSimpleName();
private final Context context;
private final Consumer<SupportSQLiteDatabase> recreateDatabase;
private final Runnable notifyWidgets;
/** /**
* Adds an account table for multi account usage in combination with SingleSignOn * Adds an account table for multi account usage in combination with SingleSignOn
*/ */
public Migration_8_9(@NonNull SQLiteDatabase db, @NonNull Context context, @NonNull Consumer<SQLiteDatabase> recreateDatabase, @NonNull Runnable notifyWidgets) { public Migration_8_9(@NonNull Context context, @NonNull Consumer<SupportSQLiteDatabase> recreateDatabase, @NonNull Runnable notifyWidgets) {
super(8, 9);
this.context = context;
this.recreateDatabase = recreateDatabase;
this.notifyWidgets = notifyWidgets;
}
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
// Create accounts table // Create accounts table
db.execSQL("CREATE TABLE ACCOUNTS ( " + db.execSQL("CREATE TABLE ACCOUNTS ( " +
"ID INTEGER PRIMARY KEY AUTOINCREMENT, " + "ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
@ -54,12 +69,12 @@ public class Migration_8_9 {
migratedAccountValues.put("URL", url); migratedAccountValues.put("URL", url);
migratedAccountValues.put("USERNAME", username); migratedAccountValues.put("USERNAME", username);
migratedAccountValues.put("ACCOUNT_NAME", accountName); migratedAccountValues.put("ACCOUNT_NAME", accountName);
db.insert("ACCOUNTS", null, migratedAccountValues); db.insert("ACCOUNTS", OnConflictStrategy.REPLACE, migratedAccountValues);
// After successful insertion of migrated account, set accountId to 1 in each note // After successful insertion of migrated account, set accountId to 1 in each note
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put("ACCOUNT_ID", 1); values.put("ACCOUNT_ID", 1);
db.update("NOTES", values, "ACCOUNT_ID = ?", new String[]{"NULL"}); db.update("NOTES", OnConflictStrategy.REPLACE, values, "ACCOUNT_ID = ?", new String[]{"NULL"});
// Add FOREIGN_KEY constraint // Add FOREIGN_KEY constraint
final String table_temp = "NOTES_TEMP"; final String table_temp = "NOTES_TEMP";

View file

@ -5,21 +5,30 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.room.OnConflictStrategy;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import it.niedermann.owncloud.notes.shared.util.NoteUtil; import it.niedermann.owncloud.notes.shared.util.NoteUtil;
public class Migration_9_10 { public class Migration_9_10 extends Migration {
public Migration_9_10() {
super(9, 10);
}
/** /**
* Adds a column to store excerpt instead of regenerating it each time * Adds a column to store excerpt instead of regenerating it each time
* https://github.com/stefan-niedermann/nextcloud-notes/issues/528 * https://github.com/stefan-niedermann/nextcloud-notes/issues/528
*/ */
public Migration_9_10(@NonNull SQLiteDatabase db) { @Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
db.execSQL("ALTER TABLE NOTES ADD COLUMN EXCERPT INTEGER NOT NULL DEFAULT ''"); db.execSQL("ALTER TABLE NOTES ADD COLUMN EXCERPT INTEGER NOT NULL DEFAULT ''");
Cursor cursor = db.query("NOTES", new String[]{"ID", "CONTENT", "TITLE"}, null, null, null, null, null, null); Cursor cursor = db.query("NOTES", new String[]{"ID", "CONTENT", "TITLE"});
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put("EXCERPT", NoteUtil.generateNoteExcerpt(cursor.getString(1), cursor.getString(2))); values.put("EXCERPT", NoteUtil.generateNoteExcerpt(cursor.getString(1), cursor.getString(2)));
db.update("NOTES", values, "ID" + " = ? ", new String[]{cursor.getString(0)}); db.update("NOTES", OnConflictStrategy.REPLACE, values, "ID" + " = ? ", new String[]{cursor.getString(0)});
} }
cursor.close(); cursor.close();
} }

View file

@ -5,6 +5,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.sqlite.db.SupportSQLiteDatabase;
public class DatabaseIndexUtil { public class DatabaseIndexUtil {
@ -14,20 +15,20 @@ public class DatabaseIndexUtil {
} }
public static void createIndex(@NonNull SQLiteDatabase db, @NonNull String table, @NonNull String... columns) { public static void createIndex(@NonNull SupportSQLiteDatabase db, @NonNull String table, @NonNull String... columns) {
for (String column : columns) { for (String column : columns) {
createIndex(db, table, column); createIndex(db, table, column);
} }
} }
public static void createIndex(@NonNull SQLiteDatabase db, @NonNull String table, @NonNull String column) { public static void createIndex(@NonNull SupportSQLiteDatabase db, @NonNull String table, @NonNull String column) {
String indexName = table + "_" + column + "_idx"; String indexName = table + "_" + column + "_idx";
Log.v(TAG, "Creating database index: CREATE INDEX IF NOT EXISTS " + indexName + " ON " + table + "(" + column + ")"); Log.v(TAG, "Creating database index: CREATE INDEX IF NOT EXISTS " + indexName + " ON " + table + "(" + column + ")");
db.execSQL("CREATE INDEX IF NOT EXISTS " + indexName + " ON " + table + "(" + column + ")"); db.execSQL("CREATE INDEX IF NOT EXISTS " + indexName + " ON " + table + "(" + column + ")");
} }
public static void dropIndexes(@NonNull SQLiteDatabase db) { public static void dropIndexes(@NonNull SupportSQLiteDatabase db) {
try (Cursor c = db.query("sqlite_master", new String[]{"name", "sql"}, "type=?", new String[]{"index"}, null, null, null)) { try (Cursor c = db.query("SELECT name, sql FROM sqlite_master WHERE type = 'index'")) {
while (c.moveToNext()) { while (c.moveToNext()) {
// Skip automatic indexes which we can't drop manually // Skip automatic indexes which we can't drop manually
if (c.getString(1) != null) { if (c.getString(1) != null) {