|
|
|
@@ -1,5 +1,5 @@
|
|
|
|
import { db, logger } from '../config.js';
|
|
|
|
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 { max, sql, eq, and, or, desc, like } from 'drizzle-orm';
|
|
|
|
import { updateJobProgress } from './job-queue.service.js';
|
|
|
|
import { updateJobProgress } from './job-queue.service.js';
|
|
|
|
import { parseADIF, normalizeBand, normalizeMode } from '../utils/adif-parser.js';
|
|
|
|
import { parseADIF, normalizeBand, normalizeMode } from '../utils/adif-parser.js';
|
|
|
|
@@ -609,10 +609,58 @@ export async function getLastLoTWQSLDate(userId) {
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Delete all QSOs for a user
|
|
|
|
* Delete all QSOs for a user
|
|
|
|
|
|
|
|
* Also deletes related qso_changes records to satisfy foreign key constraints
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export async function deleteQSOs(userId) {
|
|
|
|
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));
|
|
|
|
const result = await db.delete(qsos).where(eq(qsos.userId, userId));
|
|
|
|
return result;
|
|
|
|
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 });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Invalidate caches for this user
|
|
|
|
|
|
|
|
await invalidateStatsCache(userId);
|
|
|
|
|
|
|
|
await invalidateUserCache(userId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
|