From 300738e8cbdf9d9a3f379b576140452a8f17defe Mon Sep 17 00:00:00 2001 From: Etienne <45695613+etiennejouan@users.noreply.github.com> Date: Fri, 2 Jan 2026 14:23:47 +0100 Subject: [PATCH] Fix database event emission (#16759) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/twentyhq/private-issues/issues/395 When calling `removeUserFromWorkspaceAndPotentiallyDeleteWorkspace` from `user.service`, ``` await workspaceMemberRepository.delete({ userId: userWorkspace.userId, }); ``` related database event is not emitted. Same issue with update has been fixed [here](https://github.com/twentyhq/twenty/pull/13287/changes) The database event is not emitted because `await eventSelectQueryBuilder.getOne()` in `workspace-delete-query-builder` returns `null`. This happens because the `selectQueryBuilder` has no entity—the database request is sent and the raw result is not `null`, but the entity is `null`, causing the final result to be null. It can be fixed the same way update has been fixed, updating the `workspace-entity-manager` - Pros : consistant with update but we should not forget to fix softDelete and restore - Cons : `workspace-entity-manager` is a copy of typeORM logic + permission injection. Should it be more ? Alternatively (as featured in this PR), it can be fixed by updating computeEventSelectQueryBuilder, inspired by TypeORM's logic in typeorm/query-builder/QueryBuilder.js at line 67. - Pros : it fit with typeORM logic + It fixes all repository operations --- .../listeners/billing-workspace-member.listener.ts | 1 + .../utils/compute-event-select-query-builder.util.ts | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts b/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts index eebf419a84..60a545d1ea 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts @@ -27,6 +27,7 @@ export class BillingWorkspaceMemberListener { @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.CREATED) @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.DELETED) + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.DESTROYED) async handleCreateOrDeleteEvent( payload: WorkspaceEventBatch< ObjectRecordCreateEvent diff --git a/packages/twenty-server/src/engine/twenty-orm/utils/compute-event-select-query-builder.util.ts b/packages/twenty-server/src/engine/twenty-orm/utils/compute-event-select-query-builder.util.ts index 2d7c9c912b..fc2311b71e 100644 --- a/packages/twenty-server/src/engine/twenty-orm/utils/compute-event-select-query-builder.util.ts +++ b/packages/twenty-server/src/engine/twenty-orm/utils/compute-event-select-query-builder.util.ts @@ -46,5 +46,14 @@ export const computeEventSelectQueryBuilder = ({ eventSelectQueryBuilder.expressionMap.aliases = expressionMap.aliases; eventSelectQueryBuilder.setParameters(expressionMap.parameters); + if ( + eventSelectQueryBuilder.expressionMap.selects.length === 0 && + eventSelectQueryBuilder.expressionMap.mainAlias + ) { + eventSelectQueryBuilder.expressionMap.selects = [ + { selection: eventSelectQueryBuilder.expressionMap.mainAlias.name }, + ]; + } + return eventSelectQueryBuilder; };