Android Roomの自動マイグレーション

AndroidにRoomというSQLiteのライブラリがありますが、マイグレーションに関してはサポートが薄く単純な変更ですらコストがかかっていると思います。

という状況だったのですが、 2.4.0-alpha01 にて一部の変更の自動マイグレーションがサポートされたようです 🎉🎉

medium.com

全自動でマイグレーションされる場合

明文化はされていないようですが、以下の場合は全自動でマイグレーションされるようです。

  • テーブルの追加
  • カラムの追加

スキーマをエクスポートするように設定した後、以下のように Database アノテーションに変更バージョン情報を持った AutoMigration を指定してあげるだけです。

@Database(
        entities = [Todo::class],
        version = 2,
        autoMigrations = [
            AutoMigration(from = 1, to = 2)
        ]
)
abstract class AppDatabase : RoomDatabase() {
    abstract fun todoDao(): TodoDao
}

サポートが必要な場合

Roomのコードを少し読んでみると、SchemaDiffer クラススキーマのdiffを取り、AutoMigrationProcessor クラス ではその追加されたテーブル/カラム情報は利用していますが削除された情報は利用していません。
これはテーブル/カラムが削除されていた場合、それが単なる削除なのかリネームなのかが判定できないからです。

ということで、以下の変更は AutoMigrationSpec を実装してどう変わったかをRoomに教えてあげる必要があります。

  • テーブル名の変更 (@RenameTable(fromName, toName) )
  • テーブルの削除 ( @DeleteTable(name) )
  • カラム名の変更 ( @RenameColumn(tableName, fromColName, toColName) )
  • カラムの削除 ( @DeleteColumn(tableName, colName) )

gist.github.com

上記変更が必要な場合は、生SQLを書いてねというわけではなくしっかりサポートがあるあたり優しいですね。

また、試してみたところspecの指定が不足していた場合コンパイル時に何が必要か優しく教えてくれます。

error: 
public abstract class AppDatabase extends androidx.room.RoomDatabase {
                ^
              AutoMigration Failure: Please declare an interface extending 'AutoMigrationSpec',
              and annotate with the @RenameColumn or @RemoveColumn annotation to specify the
              change to be performed:
              1) RENAME:
                  @RenameColumn(
                          tableName = "Todo",
                          originalColumnName = "isDone",
                          newColumnName = <NEW_COLUMN_NAME>
                  )
              2) DELETE:
                  @DeleteColumn=(
                          tableName = "Todo",
                          deletedColumnName = "isDone"
                  )

複数変更がある場合は以下のように指定してあげれば良いです。

@DeleteColumn(
        tableName = "Todo",
        columnName = "isDone"
)
@RenameColumn(
        tableName = "Todo",
        fromColumnName = "text",
        toColumnName = "content"
)
class V3AutoMigrationSpec : AutoMigrationSpec

SQLが必要な場合

それ以外の複雑なテーブルの変更は生SQLマイグレーションを書いてあげる必要があります。 例えば以下のような場合です。

  • テーブルを分割/統合する
  • テーブルの正規化/非正規化
  • Viewに対する変更

Viewは試してみた限り、今回のサポートには入っていないようです。(多分)

SQLが必要な場合でも、AutoMigration機能と併用することができます。

まとめ

まだ現時点ではalpha版なのでそこは注意ですが、かなりマイグレーションの負担が減るのではないでしょうか。
個人的にはかなり嬉しいアップデートでした。