Sqldelight: Configurable Wipe Data action for Common Exceptions (like OnDowngrade)

Created on 7 Oct 2020  路  3Comments  路  Source: cashapp/sqldelight

On Android, when an app rolls back or manually loads an older version of the app with an older database version, this error occurs:

Fatal Exception: android.database.sqlite.SQLiteException: Can't downgrade database from version 5 to 4
       at androidx.sqlite.db.SupportSQLiteOpenHelper$Callback.onDowngrade(SupportSQLiteOpenHelper.java:201)
       at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onDowngrade(FrameworkSQLiteOpenHelper.java:144)
       at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:255)
       at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
       at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:96)
       at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:54)
       at com.squareup.sqldelight.android.AndroidSqliteDriver$database$2.invoke(AndroidSqliteDriver.java:30)
       at com.squareup.sqldelight.android.AndroidSqliteDriver$database$2.invoke(AndroidSqliteDriver.java:19)

This crashes the app and opens the screen to the app settings screen, and the user is unable to use the app until the user wipes app data via the settings screen. If I want to avoid that scenario, I have to write my own data integrity function that runs before any database operations and wipes the data if necessary.

If there is an easier way to do this I'd love to know. I'm not even sure if that's something I can do via SqlDelight right now.

It would be useful to have a "wipe data upon OnDowngrade" configuration setting, or any other easy way to set up default actions for certain exceptions.

feature

Most helpful comment

That link gave me a better answer.

I feel dumb for not seeing this before, but when instantiating your Database, you pass AndroidSqliteDriver into the constructor. AndroidSqliteDriver takes a callback which handles OnDowngrade, among other things. I'll attempt a solution via that method.

If it works and I'm sure I understand the process, I'll put in a PR for documentation update. I guess it'll go under migration 馃

All 3 comments

I considered asking for such a feature myself.
I only need that for development so I would enable that only in debug.

Scenario (Android app):

  1. I work on a new feature which modifies database - has a migration.
  2. Somebody asks me to review code which doesn't modify database.
  3. I want to see how new feature actually looks/works/feels and I run it on my device.
  4. Crash due to downgrade.
  5. I run adb shell pm clear packagename as it is faster than clicking through settings.

Currently we use database mostly for a network cache so clearing database if there are any incompatibilities of schema with sqlite file works fine for us.

I once asked for a destructive migration(mainly for development purpose), and the recommendation at that time was in-memory db.

https://github.com/cashapp/sqldelight/issues/1213

That link gave me a better answer.

I feel dumb for not seeing this before, but when instantiating your Database, you pass AndroidSqliteDriver into the constructor. AndroidSqliteDriver takes a callback which handles OnDowngrade, among other things. I'll attempt a solution via that method.

If it works and I'm sure I understand the process, I'll put in a PR for documentation update. I guess it'll go under migration 馃

Was this page helpful?
0 / 5 - 0 ratings