From 676c902731a11ee8aa1beaab7447324df38d67f5 Mon Sep 17 00:00:00 2001 From: Weiko Date: Thu, 1 Aug 2024 18:41:28 +0200 Subject: [PATCH] Fix timelineActivity updated fields (#6494) ## Context We recently introduced the new twenty ORM and used it in the update methods in the query runner. Initially we were using pg_graphql to fetch the record before updating it allowing us to compare the before and the after and create a diff. This diff is then used for the timeline activity creation. Now, twentyORM is doing the fetch and pg_graphql is still doing the update and their responses are not exactly the same, which means the diff is not working as intended (e.g date types were always in the diff due to one being in Date format and the other as a string) This PR introduces a updatedFields property to the update event which comes from the input. This is not ideal as this won't work for API users that send the whole payload but will be sufficient enough for our FE that only sends modified fields. We then compare only those fields in the diff. --- .../listeners/entity-events-to-db.listener.ts | 1 + .../workspace-query-runner.service.ts | 2 ++ .../types/object-record-update.event.ts | 1 + .../object-record-changed-values.spec.ts | 4 +++ .../utils/object-record-changed-values.ts | 27 ++++++++++--------- 5 files changed, 23 insertions(+), 12 deletions(-) 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 d9a018f86c..0d5909471d 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 1a5de29567..bef145c1e2 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 037b38178c..aa4b59e720 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 9e4e51791a..6772e1f871 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 062693cbd5..eaf3c4ebfe 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; },