104 lines
3.8 KiB
TypeScript
104 lines
3.8 KiB
TypeScript
|
|
import { IApiRepository } from '../repositories/IApiRepository';
|
||
|
|
import { IEntityService } from '../storage/IEntityService';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* DataSeeder - Orchestrates initial data loading from repositories into IndexedDB
|
||
|
|
*
|
||
|
|
* ARCHITECTURE:
|
||
|
|
* - Repository (Mock/Api): Fetches data from source (JSON file or backend API)
|
||
|
|
* - DataSeeder (this class): Orchestrates fetch + save operations
|
||
|
|
* - Service (EventService, etc.): Saves data to IndexedDB
|
||
|
|
*
|
||
|
|
* SEPARATION OF CONCERNS:
|
||
|
|
* - Repository does NOT know about IndexedDB or storage
|
||
|
|
* - Service does NOT know about where data comes from
|
||
|
|
* - DataSeeder connects them together
|
||
|
|
*
|
||
|
|
* POLYMORPHIC DESIGN:
|
||
|
|
* - Uses arrays of IEntityService<any>[] and IApiRepository<any>[]
|
||
|
|
* - Matches services with repositories using entityType property
|
||
|
|
* - Open/Closed Principle: Adding new entity requires no code changes here
|
||
|
|
*
|
||
|
|
* USAGE:
|
||
|
|
* Called once during app initialization in index.ts:
|
||
|
|
* 1. IndexedDBService.initialize() - open database
|
||
|
|
* 2. dataSeeder.seedIfEmpty() - load initial data if needed
|
||
|
|
* 3. CalendarManager.initialize() - start calendar
|
||
|
|
*
|
||
|
|
* NOTE: This is for INITIAL SEEDING only. Ongoing sync is handled by SyncManager.
|
||
|
|
*/
|
||
|
|
export class DataSeeder {
|
||
|
|
constructor(
|
||
|
|
// Arrays injected via DI - automatically includes all registered services/repositories
|
||
|
|
private services: IEntityService<any>[],
|
||
|
|
private repositories: IApiRepository<any>[]
|
||
|
|
) {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Seed all entity stores if they are empty
|
||
|
|
* Runs on app initialization to load initial data from repositories
|
||
|
|
*
|
||
|
|
* Uses polymorphism: loops through all services and matches with repositories by entityType
|
||
|
|
*/
|
||
|
|
async seedIfEmpty(): Promise<void> {
|
||
|
|
console.log('[DataSeeder] Checking if database needs seeding...');
|
||
|
|
|
||
|
|
try {
|
||
|
|
// Loop through all entity services (Event, Booking, Customer, Resource, etc.)
|
||
|
|
for (const service of this.services) {
|
||
|
|
// Find matching repository for this service based on entityType
|
||
|
|
const repository = this.repositories.find(repo => repo.entityType === service.entityType);
|
||
|
|
|
||
|
|
if (!repository) {
|
||
|
|
console.warn(`[DataSeeder] No repository found for entity type: ${service.entityType}, skipping`);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Seed this entity type
|
||
|
|
await this.seedEntity(service.entityType, service, repository);
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('[DataSeeder] Seeding complete');
|
||
|
|
} catch (error) {
|
||
|
|
console.error('[DataSeeder] Seeding failed:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Generic method to seed a single entity type
|
||
|
|
*
|
||
|
|
* @param entityType - Entity type ('Event', 'Booking', 'Customer', 'Resource')
|
||
|
|
* @param service - Entity service for IndexedDB operations
|
||
|
|
* @param repository - Repository for fetching data
|
||
|
|
*/
|
||
|
|
private async seedEntity<T>(
|
||
|
|
entityType: string,
|
||
|
|
service: IEntityService<any>,
|
||
|
|
repository: IApiRepository<T>
|
||
|
|
): Promise<void> {
|
||
|
|
// Check if store is empty
|
||
|
|
const existing = await service.getAll();
|
||
|
|
|
||
|
|
if (existing.length > 0) {
|
||
|
|
console.log(`[DataSeeder] ${entityType} store already has ${existing.length} items, skipping seed`);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(`[DataSeeder] ${entityType} store is empty, fetching from repository...`);
|
||
|
|
|
||
|
|
// Fetch from repository (Mock JSON or backend API)
|
||
|
|
const data = await repository.fetchAll();
|
||
|
|
|
||
|
|
console.log(`[DataSeeder] Fetched ${data.length} ${entityType} items, saving to IndexedDB...`);
|
||
|
|
|
||
|
|
// Save each entity to IndexedDB
|
||
|
|
// Note: Entities from repository should already have syncStatus='synced'
|
||
|
|
for (const entity of data) {
|
||
|
|
await service.save(entity);
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(`[DataSeeder] ${entityType} seeding complete (${data.length} items saved)`);
|
||
|
|
}
|
||
|
|
}
|