Suggest using transactions in migrations

This commit is contained in:
Simon Binder 2022-02-09 16:24:07 +01:00
parent 661227c4c3
commit 51f61a884f
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
1 changed files with 50 additions and 2 deletions

View File

@ -8,9 +8,21 @@ aliases:
template: layouts/docs/single
---
As your app grows, you may want to change the table structure for your drift database:
New features need new columns or tables, and outdated columns may have to be altered or
removed altogether.
When making changes to your database schema, you need to write migrations enabling users with
an old version of your app to convert to the database expected by the latest version.
Drift provides a set of APIs to make writing migrations easy.
## Basics
Drift provides a migration API that can be used to gradually apply schema changes after bumping
the `schemaVersion` getter inside the `Database` class. To use it, override the `migration`
getter. Here's an example: Let's say you wanted to add a due date to your todo entries:
getter.
Here's an example: Let's say you wanted to add a due date to your todo entries (`v2` of the schema).
Later, you decide to also add a priority column (`v3` of the schema).
```dart
class Todos extends Table {
@ -60,6 +72,42 @@ you've actually added the column. In general, try to avoid running queries in mi
`sqlite` can feel a bit limiting when it comes to migrations - there only are methods to create tables and columns.
Existing columns can't be altered or removed. A workaround is described [here](https://stackoverflow.com/a/805508), it
can be used together with `customStatement` to run the statements.
Alternatively, [complex migrations](#complex-migrations) help automating this.
### Tips
To ensure your schema stays consistent during a migration, you can wrap it in a `transaction` block.
However, be aware that some pragmas (including `foreign_keys`) can't be changed inside transactions.
Still, it can be useful to:
- always re-enable foreign keys before using the database, by enabling them in [`beforeOpen`](#post-migration-callbacks).
- disable foreign-keys before migrations
- run migrations inside a transaction
- make sure your migrations didn't introduce any inconsistencies with `PRAGMA foreign_key_check`.
With all of this combined, a migration callback can look like this:
```dart
MigrationStrategy(
onUpgrade: (m, from, to) async {
await customStatement('PRAGMA foreign_keys = OFF'); // disable foreign_keys before migrations
await transaction(() async {
// put your migration logic here
});
// Assert that the schema is valid after migrations
if (kDebugMode) {
final wrongForeignKeys = await customSelect('PRAGMA foreign_key_check').get();
assert(wrongForeignKeys.isEmpty, "${wrongForeignKeys.map((e) => e.data)}");
}
},
beforeOpen: (details) async {
await customStatement('PRAGMA foreign_keys = ON');
// ...
},
)
```
## Complex migrations