removed mock data! using powr pack to seed library

This commit is contained in:
DocNR 2025-03-13 23:07:09 -04:00
parent 5b706b3894
commit 80bdb87fdc
4 changed files with 24 additions and 667 deletions

View File

@ -3,7 +3,6 @@ import { View, ActivityIndicator, ScrollView, Text } from 'react-native';
import { SQLiteProvider, openDatabaseSync, SQLiteDatabase } from 'expo-sqlite';
import { schema } from '@/lib/db/schema';
import { ExerciseService } from '@/lib/db/services/ExerciseService';
import { DevSeederService } from '@/lib/db/services/DevSeederService';
import { PublicationQueueService } from '@/lib/db/services/PublicationQueueService';
import { FavoritesService } from '@/lib/db/services/FavoritesService';
import { WorkoutService } from '@/lib/db/services/WorkoutService';
@ -17,7 +16,6 @@ interface DatabaseServicesContextValue {
exerciseService: ExerciseService | null;
workoutService: WorkoutService | null;
templateService: TemplateService | null;
devSeeder: DevSeederService | null;
publicationQueue: PublicationQueueService | null;
favoritesService: FavoritesService | null;
powrPackService: POWRPackService | null;
@ -28,7 +26,6 @@ const DatabaseServicesContext = React.createContext<DatabaseServicesContextValue
exerciseService: null,
workoutService: null,
templateService: null,
devSeeder: null,
publicationQueue: null,
favoritesService: null,
powrPackService: null,
@ -64,6 +61,7 @@ const DelayedInitializer: React.FC<{children: React.ReactNode}> = ({children}) =
return <>{children}</>;
};
export function DatabaseProvider({ children }: DatabaseProviderProps) {
const [isReady, setIsReady] = React.useState(false);
const [error, setError] = React.useState<string | null>(null);
@ -71,7 +69,6 @@ export function DatabaseProvider({ children }: DatabaseProviderProps) {
exerciseService: null,
workoutService: null,
templateService: null,
devSeeder: null,
publicationQueue: null,
favoritesService: null,
powrPackService: null,
@ -83,8 +80,7 @@ export function DatabaseProvider({ children }: DatabaseProviderProps) {
// Effect to set NDK on services when it becomes available
React.useEffect(() => {
if (ndk && services.devSeeder && services.publicationQueue) {
services.devSeeder.setNDK(ndk);
if (ndk && services.publicationQueue) {
services.publicationQueue.setNDK(ndk);
}
}, [ndk, services]);
@ -129,7 +125,6 @@ export function DatabaseProvider({ children }: DatabaseProviderProps) {
const exerciseService = new ExerciseService(db);
const workoutService = new WorkoutService(db);
const templateService = new TemplateService(db, exerciseService);
const devSeeder = new DevSeederService(db, exerciseService);
const publicationQueue = new PublicationQueueService(db);
const favoritesService = new FavoritesService(db);
const powrPackService = new POWRPackService(db);
@ -139,7 +134,6 @@ export function DatabaseProvider({ children }: DatabaseProviderProps) {
// Initialize NDK on services if available
if (ndk) {
devSeeder.setNDK(ndk);
publicationQueue.setNDK(ndk);
}
@ -148,21 +142,14 @@ export function DatabaseProvider({ children }: DatabaseProviderProps) {
exerciseService,
workoutService,
templateService,
devSeeder,
publicationQueue,
favoritesService,
powrPackService,
db,
});
// Seed development database
// Display database info in development mode
if (__DEV__) {
console.log('[DB] Seeding development database...');
try {
await devSeeder.seedDatabase();
} catch (seedError) {
console.error('[DB] Error seeding database:', seedError);
// Continue even if seeding fails
}
await logDatabaseInfo();
}
@ -231,14 +218,6 @@ export function useTemplateService() {
return context.templateService;
}
export function useDevSeeder() {
const context = React.useContext(DatabaseServicesContext);
if (!context.devSeeder) {
throw new Error('Dev seeder not initialized');
}
return context.devSeeder;
}
export function usePublicationQueue() {
const context = React.useContext(DatabaseServicesContext);
if (!context.publicationQueue) {
@ -269,4 +248,4 @@ export function useDatabase() {
throw new Error('Database not initialized');
}
return context.db;
}
}

View File

@ -13,77 +13,42 @@ import { PackageOpen, ArrowRight } from 'lucide-react-native';
import { NDKEvent } from '@nostr-dev-kit/ndk-mobile';
import { usePOWRPackService } from '@/components/DatabaseProvider';
import { Clipboard } from 'react-native';
// Hardcoded test pack naddr
const TEST_PACK_NADDR = 'naddr1qq88qmmhwgkhgetnwskhqctrdvqs6amnwvaz7tmwdaejumr0dsq3gamnwvaz7tmjv4kxz7fwv3sk6atn9e5k7q3q25f8lj0pcq7xk3v68w4h9ldenhh3v3x97gumm5yl8e0mgq0dnvssxpqqqp6ng325rsl';
import { nip19 } from 'nostr-tools';
export default function POWRPackSection() {
const { ndk } = useNDK();
const powrPackService = usePOWRPackService();
const [featuredPacks, setFeaturedPacks] = useState<NDKEvent[]>([]);
const [isLoading, setIsLoading] = useState(true);
// Subscribe to POWR packs (kind 30004 with powrpack hashtag)
const { events, isLoading: isSubscribeLoading } = useSubscribe(
ndk ? [{ kinds: [30004], '#t': ['powrpack'], limit: 10 }] : false,
const { events, isLoading } = useSubscribe(
ndk ? [{ kinds: [30004], '#t': ['powrpack', 'fitness', 'workout'], limit: 10 }] : false,
{ enabled: !!ndk }
);
// Set up test data on component mount
useEffect(() => {
const setupTestData = async () => {
try {
setIsLoading(true);
// For testing, create a mock event that mimics what we'd get from the network
const testPack = new NDKEvent(ndk || undefined);
testPack.kind = 30004;
testPack.pubkey = '55127fc9e1c03c6b459a3bab72fdb99def1644c5f239bdd09f3e5fb401ed9b21';
testPack.content = 'This is a test POWR Pack containing 2 workout templates and 2 exercises. Created for testing POWR Pack import functionality.';
testPack.id = 'c1838367545275c12a969b7f1b84c60edbaec548332bfb4af7e2d12926090211';
testPack.created_at = 1741832829;
// Add all the tags
testPack.tags = [
['d', 'powr-test-pack'],
['name', 'POWR Test Pack'],
['about', 'A test collection of workout templates and exercises for POWR app'],
['a', '33402:55127fc9e1c03c6b459a3bab72fdb99def1644c5f239bdd09f3e5fb401ed9b21:e8256e9f70b87ad9fc4cf5712fe8f61641fc1313c608c38525c81537b5b411a5'],
['a', '33402:55127fc9e1c03c6b459a3bab72fdb99def1644c5f239bdd09f3e5fb401ed9b21:404faf8c2bc3cf2477b7753b0888af48fd1416c3ff77a019fef89a8199826bcd'],
['a', '33401:55127fc9e1c03c6b459a3bab72fdb99def1644c5f239bdd09f3e5fb401ed9b21:d25892222f1bb4a457c840c5c829915c4e2a0d1ced55b40d69e4682d9a8e3fb2'],
['a', '33401:55127fc9e1c03c6b459a3bab72fdb99def1644c5f239bdd09f3e5fb401ed9b21:9f93ee6c8c314e7938ebf00e3de86e6e255c3ed48ad9763843758669092bb92a']
];
// Always include the test pack in our featured packs
setFeaturedPacks([testPack]);
} catch (error) {
console.error('Error setting up test data:', error);
} finally {
setIsLoading(false);
}
};
setupTestData();
}, [ndk]);
// Update featured packs when events change
useEffect(() => {
if (events.length > 0) {
// Combine the test pack with any events from the subscription
setFeaturedPacks(prevPacks => {
// Filter out duplicates by ID
const uniqueEvents = events.filter(event =>
!prevPacks.some(pack => pack.id === event.id)
);
return [...prevPacks, ...uniqueEvents];
});
setFeaturedPacks(events);
}
}, [events]);
// Handle pack click
const handlePackClick = (packEvent: NDKEvent) => {
try {
// Get dTag for the pack
const dTag = findTagValue(packEvent.tags, 'd');
if (!dTag) {
throw new Error('Pack is missing identifier (d tag)');
}
// Create shareable naddr
const naddr = TEST_PACK_NADDR; // Use hardcoded test pack naddr for now
const naddr = nip19.naddrEncode({
kind: 30004,
pubkey: packEvent.pubkey,
identifier: dTag,
relays: ['wss://relay.damus.io', 'wss://nos.lol', 'wss://relay.nostr.band']
});
// Copy to clipboard
Clipboard.setString(naddr);
@ -104,8 +69,8 @@ export default function POWRPackSection() {
router.push('/(packs)/manage');
};
// Even if there are no network packs, we'll always show our test pack
const showSection = true;
// Only show section if we have packs or are loading
const showSection = featuredPacks.length > 0 || isLoading;
if (!showSection) {
return null;
@ -182,7 +147,7 @@ export default function POWRPackSection() {
<PackageOpen size={32} color="#6b7280" />
<Text style={styles.emptyText}>No packs found</Text>
<Button
onPress={() => router.push('/(packs)/manage')}
onPress={() => router.push('/(packs)/import')}
size="sm"
variant="outline"
style={styles.emptyButton}

View File

@ -1,297 +0,0 @@
// 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';
import { NostrEvent } from '@/types/nostr'; // Assuming you have this type defined
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, exerciseService);
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);
}
}
/**
* Seed the database with real events from Nostr relays instead of mock data
* @param filter The filter to use when fetching events from relays
* @param limit Maximum number of events to seed (optional)
*/
async seedFromNostr(filter: any, limit?: number) {
if (!this.ndk) {
console.log('NDK not available for seeding from Nostr');
return;
}
try {
console.log(`Seeding from Nostr with filter:`, filter);
// Fetch events from relays
const events = await this.ndk.fetchEvents(filter);
console.log(`Found ${events.size} events on Nostr`);
// Convert to array and limit if needed
const eventsArray = Array.from(events);
const eventsToProcess = limit ? eventsArray.slice(0, limit) : eventsArray;
// Process each event individually
let successCount = 0;
for (const ndkEvent of eventsToProcess) {
try {
// Convert NDKEvent to your NostrEvent format
const nostrEvent: NostrEvent = {
id: ndkEvent.id || '',
pubkey: ndkEvent.pubkey || '',
created_at: ndkEvent.created_at || 0, // Set a default value of 0 if undefined
kind: ndkEvent.kind || 0,
tags: ndkEvent.tags || [],
content: ndkEvent.content || '',
sig: ndkEvent.sig || ''
};
// Cache the event
if (this.eventCache) {
await this.eventCache.setEvent(nostrEvent, true);
}
// Process based on kind
if (ndkEvent.kind === 33401) { // Exercise
const exercise = convertNostrToExercise(nostrEvent);
await this.exerciseService.createExercise(exercise, true);
successCount++;
}
// Add more event type processing here as needed
} catch (error) {
console.error(`Error processing Nostr event:`, error);
// Continue with next event
}
}
console.log(`Successfully seeded ${successCount} items from Nostr`);
} catch (error) {
console.error('Error seeding from Nostr:', 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();
}
}

View File

@ -1,290 +0,0 @@
// lib/mocks/exercises.ts
import { NostrEvent } from '@/types/nostr';
import {
ExerciseDisplay,
ExerciseType,
ExerciseCategory,
Equipment,
BaseExercise
} from '@/types/exercise';
import { generateId } from '@/utils/ids';
// Mock exercise definitions that will become our initial POWR library
export const mockExerciseEvents: NostrEvent[] = [
{
kind: 33401,
content: "Stand with feet hip-width apart, barbell racked on shoulders. Bend knees and hips to squat down, keeping chest up. Drive through heels to stand.",
tags: [
["d", "bb-back-squat"],
["title", "Barbell Back Squat"],
["format", "weight", "reps", "rpe", "set_type"],
["format_units", "kg", "count", "0-10", "warmup|normal|drop|failure"],
["equipment", "barbell"],
["difficulty", "intermediate"],
["category", "legs"],
["t", "compound"],
["t", "squat"],
["t", "legs"],
["t", "quadriceps"]
],
created_at: 1708300800, // Feb 19, 2024
id: generateId('nostr'),
pubkey: "powr", // We'll update this when we create the POWR relay
sig: undefined
},
{
kind: 33401,
content: "Stand with feet shoulder-width apart, barbell on floor. Hinge at hips, grip bar outside knees. Keep back flat, drive through heels to lift.",
tags: [
["d", "bb-deadlift"],
["title", "Barbell Deadlift"],
["format", "weight", "reps", "rpe", "set_type"],
["format_units", "kg", "count", "0-10", "warmup|normal|drop|failure"],
["equipment", "barbell"],
["difficulty", "intermediate"],
["category", "legs"],
["t", "compound"],
["t", "hinge"],
["t", "legs"],
["t", "posterior"]
],
created_at: 1708300800,
id: generateId('nostr'),
pubkey: "powr",
sig: undefined
},
{
kind: 33401,
content: "Lie on bench, feet flat on floor. Grip barbell slightly wider than shoulders. Lower bar to chest, press back up to start.",
tags: [
["d", "bb-bench-press"],
["title", "Barbell Bench Press"],
["format", "weight", "reps", "rpe", "set_type"],
["format_units", "kg", "count", "0-10", "warmup|normal|drop|failure"],
["equipment", "barbell"],
["difficulty", "intermediate"],
["category", "push"],
["t", "compound"],
["t", "push"],
["t", "chest"],
["t", "triceps"]
],
created_at: 1708300800,
id: generateId('nostr'),
pubkey: "powr",
sig: undefined
},
{
kind: 33401,
content: "Start in plank position. Lower body by bending elbows, keeping body straight. Push back up to start position.",
tags: [
["d", "pushup"],
["title", "Push-Up"],
["format", "reps", "set_type"],
["format_units", "count", "warmup|normal|drop|failure"],
["equipment", "bodyweight"],
["difficulty", "beginner"],
["category", "push"],
["t", "bodyweight"],
["t", "push"],
["t", "chest"],
["t", "triceps"]
],
created_at: 1708300800,
id: generateId('nostr'),
pubkey: "powr",
sig: undefined
},
{
kind: 33401,
content: "Hang from pull-up bar with overhand grip. Pull body up until chin clears bar, lower back to start.",
tags: [
["d", "pullup"],
["title", "Pull-Up"],
["format", "reps", "set_type"],
["format_units", "count", "warmup|normal|drop|failure"],
["equipment", "bodyweight"],
["difficulty", "intermediate"],
["category", "pull"],
["t", "bodyweight"],
["t", "pull"],
["t", "back"],
["t", "biceps"]
],
created_at: 1708300800,
id: generateId('nostr'),
pubkey: "powr",
sig: undefined
},
{
kind: 33401,
content: "Sit at machine, grip handles at shoulder height. Press handles up overhead, return to start position.",
tags: [
["d", "shoulder-press-machine"],
["title", "Shoulder Press Machine"],
["format", "weight", "reps", "set_type"],
["format_units", "kg", "count", "warmup|normal|drop|failure"],
["equipment", "machine"],
["difficulty", "beginner"],
["category", "push"],
["t", "machine"],
["t", "push"],
["t", "shoulders"],
["t", "triceps"]
],
created_at: 1708300800,
id: generateId('nostr'),
pubkey: "powr",
sig: undefined
},
{
kind: 33401,
content: "Stand with dumbbell in each hand at sides. Curl weights toward shoulders, keeping elbows close to body. Lower back down.",
tags: [
["d", "db-bicep-curl"],
["title", "Dumbbell Bicep Curl"],
["format", "weight", "reps", "set_type"],
["format_units", "kg", "count", "warmup|normal|drop|failure"],
["equipment", "dumbbell"],
["difficulty", "beginner"],
["category", "pull"],
["t", "isolation"],
["t", "pull"],
["t", "biceps"]
],
created_at: 1708300800,
id: generateId('nostr'),
pubkey: "powr",
sig: undefined
},
{
kind: 33401,
content: "Attach rope to cable machine at top. Grip ends, pull down to chest level keeping elbows close. Control return.",
tags: [
["d", "cable-tricep-pushdown"],
["title", "Cable Tricep Pushdown"],
["format", "weight", "reps", "set_type"],
["format_units", "kg", "count", "warmup|normal|drop|failure"],
["equipment", "cable"],
["difficulty", "beginner"],
["category", "push"],
["t", "isolation"],
["t", "push"],
["t", "triceps"]
],
created_at: 1708300800,
id: generateId('nostr'),
pubkey: "powr",
sig: undefined
},
{
kind: 33401,
content: "Kneel before cable machine, rope attachment at bottom. Pull rope toward forehead, keeping upper arms still. Lower with control.",
tags: [
["d", "cable-face-pull"],
["title", "Cable Face Pull"],
["format", "weight", "reps", "set_type"],
["format_units", "kg", "count", "warmup|normal|drop|failure"],
["equipment", "cable"],
["difficulty", "intermediate"],
["category", "pull"],
["t", "isolation"],
["t", "pull"],
["t", "rear-deltoids"],
["t", "upper-back"]
],
created_at: 1708300800,
id: generateId('nostr'),
pubkey: "powr",
sig: undefined
},
{
kind: 33401,
content: "Stand with feet hip-width, holding kettlebell by horns at chest. Squat down keeping chest up, stand back up.",
tags: [
["d", "kb-goblet-squat"],
["title", "Kettlebell Goblet Squat"],
["format", "weight", "reps", "set_type"],
["format_units", "kg", "count", "warmup|normal|drop|failure"],
["equipment", "kettlebell"],
["difficulty", "beginner"],
["category", "legs"],
["t", "compound"],
["t", "squat"],
["t", "legs"],
["t", "quadriceps"]
],
created_at: 1708300800,
id: generateId('nostr'),
pubkey: "powr",
sig: undefined
}
];
function getTagValue(tags: string[][], name: string): string | undefined {
const tag = tags.find((tag: string[]) => tag[0] === name);
return tag ? tag[1] : undefined;
}
function getTags(tags: string[][]): string[] {
return tags
.filter((tag: string[]) => tag[0] === 't')
.map((tag: string[]) => tag[1]);
}
export function convertNostrToExercise(event: NostrEvent): ExerciseDisplay {
const baseExercise: BaseExercise = {
id: event.id || '',
title: getTagValue(event.tags, 'title') || '',
type: getTagValue(event.tags, 'equipment') === 'bodyweight'
? 'bodyweight'
: 'strength' as ExerciseType,
category: getTagValue(event.tags, 'category') as ExerciseCategory,
equipment: getTagValue(event.tags, 'equipment') as Equipment,
description: event.content,
format: getTagValue(event.tags, 'format')
?.split(',')
.reduce((acc: Record<string, boolean>, curr: string) => ({
...acc,
[curr]: true
}), {}),
format_units: getTagValue(event.tags, 'format_units')
?.split(',')
.reduce((acc: Record<string, string>, curr: string, i: number) => {
const format = getTagValue(event.tags, 'format')?.split(',')[i];
return format ? { ...acc, [format]: curr } : acc;
}, {}),
tags: getTags(event.tags),
availability: {
source: ['powr']
},
created_at: event.created_at * 1000
};
// Convert to ExerciseDisplay
return {
...baseExercise,
source: 'powr',
isFavorite: false,
usageCount: 0
};
}
// Export pre-converted exercises for easy testing
export const mockExercises = mockExerciseEvents.map(convertNostrToExercise);
// Helper to seed the database
export async function seedExercises(exerciseService: any) {
try {
const existingCount = (await exerciseService.getAllExercises()).length;
if (existingCount === 0) {
console.log('Seeding database with mock exercises...');
for (const exercise of mockExercises) {
await exerciseService.createExercise(exercise);
}
console.log('Successfully seeded database');
}
} catch (error) {
console.error('Error seeding database:', error);
}
}