I am building my first app in Flutter, this app is using the sqlite database
. So I have models and repositories.
The code layout:
I have 2 models (will have more in the finished app) UserModel
, TimesheetModel
, these both extend a BaseModel
I have 2 repositories (will have more in the finished app) UserRepository
, TimesheetRepository
, these both extend BaseRepository
What I am trying to do:
I would like to have the reusable code such as: getAll()
, countAll()
etc in the BaseRepository
that way all the repositories that extend the base repository have this functionality and all I should need to do is set the table name and set the returned Model
.
The Error:
As you can see from my code because the BaseRepository
is returning a BaseModel
type, when I call the all()
function on timesheet object, I get the following error : type 'List' is not a subtype of type 'List'
I am not sure how to fix this, any suggestions please?
BaseRepository
abstract class BaseRepository {
final String table;
final model;
BaseRepository({this.table, this.model});
// Retrieve all the items
Future<List<BaseModel>> all() async {
final sql = '''SELECT * FROM $table''';
final data = await db.rawQuery(sql);
List<BaseModel> forms = List();
for (final node in data) {
final form = model.fromJson(jsonData: node);
forms.add(form);
}
return forms;
}
// Find an item by its ID
Future findById(int id) async {
final sql = '''SELECT * FROM $table
WHERE id = ?''';
List<dynamic> params = [id];
final data = await db.rawQuery(sql, params);
final form = model.fromJson(jsonData: data.first);
return form;
}
// Count all the items
Future<int> count() async {
final data = await db.rawQuery('''SELECT COUNT(*) FROM $table''');
int count = data[0].values.elementAt(0);
int idForNewItem = count++;
return idForNewItem;
}
// clear the table
Future<void> delete() async {
// truncate current database table
await db.rawQuery('''DELETE FROM $table''');
}
}
TimesheetRepository
class TimesheetRepository extends BaseRepository {
String table = 'timesheets';
TimesheetModel model = new TimesheetModel();
// Search for a item by its name
Future<List<TimesheetModel>> findByDate(DateTime dateTime) async {
final String date = DateFormat("yyyy-MM-dd").format(dateTime);
final sql = '''SELECT * FROM $table WHERE timesheet_date = ?''';
List<dynamic> params = [date];
final data = await db.rawQuery(sql, params);
List<TimesheetModel> forms = List();
for (final node in data) {
final form = TimesheetModel.fromJson(jsonData: node);
forms.add(form);
}
return forms;
}
// Add a new item
Future<void> store(TimesheetModel timesheet) async {
final sql = '''INSERT INTO $table
(
user_id,
timesheet_date,
start_time,
end_time,
json,
is_uploaded
)
VALUES (?,?,?,?,?,?)''';
List<dynamic> params = [
timesheet.userId,
DateFormat("yyyy-MM-dd").format(timesheet.timesheetDate),
timesheet.startTime,
timesheet.endTime,
convert.json.encode(timesheet.json),
timesheet.is_uploaded,
];
final result = await db.rawInsert(sql, params);
DatabaseCreator.databaseLog('Add form', sql, null, result, params);
}
}
When calling all on Timesheet
TimesheetRepository timesheet = TimesheetRepository();
timesheet.all();
Base Model
abstract class BaseModel {
fromJson();
}
Timesheet Model
class TimesheetModel extends BaseModel {
int id;
int userId;
DateTime timesheetDate;
String startTime;
String endTime;
Map json = {
"task": "",
"detail": "",
"notes": "",
};
bool is_uploaded;
TimesheetModel({
this.id,
this.userId,
this.timesheetDate,
this.startTime,
this.endTime,
this.json,
this.is_uploaded,
});
fromJson({Map<String, dynamic> jsonData}) {
return TimesheetModel(
id: jsonData['id'] as int,
userId: jsonData['user_id'] as int,
timesheetDate: timesheetDate,
startTime: jsonData['start_time'],
endTime: jsonData['end_time'],
is_uploaded: hasUploaded,
);
}
}
Dart has single inheritance. Read more about extending classes, the optional @override annotation, and more.
No, Dart does not support multiple implementation inheritance. Dart has interfaces, and like most other similar languages it has multiple interface inheritance. For implementation, there is only a single super-class chain that a class can inherit member implementations from.
Introduction to the Dart inheritance Inheritance allows you to define a class that extends the functionality of another class. Dart supports single inheritance. It means that a class can inherit from a single class. Dart doesn't support multiple inheritances.
I wouldn't do the parse fromJson the way you're doing since you need to pass an empty instance of the model to be able to create a valid instance of the same object. But in order to have your architecture working you need to do some corrections:
1 - make usage of generics.
BaseRepository
abstract class BaseRepository<T extends BaseModel> {
BaseRepository({this.table, this.model});
final String table;
final T model;
// Retrieve all the items
Future<List<T>> all() async {
final sql = '''SELECT * FROM $table''';
final data = await db.rawQuery(sql);
return data.map((node) {
return model.fromJson(jsonData: node);
}).toList();
}
Future<T> findById(int id) async {
final sql = '''SELECT * FROM $table
WHERE id = ?''';
final data = await db.rawQuery(sql, [id]);
return model.fromJson(jsonData: data.first);
}
// Count all the items
Future<int> count() async {
final data = await db.rawQuery('''SELECT COUNT(*) FROM $table''');
int count = data[0].values.elementAt(0);
int idForNewItem = count++;
return idForNewItem;
}
// clear the table
Future<void> delete() async {
// truncate current database table
await db.rawQuery('''DELETE FROM $table''');
}
}
2 - correctly call the super constructor
TimesheetRepository
class TimesheetRepository extends BaseRepository<TimesheetModel> {
///IMHO you should not pass TimesheetModel instance here, it is really redundant
///you can create a parse class that receives the type and a json and does the
///trick
TimesheetRepository() : super(table: 'timesheets', model: TimesheetModel());
}
3 - add the correct return to your fromJson
method
abstract class BaseModel {
BaseModel fromJson({Map<String, dynamic> jsonData});
}
I could not test it integrated with the database, so let me know if that works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With