From e624d4dccab5da12f7b6fe9b0a855eab71364ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A3=E6=B8=A3=E8=BE=89?= <1@fxcdev.com> Date: Sat, 1 Jan 2022 19:22:27 +0800 Subject: [PATCH 01/15] Add check for existence when creating View --- drift/lib/src/runtime/query_builder/migration.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drift/lib/src/runtime/query_builder/migration.dart b/drift/lib/src/runtime/query_builder/migration.dart index 16d32c883..ef5b69404 100644 --- a/drift/lib/src/runtime/query_builder/migration.dart +++ b/drift/lib/src/runtime/query_builder/migration.dart @@ -326,7 +326,7 @@ class Migrator { } else if (view.query != null) { final context = GenerationContext.fromDb(_db); context.generatingForView = view.entityName; - context.buffer.write('CREATE VIEW ${view.entityName} AS '); + context.buffer.write('CREATE VIEW IF NOT EXISTS ${view.entityName} AS '); view.query!.writeInto(context); await _issueCustomQuery(context.sql, const []); } From 38fa91fa177fe83e04f27de15d6ba374562ff227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A3=E6=B8=A3=E8=BE=89?= <1@fxcdev.com> Date: Sat, 1 Jan 2022 19:42:10 +0800 Subject: [PATCH 02/15] Fix view schema test --- drift/test/schema_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drift/test/schema_test.dart b/drift/test/schema_test.dart index cee45c10d..19aa6b46e 100644 --- a/drift/test/schema_test.dart +++ b/drift/test/schema_test.dart @@ -66,7 +66,7 @@ void main() { [])); verify(mockExecutor.runCustom( - 'CREATE VIEW category_todo_count_view AS SELECT ' + 'CREATE VIEW IF NOT EXISTS category_todo_count_view AS SELECT ' 'categories."desc" AS "categories.desc", ' 'COUNT(todos.id) AS "item_count" ' 'FROM categories ' @@ -75,7 +75,7 @@ void main() { [])); verify(mockExecutor.runCustom( - 'CREATE VIEW todo_with_category_view AS SELECT ' + 'CREATE VIEW IF NOT EXISTS todo_with_category_view AS SELECT ' 'todos.title AS "todos.title", ' 'categories."desc" AS "categories.desc" ' 'FROM todos ' From 6efe6de3bacd4a81a45a7b64691c1a72be7b170b Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Sun, 2 Jan 2022 19:13:03 +0100 Subject: [PATCH 03/15] Add from(table) API to simplify common queries --- drift/CHANGELOG.md | 5 + .../lib/src/runtime/api/connection_user.dart | 133 ++++++++++++++++++ drift/test/delete_test.dart | 22 +++ drift/test/insert_test.dart | 52 +++++++ drift/test/select_test.dart | 13 ++ drift/test/update_test.dart | 20 +++ 6 files changed, 245 insertions(+) diff --git a/drift/CHANGELOG.md b/drift/CHANGELOG.md index 69d31df91..f3a560261 100644 --- a/drift/CHANGELOG.md +++ b/drift/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.3.0 + +- Add the `from(table)` method to generated databases. It can be used to write + common queries more concisely. + ## 1.2.0 - Properly support stream update queries on views. diff --git a/drift/lib/src/runtime/api/connection_user.dart b/drift/lib/src/runtime/api/connection_user.dart index d0f81b120..d2fa4dfc7 100644 --- a/drift/lib/src/runtime/api/connection_user.dart +++ b/drift/lib/src/runtime/api/connection_user.dart @@ -154,6 +154,17 @@ abstract class DatabaseConnectionUser { return executor.ensureOpen(attachedDatabase).then((_) => fn(executor)); } + /// Captures a [table] or view for easier subsequent operations. + /// + /// The [TableOrViewOperations] class (or the [TableOperations] extension + /// for tables) provides convenience methods that make common operations + /// easier to write than using the methods from this class directly. + @experimental + TableOrViewOperations from( + ResultSetImplementation table) { + return TableOrViewOperations._(this, table); + } + /// Starts an [InsertStatement] for a given table. You can use that statement /// to write data into the [table] by using [InsertStatement.insert]. InsertStatement into(TableInfo table) { @@ -539,3 +550,125 @@ abstract class DatabaseConnectionUser { return buffer.toString(); } } + +/// A capture of a table and a generated database. +/// +/// Table operations can be captured with [DatabaseConnectionUser.from], which +/// may make some common operations easier to write: +/// +/// - Use `from(table).select()` or `from(table).selectOnly()` instead of +/// `select(table)` or `selectOnly(table)`, respectively. +/// - Use `from(table).insert()` instead of `insert(table)`. You can also use +/// `from(table).insertOne`, or [TableOperations.insertOnConflictUpdate] to +/// insert rows directly. +/// - Use `from(table).update()` instead of `update(table)`. You can also use +/// `from(table).replace()` to replace an existing row. +/// - Use `from(table).delete()`, `from(table).deleteOne()` or +/// `from(table).deleteWhere` to delete rows easily. +@sealed +class TableOrViewOperations { + final DatabaseConnectionUser _user; + final ResultSetImplementation _sourceSet; + + TableOrViewOperations._(this._user, this._sourceSet); + + /// Composes a `SELECT` statement on the captured table or view. + /// + /// This is equivalent to calling [DatabaseConnectionUser.select]. + SimpleSelectStatement select({bool distinct = false}) { + return _user.select(_sourceSet, distinct: distinct); + } + + /// Composes a `SELECT` statement only selecting a subset of columns. + /// + /// This is equivalent to calling [DatabaseConnectionUser.selectOnly]. + JoinedSelectStatement selectOnly( + {bool distinct = false, bool includeJoinedTableColumns = true}) { + return _user.selectOnly(_sourceSet, + distinct: distinct, + includeJoinedTableColumns: includeJoinedTableColumns); + } +} + +/// Additional methods for a [TableOrViewOperations] that are only available on +/// tables. +extension TableOperations + on TableOrViewOperations { + TableInfo get _table => _sourceSet as TableInfo; + + /// Creates an insert statment to be used to compose an insert on the captured + /// table. + /// + /// This is equivalent to calling [DatabaseConnectionUser.into] on the + /// captured table. See that method for more information. + InsertStatement insert() => _user.into(_table); + + /// Inserts one row into the captured table. + /// + /// This is equivalent to calling [InsertStatement.insert] - see that method + /// for more information. + Future insertOne( + Insertable row, { + InsertMode? mode, + UpsertClause? onConflict, + }) { + return insert().insert(row, mode: mode, onConflict: onConflict); + } + + /// Inserts one row into the captured table, replacing an existing row if it + /// exists already. + /// + /// Please note that this method is only available on recent sqlite3 versions. + /// See also [InsertStatement.insertOnConflictUpdate]. + Future insertOnConflictUpdate(Insertable row) { + return insert().insertOnConflictUpdate(row); + } + + /// Inserts one row into the captured table and returns it, along with auto- + /// generated fields. + /// + /// Please note that this method is only available on recent sqlite3 versions. + /// See also [InsertStatement.insertReturning]. + Future insertReturning( + Insertable row, { + InsertMode? mode, + UpsertClause? onConflict, + }) { + return insert().insertReturning( + row, + mode: mode, + onConflict: onConflict, + ); + } + + /// Creates a statement to compose an `UPDATE` into the database. + /// + /// This is equivalent to calling [DatabaseConnectionUser.update] with the + /// captured table. + UpdateStatement update() => _user.update(_table); + + /// Replaces a single row with an update statement. + /// + /// See also [UpdateStatement.replace]. + Future replace(Insertable row) { + return update().replace(row); + } + + /// Creates a statement to compose a `DELETE` from the database. + /// + /// This is equivalent to calling [DatabaseConnectionUser.delete] with the + /// captured table. + DeleteStatement delete() => _user.delete(_table); + + /// Deletes the [row] from the captured table. + Future deleteOne(Insertable row) async { + return await (delete()..whereSamePrimaryKey(row)).go() != 0; + } + + /// Deletes all rows matching the [filter] from the table. + /// + /// See also [SingleTableQueryMixin.where]. + Future deleteWhere(Expression Function(Tbl tbl) filter) { + return (delete()..where(filter)).go(); + } +} diff --git a/drift/test/delete_test.dart b/drift/test/delete_test.dart index 80c8fa129..2508d1559 100644 --- a/drift/test/delete_test.dart +++ b/drift/test/delete_test.dart @@ -70,4 +70,26 @@ void main() { verifyNever(streamQueries.handleTableUpdates(any)); }); }); + + group('delete with from()', () { + test('delete()', () async { + await db.from(db.users).delete().go(); + + verify(executor.runDelete('DELETE FROM users;', [])); + }); + + test('deleteOne()', () async { + await db.from(db.users).deleteOne(const UsersCompanion(id: Value(3))); + + verify(executor.runDelete('DELETE FROM users WHERE id = ?;', [3])); + }); + + test('deleteWhere', () async { + await db + .from(db.users) + .deleteWhere((tbl) => tbl.id.isSmallerThanValue(3)); + + verify(executor.runDelete('DELETE FROM users WHERE id < ?;', [3])); + }); + }); } diff --git a/drift/test/insert_test.dart b/drift/test/insert_test.dart index 6a32b88e5..019c23af2 100644 --- a/drift/test/insert_test.dart +++ b/drift/test/insert_test.dart @@ -402,4 +402,56 @@ void main() { ['description', 1], )); }); + + group('with from()', () { + test('insert', () async { + await db + .from(db.categories) + .insert() + .insert(CategoriesCompanion.insert(description: 'description')); + + verify(executor.runInsert( + 'INSERT INTO categories ("desc") VALUES (?)', ['description'])); + }); + + test('insertOne', () async { + await db.from(db.categories).insertOne( + CategoriesCompanion.insert(description: 'description'), + mode: InsertMode.insertOrReplace); + + verify(executor.runInsert( + 'INSERT OR REPLACE INTO categories ("desc") VALUES (?)', + ['description'])); + }); + + test('insertOnConflictUpdate', () async { + when(executor.runSelect(any, any)).thenAnswer( + (_) => Future.value([ + { + 'id': 1, + 'desc': 'description', + 'description_in_upper_case': 'DESCRIPTION', + 'priority': 1, + }, + ]), + ); + + final row = await db.from(db.categories).insertReturning( + CategoriesCompanion.insert(description: 'description')); + expect( + row, + Category( + id: 1, + description: 'description', + descriptionInUpperCase: 'DESCRIPTION', + priority: CategoryPriority.medium, + ), + ); + + verify(executor.runSelect( + 'INSERT INTO categories ("desc") VALUES (?) RETURNING *', + ['description'], + )); + }); + }); } diff --git a/drift/test/select_test.dart b/drift/test/select_test.dart index 5ebc14799..ef277903a 100644 --- a/drift/test/select_test.dart +++ b/drift/test/select_test.dart @@ -211,4 +211,17 @@ void main() { await pumpEventQueue(); db.markTablesUpdated([db.categories]); }); + + test('can create select statements with from()', () async { + when(executor.runSelect(any, any)).thenAnswer((_) => Future.value([])); + + final result = await db.from(db.todosTable).select().get(); + expect(result, isEmpty); + + final anotherResult = await db.from(db.todosTable).selectOnly().get(); + expect(anotherResult, isEmpty); + + verify(executor.runSelect('SELECT * FROM todos;', [])); + verify(executor.runSelect('SELECT FROM todos;', [])); + }); } diff --git a/drift/test/update_test.dart b/drift/test/update_test.dart index 31b672e75..7d85b0ffb 100644 --- a/drift/test/update_test.dart +++ b/drift/test/update_test.dart @@ -160,4 +160,24 @@ void main() { {const TableUpdate('users'), const TableUpdate('todos')})); }); }); + + group('update with from()', () { + test('update()', () async { + await db + .from(db.users) + .update() + .write(const UsersCompanion(id: Value(3))); + + verify(executor.runUpdate('UPDATE users SET id = ?;', [3])); + }); + + test('replace', () async { + await db.from(db.categories).replace(const CategoriesCompanion( + id: Value(3), description: Value('new name'))); + + verify(executor.runUpdate( + 'UPDATE categories SET "desc" = ?, priority = 0 WHERE id = ?;', + ['new name', 3])); + }); + }); } From 573bd20eb8f5e33a40ddcdc3b9ebbe91cbcfcd37 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 5 Jan 2022 18:52:35 +0100 Subject: [PATCH 04/15] Fix missing quotes in drift files docs --- .../docs/Advanced Features/builder_options.md | 2 +- .../docs/Getting started/starting_with_sql.md | 4 ++-- docs/pages/docs/Using SQL/custom_queries.md | 10 +++++----- .../Using SQL/{moor_files.md => drift_files.md} | 16 +++++++++------- docs/pages/v2.html | 2 +- 5 files changed, 18 insertions(+), 16 deletions(-) rename docs/pages/docs/Using SQL/{moor_files.md => drift_files.md} (98%) diff --git a/docs/pages/docs/Advanced Features/builder_options.md b/docs/pages/docs/Advanced Features/builder_options.md index 03ccac317..5b2a2d922 100644 --- a/docs/pages/docs/Advanced Features/builder_options.md +++ b/docs/pages/docs/Advanced Features/builder_options.md @@ -77,7 +77,7 @@ At the moment, drift supports these options: * `new_sql_code_generation`: Generates SQL statements from the parsed AST instead of replacing substrings. This will also remove unnecessary whitespace and comments. If enabling this option breaks your queries, please file an issue! -* `scoped_dart_components`: Generates a function parameter for [Dart placeholders]({{ '../Using SQL/moor_files.md#dart-components-in-sql' | pageUrl }}) in SQL. +* `scoped_dart_components`: Generates a function parameter for [Dart placeholders]({{ '../Using SQL/drift_files.md#dart-components-in-sql' | pageUrl }}) in SQL. The function has a parameter for each table that is available in the query, making it easier to get aliases right when using Dart placeholders. * `null_aware_type_converters`: Consider the type of applied type converters to determine nullability of columns in Dart. diff --git a/docs/pages/docs/Getting started/starting_with_sql.md b/docs/pages/docs/Getting started/starting_with_sql.md index 6a7a63021..4858307f2 100644 --- a/docs/pages/docs/Getting started/starting_with_sql.md +++ b/docs/pages/docs/Getting started/starting_with_sql.md @@ -149,7 +149,7 @@ Let's take a look at what drift generated during the build: - a `Selectable todosInCategory(int)` method, which runs the `todosInCategory` query declared above. Drift has determined that the type of the variable in that query is `int`, because that's the type - of the `category` column we're comparing it to. + of the `category` column we're comparing it to. The method returns a `Selectable` to indicate that it can both be used as a regular query (`Selectable.get` returns a `Future>`) or as an auto-updating stream (by using `.watch` instead of `.get()`). @@ -169,7 +169,7 @@ further guides to help you learn more: - [Schema migrations]({{ "../Advanced Features/migrations.md" | pageUrl }}) - Writing [queries]({{ "writing_queries.md" | pageUrl }}) and [expressions]({{ "../Advanced Features/expressions.md" | pageUrl }}) in Dart -- A more [in-depth guide]({{ "../Using SQL/moor_files.md" | pageUrl }}) +- A more [in-depth guide]({{ "../Using SQL/drift_files.md" | pageUrl }}) on `drift` files, which explains `import` statements and the Dart-SQL interop. {% block "blocks/alert" title="Using the database" %} diff --git a/docs/pages/docs/Using SQL/custom_queries.md b/docs/pages/docs/Using SQL/custom_queries.md index 846fea046..5d6cbf55f 100644 --- a/docs/pages/docs/Using SQL/custom_queries.md +++ b/docs/pages/docs/Using SQL/custom_queries.md @@ -47,11 +47,11 @@ To use this feature, it's helpful to know how Dart tables are named in sql. For override `tableName`, the name in sql will be the `snake_case` of the class name. So a Dart table called `Categories` will be named `categories`, a table called `UserAddressInformation` would be called `user_address_information`. The same rule applies to column getters without an explicit name. -Tables and columns declared in [Drift files]({{ "moor_files.md" | pageUrl }}) will always have the +Tables and columns declared in [Drift files]({{ "drift_files.md" | pageUrl }}) will always have the name you specified. {% endblock %} -You can also use `UPDATE` or `DELETE` statements here. Of course, this feature is also available for +You can also use `UPDATE` or `DELETE` statements here. Of course, this feature is also available for [daos]({{ "../Advanced Features/daos.md" | pageUrl }}), and it perfectly integrates with auto-updating streams by analyzing what tables you're reading from or writing to. @@ -60,7 +60,7 @@ writing to. If you don't want to use the statements with an generated api, you can still send custom queries by calling `customSelect` for a one-time query or `customSelectStream` for a query stream that automatically emits a new set of items when -the underlying data changes. Using the todo example introduced in the +the underlying data changes. Using the todo example introduced in the [getting started guide]({{ "../Getting started/index.md" | pageUrl }}), we can write this query which will load the amount of todo entries in each category: ```dart @@ -90,7 +90,7 @@ Stream> categoriesWithCount() { ``` For custom selects, you should use the `readsFrom` parameter to specify from which tables the query is reading. When using a `Stream`, drift will be able to know after which updates the stream should emit -items. +items. You can also bind SQL variables by using question-mark placeholders and the `variables` parameter: @@ -104,7 +104,7 @@ Stream amountOfTodosInCategory(int id) { } ``` -Of course, you can also use indexed variables (like `?12`) - for more information on them, see +Of course, you can also use indexed variables (like `?12`) - for more information on them, see [the sqlite3 documentation](https://sqlite.org/lang_expr.html#varparam). ## Custom update statements diff --git a/docs/pages/docs/Using SQL/moor_files.md b/docs/pages/docs/Using SQL/drift_files.md similarity index 98% rename from docs/pages/docs/Using SQL/moor_files.md rename to docs/pages/docs/Using SQL/drift_files.md index c9f90ac22..7a6ed7bb6 100644 --- a/docs/pages/docs/Using SQL/moor_files.md +++ b/docs/pages/docs/Using SQL/drift_files.md @@ -6,6 +6,8 @@ data: aliases: - /docs/using-sql/custom_tables/ # Redirect from outdated "custom tables" page which has been deleted + - /docs/using-sql/moor_files/ + template: layouts/docs/single --- @@ -174,27 +176,27 @@ CREATE TABLE saved_routes ( id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL, "from" INTEGER NOT NULL REFERENCES coordinates (id), - to INTEGER NOT NULL REFERENCES coordinates (id) + "to" INTEGER NOT NULL REFERENCES coordinates (id) ); routesWithPoints: SELECT r.id, r.name, f.*, t.* FROM routes r INNER JOIN coordinates f ON f.id = r."from" - INNER JOIN coordinates t ON t.id = r.to; + INNER JOIN coordinates t ON t.id = r."to"; ``` -To match the returned column names while avoiding name clashes in Dart, drift +To match the returned column names while avoiding name clashes in Dart, drift will generate a class having an `id`, `name`, `id1`, `lat`, `long`, `lat1` and a `long1` field. -Of course, that's not helpful at all - was `lat1` coming from `from` or `to` +Of course, that's not helpful at all - was `lat1` coming from `from` or `to` again? Let's rewrite the query, this time using nested results: ```sql routesWithNestedPoints: SELECT r.id, r.name, f.**, t.** FROM routes r INNER JOIN coordinates f ON f.id = r."from" - INNER JOIN coordinates t ON t.id = r.to; + INNER JOIN coordinates t ON t.id = r."to"; ``` -As you can see, we can nest a result simply by using the drift-specific +As you can see, we can nest a result simply by using the drift-specific `table.**` syntax. For this query, drift will generate the following class: ```dart @@ -207,7 +209,7 @@ class RoutesWithNestedPointsResult { } ``` -Great! This class matches our intent much better than the flat result class +Great! This class matches our intent much better than the flat result class from before. At the moment, there are some limitations with this approach: diff --git a/docs/pages/v2.html b/docs/pages/v2.html index 22f04e286..7278c3fe4 100644 --- a/docs/pages/v2.html +++ b/docs/pages/v2.html @@ -25,7 +25,7 @@ The rewritten compiler is faster than ever, supports more SQL features and gives you more flexibility when writing database code. -[Check the updated documentation]({{ "docs/Using SQL/moor_files.md" | pageUrl }}) +[Check the updated documentation]({{ "docs/Using SQL/drift_files.md" | pageUrl }}) {% endblock %} {% endblock %} From 6b6663c690459c78b0c2c6a2bc998be160e421db Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 5 Jan 2022 19:04:14 +0100 Subject: [PATCH 05/15] Disable checking external links --- docs/tool/ci_check.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/tool/ci_check.dart b/docs/tool/ci_check.dart index 00d81a5ce..6c8661f4e 100644 --- a/docs/tool/ci_check.dart +++ b/docs/tool/ci_check.dart @@ -21,7 +21,9 @@ Future main() async { Uri.parse('http://localhost:8080/api/') ], {'http://localhost:8080/**'}, - true, + // todo: Re-enable. Current problem is that we link new pages to their + // final url (under drift.simonbinder.eu) before they're deployed. + false, UrlSkipper( '', ['github.com', 'pub.dev', 'api.dart.dev', 'fonts.gstatic.com']), false, From fa63d972b2b0e7790802be7e97645236ca03908a Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 7 Jan 2022 22:58:39 +0100 Subject: [PATCH 06/15] Update Stream's marketing link --- README.md | 8 ++++---- drift/README.md | 8 ++++---- moor/README.md | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 42daba122..9a73078b6 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,15 @@ _Note: Moor has been renamed to drift_ [![Build Status](https://api.cirrus-ci.com/github/simolus3/moor.svg)](https://github.com/simolus3/moor/actions/workflows/main.yml/badge.svg) [![Chat on Gitter](https://img.shields.io/gitter/room/moor-dart/community)](https://gitter.im/moor-dart/community) -## Proudly Sponsored by [Stream 💙](https://getstream.io/chat/flutter/tutorial/?utm_source=https://github.com/simolus3/moor&utm_medium=github&utm_content=developer&utm_term=flutter) +## Proudly Sponsored by [Stream 💙](https://getstream.io/chat/flutter/tutorial/?utm_source=Github&utm_medium=Github_Repo_Content_Ad&utm_content=Developer&utm_campaign=Github_Jan2022_FlutterChat&utm_term=moor)

- +
+
Try the Flutter Chat Tutorial  ðŸ’¬ +
-
Try the Flutter Chat Tutorial  ðŸ’¬ -
diff --git a/drift/README.md b/drift/README.md index 3804d1be0..c49bedf47 100644 --- a/drift/README.md +++ b/drift/README.md @@ -1,14 +1,14 @@ # Drift -## Proudly Sponsored by [Stream 💙](https://getstream.io/chat/flutter/tutorial/?utm_source=https://github.com/simolus3/moor&utm_medium=github&utm_content=developer&utm_term=flutter) +## Proudly Sponsored by [Stream 💙](https://getstream.io/chat/flutter/tutorial/?utm_source=Github&utm_medium=Github_Repo_Content_Ad&utm_content=Developer&utm_campaign=Github_Jan2022_FlutterChat&utm_term=moor)

- +
+
Try the Flutter Chat Tutorial  ðŸ’¬ +
-
Try the Flutter Chat Tutorial  ðŸ’¬ -
diff --git a/moor/README.md b/moor/README.md index 9d2c3d745..6f91dc7b9 100644 --- a/moor/README.md +++ b/moor/README.md @@ -7,15 +7,15 @@ Thank you for understanding! __To start using Drift, read our detailed [docs](https://moor.simonbinder.eu/docs/getting-started/).__ -## Proudly Sponsored by [Stream 💙](https://getstream.io/chat/flutter/tutorial/?utm_source=https://github.com/simolus3/moor&utm_medium=github&utm_content=developer&utm_term=flutter) +## Proudly Sponsored by [Stream 💙](https://getstream.io/chat/flutter/tutorial/?utm_source=Github&utm_medium=Github_Repo_Content_Ad&utm_content=Developer&utm_campaign=Github_Jan2022_FlutterChat&utm_term=moor)

- +
+
Try the Flutter Chat Tutorial  ðŸ’¬ +
-
Try the Flutter Chat Tutorial  ðŸ’¬ -
From 0563a7fa15b30ba5bb84c9a55debeb6d6cce7f44 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 7 Jan 2022 23:06:23 +0100 Subject: [PATCH 07/15] Fix link check, again --- docs/tool/ci_check.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/tool/ci_check.dart b/docs/tool/ci_check.dart index 6c8661f4e..5144ac503 100644 --- a/docs/tool/ci_check.dart +++ b/docs/tool/ci_check.dart @@ -38,7 +38,8 @@ Future main() async { var hasBrokenLinks = false; for (final result in results.destinations) { - if (result.isBroken) { + // todo: Remove !result.isExternal after external links work again + if (result.isBroken && !result.isExternal) { print('Broken: $result (${result.toMap()})'); hasBrokenLinks = true; } From 48f1aa8437ebd697771edfbfc4a4090d64ff5fed Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 10 Jan 2022 13:09:47 +0100 Subject: [PATCH 08/15] Support latest analyzer --- drift_dev/pubspec.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drift_dev/pubspec.yaml b/drift_dev/pubspec.yaml index af8b7f253..4df44c174 100644 --- a/drift_dev/pubspec.yaml +++ b/drift_dev/pubspec.yaml @@ -30,8 +30,8 @@ dependencies: sqlparser: ^0.19.0 # Dart analysis - analyzer: "^2.1.0" - analyzer_plugin: ^0.8.0 + analyzer: ">=2.1.0 <4.0.0" + analyzer_plugin: '>=0.8.0 <0.10.0' source_span: ^1.5.5 package_config: ^2.0.0 pub_semver: ^2.0.0 @@ -49,7 +49,7 @@ dev_dependencies: test_descriptor: ^2.0.0 build_runner: ^2.0.0 build_test: ^2.0.0 - json_serializable: ^5.0.0 + json_serializable: ^6.1.3 # Used to test the migration from moor to drift moor: any From b7dd8872c5323f00d6ea9d11245cbe3dcb88b542 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 11 Jan 2022 13:22:46 +0100 Subject: [PATCH 09/15] Enable checkNoTail --- drift/lib/src/ffi/database.dart | 7 ++-- .../lib/src/runtime/api/connection_user.dart | 4 +++ drift/test/ffi/vm_database_test.dart | 34 +++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/drift/lib/src/ffi/database.dart b/drift/lib/src/ffi/database.dart index 5e95aa6b6..686487bbe 100644 --- a/drift/lib/src/ffi/database.dart +++ b/drift/lib/src/ffi/database.dart @@ -182,7 +182,8 @@ class _VmDelegate extends DatabaseDelegate { @override Future runBatched(BatchedStatements statements) async { final prepared = [ - for (final stmt in statements.statements) _db.prepare(stmt), + for (final stmt in statements.statements) + _db.prepare(stmt, checkNoTail: true), ]; for (final application in statements.arguments) { @@ -202,7 +203,7 @@ class _VmDelegate extends DatabaseDelegate { if (args.isEmpty) { _db.execute(statement); } else { - final stmt = _db.prepare(statement); + final stmt = _db.prepare(statement, checkNoTail: true); stmt.execute(args); stmt.dispose(); } @@ -227,7 +228,7 @@ class _VmDelegate extends DatabaseDelegate { @override Future runSelect(String statement, List args) async { - final stmt = _db.prepare(statement); + final stmt = _db.prepare(statement, checkNoTail: true); final result = stmt.select(args); stmt.dispose(); diff --git a/drift/lib/src/runtime/api/connection_user.dart b/drift/lib/src/runtime/api/connection_user.dart index d2fa4dfc7..e40272fc6 100644 --- a/drift/lib/src/runtime/api/connection_user.dart +++ b/drift/lib/src/runtime/api/connection_user.dart @@ -386,6 +386,10 @@ abstract class DatabaseConnectionUser { } /// Executes the custom sql [statement] on the database. + /// + /// [statement] should contain exactly one SQL statement. Attempting to run + /// multiple statements with a single [customStatement] may not be fully + /// supported on all platforms. Future customStatement(String statement, [List? args]) { final engine = resolvedEngine; diff --git a/drift/test/ffi/vm_database_test.dart b/drift/test/ffi/vm_database_test.dart index 722707bb8..04647f450 100644 --- a/drift/test/ffi/vm_database_test.dart +++ b/drift/test/ffi/vm_database_test.dart @@ -25,6 +25,40 @@ void main() { underlying.dispose(); }); }); + + group('checks for trailing statement content', () { + late NativeDatabase db; + + setUp(() async { + db = NativeDatabase.memory(); + await db.ensureOpen(_FakeExecutorUser()); + }); + + tearDown(() => db.close()); + + test('multiple statements are allowed for runCustom without args', () { + return db.runCustom('SELECT 1; SELECT 2;'); + }); + + test('throws for runCustom with args', () async { + expect(db.runCustom('SELECT ?; SELECT ?;', [1, 2]), throwsArgumentError); + }); + + test('in runSelect', () async { + expect(db.runSelect('SELECT ?; SELECT ?;', [1, 2]), throwsArgumentError); + }); + + test('in runBatched', () { + expect( + db.runBatched(BatchedStatements([ + 'SELECT ?; SELECT ?;' + ], [ + ArgumentsForBatchedStatement(0, []), + ])), + throwsArgumentError, + ); + }); + }); } class _FakeExecutorUser extends QueryExecutorUser { From 25c62e567786eee58f567545f38ed912f32469f1 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 11 Jan 2022 13:31:29 +0100 Subject: [PATCH 10/15] Make groupConcat nullable in Dart (closes #1628) --- drift/CHANGELOG.md | 6 +++++- .../runtime/query_builder/expressions/aggregate.dart | 5 +++-- .../expressions/expressions_integration_test.dart | 12 +++++++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drift/CHANGELOG.md b/drift/CHANGELOG.md index f3a560261..3c5f617b9 100644 --- a/drift/CHANGELOG.md +++ b/drift/CHANGELOG.md @@ -1,7 +1,11 @@ -## 1.3.0 +## (unreleased) - Add the `from(table)` method to generated databases. It can be used to write common queries more concisely. +- Make `groupConcat` nullable in the Dart API. +- Throw an exception in a `NativeDatabase` when multiple statements are run in + a single call. In previous versions, parts of the SQL string would otherwise + be ignored. ## 1.2.0 diff --git a/drift/lib/src/runtime/query_builder/expressions/aggregate.dart b/drift/lib/src/runtime/query_builder/expressions/aggregate.dart index bd4cb3f60..b0325d800 100644 --- a/drift/lib/src/runtime/query_builder/expressions/aggregate.dart +++ b/drift/lib/src/runtime/query_builder/expressions/aggregate.dart @@ -33,12 +33,13 @@ extension BaseAggregate

on Expression
{ /// Returns the concatenation of all non-null values in the current group, /// joined by the [separator]. /// - /// The order of the concatenated elements is arbitrary. + /// The order of the concatenated elements is arbitrary. If no non-null values + /// exist in the group, `NULL` is returned. /// /// See also: /// - the sqlite documentation: https://www.sqlite.org/lang_aggfunc.html#groupconcat /// - the conceptually similar [Iterable.join] - Expression groupConcat({String separator = ','}) { + Expression groupConcat({String separator = ','}) { const sqliteDefaultSeparator = ','; if (separator == sqliteDefaultSeparator) { return _AggregateExpression('GROUP_CONCAT', this); diff --git a/drift/test/expressions/expressions_integration_test.dart b/drift/test/expressions/expressions_integration_test.dart index 6c471a52f..d30e9750e 100644 --- a/drift/test/expressions/expressions_integration_test.dart +++ b/drift/test/expressions/expressions_integration_test.dart @@ -1,5 +1,5 @@ @TestOn('vm') -import 'package:drift/drift.dart'; +import 'package:drift/drift.dart' hide isNull; import 'package:drift/native.dart'; import 'package:test/test.dart'; @@ -139,6 +139,16 @@ void main() { expect(eval(noMatch), completion(isFalse)); }); + test('groupConcat is nullable', () async { + final ids = db.users.id.groupConcat(); + final query = db.selectOnly(db.users) + ..where(db.users.id.equals(999)) + ..addColumns([ids]); + + final result = await query.getSingle(); + expect(result.read(ids), isNull); + }); + test('subqueries cause updates to stream queries', () async { await db .into(db.categories) From 3a4dbef895379b74674c56bcdad74f538f95e35b Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 11 Jan 2022 19:12:21 +0100 Subject: [PATCH 11/15] Revert "Enable checkNoTail" This reverts commit b7dd8872c5323f00d6ea9d11245cbe3dcb88b542. --- drift/CHANGELOG.md | 3 -- drift/lib/src/ffi/database.dart | 7 ++-- .../lib/src/runtime/api/connection_user.dart | 4 --- drift/test/ffi/vm_database_test.dart | 34 ------------------- 4 files changed, 3 insertions(+), 45 deletions(-) diff --git a/drift/CHANGELOG.md b/drift/CHANGELOG.md index 3c5f617b9..bee920ddd 100644 --- a/drift/CHANGELOG.md +++ b/drift/CHANGELOG.md @@ -3,9 +3,6 @@ - Add the `from(table)` method to generated databases. It can be used to write common queries more concisely. - Make `groupConcat` nullable in the Dart API. -- Throw an exception in a `NativeDatabase` when multiple statements are run in - a single call. In previous versions, parts of the SQL string would otherwise - be ignored. ## 1.2.0 diff --git a/drift/lib/src/ffi/database.dart b/drift/lib/src/ffi/database.dart index 686487bbe..5e95aa6b6 100644 --- a/drift/lib/src/ffi/database.dart +++ b/drift/lib/src/ffi/database.dart @@ -182,8 +182,7 @@ class _VmDelegate extends DatabaseDelegate { @override Future runBatched(BatchedStatements statements) async { final prepared = [ - for (final stmt in statements.statements) - _db.prepare(stmt, checkNoTail: true), + for (final stmt in statements.statements) _db.prepare(stmt), ]; for (final application in statements.arguments) { @@ -203,7 +202,7 @@ class _VmDelegate extends DatabaseDelegate { if (args.isEmpty) { _db.execute(statement); } else { - final stmt = _db.prepare(statement, checkNoTail: true); + final stmt = _db.prepare(statement); stmt.execute(args); stmt.dispose(); } @@ -228,7 +227,7 @@ class _VmDelegate extends DatabaseDelegate { @override Future runSelect(String statement, List args) async { - final stmt = _db.prepare(statement, checkNoTail: true); + final stmt = _db.prepare(statement); final result = stmt.select(args); stmt.dispose(); diff --git a/drift/lib/src/runtime/api/connection_user.dart b/drift/lib/src/runtime/api/connection_user.dart index e40272fc6..d2fa4dfc7 100644 --- a/drift/lib/src/runtime/api/connection_user.dart +++ b/drift/lib/src/runtime/api/connection_user.dart @@ -386,10 +386,6 @@ abstract class DatabaseConnectionUser { } /// Executes the custom sql [statement] on the database. - /// - /// [statement] should contain exactly one SQL statement. Attempting to run - /// multiple statements with a single [customStatement] may not be fully - /// supported on all platforms. Future customStatement(String statement, [List? args]) { final engine = resolvedEngine; diff --git a/drift/test/ffi/vm_database_test.dart b/drift/test/ffi/vm_database_test.dart index 04647f450..722707bb8 100644 --- a/drift/test/ffi/vm_database_test.dart +++ b/drift/test/ffi/vm_database_test.dart @@ -25,40 +25,6 @@ void main() { underlying.dispose(); }); }); - - group('checks for trailing statement content', () { - late NativeDatabase db; - - setUp(() async { - db = NativeDatabase.memory(); - await db.ensureOpen(_FakeExecutorUser()); - }); - - tearDown(() => db.close()); - - test('multiple statements are allowed for runCustom without args', () { - return db.runCustom('SELECT 1; SELECT 2;'); - }); - - test('throws for runCustom with args', () async { - expect(db.runCustom('SELECT ?; SELECT ?;', [1, 2]), throwsArgumentError); - }); - - test('in runSelect', () async { - expect(db.runSelect('SELECT ?; SELECT ?;', [1, 2]), throwsArgumentError); - }); - - test('in runBatched', () { - expect( - db.runBatched(BatchedStatements([ - 'SELECT ?; SELECT ?;' - ], [ - ArgumentsForBatchedStatement(0, []), - ])), - throwsArgumentError, - ); - }); - }); } class _FakeExecutorUser extends QueryExecutorUser { From 111a2e395aea873a429a74a683319c49f7779625 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 12 Jan 2022 17:49:15 +0100 Subject: [PATCH 12/15] Revert "Revert "Enable checkNoTail"" Issues with `checkNoTail` have been fixed in sqlite3 version 1.5.1, so we can enable it again here. This reverts commit 3a4dbef895379b74674c56bcdad74f538f95e35b. --- drift/CHANGELOG.md | 3 ++ drift/lib/src/ffi/database.dart | 7 ++-- .../lib/src/runtime/api/connection_user.dart | 4 +++ drift/pubspec.yaml | 2 +- drift/test/ffi/vm_database_test.dart | 34 +++++++++++++++++++ 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/drift/CHANGELOG.md b/drift/CHANGELOG.md index bee920ddd..3c5f617b9 100644 --- a/drift/CHANGELOG.md +++ b/drift/CHANGELOG.md @@ -3,6 +3,9 @@ - Add the `from(table)` method to generated databases. It can be used to write common queries more concisely. - Make `groupConcat` nullable in the Dart API. +- Throw an exception in a `NativeDatabase` when multiple statements are run in + a single call. In previous versions, parts of the SQL string would otherwise + be ignored. ## 1.2.0 diff --git a/drift/lib/src/ffi/database.dart b/drift/lib/src/ffi/database.dart index 5e95aa6b6..686487bbe 100644 --- a/drift/lib/src/ffi/database.dart +++ b/drift/lib/src/ffi/database.dart @@ -182,7 +182,8 @@ class _VmDelegate extends DatabaseDelegate { @override Future runBatched(BatchedStatements statements) async { final prepared = [ - for (final stmt in statements.statements) _db.prepare(stmt), + for (final stmt in statements.statements) + _db.prepare(stmt, checkNoTail: true), ]; for (final application in statements.arguments) { @@ -202,7 +203,7 @@ class _VmDelegate extends DatabaseDelegate { if (args.isEmpty) { _db.execute(statement); } else { - final stmt = _db.prepare(statement); + final stmt = _db.prepare(statement, checkNoTail: true); stmt.execute(args); stmt.dispose(); } @@ -227,7 +228,7 @@ class _VmDelegate extends DatabaseDelegate { @override Future runSelect(String statement, List args) async { - final stmt = _db.prepare(statement); + final stmt = _db.prepare(statement, checkNoTail: true); final result = stmt.select(args); stmt.dispose(); diff --git a/drift/lib/src/runtime/api/connection_user.dart b/drift/lib/src/runtime/api/connection_user.dart index d2fa4dfc7..e40272fc6 100644 --- a/drift/lib/src/runtime/api/connection_user.dart +++ b/drift/lib/src/runtime/api/connection_user.dart @@ -386,6 +386,10 @@ abstract class DatabaseConnectionUser { } /// Executes the custom sql [statement] on the database. + /// + /// [statement] should contain exactly one SQL statement. Attempting to run + /// multiple statements with a single [customStatement] may not be fully + /// supported on all platforms. Future customStatement(String statement, [List? args]) { final engine = resolvedEngine; diff --git a/drift/pubspec.yaml b/drift/pubspec.yaml index 959448b8c..466fe0c8a 100644 --- a/drift/pubspec.yaml +++ b/drift/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: collection: ^1.15.0 meta: ^1.3.0 stream_channel: ^2.1.0 - sqlite3: ^1.0.0 + sqlite3: ^1.5.1 dev_dependencies: build_test: ^2.0.0 diff --git a/drift/test/ffi/vm_database_test.dart b/drift/test/ffi/vm_database_test.dart index 722707bb8..04647f450 100644 --- a/drift/test/ffi/vm_database_test.dart +++ b/drift/test/ffi/vm_database_test.dart @@ -25,6 +25,40 @@ void main() { underlying.dispose(); }); }); + + group('checks for trailing statement content', () { + late NativeDatabase db; + + setUp(() async { + db = NativeDatabase.memory(); + await db.ensureOpen(_FakeExecutorUser()); + }); + + tearDown(() => db.close()); + + test('multiple statements are allowed for runCustom without args', () { + return db.runCustom('SELECT 1; SELECT 2;'); + }); + + test('throws for runCustom with args', () async { + expect(db.runCustom('SELECT ?; SELECT ?;', [1, 2]), throwsArgumentError); + }); + + test('in runSelect', () async { + expect(db.runSelect('SELECT ?; SELECT ?;', [1, 2]), throwsArgumentError); + }); + + test('in runBatched', () { + expect( + db.runBatched(BatchedStatements([ + 'SELECT ?; SELECT ?;' + ], [ + ArgumentsForBatchedStatement(0, []), + ])), + throwsArgumentError, + ); + }); + }); } class _FakeExecutorUser extends QueryExecutorUser { From 94bdab0338fa0a68caac79e3d88e05635c3e49c6 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 12 Jan 2022 18:09:13 +0100 Subject: [PATCH 13/15] Allow running multiple statements on the web --- drift/lib/src/web/sql_js.dart | 11 +++++++++-- extras/integration_tests/web/pubspec.yaml | 8 +++----- .../web/test/initializer_test.dart | 12 ++++++------ .../web/test/integration_test.dart | 15 +++++++++++++-- .../saves_after_migration_regression_test.dart | 6 +++--- .../saves_after_migration_regression_test.g.dart | 8 ++++---- 6 files changed, 38 insertions(+), 22 deletions(-) diff --git a/drift/lib/src/web/sql_js.dart b/drift/lib/src/web/sql_js.dart index 506a071d6..378ebc406 100644 --- a/drift/lib/src/web/sql_js.dart +++ b/drift/lib/src/web/sql_js.dart @@ -93,8 +93,15 @@ class SqlJsDatabase { /// Calls `run(sql, args)` on the underlying js api void runWithArgs(String sql, List args) { - final ar = JsArray.from(args); - _obj.callMethod('run', [sql, ar]); + if (args.isEmpty) { + // Call run without providing arguments. sql.js will then use sqlite3_exec + // internally, which supports running multiple statements at once. This + // matches the behavior from a `NativeDatabase`. + _obj.callMethod('run', [sql]); + } else { + final ar = JsArray.from(args); + _obj.callMethod('run', [sql, ar]); + } } /// Returns the amount of rows affected by the most recent INSERT, UPDATE or diff --git a/extras/integration_tests/web/pubspec.yaml b/extras/integration_tests/web/pubspec.yaml index e1744e78f..2cec77686 100644 --- a/extras/integration_tests/web/pubspec.yaml +++ b/extras/integration_tests/web/pubspec.yaml @@ -11,14 +11,12 @@ dev_dependencies: test: ^1.5.0 build_runner: build_web_compilers: - moor_generator: + drift_dev: ^1.0.0 dependency_overrides: drift: path: ../../../drift - moor: - path: ../../../moor - moor_generator: - path: ../../../moor_generator + drift_dev: + path: ../../../drift_dev sqlparser: path: ../../../sqlparser \ No newline at end of file diff --git a/extras/integration_tests/web/test/initializer_test.dart b/extras/integration_tests/web/test/initializer_test.dart index 7a0af28fa..ac44eb28b 100644 --- a/extras/integration_tests/web/test/initializer_test.dart +++ b/extras/integration_tests/web/test/initializer_test.dart @@ -1,7 +1,7 @@ import 'dart:convert'; -import 'package:moor/moor.dart'; -import 'package:moor/moor_web.dart'; +import 'package:drift/drift.dart'; +import 'package:drift/web.dart'; import 'package:test/test.dart'; @@ -184,23 +184,23 @@ AAAAAAAAAAAAAAAAAAAAAAANAQIjaGVsbG8gd29ybGQ= void main() { test('can initialize database when absent', () async { - await _testWith(const MoorWebStorage('name')); + await _testWith(const DriftWebStorage('name')); }); test('can initialize database when absent - IndexedDB', () async { await _testWith( - MoorWebStorage.indexedDb('name', migrateFromLocalStorage: false)); + DriftWebStorage.indexedDb('name', migrateFromLocalStorage: false)); }); } -Future _testWith(MoorWebStorage storage) async { +Future _testWith(DriftWebStorage storage) async { var didCallInitializer = false; final executor = WebDatabase.withStorage(storage, initializer: () async { didCallInitializer = true; return base64.decode(_rawDataBase64.replaceAll('\n', '')); }); - moorRuntimeOptions.dontWarnAboutMultipleDatabases = true; + driftRuntimeOptions.dontWarnAboutMultipleDatabases = true; final attachedDb = _FakeDatabase(executor); await executor.ensureOpen(attachedDb); diff --git a/extras/integration_tests/web/test/integration_test.dart b/extras/integration_tests/web/test/integration_test.dart index 1e193f693..e47aa5679 100644 --- a/extras/integration_tests/web/test/integration_test.dart +++ b/extras/integration_tests/web/test/integration_test.dart @@ -1,7 +1,7 @@ @TestOn('browser') import 'dart:html'; -import 'package:moor/moor_web.dart'; +import 'package:drift/web.dart'; import 'package:test/test.dart'; import 'package:tests/tests.dart'; @@ -30,7 +30,7 @@ class WebExecutorIndexedDb extends TestExecutor { @override DatabaseConnection createConnection() { return DatabaseConnection.fromExecutor( - WebDatabase.withStorage(MoorWebStorage.indexedDb('foo')), + WebDatabase.withStorage(DriftWebStorage.indexedDb('foo')), ); } @@ -48,4 +48,15 @@ void main() { group('using IndexedDb', () { runAllTests(WebExecutorIndexedDb()); }); + + test('can run multiple statements in one call', () async { + final db = Database(DatabaseConnection.fromExecutor( + WebDatabase.withStorage(DriftWebStorage.volatile()))); + addTearDown(db.close); + + await db.customStatement( + 'CREATE TABLE x1 (a INTEGER); INSERT INTO x1 VALUES (1);'); + final results = await db.customSelect('SELECT * FROM x1;').get(); + expect(results.length, 1); + }); } diff --git a/extras/integration_tests/web/test/saves_after_migration_regression_test.dart b/extras/integration_tests/web/test/saves_after_migration_regression_test.dart index 89a5be581..99d8cb4d1 100644 --- a/extras/integration_tests/web/test/saves_after_migration_regression_test.dart +++ b/extras/integration_tests/web/test/saves_after_migration_regression_test.dart @@ -1,8 +1,8 @@ @TestOn('browser') import 'dart:html'; -import 'package:moor/moor.dart'; -import 'package:moor/moor_web.dart'; +import 'package:drift/drift.dart'; +import 'package:drift/web.dart'; import 'package:test/test.dart'; part 'saves_after_migration_regression_test.g.dart'; @@ -17,7 +17,7 @@ class Bars extends Table { IntColumn get id => integer().autoIncrement()(); } -@UseMoor( +@DriftDatabase( tables: [Foos, Bars], ) class _FakeDb extends _$_FakeDb { diff --git a/extras/integration_tests/web/test/saves_after_migration_regression_test.g.dart b/extras/integration_tests/web/test/saves_after_migration_regression_test.g.dart index 11e957204..77b5459fe 100644 --- a/extras/integration_tests/web/test/saves_after_migration_regression_test.g.dart +++ b/extras/integration_tests/web/test/saves_after_migration_regression_test.g.dart @@ -34,14 +34,14 @@ class Foo extends DataClass implements Insertable { factory Foo.fromJson(Map json, {ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; + serializer ??= driftRuntimeOptions.defaultSerializer; return Foo( id: serializer.fromJson(json['id']), ); } @override Map toJson({ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; + serializer ??= driftRuntimeOptions.defaultSerializer; return { 'id': serializer.toJson(id), }; @@ -175,14 +175,14 @@ class Bar extends DataClass implements Insertable { factory Bar.fromJson(Map json, {ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; + serializer ??= driftRuntimeOptions.defaultSerializer; return Bar( id: serializer.fromJson(json['id']), ); } @override Map toJson({ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; + serializer ??= driftRuntimeOptions.defaultSerializer; return { 'id': serializer.toJson(id), }; From d12d8c6f4ac0974980270c7673c148a6c4ace121 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 12 Jan 2022 21:23:07 +0100 Subject: [PATCH 14/15] Close executor on isolatee shutdown (#1629) --- drift/CHANGELOG.md | 1 + drift/lib/src/remote/server_impl.dart | 2 +- drift/test/isolate_test.dart | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drift/CHANGELOG.md b/drift/CHANGELOG.md index 3c5f617b9..367a4c09d 100644 --- a/drift/CHANGELOG.md +++ b/drift/CHANGELOG.md @@ -6,6 +6,7 @@ - Throw an exception in a `NativeDatabase` when multiple statements are run in a single call. In previous versions, parts of the SQL string would otherwise be ignored. +- Close the underlying database when an isolate is shut down. ## 1.2.0 diff --git a/drift/lib/src/remote/server_impl.dart b/drift/lib/src/remote/server_impl.dart index f7753d192..fcb7723df 100644 --- a/drift/lib/src/remote/server_impl.dart +++ b/drift/lib/src/remote/server_impl.dart @@ -62,7 +62,7 @@ class ServerImplementation implements DriftServer { @override Future shutdown() { if (!_isShuttingDown) { - _done.complete(); + _done.complete(connection.executor.close()); _isShuttingDown = true; } diff --git a/drift/test/isolate_test.dart b/drift/test/isolate_test.dart index 67be91405..dee265c0a 100644 --- a/drift/test/isolate_test.dart +++ b/drift/test/isolate_test.dart @@ -5,9 +5,11 @@ import 'dart:isolate'; import 'package:drift/drift.dart'; import 'package:drift/isolate.dart'; import 'package:drift/native.dart'; +import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; import 'data/tables/todos.dart'; +import 'data/utils/mocks.dart'; void main() { // Using the DriftIsolate apis without actually running on a background @@ -105,6 +107,15 @@ void main() { final drift = await spawned.first as DriftIsolate; await drift.shutdownAll(); }, tags: 'background_isolate'); + + test('shutting down will close the underlying executor', () async { + final mockExecutor = MockExecutor(); + final isolate = DriftIsolate.inCurrent( + () => DatabaseConnection.fromExecutor(mockExecutor)); + await isolate.shutdownAll(); + + verify(mockExecutor.close()); + }); } void _runTests(FutureOr Function() spawner, bool terminateIsolate, From d6d52718d45da2178734fcdf09287b22ffadf74c Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 14 Jan 2022 19:19:14 +0100 Subject: [PATCH 15/15] Prepare 1.3.0 release --- drift/CHANGELOG.md | 4 ++-- drift/pubspec.yaml | 2 +- drift_dev/CHANGELOG.md | 4 ++++ drift_dev/pubspec.yaml | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drift/CHANGELOG.md b/drift/CHANGELOG.md index 367a4c09d..7e21c232d 100644 --- a/drift/CHANGELOG.md +++ b/drift/CHANGELOG.md @@ -1,4 +1,4 @@ -## (unreleased) +## 1.3.0 - Add the `from(table)` method to generated databases. It can be used to write common queries more concisely. @@ -6,7 +6,7 @@ - Throw an exception in a `NativeDatabase` when multiple statements are run in a single call. In previous versions, parts of the SQL string would otherwise be ignored. -- Close the underlying database when an isolate is shut down. +- Close the underlying database when a drift isolate is shut down. ## 1.2.0 diff --git a/drift/pubspec.yaml b/drift/pubspec.yaml index 466fe0c8a..2bffac59e 100644 --- a/drift/pubspec.yaml +++ b/drift/pubspec.yaml @@ -1,6 +1,6 @@ name: drift description: Drift is a reactive library to store relational data in Dart and Flutter applications. -version: 1.2.0 +version: 1.3.0 repository: https://github.com/simolus3/moor homepage: https://drift.simonbinder.eu/ issue_tracker: https://github.com/simolus3/moor/issues diff --git a/drift_dev/CHANGELOG.md b/drift_dev/CHANGELOG.md index 2ea926688..518f08897 100644 --- a/drift_dev/CHANGELOG.md +++ b/drift_dev/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.3.0 + +- Support `drift` version `1.3.x`. + ## 1.2.0 - Generate code needed to support streams of views. diff --git a/drift_dev/pubspec.yaml b/drift_dev/pubspec.yaml index 4df44c174..eb94e0bc9 100644 --- a/drift_dev/pubspec.yaml +++ b/drift_dev/pubspec.yaml @@ -1,6 +1,6 @@ name: drift_dev description: Dev-dependency for users of drift. Contains a the generator and development tools. -version: 1.2.0 +version: 1.3.0 repository: https://github.com/simolus3/moor homepage: https://drift.simonbinder.eu/ issue_tracker: https://github.com/simolus3/moor/issues @@ -25,7 +25,7 @@ dependencies: io: ^1.0.3 # Drift-specific analysis and apis - drift: '>=1.2.0 <1.3.0' + drift: '>=1.3.0 <1.4.0' sqlite3: '>=0.1.6 <2.0.0' sqlparser: ^0.19.0