init cc
This commit is contained in:
369
lib/core/database/README.md
Normal file
369
lib/core/database/README.md
Normal file
@@ -0,0 +1,369 @@
|
||||
# Hive Database Configuration
|
||||
|
||||
This directory contains the complete Hive database setup for local storage and caching in the Flutter app.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
The Hive database system is organized into the following components:
|
||||
|
||||
```
|
||||
lib/core/database/
|
||||
├── hive_service.dart # Hive initialization and box management
|
||||
├── models/
|
||||
│ ├── app_settings.dart # App settings model with Hive adapter
|
||||
│ ├── app_settings.g.dart # Generated Hive adapter
|
||||
│ ├── cache_item.dart # Generic cache wrapper model
|
||||
│ ├── cache_item.g.dart # Generated Hive adapter
|
||||
│ ├── user_preferences.dart # User preferences model
|
||||
│ └── user_preferences.g.dart # Generated Hive adapter
|
||||
├── repositories/
|
||||
│ ├── settings_repository.dart # Settings repository implementation
|
||||
│ ├── cache_repository.dart # Cache repository implementation
|
||||
│ └── user_preferences_repository.dart # User preferences repository
|
||||
├── providers/
|
||||
│ └── database_providers.dart # Riverpod providers for database access
|
||||
└── examples/
|
||||
└── database_usage_example.dart # Usage examples
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
### 1. HiveService
|
||||
- **Initialization**: Sets up Hive for Flutter and registers type adapters
|
||||
- **Box Management**: Manages three main boxes (appSettingsBox, cacheBox, userDataBox)
|
||||
- **Migration Support**: Handles database schema migrations
|
||||
- **Error Handling**: Comprehensive error handling and logging
|
||||
- **Maintenance**: Database compaction and cleanup utilities
|
||||
|
||||
### 2. Models with Type Adapters
|
||||
|
||||
#### AppSettings (TypeId: 0)
|
||||
- Application-wide configuration
|
||||
- Theme mode, locale, notifications
|
||||
- Cache settings and auto-update preferences
|
||||
- Custom settings support
|
||||
- Expiration logic for settings refresh
|
||||
|
||||
#### CacheItem (TypeId: 1)
|
||||
- Generic cache wrapper for any data type
|
||||
- Expiration logic with TTL support
|
||||
- Metadata support for cache categorization
|
||||
- Version control for cache migrations
|
||||
- Statistics and performance monitoring
|
||||
|
||||
#### UserPreferences (TypeId: 2)
|
||||
- User-specific settings and data
|
||||
- Favorites management
|
||||
- Last accessed tracking
|
||||
- Preference categories with type safety
|
||||
- User activity statistics
|
||||
|
||||
### 3. Repository Pattern
|
||||
- **SettingsRepository**: Application settings management
|
||||
- **CacheRepository**: Generic caching with TTL and expiration
|
||||
- **UserPreferencesRepository**: User-specific data management
|
||||
|
||||
### 4. Riverpod Integration
|
||||
- State management with providers
|
||||
- Reactive updates when data changes
|
||||
- Type-safe access to cached data
|
||||
- Automatic cache invalidation
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Initialization
|
||||
```dart
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// Initialize Hive database service
|
||||
await HiveService.initialize();
|
||||
|
||||
runApp(const ProviderScope(child: MyApp()));
|
||||
}
|
||||
```
|
||||
|
||||
### Settings Management
|
||||
```dart
|
||||
class SettingsScreen extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final settings = ref.watch(appSettingsProvider);
|
||||
final notifier = ref.read(appSettingsProvider.notifier);
|
||||
|
||||
return SwitchListTile(
|
||||
title: const Text('Dark Mode'),
|
||||
value: settings.themeMode == 'dark',
|
||||
onChanged: (value) => notifier.updateThemeMode(value ? 'dark' : 'light'),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Caching Data
|
||||
```dart
|
||||
class DataService {
|
||||
final CacheRepository _cache;
|
||||
|
||||
Future<UserData> getUserData(String userId) async {
|
||||
// Try cache first
|
||||
final cachedData = _cache.get<UserData>('user_$userId');
|
||||
if (cachedData != null) {
|
||||
return cachedData;
|
||||
}
|
||||
|
||||
// Fetch from API
|
||||
final userData = await api.fetchUserData(userId);
|
||||
|
||||
// Cache with 1 hour expiration
|
||||
await _cache.put<UserData>(
|
||||
key: 'user_$userId',
|
||||
data: userData,
|
||||
expirationDuration: const Duration(hours: 1),
|
||||
metadata: {'type': 'user_data', 'userId': userId},
|
||||
);
|
||||
|
||||
return userData;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### User Preferences
|
||||
```dart
|
||||
class ProfileScreen extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final preferences = ref.watch(userPreferencesProvider(null));
|
||||
final notifier = ref.read(userPreferencesProvider(null).notifier);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
SwitchListTile(
|
||||
title: const Text('Compact Mode'),
|
||||
value: preferences?.getPreference<bool>('compactMode', false) ?? false,
|
||||
onChanged: (value) => notifier.setPreference('compactMode', value),
|
||||
),
|
||||
// Favorites management
|
||||
IconButton(
|
||||
icon: Icon(preferences?.isFavorite('item123') == true
|
||||
? Icons.favorite : Icons.favorite_border),
|
||||
onPressed: () {
|
||||
if (preferences?.isFavorite('item123') == true) {
|
||||
notifier.removeFavorite('item123');
|
||||
} else {
|
||||
notifier.addFavorite('item123');
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Database Boxes
|
||||
|
||||
### appSettingsBox
|
||||
- **Purpose**: Application-wide settings
|
||||
- **Key**: String-based keys (e.g., 'app_settings')
|
||||
- **Data**: AppSettings objects
|
||||
- **Usage**: Theme, language, cache strategy, feature flags
|
||||
|
||||
### cacheBox
|
||||
- **Purpose**: Generic caching with TTL
|
||||
- **Key**: String-based cache keys
|
||||
- **Data**: CacheItem objects wrapping any data type
|
||||
- **Usage**: API responses, user data, computed values
|
||||
|
||||
### userDataBox
|
||||
- **Purpose**: User-specific preferences and data
|
||||
- **Key**: User ID or 'current_user_preferences' for default
|
||||
- **Data**: UserPreferences objects
|
||||
- **Usage**: User settings, favorites, activity tracking
|
||||
|
||||
## Cache Strategies
|
||||
|
||||
### Write-Through Cache
|
||||
```dart
|
||||
Future<void> updateUserData(UserData data) async {
|
||||
// Update API
|
||||
await api.updateUser(data);
|
||||
|
||||
// Update cache
|
||||
await cacheRepository.put<UserData>(
|
||||
key: 'user_${data.id}',
|
||||
data: data,
|
||||
expirationDuration: const Duration(hours: 1),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Cache-Aside Pattern
|
||||
```dart
|
||||
Future<UserData> getUserData(String userId) async {
|
||||
// Check cache first
|
||||
var userData = cacheRepository.get<UserData>('user_$userId');
|
||||
|
||||
if (userData == null) {
|
||||
// Cache miss - fetch from API
|
||||
userData = await api.fetchUser(userId);
|
||||
|
||||
// Store in cache
|
||||
await cacheRepository.put<UserData>(
|
||||
key: 'user_$userId',
|
||||
data: userData,
|
||||
expirationDuration: const Duration(minutes: 30),
|
||||
);
|
||||
}
|
||||
|
||||
return userData;
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
### 1. Lazy Loading
|
||||
- Boxes are opened only when needed
|
||||
- Data is loaded on-demand
|
||||
|
||||
### 2. Batch Operations
|
||||
```dart
|
||||
Future<void> cacheMultipleItems(Map<String, dynamic> items) async {
|
||||
final futures = items.entries.map((entry) =>
|
||||
cacheRepository.put<dynamic>(
|
||||
key: entry.key,
|
||||
data: entry.value,
|
||||
expirationDuration: const Duration(hours: 1),
|
||||
)
|
||||
);
|
||||
|
||||
await Future.wait(futures);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Cache Maintenance
|
||||
```dart
|
||||
// Automatic cleanup of expired items
|
||||
final result = await cacheRepository.performMaintenance();
|
||||
print('Cleaned ${result['expiredItemsRemoved']} expired items');
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Repository Level
|
||||
- All repository methods have comprehensive try-catch blocks
|
||||
- Errors are logged with stack traces
|
||||
- Graceful degradation (return defaults on errors)
|
||||
|
||||
### Provider Level
|
||||
- State management handles loading/error states
|
||||
- Automatic retry mechanisms
|
||||
- User-friendly error messages
|
||||
|
||||
### Service Level
|
||||
- Database initialization errors are handled gracefully
|
||||
- Box corruption recovery
|
||||
- Migration failure handling
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Version Control
|
||||
```dart
|
||||
class AppSettings {
|
||||
final int version; // Used for migrations
|
||||
|
||||
// Migration logic in repository
|
||||
AppSettings _migrateSettings(AppSettings oldSettings) {
|
||||
if (oldSettings.version < 2) {
|
||||
// Perform migration to version 2
|
||||
return oldSettings.copyWith(
|
||||
version: 2,
|
||||
// Add new fields with defaults
|
||||
newField: defaultValue,
|
||||
);
|
||||
}
|
||||
return oldSettings;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Data Backup
|
||||
```dart
|
||||
// Export data before migration
|
||||
final backup = settingsRepository.exportSettings();
|
||||
final userBackup = userPreferencesRepository.exportUserPreferences();
|
||||
|
||||
// Perform migration
|
||||
await HiveService.migrate();
|
||||
|
||||
// Restore if migration fails
|
||||
if (migrationFailed) {
|
||||
await settingsRepository.importSettings(backup);
|
||||
await userPreferencesRepository.importUserPreferences(userBackup);
|
||||
}
|
||||
```
|
||||
|
||||
## Monitoring and Analytics
|
||||
|
||||
### Database Statistics
|
||||
```dart
|
||||
final stats = ref.watch(databaseStatsProvider);
|
||||
print('Total items: ${stats['totalItems']}');
|
||||
print('Cache hit rate: ${stats['cache']['hitRate']}%');
|
||||
```
|
||||
|
||||
### Performance Metrics
|
||||
```dart
|
||||
final cacheStats = await cacheRepository.getStats();
|
||||
print('Cache performance:');
|
||||
print('- Hit rate: ${(cacheStats.hitRate * 100).toStringAsFixed(1)}%');
|
||||
print('- Valid items: ${cacheStats.validItems}');
|
||||
print('- Expired items: ${cacheStats.expiredItems}');
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Key Naming Convention
|
||||
- Use descriptive, hierarchical keys: `user_123_profile`
|
||||
- Include type information: `api_response_movies_popular`
|
||||
- Use consistent separators: underscores or colons
|
||||
|
||||
### 2. TTL Management
|
||||
- Short TTL for frequently changing data (5-30 minutes)
|
||||
- Medium TTL for stable data (1-24 hours)
|
||||
- Long TTL for static data (1-7 days)
|
||||
- Permanent cache only for user preferences
|
||||
|
||||
### 3. Data Validation
|
||||
- Validate data before caching
|
||||
- Check data integrity on retrieval
|
||||
- Handle corrupted data gracefully
|
||||
|
||||
### 4. Memory Management
|
||||
- Regular cleanup of expired items
|
||||
- Monitor cache size and performance
|
||||
- Use appropriate data structures
|
||||
|
||||
### 5. Security
|
||||
- Don't cache sensitive data without encryption
|
||||
- Clear caches on logout
|
||||
- Validate user access to cached data
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- Test repository methods with mock boxes
|
||||
- Validate data serialization/deserialization
|
||||
- Test error handling scenarios
|
||||
|
||||
### Integration Tests
|
||||
- Test full database workflows
|
||||
- Validate Riverpod provider interactions
|
||||
- Test migration scenarios
|
||||
|
||||
### Performance Tests
|
||||
- Measure cache hit rates
|
||||
- Test with large datasets
|
||||
- Monitor memory usage
|
||||
|
||||
This Hive database setup provides a robust, scalable foundation for local data storage and caching in your Flutter application.
|
||||
Reference in New Issue
Block a user