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.
|
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
|
## TODO-List and current limitations
|
||||||
### Limitations (at the moment)
|
### Limitations (at the moment)
|
||||||
Please note that a workaround for most on this list exists with custom statements.
|
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!
|
let us know by creating an issue!
|
||||||
- Specify primary keys
|
- Specify primary keys
|
||||||
- Support an simplified update that doesn't need an explicit where based on the primary key
|
- 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)
|
- Simple `COUNT(*)` operations (group operations will be much more complicated)
|
||||||
- Support default values and expressions
|
- 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,
|
- Support more Datatypes: We should at least support `Uint8List` out of the box,
|
||||||
supporting floating / fixed point numbers as well would be awesome
|
supporting floating / fixed point numbers as well would be awesome
|
||||||
- Nullable / non-nullable datatypes
|
- 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.
|
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
|
## TODO-List and current limitations
|
||||||
### Limitations (at the moment)
|
### Limitations (at the moment)
|
||||||
Please note that a workaround for most on this list exists with custom statements.
|
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!
|
let us know by creating an issue!
|
||||||
- Specify primary keys
|
- Specify primary keys
|
||||||
- Support an simplified update that doesn't need an explicit where based on the primary key
|
- 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)
|
- Simple `COUNT(*)` operations (group operations will be much more complicated)
|
||||||
- Support default values and expressions
|
- 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,
|
- Support more Datatypes: We should at least support `Uint8List` out of the box,
|
||||||
supporting floating / fixed point numbers as well would be awesome
|
supporting floating / fixed point numbers as well would be awesome
|
||||||
- Nullable / non-nullable datatypes
|
- 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']),
|
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
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
(((id.hashCode) * 31 + content.hashCode) * 31 + targetDate.hashCode) *
|
(((id.hashCode) * 31 + content.hashCode) * 31 + targetDate.hashCode) *
|
||||||
|
@ -109,6 +117,10 @@ class Category {
|
||||||
description: stringType.mapFromDatabaseResponse(data['`desc`']),
|
description: stringType.mapFromDatabaseResponse(data['`desc`']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Category copyWith({int id, String description}) => Category(
|
||||||
|
id: id ?? this.id,
|
||||||
|
description: description ?? this.description,
|
||||||
|
);
|
||||||
@override
|
@override
|
||||||
int get hashCode => (id.hashCode) * 31 + description.hashCode;
|
int get hashCode => (id.hashCode) * 31 + description.hashCode;
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -26,6 +26,9 @@ class DataClassWriter {
|
||||||
// Also write parsing factory
|
// Also write parsing factory
|
||||||
_writeMappingConstructor(buffer);
|
_writeMappingConstructor(buffer);
|
||||||
|
|
||||||
|
// And a convenience method to copy data from this class.
|
||||||
|
_writeCopyWith(buffer);
|
||||||
|
|
||||||
buffer.write('@override\n int get hashCode => ');
|
buffer.write('@override\n int get hashCode => ');
|
||||||
|
|
||||||
if (table.columns.isEmpty) {
|
if (table.columns.isEmpty) {
|
||||||
|
@ -36,7 +39,7 @@ class DataClassWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// override ==
|
// override ==
|
||||||
// return identical(this, other) || (other is DataClass && other.id == id && other.)
|
// return identical(this, other) || (other is DataClass && other.id == id && ...)
|
||||||
buffer
|
buffer
|
||||||
..write('@override\nbool operator ==(other) => ')
|
..write('@override\nbool operator ==(other) => ')
|
||||||
..write('identical(this, other) || (other is ${table.dartTypeName}');
|
..write('identical(this, other) || (other is ${table.dartTypeName}');
|
||||||
|
@ -89,6 +92,32 @@ class DataClassWriter {
|
||||||
buffer.write(');}\n');
|
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,
|
/// 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
|
/// 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
|
/// the hash code of that field. Otherwise, we multiply it with 31 and add
|
||||||
|
|
Loading…
Reference in New Issue