383 lines
9.8 KiB
Dart
383 lines
9.8 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:isar/isar.dart';
|
|
import 'package:get_it/get_it.dart';
|
|
import 'package:more/collection.dart';
|
|
import 'package:okane/database/collections/account.dart';
|
|
import 'package:okane/database/collections/beneficiary.dart';
|
|
import 'package:okane/database/collections/expense_category.dart';
|
|
import 'package:okane/database/collections/loan.dart';
|
|
import 'package:okane/database/collections/recurrent.dart';
|
|
import 'package:okane/database/collections/template.dart';
|
|
import 'package:okane/database/collections/transaction.dart';
|
|
import 'package:okane/ui/state/core.dart';
|
|
import 'package:okane/ui/utils.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
import 'collections/budget.dart';
|
|
|
|
Future<Isar> openDatabase() async {
|
|
final dir = await getApplicationDocumentsDirectory();
|
|
return Isar.open([
|
|
AccountSchema,
|
|
BeneficiarySchema,
|
|
TransactionSchema,
|
|
TransactionTemplateSchema,
|
|
RecurringTransactionSchema,
|
|
ExpenseCategorySchema,
|
|
BudgetSchema,
|
|
BudgetItemSchema,
|
|
LoanSchema,
|
|
LoanChangeSchema,
|
|
], directory: dir.path);
|
|
}
|
|
|
|
Future<List<Account>> getAccounts() {
|
|
return GetIt.I.get<Isar>().accounts.where().findAll();
|
|
}
|
|
|
|
Future<double> getTotalBalance(Account account) async {
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.transactions
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.amountProperty()
|
|
.sum();
|
|
}
|
|
|
|
Future<List<Transaction>> getLastTransactions(
|
|
Account account,
|
|
DateTime today,
|
|
int days,
|
|
) async {
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.transactions
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.dateGreaterThan(toMidnight(today.subtract(Duration(days: days))))
|
|
.findAll();
|
|
}
|
|
|
|
Future<List<RecurringTransaction>> getRecurringTransactions(Account? account) {
|
|
if (account == null) {
|
|
return Future.value([]);
|
|
}
|
|
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.recurringTransactions
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.findAll();
|
|
}
|
|
|
|
Stream<void> watchRecurringTransactions(Account account) {
|
|
final account = GetIt.I.get<CoreCubit>().activeAccount!;
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.recurringTransactions
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.build()
|
|
.watchLazy(fireImmediately: true);
|
|
}
|
|
|
|
Future<void> upsertAccount(Account account) async {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.accounts.put(account);
|
|
});
|
|
}
|
|
|
|
Future<void> upsertBeneficiary(Beneficiary beneficiary) async {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.beneficiarys.put(beneficiary);
|
|
await beneficiary.account.save();
|
|
});
|
|
}
|
|
|
|
Future<Beneficiary?> getAccountBeneficiary(Account account) {
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.beneficiarys
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.findFirst();
|
|
}
|
|
|
|
Future<void> upsertTransactionTemplate(TransactionTemplate template) async {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.transactionTemplates.put(template);
|
|
await template.beneficiary.save();
|
|
await template.account.save();
|
|
await template.expenseCategory.save();
|
|
});
|
|
}
|
|
|
|
Future<void> deleteRecurringTransactionTemplate(RecurringTransaction template) {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.transactionTemplates.delete(template.template.value!.id);
|
|
await db.recurringTransactions.delete(template.id);
|
|
});
|
|
}
|
|
|
|
Future<void> upsertRecurringTransaction(RecurringTransaction template) async {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.recurringTransactions.put(template);
|
|
await template.template.save();
|
|
await template.account.save();
|
|
});
|
|
}
|
|
|
|
Future<void> upsertTransaction(Transaction transaction) async {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.transactions.put(transaction);
|
|
await transaction.beneficiary.save();
|
|
await transaction.account.save();
|
|
await transaction.expenseCategory.save();
|
|
});
|
|
}
|
|
|
|
Stream<void> watchAccounts() {
|
|
return GetIt.I.get<Isar>().accounts.watchLazy();
|
|
}
|
|
|
|
Stream<void> watchTransactionTemplates(Account account) {
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.transactionTemplates
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.watchLazy(fireImmediately: true);
|
|
}
|
|
|
|
Future<void> deleteTransactionTemplate(TransactionTemplate template) {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.transactionTemplates.delete(template.id);
|
|
});
|
|
}
|
|
|
|
Future<List<TransactionTemplate>> getTransactionTemplates(Account? account) {
|
|
if (account == null) {
|
|
return Future.value([]);
|
|
}
|
|
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.transactionTemplates
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.findAll();
|
|
}
|
|
|
|
Stream<void> watchTransactions(Account account) {
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.transactions
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.watchLazy(fireImmediately: true);
|
|
}
|
|
|
|
Future<List<Transaction>> getTransactions(Account? account) {
|
|
if (account == null) {
|
|
return Future.value([]);
|
|
}
|
|
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.transactions
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.findAll();
|
|
}
|
|
|
|
Stream<void> watchBeneficiaries() {
|
|
return GetIt.I.get<Isar>().beneficiarys.watchLazy(fireImmediately: true);
|
|
}
|
|
|
|
Future<List<Beneficiary>> getBeneficiaries() {
|
|
return GetIt.I.get<Isar>().beneficiarys.where().findAll();
|
|
}
|
|
|
|
Stream<Beneficiary?> watchBeneficiaryObject(Id id) {
|
|
return GetIt.I.get<Isar>().beneficiarys.watchObject(id);
|
|
}
|
|
|
|
Future<void> upsertExpenseCategory(ExpenseCategory category) {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() => db.expenseCategorys.put(category));
|
|
}
|
|
|
|
Future<List<ExpenseCategory>> getExpenseCategories() {
|
|
return GetIt.I.get<Isar>().expenseCategorys.where().findAll();
|
|
}
|
|
|
|
Stream<void> watchExpenseCategory() {
|
|
return GetIt.I.get<Isar>().expenseCategorys.watchLazy(fireImmediately: true);
|
|
}
|
|
|
|
Stream<void> watchBudgets(Account account) {
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.budgets
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.watchLazy(fireImmediately: true);
|
|
}
|
|
|
|
Future<List<Budget>> getBudgets(Account? account) {
|
|
if (account == null) {
|
|
return Future.value([]);
|
|
}
|
|
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.budgets
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.findAll();
|
|
}
|
|
|
|
Future<void> upsertBudget(Budget budget) {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.budgets.put(budget);
|
|
await budget.items.save();
|
|
await budget.account.save();
|
|
});
|
|
}
|
|
|
|
Future<void> upsertBudgetItem(BudgetItem item) {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.budgetItems.put(item);
|
|
await item.expenseCategory.save();
|
|
});
|
|
}
|
|
|
|
enum TransactionQueryDateOption { thisMonth }
|
|
|
|
Future<List<Transaction>> getTransactionsInTimeframe(
|
|
Account account,
|
|
DateTime today,
|
|
TransactionQueryDateOption option,
|
|
) async {
|
|
final lower = switch (option) {
|
|
TransactionQueryDateOption.thisMonth => DateTime(
|
|
today.year,
|
|
today.month,
|
|
0,
|
|
),
|
|
};
|
|
final upper = switch (option) {
|
|
TransactionQueryDateOption.thisMonth => monthEnding(today),
|
|
};
|
|
|
|
return GetIt.I
|
|
.get<Isar>()
|
|
.transactions
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.dateBetween(lower, upper)
|
|
.findAll();
|
|
}
|
|
|
|
Future<void> upsertLoan(Loan loan) {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.loans.put(loan);
|
|
await loan.beneficiary.save();
|
|
await loan.changes.save();
|
|
});
|
|
}
|
|
|
|
Future<List<Loan>> getLoans() {
|
|
return GetIt.I.get<Isar>().loans.where().findAll();
|
|
}
|
|
|
|
Stream<void> watchLoans() {
|
|
return GetIt.I.get<Isar>().loans.where().watchLazy(fireImmediately: true);
|
|
}
|
|
|
|
Future<void> deleteLoan(Loan loan) async {
|
|
final db = GetIt.I.get<Isar>();
|
|
final loanChangeIds = loan.changes.map((c) => c.id).toList();
|
|
return db.writeTxn(() async {
|
|
await db.loans.delete(loan.id);
|
|
await db.loanChanges.deleteAll(loanChangeIds);
|
|
});
|
|
}
|
|
|
|
Future<void> upsertLoanChange(LoanChange loanChange) {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.loanChanges.put(loanChange);
|
|
});
|
|
}
|
|
|
|
Future<void> deleteLoanChange(LoanChange loanChange) {
|
|
final db = GetIt.I.get<Isar>();
|
|
return db.writeTxn(() async {
|
|
await db.loanChanges.delete(loanChange.id);
|
|
});
|
|
}
|
|
|
|
Future<double> getTotalLoanSum() async {
|
|
final loans = await getLoans();
|
|
return loans
|
|
.map(
|
|
(loan) =>
|
|
loan.changes.map((l) => l.amount).reduce((acc, val) => acc + val),
|
|
)
|
|
.reduce((acc, val) => acc + val);
|
|
}
|
|
|
|
Future<void> deleteAccount(Account account) async {
|
|
final db = GetIt.I.get<Isar>();
|
|
final affectedBudgets =
|
|
await db.budgets
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.findAll();
|
|
final budgetIds = affectedBudgets.map((a) => a.id).toList();
|
|
final budgetItemIds =
|
|
affectedBudgets.map((a) => a.items.map((i) => i.id)).flatten().toList();
|
|
return db.writeTxn(() async {
|
|
// Remove transactions
|
|
await db.transactions
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.deleteAll();
|
|
await db.beneficiarys
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.deleteAll();
|
|
|
|
// Remove templates
|
|
await db.recurringTransactions
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.deleteAll();
|
|
await db.transactionTemplates
|
|
.filter()
|
|
.account((q) => q.idEqualTo(account.id))
|
|
.deleteAll();
|
|
|
|
// Remove all budgets
|
|
await db.budgetItems.deleteAll(budgetItemIds);
|
|
await db.budgets.deleteAll(budgetIds);
|
|
|
|
// Remove account
|
|
await db.accounts.delete(account.id);
|
|
});
|
|
}
|