mirror of
https://github.com/DocNR/POWR.git
synced 2025-06-06 18:31:03 +00:00

Implements database tables and services for workout and template storage: - Updates schema to version 5 with new workout and template tables - Adds WorkoutService for CRUD operations on workouts - Enhances TemplateService for template management - Creates NostrWorkoutService for bidirectional Nostr event handling - Implements React hooks for database access - Connects workout store to database layer for persistence - Improves offline support with publication queue This change ensures workouts and templates are properly saved to SQLite and can be referenced across app sessions, while maintaining Nostr integration for social sharing.
231 lines
7.1 KiB
TypeScript
231 lines
7.1 KiB
TypeScript
// lib/db/services/DevSeederService.ts
|
|
import { SQLiteDatabase } from 'expo-sqlite';
|
|
import { ExerciseService } from './ExerciseService';
|
|
import { EventCache } from '@/lib/db/services/EventCache';
|
|
import { WorkoutService } from './WorkoutService';
|
|
import { TemplateService } from './TemplateService';
|
|
import { logDatabaseInfo } from '../debug';
|
|
import { mockExerciseEvents, convertNostrToExercise } from '../../mocks/exercises';
|
|
import { DbService } from '../db-service';
|
|
import NDK, { NDKEvent } from '@nostr-dev-kit/ndk-mobile';
|
|
|
|
export class DevSeederService {
|
|
private db: SQLiteDatabase;
|
|
private dbService: DbService;
|
|
private exerciseService: ExerciseService;
|
|
private workoutService: WorkoutService | null = null;
|
|
private templateService: TemplateService | null = null;
|
|
private eventCache: EventCache | null = null;
|
|
private ndk: NDK | null = null;
|
|
|
|
constructor(
|
|
db: SQLiteDatabase,
|
|
exerciseService: ExerciseService
|
|
) {
|
|
this.db = db;
|
|
this.dbService = new DbService(db);
|
|
this.exerciseService = exerciseService;
|
|
|
|
// Try to initialize other services if needed
|
|
try {
|
|
this.workoutService = new WorkoutService(db);
|
|
this.templateService = new TemplateService(db);
|
|
this.eventCache = new EventCache(db);
|
|
} catch (error) {
|
|
console.log('Some services not available yet:', error);
|
|
}
|
|
}
|
|
|
|
setNDK(ndk: NDK) {
|
|
this.ndk = ndk;
|
|
}
|
|
|
|
async seedDatabase() {
|
|
if (!__DEV__) return;
|
|
|
|
try {
|
|
console.log('Starting development database seeding...');
|
|
|
|
// Log initial database state
|
|
await logDatabaseInfo();
|
|
|
|
// Check if we already have exercises
|
|
const existingCount = (await this.exerciseService.getAllExercises()).length;
|
|
|
|
if (existingCount > 0) {
|
|
console.log('Database already seeded with', existingCount, 'exercises');
|
|
} else {
|
|
// Start transaction for all seeding operations
|
|
await this.db.withTransactionAsync(async () => {
|
|
console.log('Seeding mock exercises...');
|
|
|
|
// Process all events within the same transaction
|
|
for (const eventData of mockExerciseEvents) {
|
|
if (this.ndk) {
|
|
// If NDK is available, use it to cache the event
|
|
const event = new NDKEvent(this.ndk);
|
|
Object.assign(event, eventData);
|
|
|
|
// Cache the event in NDK
|
|
const ndkEvent = new NDKEvent(this.ndk);
|
|
|
|
// Copy event properties
|
|
ndkEvent.kind = eventData.kind;
|
|
ndkEvent.content = eventData.content;
|
|
ndkEvent.created_at = eventData.created_at;
|
|
ndkEvent.tags = eventData.tags;
|
|
|
|
// If we have mock signatures, use them
|
|
if (eventData.sig) {
|
|
ndkEvent.sig = eventData.sig;
|
|
ndkEvent.id = eventData.id || '';
|
|
ndkEvent.pubkey = eventData.pubkey || '';
|
|
} else if (this.ndk.signer) {
|
|
// Otherwise sign if possible
|
|
await ndkEvent.sign();
|
|
}
|
|
}
|
|
|
|
// Cache the event if possible
|
|
if (this.eventCache) {
|
|
try {
|
|
await this.eventCache.setEvent(eventData, true);
|
|
} catch (error) {
|
|
console.log('Error caching event:', error);
|
|
}
|
|
}
|
|
|
|
// Create exercise from the mock data regardless of NDK availability
|
|
const exercise = convertNostrToExercise(eventData);
|
|
await this.exerciseService.createExercise(exercise, true);
|
|
}
|
|
|
|
console.log('Successfully seeded', mockExerciseEvents.length, 'exercises');
|
|
});
|
|
}
|
|
|
|
// Seed workout and template tables
|
|
await this.seedWorkoutTables();
|
|
await this.seedTemplates();
|
|
|
|
// Log final database state
|
|
await logDatabaseInfo();
|
|
|
|
} catch (error) {
|
|
console.error('Error seeding database:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async seedWorkoutTables() {
|
|
if (!__DEV__) return;
|
|
|
|
try {
|
|
console.log('Checking workout tables seeding...');
|
|
|
|
// Check if we already have workout data
|
|
try {
|
|
const hasWorkouts = await this.dbService.getFirstAsync<{ count: number }>(
|
|
'SELECT COUNT(*) as count FROM workouts'
|
|
);
|
|
|
|
if (hasWorkouts && hasWorkouts.count > 0) {
|
|
console.log('Workout tables already seeded with', hasWorkouts.count, 'workouts');
|
|
return;
|
|
}
|
|
|
|
console.log('No workout data found, but tables should be created');
|
|
|
|
// Optional: Add mock workout data here
|
|
// if (this.workoutService) {
|
|
// // Create mock workouts
|
|
// // await this.workoutService.saveWorkout(mockWorkout);
|
|
// }
|
|
} catch (error) {
|
|
console.log('Workout tables may not exist yet - will be created in schema update');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error checking workout tables:', error);
|
|
}
|
|
}
|
|
|
|
async seedTemplates() {
|
|
if (!__DEV__) return;
|
|
|
|
try {
|
|
console.log('Checking template tables seeding...');
|
|
|
|
// Check if templates table exists and has data
|
|
try {
|
|
const hasTemplates = await this.dbService.getFirstAsync<{ count: number }>(
|
|
'SELECT COUNT(*) as count FROM templates'
|
|
);
|
|
|
|
if (hasTemplates && hasTemplates.count > 0) {
|
|
console.log('Template tables already seeded with', hasTemplates.count, 'templates');
|
|
return;
|
|
}
|
|
|
|
console.log('No template data found, but tables should be created');
|
|
|
|
// Optional: Add mock template data here
|
|
// if (this.templateService) {
|
|
// // Create mock templates
|
|
// // await this.templateService.createTemplate(mockTemplate);
|
|
// }
|
|
} catch (error) {
|
|
console.log('Template tables may not exist yet - will be created in schema update');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error checking template tables:', error);
|
|
}
|
|
}
|
|
|
|
async clearDatabase() {
|
|
if (!__DEV__) return;
|
|
|
|
try {
|
|
console.log('Clearing development database...');
|
|
|
|
await this.db.withTransactionAsync(async () => {
|
|
const tables = [
|
|
// Original tables
|
|
'exercises',
|
|
'exercise_tags',
|
|
'nostr_events',
|
|
'event_tags',
|
|
'cache_metadata',
|
|
'ndk_cache',
|
|
|
|
// New tables
|
|
'workouts',
|
|
'workout_exercises',
|
|
'workout_sets',
|
|
'templates',
|
|
'template_exercises'
|
|
];
|
|
|
|
for (const table of tables) {
|
|
try {
|
|
await this.db.runAsync(`DELETE FROM ${table}`);
|
|
console.log(`Cleared table: ${table}`);
|
|
} catch (error) {
|
|
console.log(`Table ${table} might not exist yet, skipping`);
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log('Successfully cleared database');
|
|
} catch (error) {
|
|
console.error('Error clearing database:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async resetDatabase() {
|
|
if (!__DEV__) return;
|
|
|
|
await this.clearDatabase();
|
|
await this.seedDatabase();
|
|
}
|
|
} |