diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service.ts index b79137ab8..d1aabdd11 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.service.ts @@ -28,7 +28,6 @@ import { } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; import { GraphqlQueryResolverFactory } from 'src/engine/api/graphql/graphql-query-runner/factories/graphql-query-resolver.factory'; -import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service'; import { QueryResultGettersFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/query-result-getters.factory'; import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory'; import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service'; @@ -42,7 +41,6 @@ export class GraphqlQueryRunnerService { private readonly queryRunnerArgsFactory: QueryRunnerArgsFactory, private readonly queryResultGettersFactory: QueryResultGettersFactory, private readonly graphqlQueryResolverFactory: GraphqlQueryResolverFactory, - private readonly apiEventEmitterService: ApiEventEmitterService, ) {} /** QUERIES */ @@ -109,15 +107,6 @@ export class GraphqlQueryRunnerService { T[] >('createMany', { data: [args.data], upsert: args.upsert }, options); - // TODO: emitCreateEvents should be moved to the ORM layer - if (results) { - this.apiEventEmitterService.emitCreateEvents( - results, - options.authContext, - options.objectMetadataItemWithFieldMaps, - ); - } - return results[0]; } @@ -126,20 +115,11 @@ export class GraphqlQueryRunnerService { args: CreateManyResolverArgs>, options: WorkspaceQueryRunnerOptions, ): Promise { - const results = await this.executeQuery< - CreateManyResolverArgs>, - T[] - >('createMany', args, options); - - if (results) { - this.apiEventEmitterService.emitCreateEvents( - results, - options.authContext, - options.objectMetadataItemWithFieldMaps, - ); - } - - return results; + return this.executeQuery>, T[]>( + 'createMany', + args, + options, + ); } @LogExecutionTime() @@ -147,28 +127,11 @@ export class GraphqlQueryRunnerService { args: UpdateOneResolverArgs>, options: WorkspaceQueryRunnerOptions, ): Promise { - const existingRecord = await this.executeQuery( - 'findOne', - { - filter: { id: { eq: args.id } }, - }, + return await this.executeQuery>, T>( + 'updateOne', + args, options, ); - - const result = await this.executeQuery< - UpdateOneResolverArgs>, - T - >('updateOne', args, options); - - this.apiEventEmitterService.emitUpdateEvents( - [existingRecord], - [result], - Object.keys(args.data), - options.authContext, - options.objectMetadataItemWithFieldMaps, - ); - - return result; } @LogExecutionTime() @@ -176,31 +139,11 @@ export class GraphqlQueryRunnerService { args: UpdateManyResolverArgs>, options: WorkspaceQueryRunnerOptions, ): Promise { - const existingRecords = await this.executeQuery< - FindManyResolverArgs, - IConnection> - >( - 'findMany', - { - filter: args.filter, - }, + return this.executeQuery>, T[]>( + 'updateMany', + args, options, ); - - const result = await this.executeQuery< - UpdateManyResolverArgs>, - T[] - >('updateMany', args, options); - - this.apiEventEmitterService.emitUpdateEvents( - existingRecords.edges.map((edge) => edge.node), - result, - Object.keys(args.data), - options.authContext, - options.objectMetadataItemWithFieldMaps, - ); - - return result; } @LogExecutionTime() @@ -208,10 +151,7 @@ export class GraphqlQueryRunnerService { args: DeleteOneResolverArgs, options: WorkspaceQueryRunnerOptions, ): Promise { - const result = await this.executeQuery< - UpdateOneResolverArgs>, - T - >( + return this.executeQuery>, T>( 'deleteOne', { id: args.id, @@ -219,14 +159,6 @@ export class GraphqlQueryRunnerService { }, options, ); - - this.apiEventEmitterService.emitDeletedEvents( - [result], - options.authContext, - options.objectMetadataItemWithFieldMaps, - ); - - return result; } @LogExecutionTime() @@ -234,10 +166,7 @@ export class GraphqlQueryRunnerService { args: DeleteManyResolverArgs, options: WorkspaceQueryRunnerOptions, ): Promise { - const result = await this.executeQuery< - UpdateManyResolverArgs>, - T[] - >( + return this.executeQuery>, T[]>( 'deleteMany', { filter: args.filter, @@ -246,14 +175,6 @@ export class GraphqlQueryRunnerService { }, options, ); - - this.apiEventEmitterService.emitDeletedEvents( - result, - options.authContext, - options.objectMetadataItemWithFieldMaps, - ); - - return result; } @LogExecutionTime() @@ -261,19 +182,11 @@ export class GraphqlQueryRunnerService { args: DestroyOneResolverArgs, options: WorkspaceQueryRunnerOptions, ): Promise { - const result = await this.executeQuery( + return this.executeQuery( 'destroyOne', args, options, ); - - this.apiEventEmitterService.emitDestroyEvents( - [result], - options.authContext, - options.objectMetadataItemWithFieldMaps, - ); - - return result; } @LogExecutionTime() @@ -281,19 +194,11 @@ export class GraphqlQueryRunnerService { args: DestroyManyResolverArgs, options: WorkspaceQueryRunnerOptions, ): Promise { - const result = await this.executeQuery( + return this.executeQuery( 'destroyMany', args, options, ); - - this.apiEventEmitterService.emitDestroyEvents( - result, - options.authContext, - options.objectMetadataItemWithFieldMaps, - ); - - return result; } @LogExecutionTime() @@ -301,7 +206,7 @@ export class GraphqlQueryRunnerService { args: RestoreManyResolverArgs, options: WorkspaceQueryRunnerOptions, ): Promise { - return await this.executeQuery>, T>( + return this.executeQuery>, T>( 'restoreMany', { filter: args.filter, diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts index 19bc28cf0..3880419f8 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts @@ -12,6 +12,7 @@ import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/c import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser'; import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper'; +import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service'; import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util'; import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; @@ -23,6 +24,7 @@ export class GraphqlQueryCreateManyResolverService { constructor( private readonly twentyORMGlobalManager: TwentyORMGlobalManager, + private readonly apiEventEmitterService: ApiEventEmitterService, ) {} async resolve( @@ -80,6 +82,12 @@ export class GraphqlQueryCreateManyResolverService objectMetadataMaps, ); + this.apiEventEmitterService.emitCreateEvents( + upsertedRecords, + options.authContext, + options.objectMetadataItemWithFieldMaps, + ); + const processNestedRelationsHelper = new ProcessNestedRelationsHelper(); if (relations) { diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts index 8b4176d26..2ab596514 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts @@ -11,6 +11,7 @@ import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/c import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser'; import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper'; +import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util'; @@ -20,6 +21,7 @@ export class GraphqlQueryDestroyManyResolverService { constructor( private readonly twentyORMGlobalManager: TwentyORMGlobalManager, + private readonly apiEventEmitterService: ApiEventEmitterService, ) {} async resolve( @@ -75,6 +77,12 @@ export class GraphqlQueryDestroyManyResolverService objectMetadataMaps, ); + this.apiEventEmitterService.emitDestroyEvents( + deletedRecords, + options.authContext, + options.objectMetadataItemWithFieldMaps, + ); + const processNestedRelationsHelper = new ProcessNestedRelationsHelper(); if (relations) { diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts index 044370a07..3c0e0b3c5 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts @@ -15,6 +15,7 @@ import { import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser'; import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper'; +import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util'; @@ -24,6 +25,7 @@ export class GraphqlQueryDestroyOneResolverService { constructor( private readonly twentyORMGlobalManager: TwentyORMGlobalManager, + private readonly apiEventEmitterService: ApiEventEmitterService, ) {} async resolve( @@ -78,11 +80,17 @@ export class GraphqlQueryDestroyOneResolverService ); } - const recordBeforeDeletion = formatResult( + const deletedRecords = formatResult( nonFormattedDeletedObjectRecords.raw, objectMetadataItemWithFieldMaps, objectMetadataMaps, - )[0]; + ); + + this.apiEventEmitterService.emitDestroyEvents( + deletedRecords, + options.authContext, + options.objectMetadataItemWithFieldMaps, + ); const processNestedRelationsHelper = new ProcessNestedRelationsHelper(); @@ -90,7 +98,7 @@ export class GraphqlQueryDestroyOneResolverService await processNestedRelationsHelper.processNestedRelations({ objectMetadataMaps, parentObjectMetadataItem: objectMetadataItemWithFieldMaps, - parentObjectRecords: [recordBeforeDeletion], + parentObjectRecords: deletedRecords, relations, limit: QUERY_MAX_RECORDS, authContext, @@ -102,7 +110,7 @@ export class GraphqlQueryDestroyOneResolverService new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps); return typeORMObjectRecordsParser.processRecord({ - objectRecord: recordBeforeDeletion, + objectRecord: deletedRecords[0], objectName: objectMetadataItemWithFieldMaps.nameSingular, take: 1, totalCount: 1, diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts index 461940be3..7595d676a 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts @@ -11,6 +11,7 @@ import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/c import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser'; import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper'; +import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service'; import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util'; import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; @@ -24,6 +25,7 @@ export class GraphqlQueryUpdateManyResolverService { constructor( private readonly twentyORMGlobalManager: TwentyORMGlobalManager, + private readonly apiEventEmitterService: ApiEventEmitterService, ) {} async resolve( @@ -73,6 +75,16 @@ export class GraphqlQueryUpdateManyResolverService args.filter, ); + const existingRecordsBuilder = withFilterQueryBuilder.clone(); + + const existingRecords = await existingRecordsBuilder.getMany(); + + const formattedExistingRecords = formatResult( + existingRecords, + objectMetadataItemWithFieldMaps, + objectMetadataMaps, + ); + const data = formatData(args.data, objectMetadataItemWithFieldMaps); const nonFormattedUpdatedObjectRecords = await withFilterQueryBuilder @@ -80,19 +92,27 @@ export class GraphqlQueryUpdateManyResolverService .returning('*') .execute(); - const updatedRecords = formatResult( + const formattedUpdatedRecords = formatResult( nonFormattedUpdatedObjectRecords.raw, objectMetadataItemWithFieldMaps, objectMetadataMaps, ); + this.apiEventEmitterService.emitUpdateEvents( + formattedExistingRecords, + formattedUpdatedRecords, + Object.keys(args.data), + options.authContext, + options.objectMetadataItemWithFieldMaps, + ); + const processNestedRelationsHelper = new ProcessNestedRelationsHelper(); if (relations) { await processNestedRelationsHelper.processNestedRelations({ objectMetadataMaps, parentObjectMetadataItem: objectMetadataItemWithFieldMaps, - parentObjectRecords: updatedRecords, + parentObjectRecords: formattedUpdatedRecords, relations, limit: QUERY_MAX_RECORDS, authContext, @@ -103,7 +123,7 @@ export class GraphqlQueryUpdateManyResolverService const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps); - return updatedRecords.map((record: T) => + return formattedUpdatedRecords.map((record: T) => typeORMObjectRecordsParser.processRecord({ objectRecord: record, objectName: objectMetadataItemWithFieldMaps.nameSingular, diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts index 6475e6488..6c40b9d50 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts @@ -15,6 +15,7 @@ import { import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser'; import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper'; +import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service'; import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util'; import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; @@ -27,6 +28,7 @@ export class GraphqlQueryUpdateOneResolverService { constructor( private readonly twentyORMGlobalManager: TwentyORMGlobalManager, + private readonly apiEventEmitterService: ApiEventEmitterService, ) {} async resolve( @@ -67,6 +69,18 @@ export class GraphqlQueryUpdateOneResolverService const data = formatData(args.data, objectMetadataItemWithFieldMaps); + const existingRecordBuilder = queryBuilder.clone(); + + const existingRecords = await existingRecordBuilder + .where({ id: args.id }) + .execute(); + + const formattedExistingRecords = formatResult( + existingRecords, + objectMetadataItemWithFieldMaps, + objectMetadataMaps, + ); + const result = await queryBuilder .update(data) .where({ id: args.id }) @@ -75,20 +89,28 @@ export class GraphqlQueryUpdateOneResolverService const nonFormattedUpdatedObjectRecords = result.raw; - const updatedRecords = formatResult( + const formattedUpdatedRecords = formatResult( nonFormattedUpdatedObjectRecords, objectMetadataItemWithFieldMaps, objectMetadataMaps, ); - if (updatedRecords.length === 0) { + this.apiEventEmitterService.emitUpdateEvents( + formattedExistingRecords, + formattedUpdatedRecords, + Object.keys(args.data), + options.authContext, + options.objectMetadataItemWithFieldMaps, + ); + + if (formattedUpdatedRecords.length === 0) { throw new GraphqlQueryRunnerException( 'Record not found', GraphqlQueryRunnerExceptionCode.RECORD_NOT_FOUND, ); } - const updatedRecord = updatedRecords[0] as T; + const updatedRecord = formattedUpdatedRecords[0] as T; const processNestedRelationsHelper = new ProcessNestedRelationsHelper();