mirror of https://github.com/AMT-Cheif/drift.git
Generate copyWith method for data classes
This commit is contained in:
parent
d818942c8d
commit
2b24684abb
32
README.md
32
README.md
|
@ -253,6 +253,35 @@ We can now change the `database` class like this:
|
|||
```
|
||||
You can also add individual tables or drop them.
|
||||
|
||||
### Extracting functionality with DAOs
|
||||
When you have a lot of queries, putting them all into one class quickly becomes
|
||||
tedious. You can avoid this by extracting some queries into classes that are
|
||||
available from your main database class. Consider the following code:
|
||||
```dart
|
||||
part 'todos_dao.g.dart';
|
||||
|
||||
// the _TodosDaoMixin will be created by sally. It contains all the necessary
|
||||
// fields for the tables. The <MyDatabase> type annotation is the database class
|
||||
// that should use this dao.
|
||||
@UseDao(tables: [Todos])
|
||||
class TodosDao extends DatabaseAccessor<MyDatabase> with _TodosDaoMixin {
|
||||
// this constructor is required so that the main database can create an instance
|
||||
// of this object.
|
||||
TodosDao(Database db) : super(db);
|
||||
|
||||
Stream<List<TodoEntry>> todosInCategory(Category category) {
|
||||
if (category == null) {
|
||||
return (select(todos)..where((t) => isNull(t.category))).watch();
|
||||
} else {
|
||||
return (select(todos)..where((t) => t.category.equals(category.id)))
|
||||
.watch();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
If we now change the annotation on the `MyDatabase` class to `@UseSally(tables: [Todos, Categories], daos: [TodosDao])`
|
||||
and re-run the code generation, a getter `todosDao` can be used to access the instance of that dao.
|
||||
|
||||
## TODO-List and current limitations
|
||||
### Limitations (at the moment)
|
||||
Please note that a workaround for most on this list exists with custom statements.
|
||||
|
@ -266,11 +295,8 @@ These aren't sorted by priority. If you have more ideas or want some features ha
|
|||
let us know by creating an issue!
|
||||
- Specify primary keys
|
||||
- Support an simplified update that doesn't need an explicit where based on the primary key
|
||||
- Data classes: Generate a `copyWith` method.
|
||||
- Simple `COUNT(*)` operations (group operations will be much more complicated)
|
||||
- Support default values and expressions
|
||||
- Allow using DAOs or some other mechanism instead of having to put everything in the main
|
||||
database class.
|
||||
- Support more Datatypes: We should at least support `Uint8List` out of the box,
|
||||
supporting floating / fixed point numbers as well would be awesome
|
||||
- Nullable / non-nullable datatypes
|
||||
|
|
|
@ -253,6 +253,35 @@ We can now change the `database` class like this:
|
|||
```
|
||||
You can also add individual tables or drop them.
|
||||
|
||||
### Extracting functionality with DAOs
|
||||
When you have a lot of queries, putting them all into one class quickly becomes
|
||||
tedious. You can avoid this by extracting some queries into classes that are
|
||||
available from your main database class. Consider the following code:
|
||||
```dart
|
||||
part 'todos_dao.g.dart';
|
||||
|
||||
// the _TodosDaoMixin will be created by sally. It contains all the necessary
|
||||
// fields for the tables. The <MyDatabase> type annotation is the database class
|
||||
// that should use this dao.
|
||||
@UseDao(tables: [Todos])
|
||||
class TodosDao extends DatabaseAccessor<MyDatabase> with _TodosDaoMixin {
|
||||
// this constructor is required so that the main database can create an instance
|
||||
// of this object.
|
||||
TodosDao(Database db) : super(db);
|
||||
|
||||
Stream<List<TodoEntry>> todosInCategory(Category category) {
|
||||
if (category == null) {
|
||||
return (select(todos)..where((t) => isNull(t.category))).watch();
|
||||
} else {
|
||||
return (select(todos)..where((t) => t.category.equals(category.id)))
|
||||
.watch();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
If we now change the annotation on the `MyDatabase` class to `@UseSally(tables: [Todos, Categories], daos: [TodosDao])`
|
||||
and re-run the code generation, a getter `todosDao` can be used to access the instance of that dao.
|
||||
|
||||
## TODO-List and current limitations
|
||||
### Limitations (at the moment)
|
||||
Please note that a workaround for most on this list exists with custom statements.
|
||||
|
@ -266,11 +295,8 @@ These aren't sorted by priority. If you have more ideas or want some features ha
|
|||
let us know by creating an issue!
|
||||
- Specify primary keys
|
||||
- Support an simplified update that doesn't need an explicit where based on the primary key
|
||||
- Data classes: Generate a `copyWith` method.
|
||||
- Simple `COUNT(*)` operations (group operations will be much more complicated)
|
||||
- Support default values and expressions
|
||||
- Allow using DAOs or some other mechanism instead of having to put everything in the main
|
||||
database class.
|
||||
- Support more Datatypes: We should at least support `Uint8List` out of the box,
|
||||
supporting floating / fixed point numbers as well would be awesome
|
||||
- Nullable / non-nullable datatypes
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# sally_example
|
||||
|
||||
This is a simple todo list app that uses sally as a persistence library.
|
|
@ -23,6 +23,14 @@ class TodoEntry {
|
|||
category: intType.mapFromDatabaseResponse(data['category']),
|
||||
);
|
||||
}
|
||||
TodoEntry copyWith(
|
||||
{int id, String content, DateTime targetDate, int category}) =>
|
||||
TodoEntry(
|
||||
id: id ?? this.id,
|
||||
content: content ?? this.content,
|
||||
targetDate: targetDate ?? this.targetDate,
|
||||
category: category ?? this.category,
|
||||
);
|
||||
@override
|
||||
int get hashCode =>
|
||||
(((id.hashCode) * 31 + content.hashCode) * 31 + targetDate.hashCode) *
|
||||
|
@ -109,6 +117,10 @@ class Category {
|
|||
description: stringType.mapFromDatabaseResponse(data['`desc`']),
|
||||
);
|
||||
}
|
||||
Category copyWith({int id, String description}) => Category(
|
||||
id: id ?? this.id,
|
||||
description: description ?? this.description,
|
||||
);
|
||||
@override
|
||||
int get hashCode => (id.hashCode) * 31 + description.hashCode;
|
||||
@override
|
||||
|
|
|
@ -26,6 +26,9 @@ class DataClassWriter {
|
|||
// Also write parsing factory
|
||||
_writeMappingConstructor(buffer);
|
||||
|
||||
// And a convenience method to copy data from this class.
|
||||
_writeCopyWith(buffer);
|
||||
|
||||
buffer.write('@override\n int get hashCode => ');
|
||||
|
||||
if (table.columns.isEmpty) {
|
||||
|
@ -36,7 +39,7 @@ class DataClassWriter {
|
|||
}
|
||||
|
||||
// override ==
|
||||
// return identical(this, other) || (other is DataClass && other.id == id && other.)
|
||||
// return identical(this, other) || (other is DataClass && other.id == id && ...)
|
||||
buffer
|
||||
..write('@override\nbool operator ==(other) => ')
|
||||
..write('identical(this, other) || (other is ${table.dartTypeName}');
|
||||
|
@ -89,6 +92,32 @@ class DataClassWriter {
|
|||
buffer.write(');}\n');
|
||||
}
|
||||
|
||||
void _writeCopyWith(StringBuffer buffer) {
|
||||
final dataClassName = table.dartTypeName;
|
||||
|
||||
buffer.write('$dataClassName copyWith({');
|
||||
for (var i = 0; i < table.columns.length; i++) {
|
||||
final column = table.columns[i];
|
||||
final last = i == table.columns.length - 1;
|
||||
|
||||
buffer.write('${column.dartTypeName} ${column.dartGetterName}');
|
||||
if (!last) {
|
||||
buffer.write(',');
|
||||
}
|
||||
}
|
||||
|
||||
buffer.write('}) => $dataClassName(');
|
||||
|
||||
for (var column in table.columns) {
|
||||
// we also have a method parameter called getter, so we can use
|
||||
// field: field ?? this.field
|
||||
final getter = column.dartGetterName;
|
||||
buffer.write('$getter: $getter ?? this.$getter,');
|
||||
}
|
||||
|
||||
buffer.write(');');
|
||||
}
|
||||
|
||||
/// Recursively creates the implementation for hashCode of the data class,
|
||||
/// assuming it has at least one field. When it has one field, we just return
|
||||
/// the hash code of that field. Otherwise, we multiply it with 31 and add
|
||||
|
|
Loading…
Reference in New Issue