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 78a98aa72..c709a711e 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 @@ -8,10 +8,12 @@ import { import { IConnection } from 'src/engine/api/graphql/workspace-query-runner/interfaces/connection.interface'; import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface'; import { + CreateManyResolverArgs, FindManyResolverArgs, FindOneResolverArgs, } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; +import { GraphqlQueryCreateManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service'; import { GraphqlQueryFindManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service'; import { GraphqlQueryFindOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service'; import { LogExecutionTime } from 'src/engine/decorators/observability/log-execution-time.decorator'; @@ -51,4 +53,15 @@ export class GraphqlQueryRunnerService { return graphqlQueryFindManyResolverService.findMany(args, options); } + + @LogExecutionTime() + async createMany( + args: CreateManyResolverArgs>, + options: WorkspaceQueryRunnerOptions, + ): Promise { + const graphqlQueryCreateManyResolverService = + new GraphqlQueryCreateManyResolverService(this.twentyORMGlobalManager); + + return graphqlQueryCreateManyResolverService.createMany(args, options); + } } 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 new file mode 100644 index 000000000..34ab5e849 --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts @@ -0,0 +1,33 @@ +import { InsertResult } from 'typeorm'; + +import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; +import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface'; +import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; + +export class GraphqlQueryCreateManyResolverService { + private twentyORMGlobalManager: TwentyORMGlobalManager; + + constructor(twentyORMGlobalManager: TwentyORMGlobalManager) { + this.twentyORMGlobalManager = twentyORMGlobalManager; + } + + async createMany( + args: CreateManyResolverArgs>, + options: WorkspaceQueryRunnerOptions, + ): Promise { + const { authContext, objectMetadataItem } = options; + const repository = + await this.twentyORMGlobalManager.getRepositoryForWorkspace( + authContext.workspace.id, + objectMetadataItem.nameSingular, + ); + + const insertResult: InsertResult = !args.upsert + ? await repository.insert(args.data) + : await repository.upsert(args.data, ['id']); + + return insertResult.generatedMaps as ObjectRecord[]; + } +} 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 6c7a36c9c..cc70a9c5b 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 @@ -36,19 +36,18 @@ import { } from 'src/engine/api/graphql/workspace-query-runner/jobs/call-webhook-jobs.job'; import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util'; import { parseResult } from 'src/engine/api/graphql/workspace-query-runner/utils/parse-result.util'; -import { withSoftDeleted } from 'src/engine/api/graphql/workspace-query-runner/utils/with-soft-deleted.util'; import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service'; import { WorkspaceQueryRunnerException, WorkspaceQueryRunnerExceptionCode, } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.exception'; import { DuplicateService } from 'src/engine/core-modules/duplicate/duplicate.service'; -import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; -import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event'; import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/types/object-record-delete.event'; import { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.event'; +import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; +import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; @@ -99,13 +98,6 @@ export class WorkspaceQueryRunnerService { options: WorkspaceQueryRunnerOptions, ): Promise | undefined> { const { authContext, objectMetadataItem } = options; - const start = performance.now(); - - const isQueryRunnerTwentyORMEnabled = - await this.featureFlagService.isFeatureEnabled( - FeatureFlagKey.IsQueryRunnerTwentyORMEnabled, - authContext.workspace.id, - ); const hookedArgs = await this.workspaceQueryHookService.executePreQueryHooks( @@ -121,34 +113,7 @@ export class WorkspaceQueryRunnerService { ResolverArgsType.FindMany, )) as FindManyResolverArgs; - if (isQueryRunnerTwentyORMEnabled) { - return this.graphqlQueryRunnerService.findMany(computedArgs, options); - } - - const query = await this.workspaceQueryBuilderFactory.findMany( - computedArgs, - { - ...options, - withSoftDeleted: withSoftDeleted(args.filter), - }, - ); - - const result = await this.execute(query, authContext.workspace.id); - - const end = performance.now(); - - this.logger.log( - `query time: ${end - start} ms on query ${ - options.objectMetadataItem.nameSingular - }`, - ); - - return this.parseResult>( - result, - objectMetadataItem, - '', - authContext.workspace.id, - ); + return this.graphqlQueryRunnerService.findMany(computedArgs, options); } async findOne< @@ -166,12 +131,6 @@ export class WorkspaceQueryRunnerService { } const { authContext, objectMetadataItem } = options; - const isQueryRunnerTwentyORMEnabled = - await this.featureFlagService.isFeatureEnabled( - FeatureFlagKey.IsQueryRunnerTwentyORMEnabled, - authContext.workspace.id, - ); - const hookedArgs = await this.workspaceQueryHookService.executePreQueryHooks( authContext, @@ -186,27 +145,7 @@ export class WorkspaceQueryRunnerService { ResolverArgsType.FindOne, )) as FindOneResolverArgs; - if (isQueryRunnerTwentyORMEnabled) { - return this.graphqlQueryRunnerService.findOne(computedArgs, options); - } - - const query = await this.workspaceQueryBuilderFactory.findOne( - computedArgs, - { - ...options, - withSoftDeleted: withSoftDeleted(args.filter), - }, - ); - - const result = await this.execute(query, authContext.workspace.id); - const parsedResult = await this.parseResult>( - result, - objectMetadataItem, - '', - authContext.workspace.id, - ); - - return parsedResult?.edges?.[0]?.node; + return this.graphqlQueryRunnerService.findOne(computedArgs, options); } async findDuplicates( @@ -283,6 +222,12 @@ export class WorkspaceQueryRunnerService { ): Promise { const { authContext, objectMetadataItem } = options; + const isQueryRunnerTwentyORMEnabled = + await this.featureFlagService.isFeatureEnabled( + FeatureFlagKey.IsQueryRunnerTwentyORMEnabled, + authContext.workspace.id, + ); + assertMutationNotOnRemoteObject(objectMetadataItem); if (args.upsert) { @@ -309,6 +254,13 @@ export class WorkspaceQueryRunnerService { ResolverArgsType.CreateMany, )) as CreateManyResolverArgs; + if (isQueryRunnerTwentyORMEnabled) { + return (await this.graphqlQueryRunnerService.createMany( + computedArgs, + options, + )) as Record[]; + } + const query = await this.workspaceQueryBuilderFactory.createMany( computedArgs, options, diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts index 06335af63..a264b44bf 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts @@ -428,9 +428,13 @@ export class WorkspaceRepository< const formatedEntity = await this.formatData(entity); const result = await manager.insert(this.target, formatedEntity); - const formattedResult = await this.formatResult(result); + const formattedResult = await this.formatResult(result.generatedMaps); - return formattedResult; + return { + raw: result.raw, + generatedMaps: formattedResult, + identifiers: result.identifiers, + }; } /** @@ -470,11 +474,19 @@ export class WorkspaceRepository< const formattedEntityOrEntities = await this.formatData(entityOrEntities); - return manager.upsert( + const result = await manager.upsert( this.target, formattedEntityOrEntities, conflictPathsOrOptions, ); + + const formattedResult = await this.formatResult(result.generatedMaps); + + return { + raw: result.raw, + generatedMaps: formattedResult, + identifiers: result.identifiers, + }; } /**