From 554c4cee12fc83868d17111a34517642fdad0c0f Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Wed, 3 Jan 2024 12:40:46 +0800 Subject: [PATCH] add test cases --- .../api/src/resolvers/function_resolvers.ts | 3 ++ packages/api/src/services/library_item.ts | 2 +- packages/api/src/services/user.ts | 10 ++-- packages/api/test/resolvers/article.test.ts | 54 +++++++++++++++++++ 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index 7c4616ea1..6cff177ca 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -38,6 +38,7 @@ import { generateDownloadSignedUrl, generateUploadFilePathName, } from '../utils/uploads' +import { emptyTrashResolver } from './article' import { optInFeatureResolver } from './features' import { uploadImportFileResolver } from './importers/uploadImportFileResolver' import { @@ -231,6 +232,7 @@ export const functionResolvers = { updateEmail: updateEmailResolver, moveToFolder: moveToFolderResolver, updateNewsletterEmail: updateNewsletterEmailResolver, + emptyTrash: emptyTrashResolver, }, Query: { me: getMeUserResolver, @@ -578,4 +580,5 @@ export const functionResolvers = { ...resultResolveTypeResolver('ScanFeeds'), ...resultResolveTypeResolver('MoveToFolder'), ...resultResolveTypeResolver('UpdateNewsletterEmail'), + ...resultResolveTypeResolver('EmptyTrash'), } diff --git a/packages/api/src/services/library_item.ts b/packages/api/src/services/library_item.ts index 9aca2c098..5fabc2828 100644 --- a/packages/api/src/services/library_item.ts +++ b/packages/api/src/services/library_item.ts @@ -1088,7 +1088,7 @@ export const batchDelete = async (criteria: FindOptionsWhere) => { batch_size INT := ${batchSize}; BEGIN -- Loop through batches - FOR i IN 0..CEIL((${countSql})) * 1.0 / batch_size) - 1 LOOP + FOR i IN 0..CEIL((${countSql}) * 1.0 / batch_size) - 1 LOOP -- Delete batch DELETE FROM omnivore.library_item WHERE id = ANY( diff --git a/packages/api/src/services/user.ts b/packages/api/src/services/user.ts index 4c8cabbd7..d7f9fa0d3 100644 --- a/packages/api/src/services/user.ts +++ b/packages/api/src/services/user.ts @@ -51,7 +51,9 @@ export const createUsers = async (users: DeepPartial[]) => { export const batchDelete = async (criteria: FindOptionsWhere) => { const userQb = getRepository(User).createQueryBuilder().where(criteria) const userCountSql = queryBuilderToRawSql(userQb.select('COUNT(1)')) - const userSubQuery = queryBuilderToRawSql(userQb.select('id INTO user_ids')) + const userSubQuery = queryBuilderToRawSql( + userQb.select('array_agg(id::UUID) into user_ids') + ) const batchSize = 1000 const sql = ` @@ -62,12 +64,12 @@ export const batchDelete = async (criteria: FindOptionsWhere) => { user_ids UUID[]; BEGIN -- Loop through batches of users - FOR i IN 0..CEIL((${userCountSql})) * 1.0 / batch_size) - 1 LOOP + FOR i IN 0..CEIL((${userCountSql}) * 1.0 / batch_size) - 1 LOOP -- GET batch of user ids - ${userSubQuery} LIMIT batch_size OFFSET i * batch_size; + ${userSubQuery} LIMIT batch_size; -- Loop through batches of items - FOR j IN 0..CEIL((SELECT COUNT(1) FROM omnivore.library_item WHERE user_id = ANY(user_ids))) * 1.0 / batch_size) - 1 LOOP + FOR j IN 0..CEIL((SELECT COUNT(1) FROM omnivore.library_item WHERE user_id = ANY(user_ids)) * 1.0 / batch_size) - 1 LOOP -- Delete batch of items DELETE FROM omnivore.library_item WHERE id = ANY( diff --git a/packages/api/test/resolvers/article.test.ts b/packages/api/test/resolvers/article.test.ts index b6e781597..090e31208 100644 --- a/packages/api/test/resolvers/article.test.ts +++ b/packages/api/test/resolvers/article.test.ts @@ -2285,4 +2285,58 @@ describe('Article API', () => { expect(item?.labels?.map((l) => l.name)).to.eql(['Favorites']) }) }) + + describe('EmptyTrash API', () => { + const emptyTrashQuery = () => ` + mutation { + emptyTrash { + ... on EmptyTrashSuccess { + success + } + ... on EmptyTrashError { + errorCodes + } + } + }` + + let items: LibraryItem[] = [] + + before(async () => { + // Create some test items + for (let i = 0; i < 5; i++) { + const itemToSave: DeepPartial = { + user, + title: 'test item', + readableContent: '

test

', + slug: '', + originalUrl: `https://blog.omnivore.app/p/empty-trash-${i}`, + deletedAt: new Date(), + state: LibraryItemState.Deleted, + } + const item = await createLibraryItem(itemToSave, user.id) + items.push(item) + } + }) + + after(async () => { + // Delete all items + await deleteLibraryItemsByUserId(user.id) + }) + + it('empties the trash', async () => { + let response = await graphqlRequest( + searchQuery('in:trash'), + authToken + ).expect(200) + expect(response.body.data.search.pageInfo.totalCount).to.eql(5) + + await graphqlRequest(emptyTrashQuery(), authToken).expect(200) + + response = await graphqlRequest( + searchQuery('in:trash'), + authToken + ).expect(200) + expect(response.body.data.search.pageInfo.totalCount).to.eql(0) + }) + }) })