Expose `runMigrationSteps`, add docs

This commit is contained in:
Simon Binder 2023-08-27 15:31:04 +02:00
parent 18b11d7bb5
commit 3403161178
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
6 changed files with 106 additions and 2 deletions

View File

@ -16,5 +16,6 @@ dart run build_runner serve web:8080 --live-reload
To build the website into a directory `out`, use:
```
dart run drift_dev schema steps lib/snippets/migrations/exported_eschema/ lib/database/schema_versions.dart
dart run build_runner build --release --output web:out
```

View File

@ -1,7 +1,7 @@
import 'package:drift/drift.dart';
// #docregion stepbystep
// This file was generated by `drift_dev schema steps drift_schemas lib/database/schema_versions.dart
// This file was generated by `drift_dev schema steps drift_schemas lib/database/schema_versions.dart`
import 'schema_versions.dart';
// #enddocregion stepbystep
@ -121,3 +121,47 @@ class StepByStep {
}
// #enddocregion stepbystep
}
extension StepByStep2 on GeneratedDatabase {
MigrationStrategy get migration {
return MigrationStrategy(
onCreate: (Migrator m) async {
await m.createAll();
},
// #docregion stepbystep2
onUpgrade: (m, from, to) async {
// Run migration steps without foreign keys and re-enable them later
// (https://drift.simonbinder.eu/docs/advanced-features/migrations/#tips)
await customStatement('PRAGMA foreign_keys = OFF');
await m.runMigrationSteps(
from: from,
to: to,
steps: migrationSteps(
from1To2: (m, schema) async {
// we added the dueDate property in the change from version 1 to
// version 2
await m.addColumn(schema.todos, schema.todos.dueDate);
},
from2To3: (m, schema) async {
// we added the priority property in the change from version 1 or 2
// to version 3
await m.addColumn(schema.todos, schema.todos.priority);
},
),
);
if (kDebugMode) {
// Fail if the migration broke foreign keys
final wrongForeignKeys =
await customSelect('PRAGMA foreign_key_check').get();
assert(wrongForeignKeys.isEmpty,
'${wrongForeignKeys.map((e) => e.data)}');
}
await customStatement('PRAGMA foreign_keys = ON;');
},
// #enddocregion stepbystep2
);
}
}

View File

@ -180,6 +180,22 @@ For instance, in the `from1To2` function, `schema` provides getters for the data
The migrator passed to the function is also set up to consider that specific version by default.
A call to `m.recreateAllViews()` would re-create views at the expected state of schema version 2, for instance.
#### Customizing step-by-step migrations
The `stepByStep` function generated by the `drift_dev schema steps` command gives you an
`OnUpgrade` callback.
But you might want to customize the upgrade behavior, for instance by adding foreign key
checks afterwards (as described in [tips](#tips)).
The `Migrator.runMigrationSteps` helper method can be used for that, as this example
shows:
{% include "blocks/snippet" snippets = snippets name = 'stepbystep2' %}
Here, foreign keys are disabled before runnign the migration and re-enabled afterwards.
A check ensuring no inconsistencies occurred helps catching issues with the migration
in debug modes.
### Writing tests
After you've exported the database schemas into a folder, you can generate old versions of your database class

View File

@ -2,6 +2,7 @@
- Allow using `.read()` for a column added to a join from the table, fixing a
regression in drift 2.11.0.
- Make step-by-step migrations easier to customize with `Migrator.runMigrationSteps`.
## 2.11.0

View File

@ -91,7 +91,6 @@ abstract base class VersionedSchema {
/// await customStatement('PRAGMA foreign_keys = ON;');
/// },
/// ```
static Future<void> runMigrationSteps({
required Migrator migrator,
required int from,

View File

@ -514,6 +514,49 @@ class Migrator {
}) {
return VersionedSchema.stepByStepHelper(step: step);
}
/// Allows customizing step-by-step migrations (like the `OnUpgrade` callback
/// returned by the generated `stepByStep` function) by invoking the [steps]
/// function for each intermediate schema version from [from] until [to] is
/// reached.
///
/// This can be used to implement a custom `OnUpgrade` callback that runs
/// additional checks before and after the migrations:
///
/// ```dart
/// onUpgrade: (m, from, to) async {
/// await customStatement('PRAGMA foreign_keys = OFF');
///
/// await transaction(
/// () => m.runMigrationSteps(
/// from: from,
/// to: to,
/// steps: migrationSteps(
/// from1To2: ...,
/// ...
/// ),
/// ),
/// );
///
/// if (kDebugMode) {
/// final wrongForeignKeys = await customSelect('PRAGMA foreign_key_check').get();
/// assert(wrongForeignKeys.isEmpty, '${wrongForeignKeys.map((e) => e.data)}');
/// }
///
/// await customStatement('PRAGMA foreign_keys = ON;');
/// },
/// ```
///
/// Here, the `migrationSteps` method is generated by drift with the
/// `drift_dev schema steps` command. For details, see the [documentation](https://drift.simonbinder.eu/docs/advanced-features/migrations/#step-by-step).
Future<void> runMigrationSteps({
required int from,
required int to,
required MigrationStepWithVersion steps,
}) {
return VersionedSchema.runMigrationSteps(
migrator: this, from: from, to: to, steps: steps);
}
}
/// Provides information about whether migrations ran before opening the