mirror of
https://github.com/DocNR/POWR.git
synced 2025-04-23 01:01:27 +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.
121 lines
3.1 KiB
TypeScript
121 lines
3.1 KiB
TypeScript
// lib/db/services/EventCache.ts
|
|
import { SQLiteDatabase } from 'expo-sqlite';
|
|
import { NostrEvent } from '@/types/nostr';
|
|
import { DbService } from '../db-service';
|
|
|
|
export class EventCache {
|
|
private db: DbService;
|
|
|
|
constructor(database: SQLiteDatabase) {
|
|
this.db = new DbService(database);
|
|
}
|
|
|
|
/**
|
|
* Store a Nostr event in the cache
|
|
*/
|
|
async setEvent(event: NostrEvent, skipExisting: boolean = false): Promise<void> {
|
|
if (!event.id) return;
|
|
|
|
try {
|
|
// Check if event already exists
|
|
if (skipExisting) {
|
|
const exists = await this.db.getFirstAsync<{ id: string }>(
|
|
'SELECT id FROM nostr_events WHERE id = ?',
|
|
[event.id]
|
|
);
|
|
|
|
if (exists) return;
|
|
}
|
|
|
|
// Store the event
|
|
await this.db.withTransactionAsync(async () => {
|
|
await this.db.runAsync(
|
|
`INSERT OR REPLACE INTO nostr_events
|
|
(id, pubkey, kind, created_at, content, sig, raw_event, received_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
[
|
|
event.id,
|
|
event.pubkey || '',
|
|
event.kind,
|
|
event.created_at,
|
|
event.content,
|
|
event.sig || '',
|
|
JSON.stringify(event),
|
|
Date.now()
|
|
]
|
|
);
|
|
|
|
// Store event tags
|
|
if (event.tags && event.tags.length > 0) {
|
|
// Delete existing tags first
|
|
await this.db.runAsync(
|
|
'DELETE FROM event_tags WHERE event_id = ?',
|
|
[event.id]
|
|
);
|
|
|
|
// Insert new tags
|
|
for (let i = 0; i < event.tags.length; i++) {
|
|
const tag = event.tags[i];
|
|
if (tag.length >= 2) {
|
|
await this.db.runAsync(
|
|
'INSERT INTO event_tags (event_id, name, value, index_num) VALUES (?, ?, ?, ?)',
|
|
[event.id, tag[0], tag[1], i]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Error caching event:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get an event from the cache by ID
|
|
*/
|
|
async getEvent(id: string): Promise<NostrEvent | null> {
|
|
try {
|
|
const event = await this.db.getFirstAsync<{
|
|
id: string;
|
|
pubkey: string;
|
|
kind: number;
|
|
created_at: number;
|
|
content: string;
|
|
sig: string;
|
|
raw_event: string;
|
|
}>(
|
|
'SELECT * FROM nostr_events WHERE id = ?',
|
|
[id]
|
|
);
|
|
|
|
if (!event) return null;
|
|
|
|
// Get tags
|
|
const tags = await this.db.getAllAsync<{
|
|
name: string;
|
|
value: string;
|
|
index_num: number;
|
|
}>(
|
|
'SELECT name, value, index_num FROM event_tags WHERE event_id = ? ORDER BY index_num',
|
|
[id]
|
|
);
|
|
|
|
// Build the event object
|
|
const nostrEvent: NostrEvent = {
|
|
id: event.id,
|
|
pubkey: event.pubkey,
|
|
kind: event.kind,
|
|
created_at: event.created_at,
|
|
content: event.content,
|
|
sig: event.sig,
|
|
tags: tags.map(tag => [tag.name, tag.value])
|
|
};
|
|
|
|
return nostrEvent;
|
|
} catch (error) {
|
|
console.error('Error retrieving event:', error);
|
|
return null;
|
|
}
|
|
}
|
|
} |