From 9286ffb88d4f6512ce7b589b0a6ae4942894b6a6 Mon Sep 17 00:00:00 2001 From: neo773 <62795688+neo773@users.noreply.github.com> Date: Thu, 25 Sep 2025 13:44:03 +0530 Subject: [PATCH] batched updates/insert and delete invalid folders (#14702) --- .../services/sync-message-folders.service.ts | 91 ++++++++++++++----- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/packages/twenty-server/src/modules/messaging/message-folder-manager/services/sync-message-folders.service.ts b/packages/twenty-server/src/modules/messaging/message-folder-manager/services/sync-message-folders.service.ts index 1f778e90dae..56451e46129 100644 --- a/packages/twenty-server/src/modules/messaging/message-folder-manager/services/sync-message-folders.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-folder-manager/services/sync-message-folders.service.ts @@ -6,7 +6,6 @@ import { v4 } from 'uuid'; import { MessageFolder } from 'src/modules/messaging/message-folder-manager/interfaces/message-folder-driver.interface'; -import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; @@ -24,11 +23,25 @@ type SyncMessageFoldersInput = { manager: WorkspaceEntityManager; }; +type MessageFolderToInsert = Pick< + MessageFolderWorkspaceEntity, + | 'id' + | 'messageChannelId' + | 'name' + | 'syncCursor' + | 'isSynced' + | 'isSentFolder' + | 'externalId' +>; + +type MessageFolderToUpdate = Partial< + Pick +>; + @Injectable() export class SyncMessageFoldersService { constructor( private readonly twentyORMGlobalManager: TwentyORMGlobalManager, - private readonly featureFlagService: FeatureFlagService, private readonly gmailGetAllFoldersService: GmailGetAllFoldersService, private readonly microsoftGetAllFoldersService: MicrosoftGetAllFoldersService, private readonly imapGetAllFoldersService: ImapGetAllFoldersService, @@ -69,7 +82,25 @@ export class SyncMessageFoldersService { messageFolderRepository, }); - // TODO: we should delete folders that are not in the list anymore + const inserts: MessageFolderToInsert[] = []; + const updates: [string, MessageFolderToUpdate][] = []; + const deletes: string[] = []; + + const discoveredExternalIds = new Set( + folders + .filter((folder) => folder.externalId) + .map((folder) => folder.externalId!), + ); + + for (const existingFolder of existingFolderMap.values()) { + if ( + existingFolder.externalId && + !discoveredExternalIds.has(existingFolder.externalId) + ) { + deletes.push(existingFolder.id); + } + } + for (const folder of folders) { const existingFolder = this.findExistingFolderInMap( existingFolderMap, @@ -77,32 +108,44 @@ export class SyncMessageFoldersService { ); if (existingFolder) { - // TODO: this code should be refactored to use the updateMany method and only on folders that need to be updated - // await messageFolderRepository.update( - // existingFolder.id, - // { - // name: folder.name, - // externalId: folder.externalId, - // isSentFolder: folder.isSentFolder, - // }, - // manager, - // ); - } else { - // TODO: this code should be refactored to use the create (many) - await messageFolderRepository.save( + updates.push([ + existingFolder.id, { - id: v4(), - messageChannelId, name: folder.name, - syncCursor: '', - isSynced: folder.isSynced, - isSentFolder: folder.isSentFolder, externalId: folder.externalId, + isSentFolder: folder.isSentFolder, }, - {}, - manager, - ); + ]); + continue; } + + inserts.push({ + id: v4(), + messageChannelId, + name: folder.name, + syncCursor: '', + isSynced: folder.isSynced, + isSentFolder: folder.isSentFolder, + externalId: folder.externalId, + }); + } + + if (inserts.length > 0) { + await messageFolderRepository.insert(inserts, manager); + } + + if (updates.length > 0) { + await messageFolderRepository.updateMany( + updates.map(([id, data]) => ({ + criteria: id, + partialEntity: data, + })), + manager, + ); + } + + if (deletes.length > 0) { + await messageFolderRepository.delete(deletes, manager); } }