Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions lib/core/database/app_database.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'dart:io';
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:zplit/core/database/daos/balances_dao.dart';

import 'package:zplit/core/database/daos/groups_dao.dart';
import 'package:zplit/core/database/daos/transactions_dao.dart';
import 'package:zplit/core/database/daos/users_dao.dart';

import 'package:zplit/core/database/tables/groups_table.dart';

import 'tables/users_table.dart';
import 'tables/transactions_table.dart';
import 'tables/balances_table.dart';

import 'package:uuid/uuid.dart';

part 'app_database.g.dart';

const _uuid = Uuid();

@DriftDatabase(
tables: [UsersTable, TransactionsTable, BalancesTable, GroupsTable],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scope (issue #47) lists 5 tables it's missing WalletDetailsTable

@4555jan 4555jan Jun 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually i discussed with the mentors and turns out we no longer need that table and i also modified the initial issue template

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay

daos: [TransactionsDao, GroupsDao, UsersDao, BalancesDao],
)
class AppDatabase extends _$AppDatabase {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQLite doesn't enforce foreign keys by default, so the .references() in transactions and balances are currently non-functional

AppDatabase() : super(_openConnection());
AppDatabase.forTesting(QueryExecutor executor) : super(executor);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be AppDatabase.forTesting(super.executor); instead of AppDatabase.forTesting(QueryExecutor executor) : super(executor);
it'll raise analyser problem


@override
int get schemaVersion => 1;
@override
MigrationStrategy get migration => MigrationStrategy(
beforeOpen: (details) async {
await customStatement('PRAGMA foreign_keys = ON;');
},
);
}

LazyDatabase _openConnection() {
return LazyDatabase(() async {
final dir = await getApplicationDocumentsDirectory();
final file = File(p.join(dir.path, 'zplit.sqlite'));
return NativeDatabase.createInBackground(file);
});
}
32 changes: 32 additions & 0 deletions lib/core/database/daos/balances_dao.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'package:drift/drift.dart';
import 'package:zplit/core/database/tables/balances_table.dart';
import 'package:zplit/core/database/app_database.dart';

part 'balances_dao.g.dart';

@DriftAccessor(tables: [BalancesTable])
class BalancesDao extends DatabaseAccessor<AppDatabase>
with _$BalancesDaoMixin {
BalancesDao(super.db);

Future<List<BalancesTableData>> getAll() {
return select(balancesTable).get();
}

Future<BalancesTableData?> getByPublicKey(String userPublicKey) {
final query = select(balancesTable);
query.where((t) => t.userPublicKey.equals(userPublicKey));
return query.getSingleOrNull();
}

// we can just use upsert for update and insert
Future<void> upsert(BalancesTableCompanion balance) {
return into(balancesTable).insertOnConflictUpdate(balance);
}

Future<int> deleteBalances(String userPublicKey) {
final query = delete(balancesTable);
query.where((t) => t.userPublicKey.equals(userPublicKey));
return query.go();
}
}
30 changes: 30 additions & 0 deletions lib/core/database/daos/groups_dao.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:drift/drift.dart';
import 'package:zplit/core/database/tables/groups_table.dart';
import 'package:zplit/core/database/app_database.dart';

part 'groups_dao.g.dart';

@DriftAccessor(tables: [GroupsTable])
class GroupsDao extends DatabaseAccessor<AppDatabase> with _$GroupsDaoMixin {
GroupsDao(super.db);

Future<List<GroupsTableData>> getAll() {
return select(groupsTable).get();
}

Future<GroupsTableData?> getById(String id) {
final query = select(groupsTable);
query.where((t) => t.id.equals(id));
return query.getSingleOrNull();
}

Future<void> upsert(GroupsTableCompanion group) {
return into(groupsTable).insertOnConflictUpdate(group);
}

Future<int> deletegroup(String id) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use lower camel case

final query = delete(groupsTable);
query.where((t) => t.id.equals(id));
return query.go();
}
}
25 changes: 25 additions & 0 deletions lib/core/database/daos/transactions_dao.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'package:drift/drift.dart';
import 'package:zplit/core/database/tables/transactions_table.dart';
import 'package:zplit/core/database/app_database.dart';

part 'transactions_dao.g.dart';

@DriftAccessor(tables: [TransactionsTable])
class TransactionsDao extends DatabaseAccessor<AppDatabase>
with _$TransactionsDaoMixin {
TransactionsDao(super.db);

Future<List<TransactionsTableData>> getAll() {
return select(transactionsTable).get();
}

Future<TransactionsTableData?> getById(String id) {
final query = select(transactionsTable);
query.where((t) => t.id.equals(id));
return query.getSingleOrNull();
}

Future<int> insert(TransactionsTableCompanion transaction) {
return into(transactionsTable).insert(transaction);
}
}
30 changes: 30 additions & 0 deletions lib/core/database/daos/users_dao.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:drift/drift.dart';
import 'package:zplit/core/database/tables/users_table.dart';
import 'package:zplit/core/database/app_database.dart';

part 'users_dao.g.dart';

@DriftAccessor(tables: [UsersTable])
class UsersDao extends DatabaseAccessor<AppDatabase> with _$UsersDaoMixin {
UsersDao(super.db);

Future<List<UsersTableData>> getAll() {
return select(usersTable).get();
}

Future<UsersTableData?> getByPublicKey(String publicKey) {
final query = select(usersTable);
query.where((t) => t.publicKey.equals(publicKey));
return query.getSingleOrNull();
}

Future<void> upsert(UsersTableCompanion user) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use lower camel case

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

upsert is already in lower camel case could you clarify what you'd like changed here

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this was marked by mistake

return into(usersTable).insertOnConflictUpdate(user);
}

Future<int> deleteUser(String publicKey) {
final query = delete(usersTable);
query.where((t) => t.publicKey.equals(publicKey));
return query.go();
}
}
15 changes: 15 additions & 0 deletions lib/core/database/tables/balances_table.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:drift/drift.dart';
import 'package:zplit/core/database/tables/users_table.dart';

class BalancesTable extends Table {
TextColumn get userPublicKey => text().references(UsersTable, #publicKey)();
IntColumn get netAmount => integer()();
TextColumn get signed => text().nullable()();
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();

@override
String get tableName => 'balances';

@override
Set<Column> get primaryKey => {userPublicKey};
}
18 changes: 18 additions & 0 deletions lib/core/database/tables/groups_table.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:drift/drift.dart';
import 'package:uuid/uuid.dart';

const _uuid = Uuid();

class GroupsTable extends Table {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintain a reference for transaction table to access the transactions in groups, also using a simple FK here will not be a good approach since one group can have multiple transactions

TextColumn get id => text().clientDefault(() => _uuid.v4())();
TextColumn get name => text()();

@Mayank4352 Mayank4352 Jun 5, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's still just a string relabeled as set, so no dupe protection ("abc,def,abc" is allowed), no FK integrity (foreign keys can't reach inside a CSV, so the PRAGMA foreign_keys = ON doesn't protect membership), and "which groups is user X in?" are still unindexed and gets false-matches on substrings like (alice matches alice99).

Standard fix is a join table, one row per membership, but you can look for better solution as well

// storing member public keys as a set (comma separated string)
TextColumn get users => text().withDefault(const Constant(''))();
TextColumn get description => text().nullable()();

@override
String get tableName => 'groups';

@override
Set<Column> get primaryKey => {id};
}
24 changes: 24 additions & 0 deletions lib/core/database/tables/transactions_table.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:drift/drift.dart';
import 'package:zplit/core/database/tables/users_table.dart';

enum TransactionStatus { unsigned, partiallySigned, signed }

class TransactionsTable extends Table {
TextColumn get id => text()();
TextColumn get fromUserPublicKey =>
text().references(UsersTable, #publicKey)();
TextColumn get toUserPublicKey => text().references(UsersTable, #publicKey)();
Int64Column get amount => int64()();
TextColumn get description => text().nullable()();
TextColumn get tag => text().nullable()();
TextColumn get status => textEnum<TransactionStatus>()();
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
TextColumn get senderSignature => text().nullable()();
TextColumn get receiverSignature => text().nullable()();

@override
String get tableName => 'transactions';

@override
Set<Column> get primaryKey => {id};
}
14 changes: 14 additions & 0 deletions lib/core/database/tables/users_table.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:drift/drift.dart';

class UsersTable extends Table {
TextColumn get publicKey => text()();
TextColumn get displayName => text()();
TextColumn get cryptoAddress => text().nullable()();
TextColumn get profilePicture => text().nullable()();

@override
String get tableName => 'users';

@override
Set<Column> get primaryKey => {publicKey};
}
Loading