6071 return only updated fields of records in zapier update trigger (#8193)
- move webhook triggers into `entity-events-to-db.listener.ts` - refactor event management - add a `@OnDatabaseEvent` decorator to manage database events - add updatedFields in updated events - update openApi webhooks docs - update zapier integration
This commit is contained in:
@ -1,10 +1,14 @@
|
||||
import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event';
|
||||
|
||||
type Diff<T> = {
|
||||
[K in keyof T]: { before: T[K]; after: T[K] };
|
||||
};
|
||||
|
||||
export class ObjectRecordUpdateEvent<T> extends ObjectRecordBaseEvent {
|
||||
properties: {
|
||||
updatedFields?: string[];
|
||||
before: T;
|
||||
after: T;
|
||||
diff?: Partial<T>;
|
||||
diff?: Partial<Diff<T>>;
|
||||
};
|
||||
}
|
||||
|
||||
@ -7,8 +7,3 @@ export class ObjectRecordBaseEvent {
|
||||
objectMetadata: ObjectMetadataInterface;
|
||||
properties: any;
|
||||
}
|
||||
|
||||
export class ObjectRecordBaseEventWithNameAndWorkspaceId extends ObjectRecordBaseEvent {
|
||||
name: string;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
@ -45,76 +45,76 @@ describe('objectRecordChangedValues', () => {
|
||||
name: { before: 'Original Name', after: 'Updated Name' },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('ignores changes to the updatedAt field', () => {
|
||||
const oldRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516d',
|
||||
updatedAt: new Date('2020-01-01').toDateString(),
|
||||
};
|
||||
const newRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516d',
|
||||
updatedAt: new Date('2024-01-01').toDateString(),
|
||||
};
|
||||
|
||||
const result = objectRecordChangedValues(
|
||||
oldRecord,
|
||||
newRecord,
|
||||
[],
|
||||
mockObjectMetadata,
|
||||
);
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('returns an empty object when there are no changes', () => {
|
||||
const oldRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516k',
|
||||
name: 'Name',
|
||||
value: 100,
|
||||
};
|
||||
const newRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516k',
|
||||
name: 'Name',
|
||||
value: 100,
|
||||
};
|
||||
|
||||
const result = objectRecordChangedValues(
|
||||
oldRecord,
|
||||
newRecord,
|
||||
['name', 'value'],
|
||||
mockObjectMetadata,
|
||||
);
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('correctly handles a mix of changed, unchanged, and special case values', () => {
|
||||
const oldRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516l',
|
||||
name: 'Original',
|
||||
status: 'active',
|
||||
updatedAt: new Date(2020, 1, 1).toDateString(),
|
||||
config: { theme: 'dark' },
|
||||
};
|
||||
const newRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516l',
|
||||
name: 'Updated',
|
||||
status: 'active',
|
||||
updatedAt: new Date(2021, 1, 1).toDateString(),
|
||||
config: { theme: 'light' },
|
||||
};
|
||||
const expectedChanges = {
|
||||
name: { before: 'Original', after: 'Updated' },
|
||||
config: { before: { theme: 'dark' }, after: { theme: 'light' } },
|
||||
};
|
||||
|
||||
const result = objectRecordChangedValues(
|
||||
oldRecord,
|
||||
newRecord,
|
||||
['name', 'config', 'status'],
|
||||
mockObjectMetadata,
|
||||
);
|
||||
|
||||
expect(result).toEqual(expectedChanges);
|
||||
|
||||
it('ignores changes to the updatedAt field', () => {
|
||||
const oldRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516d',
|
||||
updatedAt: new Date('2020-01-01').toDateString(),
|
||||
};
|
||||
const newRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516d',
|
||||
updatedAt: new Date('2024-01-01').toDateString(),
|
||||
};
|
||||
|
||||
const result = objectRecordChangedValues(
|
||||
oldRecord,
|
||||
newRecord,
|
||||
[],
|
||||
mockObjectMetadata,
|
||||
);
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('returns an empty object when there are no changes', () => {
|
||||
const oldRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516k',
|
||||
name: 'Name',
|
||||
value: 100,
|
||||
};
|
||||
const newRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516k',
|
||||
name: 'Name',
|
||||
value: 100,
|
||||
};
|
||||
|
||||
const result = objectRecordChangedValues(
|
||||
oldRecord,
|
||||
newRecord,
|
||||
['name', 'value'],
|
||||
mockObjectMetadata,
|
||||
);
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('correctly handles a mix of changed, unchanged, and special case values', () => {
|
||||
const oldRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516l',
|
||||
name: 'Original',
|
||||
status: 'active',
|
||||
updatedAt: new Date(2020, 1, 1).toDateString(),
|
||||
config: { theme: 'dark' },
|
||||
};
|
||||
const newRecord = {
|
||||
id: '74316f58-29b0-4a6a-b8fa-d2b506d5516l',
|
||||
name: 'Updated',
|
||||
status: 'active',
|
||||
updatedAt: new Date(2021, 1, 1).toDateString(),
|
||||
config: { theme: 'light' },
|
||||
};
|
||||
const expectedChanges = {
|
||||
name: { before: 'Original', after: 'Updated' },
|
||||
config: { before: { theme: 'dark' }, after: { theme: 'light' } },
|
||||
};
|
||||
|
||||
const result = objectRecordChangedValues(
|
||||
oldRecord,
|
||||
newRecord,
|
||||
['name', 'config', 'status'],
|
||||
mockObjectMetadata,
|
||||
);
|
||||
|
||||
expect(result).toEqual(expectedChanges);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event';
|
||||
import { generateFakeValue } from 'src/engine/utils/generate-fake-value';
|
||||
import { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.event';
|
||||
import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/types/object-record-delete.event';
|
||||
import { ObjectRecordDestroyEvent } from 'src/engine/core-modules/event-emitter/types/object-record-destroy.event';
|
||||
|
||||
export const generateFakeObjectRecordEvent = <Entity>(
|
||||
objectMetadataEntity: ObjectMetadataEntity,
|
||||
action: 'created' | 'updated' | 'deleted' | 'destroyed',
|
||||
):
|
||||
| ObjectRecordCreateEvent<Entity>
|
||||
| ObjectRecordUpdateEvent<Entity>
|
||||
| ObjectRecordDeleteEvent<Entity>
|
||||
| ObjectRecordDestroyEvent<Entity> => {
|
||||
const recordId = v4();
|
||||
const userId = v4();
|
||||
const workspaceMemberId = v4();
|
||||
|
||||
const after = objectMetadataEntity.fields.reduce((acc, field) => {
|
||||
acc[field.name] = generateFakeValue(field.type);
|
||||
|
||||
return acc;
|
||||
}, {} as Entity);
|
||||
|
||||
if (action === 'created') {
|
||||
return {
|
||||
recordId,
|
||||
userId,
|
||||
workspaceMemberId,
|
||||
objectMetadata: objectMetadataEntity,
|
||||
properties: {
|
||||
after,
|
||||
},
|
||||
} satisfies ObjectRecordCreateEvent<Entity>;
|
||||
}
|
||||
|
||||
const before = objectMetadataEntity.fields.reduce((acc, field) => {
|
||||
acc[field.name] = generateFakeValue(field.type);
|
||||
|
||||
return acc;
|
||||
}, {} as Entity);
|
||||
|
||||
if (action === 'updated') {
|
||||
return {
|
||||
recordId,
|
||||
userId,
|
||||
workspaceMemberId,
|
||||
objectMetadata: objectMetadataEntity,
|
||||
properties: {
|
||||
before,
|
||||
after,
|
||||
diff: after,
|
||||
},
|
||||
} satisfies ObjectRecordUpdateEvent<Entity>;
|
||||
}
|
||||
|
||||
if (action === 'deleted') {
|
||||
return {
|
||||
recordId,
|
||||
userId,
|
||||
workspaceMemberId,
|
||||
objectMetadata: objectMetadataEntity,
|
||||
properties: {
|
||||
before,
|
||||
},
|
||||
} satisfies ObjectRecordDeleteEvent<Entity>;
|
||||
}
|
||||
|
||||
if (action === 'destroyed') {
|
||||
return {
|
||||
recordId,
|
||||
userId,
|
||||
workspaceMemberId,
|
||||
objectMetadata: objectMetadataEntity,
|
||||
properties: {
|
||||
before,
|
||||
},
|
||||
} satisfies ObjectRecordDestroyEvent<Entity>;
|
||||
}
|
||||
|
||||
throw new Error(`Unknown action '${action}'`);
|
||||
};
|
||||
@ -15,7 +15,7 @@ export const objectRecordChangedValues = (
|
||||
objectMetadata.fields.map((field) => [field.name, field]),
|
||||
);
|
||||
|
||||
const changedValues = Object.keys(newRecord).reduce(
|
||||
return Object.keys(newRecord).reduce(
|
||||
(acc, key) => {
|
||||
const field = fieldsByKey.get(key);
|
||||
const oldRecordValue = oldRecord[key];
|
||||
@ -36,6 +36,4 @@ export const objectRecordChangedValues = (
|
||||
},
|
||||
{} as Record<string, { before: any; after: any }>,
|
||||
);
|
||||
|
||||
return changedValues;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user