diff --git a/apps/papra-server/src/modules/documents/documents.repository.ts b/apps/papra-server/src/modules/documents/documents.repository.ts index c59e274..8b408f6 100644 --- a/apps/papra-server/src/modules/documents/documents.repository.ts +++ b/apps/papra-server/src/modules/documents/documents.repository.ts @@ -29,7 +29,7 @@ export function createDocumentsRepository({ db }: { db: Database }) { getExpiredDeletedDocuments, getOrganizationStats, getOrganizationDocumentBySha256Hash, - getAllOrganizationTrashDocumentIds, + getAllOrganizationTrashDocuments, updateDocument, }, { db }, @@ -258,6 +258,7 @@ async function getExpiredDeletedDocuments({ db, expirationDelayInDays, now = new const documents = await db.select({ id: documentsTable.id, + originalStorageKey: documentsTable.originalStorageKey, }).from(documentsTable).where( and( eq(documentsTable.isDeleted, true), @@ -266,7 +267,7 @@ async function getExpiredDeletedDocuments({ db, expirationDelayInDays, now = new ); return { - documentIds: documents.map(document => document.id), + documents, }; } @@ -312,9 +313,10 @@ async function getOrganizationStats({ organizationId, db }: { organizationId: st }; } -async function getAllOrganizationTrashDocumentIds({ organizationId, db }: { organizationId: string; db: Database }) { +async function getAllOrganizationTrashDocuments({ organizationId, db }: { organizationId: string; db: Database }) { const documents = await db.select({ id: documentsTable.id, + originalStorageKey: documentsTable.originalStorageKey, }).from(documentsTable).where( and( eq(documentsTable.organizationId, organizationId), @@ -323,7 +325,7 @@ async function getAllOrganizationTrashDocumentIds({ organizationId, db }: { orga ); return { - documentIds: documents.map(document => document.id), + documents, }; } diff --git a/apps/papra-server/src/modules/documents/documents.usecases.ts b/apps/papra-server/src/modules/documents/documents.usecases.ts index 5d8a5ef..3e26875 100644 --- a/apps/papra-server/src/modules/documents/documents.usecases.ts +++ b/apps/papra-server/src/modules/documents/documents.usecases.ts @@ -286,17 +286,19 @@ export async function ensureDocumentExists({ } export async function hardDeleteDocument({ - documentId, + document, documentsRepository, documentsStorageService, }: { - documentId: string; + document: Pick; documentsRepository: DocumentsRepository; documentsStorageService: DocumentStorageService; }) { - await Promise.allSettled([ - documentsRepository.hardDeleteDocument({ documentId }), - documentsStorageService.deleteFile({ storageKey: documentId }), + // TODO: use transaction + + await Promise.all([ + documentsRepository.hardDeleteDocument({ documentId: document.id }), + documentsStorageService.deleteFile({ storageKey: document.originalStorageKey }), ]); } @@ -313,23 +315,25 @@ export async function deleteExpiredDocuments({ now?: Date; logger?: Logger; }) { - const { documentIds } = await documentsRepository.getExpiredDeletedDocuments({ + const { documents } = await documentsRepository.getExpiredDeletedDocuments({ expirationDelayInDays: config.documents.deletedDocumentsRetentionDays, now, }); + const limit = pLimit(10); + await Promise.all( - documentIds.map(async (documentId) => { - const [, error] = await safely(hardDeleteDocument({ documentId, documentsRepository, documentsStorageService })); + documents.map(document => limit(async () => { + const [, error] = await safely(hardDeleteDocument({ document, documentsRepository, documentsStorageService })); if (error) { - logger.error({ documentId, error }, 'Error while deleting expired document'); + logger.error({ document, error }, 'Error while deleting expired document'); } - }), + })), ); return { - deletedDocumentsCount: documentIds.length, + deletedDocumentsCount: documents.length, }; } @@ -354,7 +358,7 @@ export async function deleteTrashDocument({ throw createDocumentNotDeletedError(); } - await hardDeleteDocument({ documentId, documentsRepository, documentsStorageService }); + await hardDeleteDocument({ document, documentsRepository, documentsStorageService }); } export async function deleteAllTrashDocuments({ @@ -366,13 +370,13 @@ export async function deleteAllTrashDocuments({ documentsRepository: DocumentsRepository; documentsStorageService: DocumentStorageService; }) { - const { documentIds } = await documentsRepository.getAllOrganizationTrashDocumentIds({ organizationId }); + const { documents } = await documentsRepository.getAllOrganizationTrashDocuments({ organizationId }); // TODO: refactor to use batching and transaction const limit = pLimit(10); await Promise.all( - documentIds.map(documentId => limit(() => hardDeleteDocument({ documentId, documentsRepository, documentsStorageService }))), + documents.map(document => limit(() => hardDeleteDocument({ document, documentsRepository, documentsStorageService }))), ); }