diff --git a/src/backend/index.js b/src/backend/index.js index 6bc1bda..bfa4619 100644 --- a/src/backend/index.js +++ b/src/backend/index.js @@ -867,6 +867,7 @@ const app = new Elysia() message: `Deleted ${deleted} QSO(s)`, }; } catch (error) { + logger.error('Failed to delete QSOs', { error: error.message, stack: error.stack }); set.status = 500; return { success: false, diff --git a/src/backend/services/lotw.service.js b/src/backend/services/lotw.service.js index 3d89512..b3c9699 100644 --- a/src/backend/services/lotw.service.js +++ b/src/backend/services/lotw.service.js @@ -1,5 +1,5 @@ import { db, logger } from '../config.js'; -import { qsos, qsoChanges } from '../db/schema/index.js'; +import { qsos, qsoChanges, syncJobs, awardProgress } from '../db/schema/index.js'; import { max, sql, eq, and, or, desc, like } from 'drizzle-orm'; import { updateJobProgress } from './job-queue.service.js'; import { parseADIF, normalizeBand, normalizeMode } from '../utils/adif-parser.js'; @@ -609,11 +609,54 @@ export async function getLastLoTWQSLDate(userId) { /** * Delete all QSOs for a user + * Also deletes related qso_changes records to satisfy foreign key constraints */ export async function deleteQSOs(userId) { + logger.debug('Deleting all QSOs for user', { userId }); + + // Step 1: Delete qso_changes that reference QSOs for this user + // Need to use a subquery since qso_changes doesn't have userId directly + const qsoIdsResult = await db + .select({ id: qsos.id }) + .from(qsos) + .where(eq(qsos.userId, userId)); + + const qsoIds = qsoIdsResult.map(r => r.id); + + let deletedChanges = 0; + if (qsoIds.length > 0) { + // Delete qso_changes where qsoId is in the list of QSO IDs + const changesResult = await db + .delete(qsoChanges) + .where(sql`${qsoChanges.qsoId} IN ${sql.raw(`(${qsoIds.join(',')})`)}`); + + deletedChanges = changesResult.changes || changesResult || 0; + logger.debug('Deleted qso_changes', { count: deletedChanges }); + } + + // Step 2: Delete the QSOs const result = await db.delete(qsos).where(eq(qsos.userId, userId)); - // Drizzle with SQLite/bun:sqlite returns { changes: number } indicating affected rows - return result.changes || 0; + logger.debug('Delete result', { result, type: typeof result, keys: Object.keys(result || {}) }); + + // Drizzle with SQLite/bun:sqlite returns various formats depending on driver + let count = 0; + if (result) { + if (typeof result === 'number') { + count = result; + } else if (result.changes !== undefined) { + count = result.changes; + } else if (result.rows !== undefined) { + count = result.rows; + } else if (result.meta?.changes !== undefined) { + count = result.meta.changes; + } else if (result.meta?.rows !== undefined) { + count = result.meta.rows; + } + } + + logger.info('Deleted QSOs', { userId, count, deletedChanges }); + + return count; } /**