Been trying to implement simple expense tracking app and got myself tangled in dependencies. Before null-safety deleting rows was easy, now I have to use """companions""" and their concept is a bit unintuitive for me. I've been trying to upgrade this app as a learning attempt of mvvm in flutter (kinda useless knowledge) (https://github.com/musabagab/Money-Manager-Expenses-tracker-app)
Pre-ambula: they did NBBD and now auto-increment id param is marked as required and I have 0 idea how to implement deletions without knowing said ID. And moor docs are not helpful with examples, I want to delete by ID\in any way they intended to do this (https://drift.simonbinder.eu/docs/getting-started/writing_queries/#updates-and-deletes)
Before null-safety db code looked like this + generated file, and inserts\deletions worked just fine:
import 'package:moor_flutter/moor_flutter.dart';
part 'moor_database.g.dart';
class Transactions extends Table {
TextColumn get type => text()(); //expense /income
IntColumn get id => integer().autoIncrement()();
IntColumn get amount => integer()(); // 300 or 200
}
@UseMoor(tables: [Transactions], daos: [TransactionDao])
class AppDatabase extends _$AppDatabase {
AppDatabase()
: super(FlutterQueryExecutor.inDatabaseFolder(
path: "db.sqlite", logStatements: true));
int get schemaVersion => 1;
}
// Denote which tables this DAO can access
@UseDao(
tables: [Transactions],
queries: {
// this method will be generated
'getTransactionForMonth': 'SELECT * FROM transactions WHERE month = :month',
'sumTheMoneyForMonth':
'SELECT SUM(amount) FROM transactions WHERE month = :month AND type = :type'
},
)
class TransactionDao extends DatabaseAccessor<AppDatabase>
with _$TransactionDaoMixin {
final AppDatabase db;
// Called by the AppDatabase class
TransactionDao(this.db) : super(db);
Future insertTransaction(Transaction transaction) =>
into(transactions).insert(transaction);
Future deleteTransaction(Transaction transaction) =>
delete(transactions).delete(transaction);
}
and database service
import 'package:finances/core/database/moor_database.dart';
class MoorDatabaseService {
final AppDatabase _database = AppDatabase();
getAllTransactions(String month) async {
List<Transaction> allTrans = List<Transaction>();
TransactionDao transactionDao = _database.transactionDao;
allTrans = await transactionDao.getTransactionForMonth(month).get();
return allTrans;
}
Future deleteTransaction(Transaction transaction) async {
return await _database.transactionDao.deleteTransaction(transaction);
}
Future insertTransaction(Transaction transaction) async {
return await _database.transactionDao.insertTransaction(transaction);
}
insert model (yes mvvm in flutter lol)
class InsertTransactionModel extends BaseModel {
TextEditingController memoController = TextEditingController();
TextEditingController amountController = TextEditingController();
final MoorDatabaseService _moorDatabaseService =
locator<MoorDatabaseService>();
<code skipped>
Transaction newTransaction = new Transaction(
type: type,
day: selectedDay,
month: selectedMonth,
memo: memoController.text,
amount: int.parse(amount),
categoryindex: cateogryIndex);
// insert it!
await _moorDatabaseService.insertTransaction(newTransaction);
Toast.show("Added successfully!", context,
duration: Toast.LENGTH_SHORT, gravity: Toast.BOTTOM);
// return to the home
Navigator.of(context)
.pushNamedAndRemoveUntil('home', (Route<dynamic> route) => false);
}
}
insert viewmodel
class InsertTranscationView extends StatelessWidget {
final Category category;
final int selectedCategory;
InsertTranscationView(this.category, this.selectedCategory);
@override
Widget build(BuildContext context) {
return BaseView<InsertTransactionModel>(
onModelReady: (model) => model.init(selectedCategory, category.index),
builder: (context, model, child) => Scaffold(
appBar: AppBar(
title: selectedCategory == 1 ? Text('Income') : Text('Expense'),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: ListView(
children: <Widget>[
ListTile(
**<code skipped>**
Align(
alignment: Alignment.centerLeft,
child: RaisedButton(
child: Text(
'ADD',
style: TextStyle(fontSize: 16),
),
color: backgroundColor,
textColor: Colors.black,
**onPressed: () async {
await model.addTransaction(context);**
},
),
)
],
),
),
),
),
);
}
}
FIXING INSERT FOR NULL-SAFETY##
this was the easy part.
final newTransaction = TransactionsCompanion(
type: Value.ofNullable(type),
day: Value.ofNullable(selectedDay),
month: Value.ofNullable(selectedMonth),
memo: Value.ofNullable(memoController.text),
amount: Value.ofNullable(int.parse(amount)),
categoryindex: Value.ofNullable(categoryIndex));
// insert it!
await _databaseService.insertTransaction(newTransaction);
and in service
Future<int> insertTransaction(TransactionsCompanion transaction) async {
return await _database.transactionDao.insertTransaction(transaction);
}
and in database
Future<int> insertTransaction(TransactionsCompanion transaction) =>
into(transactions).insert(transaction);
Delete is a bit hard
My attempt at fixing null errors:
in delete model
Future deleteTransacation(Transaction transaction) async {
final newTransaction = TransactionsCompanion(
type: Value.ofNullable(transaction.type),
day: Value.ofNullable(transaction.day),
month: Value.ofNullable(transaction.month),
memo: Value.ofNullable(transaction.memo),
amount: Value.ofNullable(transaction.amount),
categoryindex: Value.ofNullable(transaction.categoryindex));
// delet it!
return await _databaseService.deleteTransaction(newTransaction);
}
and service
Future deleteTransaction(TransactionsCompanion transaction) async {
return await _database.transactionDao.deleteTransaction(transaction);
}
and database
Future deleteTransaction(TransactionsCompanion transaction) =>
delete(transactions).delete(transaction);
I suppose delete method in database itself is faulty, because insertions work without issues. I tried assembling TransactionCompanion and pass it as an argument into db service for it to delete same transaction by 1:1 comparision i guess?
Thanks for your efforts!