diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts index d9a018f86ceb..0d5909471ddb 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts @@ -28,6 +28,7 @@ export class EntityEventsToDbListener { payload.properties.diff = objectRecordChangedValues( payload.properties.before, payload.properties.after, + payload.properties.updatedFields, payload.objectMetadata, ); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts index 1a5de2956757..bef145c1e2c8 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts @@ -439,6 +439,7 @@ export class WorkspaceQueryRunnerService { recordId: existingRecord.id, objectMetadata: objectMetadataItem, properties: { + updatedFields: Object.keys(args.data), before: this.removeNestedProperties(existingRecord as Record), after: this.removeNestedProperties(parsedResults?.[0]), }, @@ -518,6 +519,7 @@ export class WorkspaceQueryRunnerService { recordId: existingRecord.id, objectMetadata: objectMetadataItem, properties: { + updatedFields: Object.keys(args.data), before: this.removeNestedProperties(existingRecord as Record), after: this.removeNestedProperties(record), }, diff --git a/packages/twenty-server/src/engine/integrations/event-emitter/types/object-record-update.event.ts b/packages/twenty-server/src/engine/integrations/event-emitter/types/object-record-update.event.ts index 037b38178c14..aa4b59e7208c 100644 --- a/packages/twenty-server/src/engine/integrations/event-emitter/types/object-record-update.event.ts +++ b/packages/twenty-server/src/engine/integrations/event-emitter/types/object-record-update.event.ts @@ -2,6 +2,7 @@ import { ObjectRecordBaseEvent } from 'src/engine/integrations/event-emitter/typ export class ObjectRecordUpdateEvent extends ObjectRecordBaseEvent { properties: { + updatedFields: string[]; before: T; after: T; diff?: Partial; diff --git a/packages/twenty-server/src/engine/integrations/event-emitter/utils/__tests__/object-record-changed-values.spec.ts b/packages/twenty-server/src/engine/integrations/event-emitter/utils/__tests__/object-record-changed-values.spec.ts index 9e4e51791a20..6772e1f8715e 100644 --- a/packages/twenty-server/src/engine/integrations/event-emitter/utils/__tests__/object-record-changed-values.spec.ts +++ b/packages/twenty-server/src/engine/integrations/event-emitter/utils/__tests__/object-record-changed-values.spec.ts @@ -36,6 +36,7 @@ describe('objectRecordChangedValues', () => { const result = objectRecordChangedValues( oldRecord, newRecord, + ['name'], mockObjectMetadata, ); @@ -58,6 +59,7 @@ it('ignores changes to the updatedAt field', () => { const result = objectRecordChangedValues( oldRecord, newRecord, + [], mockObjectMetadata, ); @@ -79,6 +81,7 @@ it('returns an empty object when there are no changes', () => { const result = objectRecordChangedValues( oldRecord, newRecord, + ['name', 'value'], mockObjectMetadata, ); @@ -108,6 +111,7 @@ it('correctly handles a mix of changed, unchanged, and special case values', () const result = objectRecordChangedValues( oldRecord, newRecord, + ['name', 'config', 'status'], mockObjectMetadata, ); diff --git a/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-values.ts b/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-values.ts index 062693cbd5d1..eaf3c4ebfe00 100644 --- a/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-values.ts +++ b/packages/twenty-server/src/engine/integrations/event-emitter/utils/object-record-changed-values.ts @@ -1,33 +1,36 @@ import deepEqual from 'deep-equal'; -import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; +import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; export const objectRecordChangedValues = ( oldRecord: Partial, newRecord: Partial, + updatedKeys: string[], objectMetadata: ObjectMetadataInterface, ) => { + const fieldsByKey = new Map( + objectMetadata.fields.map((field) => [field.name, field]), + ); + const changedValues = Object.keys(newRecord).reduce( (acc, key) => { + const field = fieldsByKey.get(key); + const oldRecordValue = oldRecord[key]; + const newRecordValue = newRecord[key]; + if ( - objectMetadata.fields.find( - (field) => - field.type === FieldMetadataType.RELATION && field.name === key, - ) + key === 'updatedAt' || + !updatedKeys.includes(key) || + field?.type === FieldMetadataType.RELATION || + deepEqual(oldRecordValue, newRecordValue) ) { return acc; } - if (objectMetadata.nameSingular === 'activity' && key === 'body') { - return acc; - } - - if (!deepEqual(oldRecord[key], newRecord[key]) && key !== 'updatedAt') { - acc[key] = { before: oldRecord[key], after: newRecord[key] }; - } + acc[key] = { before: oldRecordValue, after: newRecordValue }; return acc; },