From 14134e17a82643e136ad17d8793518e25fe0fbcf Mon Sep 17 00:00:00 2001 From: Vitus Ortner Date: Sun, 24 Feb 2019 08:57:11 +0100 Subject: [PATCH 1/2] Add support for running queries that don't return an Entity --- README.md | 4 +-- floor_generator/lib/model/query_method.dart | 4 +++ .../lib/writer/query_method_writer.dart | 8 +++-- floor_test/test/database.dart | 29 +++++++++++++++++++ floor_test/test/database_test.dart | 12 ++++++++ 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 973e9ace..1582b077 100644 --- a/README.md +++ b/README.md @@ -126,8 +126,8 @@ For further examples take a look at the [example](https://github.com/vitusortner ## Querying Method signatures turn into query methods by adding the `@Query()` annotation with the query in parenthesis to them. Be patient about the correctness of your SQL statements. -The are only partly validated while generating the code. -These queries have to return an entity. +They are only partly validated while generating the code. +These queries have to return either a `Future` of an entity or `void`. ````dart @Query('SELECT * FROM Person WHERE id = :id') diff --git a/floor_generator/lib/model/query_method.dart b/floor_generator/lib/model/query_method.dart index 73c8a8e8..8a0ba2eb 100644 --- a/floor_generator/lib/model/query_method.dart +++ b/floor_generator/lib/model/query_method.dart @@ -64,6 +64,10 @@ class QueryMethod { return isList(type); } + bool get returnsVoid { + return method.returnType.flattenFutures(method.context.typeSystem).isVoid; + } + Entity getEntity(final LibraryReader library) { final entity = _getEntities(library).firstWhere( (entity) => entity.displayName == flattenedReturnType.displayName, diff --git a/floor_generator/lib/writer/query_method_writer.dart b/floor_generator/lib/writer/query_method_writer.dart index 3f05ddcb..9e398246 100644 --- a/floor_generator/lib/writer/query_method_writer.dart +++ b/floor_generator/lib/writer/query_method_writer.dart @@ -20,7 +20,6 @@ class QueryMethodWriter implements Writer { Method _generateQueryMethod() { _assertReturnsFuture(); - _assertReturnsEntity(); _assertQueryParameters(); return Method((builder) => builder @@ -106,11 +105,14 @@ class QueryMethodWriter implements Writer { } String _generateMethodBody() { - final mapping = _generateMapping(); + if (queryMethod.returnsVoid) { + return "await database.rawQuery('${queryMethod.query}');"; + } + _assertReturnsEntity(); return ''' final rows = await database.rawQuery('${queryMethod.query}'); - $mapping + ${_generateMapping()} '''; } diff --git a/floor_test/test/database.dart b/floor_test/test/database.dart index 3d6f0701..9a05a826 100644 --- a/floor_test/test/database.dart +++ b/floor_test/test/database.dart @@ -67,6 +67,9 @@ abstract class TestDatabase extends FloorDatabase { @Query('SELECT * FROM dog') Future> findAllDogs(); + + @Query('DELETE FROM person') + Future deleteAllPersons(); } @Entity(tableName: 'person') @@ -77,6 +80,9 @@ class Person { @ColumnInfo(name: 'custom_name', nullable: false) final String name; +// @embedded +// final Address address; + Person(this.id, this.name); @override @@ -135,3 +141,26 @@ class Dog { return 'Dog{id: $id, name: $name, ownerId: $ownerId}'; } } + +class Address { + final String street; + final String city; + + Address(this.street, this.city); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Address && + runtimeType == other.runtimeType && + street == other.street && + city == other.city; + + @override + int get hashCode => street.hashCode ^ city.hashCode; + + @override + String toString() { + return 'Address{street: $street, city: $city}'; + } +} diff --git a/floor_test/test/database_test.dart b/floor_test/test/database_test.dart index 3f609a80..d66fce3a 100644 --- a/floor_test/test/database_test.dart +++ b/floor_test/test/database_test.dart @@ -198,6 +198,18 @@ void main() { expect(actual, isEmpty); }); }); + + group('query with void return', () { + test('delete all persons', () async { + final persons = [Person(1, 'Simon'), Person(2, 'Frank')]; + await database.insertPersons(persons); + + await database.deleteAllPersons(); + final actual = await database.findAllPersons(); + + expect(actual, isEmpty); + }); + }); }); } From 21afe415b6f3ee5fb8e97d4f5abf80e0a776d45d Mon Sep 17 00:00:00 2001 From: Vitus Ortner Date: Sun, 24 Feb 2019 09:01:40 +0100 Subject: [PATCH 2/2] Improve documentation --- README.md | 7 +++++-- floor_test/test/database.dart | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1582b077..83b549d3 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,7 @@ Method signatures turn into query methods by adding the `@Query()` annotation wi Be patient about the correctness of your SQL statements. They are only partly validated while generating the code. These queries have to return either a `Future` of an entity or `void`. +Returning `Future` comes in handy whenever you want to delete the full content of a table. ````dart @Query('SELECT * FROM Person WHERE id = :id') @@ -138,6 +139,9 @@ Future findPersonByIdAndName(int id, String name); @Query('SELECT * FROM Person') Future> findAllPersons(); // select multiple items + +@Query('DELETE FROM person') +Future deleteAllPersons(); // query without returning an entity ```` ## Persisting Data Changes @@ -186,8 +190,7 @@ It's also required to add the `async` modifier. These methods can only return `F ```dart @transaction Future replacePersons(List persons) async { - // execute SQL without automatically generated code - await database.execute('DELETE FROM Person'); + await deleteAllPersons(); await insertPersons(persons); } ``` diff --git a/floor_test/test/database.dart b/floor_test/test/database.dart index 9a05a826..52bb724c 100644 --- a/floor_test/test/database.dart +++ b/floor_test/test/database.dart @@ -55,7 +55,7 @@ abstract class TestDatabase extends FloorDatabase { @transaction Future replacePersons(List persons) async { - await database.execute('DELETE FROM person'); + await deleteAllPersons(); await insertPersons(persons); }