diff --git a/docs/content/en/docs/Advanced Features/migrations.md b/docs/content/en/docs/Advanced Features/migrations.md index 70fda207..2f891632 100644 --- a/docs/content/en/docs/Advanced Features/migrations.md +++ b/docs/content/en/docs/Advanced Features/migrations.md @@ -3,12 +3,13 @@ title: "Migrations" weight: 10 description: Define what happens when your database gets created or updated aliases: - - /migrations + - /migrations --- Moor 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: + ```dart class Todos extends Table { IntColumn get id => integer().autoIncrement()(); @@ -18,7 +19,9 @@ class Todos extends Table { DateTimeColumn get dueDate => dateTime().nullable()(); // new, added column } ``` + We can now change the `database` class like this: + ```dart @override int get schemaVersion => 2; // bump because the tables have changed @@ -38,8 +41,9 @@ We can now change the `database` class like this: // rest of class can stay the same ``` + You can also add individual tables or drop them - see the reference of [Migrator](https://pub.dev/documentation/moor/latest/moor/Migrator-class.html) -for all the available options. You can't use the high-level query API in migrations - calling `select` or similar +for all the available options. You can't use the high-level query API in migrations - calling `select` or similar methods will throw. `sqlite` can feel a bit limiting when it comes to migrations - there only are methods to create tables and columns. @@ -70,7 +74,7 @@ columnTransformer: { Internally, moor will use a `INSERT INTO SELECT` statement to copy old data. In this case, it would look like `INSERT INTO temporary_todos_copy SELECT id, title, content, CAST(category AS INT) FROM todos`. As you can see, moor will use the expression from the `columnTransformer` map and fall back to just copying the column -otherwise. +otherwise. If you're introducing new columns in a table migration, be sure to include them in the `newColumns` parameter of `TableMigration`. Moor will ensure that those columns have a default value or a transformation in `columnTransformer`. Of course, moor won't attempt to copy `newColumns` from the old table either. @@ -149,7 +153,7 @@ use an old column with a different name: ```dart await m.alterTable( TableMigration( - yourTable, + yourTable, columnTransformer: { yourTable.newColumn: const CustomExpression('old_column_name') }, @@ -168,13 +172,13 @@ check whether migrations were necessary: beforeOpen: (details) async { if (details.wasCreated) { final workId = await into(categories).insert(Category(description: 'Work')); - + await into(todos).insert(TodoEntry( content: 'A first todo entry', category: null, targetDate: DateTime.now(), )); - + await into(todos).insert( TodoEntry( content: 'Rework persistence code', @@ -184,7 +188,9 @@ beforeOpen: (details) async { } }, ``` + You could also activate pragma statements that you need: + ```dart beforeOpen: (details) async { if (details.wasCreated) { @@ -206,7 +212,7 @@ on how that can be achieved. ## Verifying migrations -Since version 3.4, moor contains __experimental__ support to verify the integrity of your migrations. +Since version 3.4, moor contains **experimental** support to verify the integrity of your migrations. To support this feature, moor can help you generate @@ -220,7 +226,7 @@ By using those test databases, moor can help you test migrations from and to any To use this feature, moor needs to know all schemas of your database. A schema is the set of all tables, triggers and indices that you use in your database. -You can use the [CLI tools]({{< relref "../CLI.md" >}}) to export a json representation of your schema. +You can use the [CLI tools]({{< relref "../CLI.md" >}}) to export a json representation of your schema. In this guide, we'll assume a file layout like the following, where `my_app` is the root folder of your project: ``` @@ -241,8 +247,8 @@ my_app pubspec.yaml ``` -The generated migrations implementation and the schema jsons will be generated by moor. -To start writing schemas, create an empty folder named `moor_schemas` in your project. +The generated migrations implementation and the schema jsons will be generated by moor. +To start writing schemas, create an empty folder named `moor_schemas` in your project. Of course, you can also choose a different name or use a nested subfolder if you want to. #### Exporting the schema @@ -278,7 +284,7 @@ You can put this test code whereever you want, but it makes sense to put it in a If we wanted to write them to `test/generated_migrations/`, we could use ``` -$ dart pub run moor_generator schema generate moor_migrations/ test/generated/ +$ dart pub run moor_generator schema generate moor_schemas/ test/generated_migrations/ ``` ### Writing tests @@ -292,7 +298,7 @@ import 'package:test/test.dart'; import 'package:moor_generator/api/migrations.dart'; // The generated directory from before. -import 'generated/schema.dart'; +import 'generated_migrations/schema.dart'; void main() { SchemaVerifier verifier; @@ -326,7 +332,7 @@ In general, a test looks like this: - Call `verifier.migrateAndValidate(db, version)`. This will initiate a migration towards the target version (here, `2`). Unlike the database created by `startAt`, this uses the migration logic you wrote for your database. -`migrateAndValidate` will extract all `CREATE` statement from the `sqlite_schema` table and semantically compare them. +`migrateAndValidate` will extract all `CREATE` statement from the `sqlite_schema` table and semantically compare them. If it sees anything unexpected, it will throw a `SchemaMismatch` exception to fail your test. {{% alert title="Writing testable migrations" %}}