This commit is contained in:
2026-03-29 15:59:49 +03:00
parent 1f6d129fc2
commit bc8c272e63
21 changed files with 114 additions and 327 deletions
+1 -67
View File
@@ -18,10 +18,7 @@ class AppDatabase extends _$AppDatabase {
@override
MigrationStrategy get migration => MigrationStrategy(
onUpgrade: (migrator, from, to) async {
print('--- DATABASE MIGRATION: from=$from to=$to ---');
if (from == 1) {
print('Migration: Creating accounts table');
await migrator.createTable(accounts);
await customStatement(
'INSERT INTO accounts (name, is_main, currency, sort_order, created_at) '
@@ -31,17 +28,13 @@ class AppDatabase extends _$AppDatabase {
}
if (from == 2) {
print('Migration: Adding currency column to accounts');
await customStatement(
'ALTER TABLE accounts ADD COLUMN currency TEXT NOT NULL DEFAULT "USD"',
);
}
// Add account_id column to transactions if upgrading from version < 5
if (from < 5) {
print('Migration: Adding account_id column to transactions');
try {
// Check if column exists first
final result = await customSelect(
'PRAGMA table_info(transactions)',
).get();
@@ -49,36 +42,23 @@ class AppDatabase extends _$AppDatabase {
final hasAccountId = result.any((row) => row.data['name'] == 'account_id');
if (!hasAccountId) {
print('Migration: account_id column does not exist, adding it now');
await customStatement(
'ALTER TABLE transactions ADD COLUMN account_id INTEGER NOT NULL DEFAULT 1',
);
print('Migration: account_id column added successfully');
} else {
print('Migration: account_id column already exists, skipping');
}
}
} catch (e) {
print('Migration: Error adding account_id column: $e');
// If the column already exists, this will fail, which is fine
}
}
print('--- DATABASE MIGRATION: COMPLETE ---');
},
);
// ============================================================================
// TRANSACTIONS
// ============================================================================
/// Get all transactions ordered by date descending
Future<List<dynamic>> getAllTransactions() {
return (select(
transactions,
)..orderBy([(t) => OrderingTerm.desc(t.date)])).get();
}
/// Get transactions by date range
Future<List<dynamic>> getTransactionsByDateRange(
DateTime start,
DateTime end,
@@ -90,7 +70,6 @@ class AppDatabase extends _$AppDatabase {
.get();
}
/// Get transactions by type
Future<List<dynamic>> getTransactionsByType(String type) {
return (select(transactions)
..where((t) => t.type.equals(type))
@@ -98,7 +77,6 @@ class AppDatabase extends _$AppDatabase {
.get();
}
/// Get transactions by category
Future<List<dynamic>> getTransactionsByCategory(String category) {
return (select(transactions)
..where((t) => t.category.equals(category))
@@ -106,7 +84,6 @@ class AppDatabase extends _$AppDatabase {
.get();
}
/// Search transactions by note or category
Future<List<dynamic>> searchTransactions(String query) {
final lowerQuery = query.toLowerCase();
return (select(transactions)
@@ -119,14 +96,12 @@ class AppDatabase extends _$AppDatabase {
.get();
}
/// Get transaction by ID
Future<dynamic> getTransactionById(String id) {
return (select(
transactions,
)..where((t) => t.id.equals(id))).getSingleOrNull();
}
/// Insert transaction
Future<Result<void>> insertTransaction(
TransactionsCompanion transaction,
) async {
@@ -135,7 +110,6 @@ class AppDatabase extends _$AppDatabase {
});
}
/// Update transaction
Future<Result<void>> updateTransaction(dynamic transaction) async {
return asyncResultOf(() async {
final companion = transaction as TransactionsCompanion;
@@ -149,7 +123,6 @@ class AppDatabase extends _$AppDatabase {
});
}
/// Delete transaction
Future<Result<void>> deleteTransaction(String id) async {
return asyncResultOf(() async {
final deleted = await (delete(
@@ -162,90 +135,64 @@ class AppDatabase extends _$AppDatabase {
});
}
/// Delete all transactions
Future<void> deleteAllTransactions() {
return delete(transactions).go();
}
/// Get recurring transactions that need processing
Future<List<dynamic>> getRecurringTransactions() {
return (select(
transactions,
)..where((t) => t.recurrence.equals('none').not())).get();
}
// ============================================================================
// CATEGORIES
// ============================================================================
/// Get all categories
Future<List<Category>> getAllCategories() {
return select(categories).get();
}
/// Get categories by type
Future<List<Category>> getCategoriesByType(String type) {
return (select(categories)..where((c) => c.type.equals(type))).get();
}
/// Insert category
Future<int> insertCategory(CategoriesCompanion category) {
return into(categories).insert(category);
}
/// Update category
Future<bool> updateCategory(Category category) {
return update(categories).replace(category);
}
/// Delete category
Future<int> deleteCategory(int id) {
return (delete(categories)..where((c) => c.id.equals(id))).go();
}
// ============================================================================
// BUDGETS
// ============================================================================
/// Get budget for month/year
Future<Budget?> getBudget(int month, int year) {
return (select(budgets)
..where((b) => b.month.equals(month) & b.year.equals(year)))
.getSingleOrNull();
}
/// Insert or update budget
Future<void> upsertBudget(BudgetsCompanion budget) {
return into(budgets).insertOnConflictUpdate(budget);
}
/// Delete budget
Future<int> deleteBudget(int id) {
return (delete(budgets)..where((b) => b.id.equals(id))).go();
}
// ============================================================================
// EXCHANGE RATES
// ============================================================================
/// Get exchange rate
Future<ExchangeRate?> getExchangeRate(String from, String to) {
return (select(exchangeRates)
..where((r) => r.fromCurrency.equals(from) & r.toCurrency.equals(to)))
.getSingleOrNull();
}
/// Insert or update exchange rate
Future<void> upsertExchangeRate(ExchangeRatesCompanion rate) {
return into(exchangeRates).insertOnConflictUpdate(rate);
}
/// Get all exchange rates
Future<List<ExchangeRate>> getAllExchangeRates() {
return select(exchangeRates).get();
}
/// Delete old exchange rates (older than 24 hours)
Future<int> deleteOldExchangeRates() {
final yesterday = DateTime.now().subtract(const Duration(hours: 24));
return (delete(
@@ -253,11 +200,6 @@ class AppDatabase extends _$AppDatabase {
)..where((r) => r.updatedAt.isSmallerThanValue(yesterday))).go();
}
// ============================================================================
// STATISTICS & AGGREGATIONS
// ============================================================================
/// Get total balance
Future<double> getTotalBalance() async {
final txs = await getAllTransactions();
return txs.fold<double>(0.0, (sum, tx) {
@@ -265,7 +207,6 @@ class AppDatabase extends _$AppDatabase {
});
}
/// Get total income for date range
Future<double> getTotalIncome(DateTime start, DateTime end) async {
final txs = await getTransactionsByDateRange(start, end);
return txs
@@ -273,7 +214,6 @@ class AppDatabase extends _$AppDatabase {
.fold<double>(0.0, (sum, tx) => sum + tx.amount);
}
/// Get total expense for date range
Future<double> getTotalExpense(DateTime start, DateTime end) async {
final txs = await getTransactionsByDateRange(start, end);
return txs
@@ -281,7 +221,6 @@ class AppDatabase extends _$AppDatabase {
.fold<double>(0.0, (sum, tx) => sum + tx.amount);
}
/// Get category totals for date range
Future<Map<String, double>> getCategoryTotals(
DateTime start,
DateTime end,
@@ -298,11 +237,6 @@ class AppDatabase extends _$AppDatabase {
return totals;
}
// ============================================================================
// ACCOUNTS
// ============================================================================
/// Update an account
Future<void> updateAccount(AccountsCompanion account) async {
await update(accounts).replace(account);
}