3.2 KiB
3.2 KiB
TT-004 — Repository Implementations
Type: Story
Priority: High
Labels: data-layer, repositories
Depends on: TT-002, TT-003
Blocks: TT-005
Summary
Implement the concrete repository classes for each feature. Repositories act as the single access point for the data layer; they delegate to Drift DAOs and map DB rows to domain models.
Repositories to implement
ProjectsRepository
File: lib/features/projects/data/projects_repository.dart
abstract class ProjectsRepository {
Stream<List<Project>> watchAll();
Stream<List<Project>> watchActive(); // archivedAt IS NULL
Future<Project> getById(int id);
Future<int> create({required String name, required int colorValue, String? description});
Future<void> update(Project project);
Future<void> archive(int id); // sets archivedAt = now
Future<void> delete(int id);
}
TimeEntriesRepository
File: lib/features/entries/data/entries_repository.dart
abstract class TimeEntriesRepository {
Stream<List<TimeEntry>> watchAll();
Stream<List<TimeEntry>> watchByProject(int projectId);
Stream<List<TimeEntry>> watchByDateRange(DateTime from, DateTime to);
Future<TimeEntry?> getActiveEntry(); // end_time IS NULL
Future<int> create(TimeEntry entry);
Future<void> update(TimeEntry entry);
Future<void> delete(int id);
}
TagsRepository
File: lib/features/entries/data/tags_repository.dart
abstract class TagsRepository {
Stream<List<Tag>> watchAll();
Future<Tag> findOrCreate(String name);
Future<void> setTagsForEntry(int entryId, List<String> tagNames);
Future<List<Tag>> getTagsForEntry(int entryId);
}
ReportsRepository
File: lib/features/reports/data/reports_repository.dart
abstract class ReportsRepository {
Future<Duration> getTotalDuration(DateTime from, DateTime to, {int? projectId});
Future<Map<int, Duration>> getDurationByProject(DateTime from, DateTime to);
Future<Map<int, Duration>> getDurationByWeekday(DateTime weekStart);
Future<Map<int, Duration>> getDurationByDay(DateTime monthStart);
}
Acceptance Criteria
- Abstract interface + concrete
DriftXxxRepositoryimplementation for each - Riverpod provider for each concrete implementation
- All DB access goes through DAOs — no raw SQL in repositories
- Mapper extension methods convert
Drift row → domain model - Unit tests for each repository method using in-memory Drift DB
Files to create / modify
lib/features/projects/data/projects_repository.dart(replace stub)lib/features/projects/data/drift_projects_repository.dartlib/features/entries/data/entries_repository.dart(replace stub)lib/features/entries/data/drift_entries_repository.dartlib/features/entries/data/tags_repository.dartlib/features/entries/data/drift_tags_repository.dartlib/features/reports/data/reports_repository.dart(replace stub)lib/features/reports/data/drift_reports_repository.darttest/features/*/— unit tests for each
Notes
- Keep repositories free of Flutter/UI imports
- Streams from Drift are reactive — repositories expose them directly to Riverpod providers