# Database Service Module A unified database abstraction layer implementing the Strategy pattern for flexible data persistence in the RxMinder application. ## Overview This module provides a clean, consistent interface for all database operations while supporting multiple backend implementations. It automatically selects the appropriate strategy based on environment configuration. ## Architecture ``` services/database/ ├── README.md # This file ├── index.ts # Public exports ├── types.ts # Type definitions and interfaces ├── DatabaseService.ts # Main service class (Strategy Context) ├── MockDatabaseStrategy.ts # In-memory implementation ├── ProductionDatabaseStrategy.ts # CouchDB implementation └── __tests__/ # Test files ├── DatabaseService.test.ts └── MockDatabaseStrategy.test.ts ``` ## Quick Start ```typescript import { databaseService } from './services/database'; // Service automatically selects appropriate strategy const users = await databaseService.getAllUsers(); const user = await databaseService.getUserById('user123'); ``` ## Strategy Selection The service automatically chooses the implementation based on environment: | Environment | Strategy | Backend | | ---------------------- | -------------------------- | --------- | | `NODE_ENV=test` | MockDatabaseStrategy | In-memory | | CouchDB URL configured | ProductionDatabaseStrategy | CouchDB | | Default/Fallback | MockDatabaseStrategy | In-memory | ## Environment Variables ```bash # Production CouchDB VITE_COUCHDB_URL=http://localhost:5984 COUCHDB_URL=http://localhost:5984 # Force mock strategy (optional) VITE_COUCHDB_URL=mock ``` ## Core Interfaces ### DatabaseStrategy All implementations must conform to this interface: ```typescript interface DatabaseStrategy { // User operations createUser(user: Omit): Promise; updateUser(user: User): Promise; getUserById(id: string): Promise; findUserByEmail(email: string): Promise; deleteUser(id: string): Promise; getAllUsers(): Promise; // Auth operations createUserWithPassword(email: string, hashedPassword: string, username?: string): Promise; createUserFromOAuth(email: string, username: string, provider: string): Promise; // Medication operations createMedication(userId: string, medication: Omit): Promise; updateMedication(medication: Medication): Promise; getMedications(userId: string): Promise; deleteMedication(id: string): Promise; // Settings operations getUserSettings(userId: string): Promise; updateUserSettings(settings: UserSettings): Promise; // Doses operations getTakenDoses(userId: string): Promise; updateTakenDoses(takenDoses: TakenDoses): Promise; // Reminders operations createCustomReminder(userId: string, reminder: Omit): Promise; updateCustomReminder(reminder: CustomReminder): Promise; getCustomReminders(userId: string): Promise; deleteCustomReminder(id: string): Promise; } ``` ## Implementations ### MockDatabaseStrategy **Use Cases:** - Development environment - Unit testing - Integration testing - Demos and prototyping **Features:** - In-memory storage using Maps - Immediate consistency - No network dependencies - Automatic data reset between tests - Fast operations **Limitations:** - Data lost on application restart - No persistence across sessions - Single-process only ### ProductionDatabaseStrategy **Use Cases:** - Production deployments - Staging environments - Data persistence requirements **Features:** - CouchDB backend - Persistent storage - Document versioning with `_rev` - ACID compliance - Horizontal scaling support **Requirements:** - CouchDB server running - Network connectivity - Proper authentication/authorization ## Usage Examples ### Basic Operations ```typescript import { databaseService } from './services/database'; // Create a user const user = await databaseService.createUser({ _id: 'user123', username: 'john_doe', email: 'john@example.com', role: UserRole.USER, status: AccountStatus.ACTIVE, }); // Add medication const medication = await databaseService.createMedication(user._id, { name: 'Aspirin', dosage: '100mg', frequency: Frequency.Daily, startTime: '08:00', }); // Update user settings const settings = await databaseService.getUserSettings(user._id); await databaseService.updateUserSettings({ ...settings, notificationsEnabled: true, }); ``` ### Administrative Operations ```typescript // User management await databaseService.suspendUser('user123'); await databaseService.activateUser('user123'); await databaseService.changeUserPassword('user123', 'new_hashed_password'); // Complete data deletion await databaseService.deleteAllUserData('user123'); ``` ### Strategy Inspection ```typescript // Check active strategy console.log('Strategy:', databaseService.getStrategyType()); // Strategy-specific logic (avoid when possible) if (databaseService.isUsingMockStrategy()) { console.log('Using in-memory storage'); } else if (databaseService.isUsingProductionStrategy()) { console.log('Using CouchDB storage'); } ``` ## Testing ### Unit Tests ```typescript import { DatabaseService } from './DatabaseService'; import { MockDatabaseStrategy } from './MockDatabaseStrategy'; describe('DatabaseService', () => { let service: DatabaseService; beforeEach(() => { // In test environment, automatically uses MockDatabaseStrategy service = new DatabaseService(); }); test('should create user', async () => { const user = await service.createUser(mockUser); expect(user._id).toBeDefined(); expect(user.username).toBe(mockUser.username); }); }); ``` ### Test Utilities ```typescript import { testUtils } from '../../tests/setup'; const mockUser = testUtils.createMockUser(); const mockMedication = testUtils.createMockMedication(); ``` ## Error Handling ### DatabaseError ```typescript import { DatabaseError } from './services/database'; try { const user = await databaseService.getUserById('invalid-id'); } catch (error) { if (error instanceof DatabaseError) { console.error('Database operation failed:', error.message); } } ``` ### Fallback Behavior ```typescript // Service automatically falls back to MockDatabaseStrategy // if ProductionDatabaseStrategy fails to initialize const service = new DatabaseService(); // Safe to use ``` ## Performance ### MockDatabaseStrategy - **Pros:** Instant operations, no I/O overhead - **Cons:** Memory usage grows with data size - **Best for:** Development, testing, small datasets ### ProductionDatabaseStrategy - **Pros:** Persistent storage, designed for scale - **Cons:** Network latency, connection overhead - **Best for:** Production, large datasets, multi-user ## Security ### Data Isolation - Users can only access their own data - User ID validation on all operations - Role-based access for administrative functions ### Input Validation - TypeScript interfaces enforce type safety - Required field validation - Email format validation - ID format validation ### Authentication - No anonymous access allowed - User context required for all operations - Password hashing handled by auth service ## Migration Guide ### From Legacy CouchDB Service ```typescript // Old import import { couchdbService } from './services/couchdb'; // New import import { databaseService } from './services/database'; // Old method signature await couchdbService.updateMedication(userId, medication); // New method signature await databaseService.updateMedication(medication); ``` ### Breaking Changes 1. **Method signatures:** Some methods now accept the full entity instead of separate parameters 2. **Return types:** Consistent return types across all operations 3. **Error handling:** Unified error types with `DatabaseError` ## Troubleshooting ### Common Issues **1. Strategy Selection** ```bash # Check environment variables echo $VITE_COUCHDB_URL echo $NODE_ENV # Verify strategy selection console.log(databaseService.getStrategyType()); ``` **2. CouchDB Connection** ```bash # Test CouchDB connectivity curl $VITE_COUCHDB_URL # Check CouchDB logs docker logs couchdb-container ``` **3. Test Environment** ```bash # Ensure test environment NODE_ENV=test npm test # Verify mock strategy in tests expect(databaseService.isUsingMockStrategy()).toBe(true); ``` ### Debug Logging ```typescript // Enable debug information const strategy = databaseService.getStrategyType(); console.log(`Using ${strategy} for database operations`); // Check environment console.log('Environment:', process.env.NODE_ENV); console.log('CouchDB URL:', process.env.VITE_COUCHDB_URL); ``` ## Development ### Adding New Operations 1. **Update DatabaseStrategy interface** in `types.ts` 2. **Implement in MockDatabaseStrategy** 3. **Implement in ProductionDatabaseStrategy** 4. **Add delegation method** in `DatabaseService` 5. **Write tests** for all implementations 6. **Update documentation** ### Creating New Strategies ```typescript class CustomDatabaseStrategy implements DatabaseStrategy { // Implement all required methods async createUser(user: Omit): Promise { // Custom implementation } // ... implement all other methods } ``` ## Contributing 1. **Tests required** for all new features 2. **Type safety** - no `any` types 3. **Error handling** - proper error propagation 4. **Documentation** - update README and JSDoc 5. **Strategy pattern** - maintain abstraction ## Dependencies ### Production - None (strategy implementations may have their own) ### Development - `@types/jest` - Testing types - `ts-jest` - TypeScript testing - `@testing-library/react` - Component testing ## Changelog ### v2.0.0 - ✅ Unified database service with Strategy pattern - ✅ Removed legacy CouchDB service files - ✅ Added comprehensive test coverage - ✅ Improved error handling - ✅ TypeScript strict mode compliance ### v1.x.x - ❌ Legacy CouchDB-only implementation (deprecated) --- **Maintainers:** Development Team **Last Updated:** January 2024 **License:** MIT