-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
Overview
Refactor the db_client package to decouple domain models from Drift implementation, enabling database technology swap (e.g., Drift → Isar/Hive) while maintaining OSS project maintainability. Use @UseRowClass pattern to eliminate conversion overhead while keeping domain models as pure Dart classes.
Requirements
Domain Model Definition
- Create pure Dart domain model classes independent of database implementation
Diaryclass withid,content,datefieldsDiaryImageclass withid,diaryId,photoIdfields
- Place models in
lib/src/models/directory - Implement
==,hashCode,toStringfor each model - Use immutable design with
constconstructors - No database-specific annotations or dependencies
Abstract Interface
- Define abstract
DbClientinterface for database operations - Return domain models (
Diary,DiaryImage) instead of Drift-generated classes - Support all current database operations:
- CRUD operations for diaries and diary images
- Date range queries with JOIN support
- Full-text search
- Backup/restore functionality
- Place interface in
lib/src/db_client.dart
Drift Implementation with @UseRowClass
- Apply
@UseRowClass(Diary)toDiariestable definition - Apply
@UseRowClass(DiaryImage)toDiaryImagestable definition - Rename current
DbClientclass toDriftDbClient - Make
DriftDbClientimplement abstractDbClientinterface - Eliminate conversion code between Drift entities and domain models
- Organize Drift-specific code under
lib/src/drift/directory
Package Structure
packages/core/db_client/
lib/
src/
models/ # Pure domain models (DB-agnostic)
diary.dart
diary_image.dart
db_client.dart # Abstract interface
drift/ # Drift implementation (internal)
drift_db_client.dart
tables.dart
db_client.steps.dart
connection/
db_client.dart # Public API exports
Public API Design
- Export domain models from
db_clientpackage - Export abstract
DbClientinterface - Export
DriftDbClientconcrete implementation - Hide Drift-specific implementation details (tables, migrations)
- Follow API client pattern: one model class, multiple implementations
Migration Steps
Phase 1: Create Domain Models
- Create
lib/src/models/diary.dart - Create
lib/src/models/diary_image.dart - Define as pure Dart classes
Phase 2: Create Abstract Interface
- Create abstract
DbClientinterface - Rename existing
DbClienttoDriftDbClient - Make
DriftDbClientimplementDbClient
Phase 3: Apply @UseRowClass
- Add
@UseRowClass(Diary)toDiariestable - Add
@UseRowClass(DiaryImage)toDiaryImagestable - Run
dart run build_runner build
Phase 4: Update Implementation
- Verify Drift generates code using domain models
- Remove conversion/mapping code
- Update method signatures to use domain models
Phase 5: Update Dependent Packages
- Verify
features/diaryworks without changes - Verify
apppackage works without changes - Run all tests
Phase 6: Clean Up Public API
- Update
lib/db_client.dartexports - Remove unnecessary exports
Testing Requirements
- Existing tests continue to work without modification
- Add tests for domain model equality and toString
- Add interface contract tests
- Add integration tests for Drift implementation
- Maintain 100% test coverage for db_client package
Future Database Swap Support
- Design allows adding new implementations (e.g.,
IsarDbClient) - Conversion code only needed within new implementation
- No changes required in
features/orapp/packages - Domain models remain unchanged across implementations
Benefits
Immediate Benefits
- No conversion overhead (via @UseRowClass)
- Cleaner codebase with separated concerns
- Domain models are pure Dart classes
- Easier to understand for OSS contributors
Long-term Benefits
- Database technology can be swapped
- Conversion code isolated to implementation layer
- Features/app packages unchanged during DB migration
- Tests remain valid across implementations
- Gradual migration possible (old and new implementations can coexist)
Technical Constraints
@UseRowClass Requirements
- Class fields must match table columns
- Constructor must accept all fields (positional or named)
- Not an issue for simple CRUD operations
When Conversion May Be Needed
- If future requirements need complex mapping between normalized DB schema and denormalized domain models
- Can add conversion layer incrementally when needed
References
- Drift Documentation - Custom Row Classes
- API client pattern analogy: Same model class, different client implementations
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels