From 214b5fd97869d8d144e9d4bf00387a2ce25f35a4 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Thu, 20 Jun 2019 13:08:34 +0200 Subject: [PATCH] Improve documentation on migrations, add custom statement --- docs/docs/migrations.md | 49 +++++++++++++++++++++++++++--- moor/lib/src/runtime/database.dart | 5 +++ moor/test/schema_test.dart | 9 +++++- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/docs/docs/migrations.md b/docs/docs/migrations.md index 9ad22cbf..4418725b 100644 --- a/docs/docs/migrations.md +++ b/docs/docs/migrations.md @@ -14,7 +14,7 @@ class Todos extends Table { TextColumn get title => text().withLength(min: 6, max: 10)(); TextColumn get content => text().named('body')(); IntColumn get category => integer().nullable()(); - DateTimeColumn get dueDate => dateTime().nullable()(); // we just added this column + DateTimeColumn get dueDate => dateTime().nullable()(); // new, added column } ``` We can now change the `database` class like this: @@ -37,7 +37,46 @@ 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. You can't use the high-level query API in -migrations. If you need to use it, please specify the `onFinished` method on the -`MigrationStrategy`. It will be called after a migration happened and it's safe to call methods -on your database from inside that method. \ No newline at end of file +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 +methods will throw. + +`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 [`issueCustomQuery`](https://pub.dev/documentation/moor/latest/moor/Migrator/issueCustomQuery.html) +to run the statements. + +## Post-migration callbacks +Starting from moor 1.5, you can use the `beforeOpen` parameter in the `MigrationStrategy` which will be called after +migrations, but after any other queries are run. You could use it to populate data after the database has been created: +```dart +beforeOpen: (db, details) async { + if (details.wasCreated) { + final workId = await db.into(categories).insert(Category(description: 'Work')); + + await db.into(todos).insert(TodoEntry( + content: 'A first todo entry', + category: null, + targetDate: DateTime.now(), + )); + + await db.into(todos).insert( + TodoEntry( + content: 'Rework persistence code', + category: workId, + targetDate: DateTime.now().add(const Duration(days: 4)), + )); + } +}, +``` +You could also activate pragma statements that you need: +```dart +beforeOpen: (db, details) async { + if (details.wasCreated) { + // ... + } + await db.customStatement('PRAGMA foreign_keys = ON'); +} +``` +It is important that you run these queries on `db` explicitly. Failing to do so causes a deadlock which prevents the +database from being opened. \ No newline at end of file diff --git a/moor/lib/src/runtime/database.dart b/moor/lib/src/runtime/database.dart index a48bff31..25be3514 100644 --- a/moor/lib/src/runtime/database.dart +++ b/moor/lib/src/runtime/database.dart @@ -158,6 +158,11 @@ mixin QueryEngine on DatabaseConnectionUser { return statement.watch(); } + /// Executes the custom sql [statement] on the database. + Future customStatement(String statement) { + return executor.runCustom(statement); + } + /// Executes [action] in a transaction, which means that all its queries and /// updates will be called atomically. /// diff --git a/moor/test/schema_test.dart b/moor/test/schema_test.dart index a344d4d4..936f622a 100644 --- a/moor/test/schema_test.dart +++ b/moor/test/schema_test.dart @@ -7,10 +7,12 @@ import 'data/utils/mocks.dart'; void main() { TodoDb db; MockQueryExecutor mockQueryExecutor; + QueryExecutor mockExecutor; setUp(() { mockQueryExecutor = MockQueryExecutor(); - db = TodoDb(null); + mockExecutor = MockExecutor(); + db = TodoDb(mockExecutor); }); group('Migrations', () { @@ -73,4 +75,9 @@ void main() { 'is_awesome BOOLEAN NOT NULL DEFAULT 1 CHECK (is_awesome in (0, 1));')); }); }); + + test('custom statements', () async { + await db.customStatement('some custom statement'); + verify(mockExecutor.runCustom('some custom statement')); + }); }