diff --git a/packages/twenty-server/patches/@graphql-yoga+nestjs+2.1.0.patch b/packages/twenty-server/patches/@graphql-yoga+nestjs+2.1.0.patch index 7c928da504..5479588335 100644 --- a/packages/twenty-server/patches/@graphql-yoga+nestjs+2.1.0.patch +++ b/packages/twenty-server/patches/@graphql-yoga+nestjs+2.1.0.patch @@ -1,5 +1,5 @@ diff --git a/dist/cjs/index.js b/dist/cjs/index.js -index 1684394..32602b3 100644 +index 1684394..dd0773d 100644 --- a/dist/cjs/index.js +++ b/dist/cjs/index.js @@ -3,10 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); @@ -26,18 +26,16 @@ index 1684394..32602b3 100644 const app = this.httpAdapterHost.httpAdapter.getInstance(); preStartHook?.(app); // nest's logger doesnt have the info method -@@ -42,6 +46,47 @@ class AbstractYogaDriver extends graphql_2.AbstractGraphQLDriver { +@@ -42,6 +46,45 @@ class AbstractYogaDriver extends graphql_2.AbstractGraphQLDriver { } const yoga = (0, graphql_yoga_1.createYoga)({ ...options, + schema: async (request) => { + const workspaceId = request.req.workspace?.id ?? 'anonymous' + const workspaceCacheVersion = request.req.workspaceMetadataVersion ?? '0' -+ const workspaceUserId = request.req.user?.id ?? 'anonymous' -+ const apiKeyId = request.req.apiKey?.id ?? 'no-api-key' + const url = request.req.baseUrl + -+ const cacheKey = `${workspaceId}-${workspaceUserId}-${apiKeyId}-${url}-${workspaceCacheVersion}` ++ const cacheKey = `${workspaceId}-${url}-${workspaceCacheVersion}` + + if(this.schemaCache.has(cacheKey)) { + return this.schemaCache.get(cacheKey) @@ -62,7 +60,7 @@ index 1684394..32602b3 100644 + }); + + for (const key of this.schemaCache.keys()) { -+ if (key.startsWith(`${workspaceId}-${workspaceUserId}-${url}-`)) { ++ if (key.startsWith(`${workspaceId}-${url}-`)) { + this.schemaCache.delete(key); + } + } @@ -74,7 +72,7 @@ index 1684394..32602b3 100644 graphqlEndpoint: options.path, // disable logging by default // however, if `true` use nest logger -@@ -54,11 +98,52 @@ class AbstractYogaDriver extends graphql_2.AbstractGraphQLDriver { +@@ -54,11 +97,50 @@ class AbstractYogaDriver extends graphql_2.AbstractGraphQLDriver { this.yoga = yoga; app.use(yoga.graphqlEndpoint, (req, res) => yoga(req, res, { req, res })); } @@ -87,11 +85,9 @@ index 1684394..32602b3 100644 + schema: async (request) => { + const workspaceId = request.req.workspace?.id ?? 'anonymous' + const workspaceCacheVersion = request.req.workspaceMetadataVersion ?? '0' -+ const workspaceUserId = request.req.user?.id ?? 'anonymous' -+ const apiKeyId = request.req.apiKey?.id ?? 'no-api-key' + const url = request.req.baseUrl + -+ const cacheKey = `${workspaceId}-${workspaceUserId}-${apiKeyId}-${url}-${workspaceCacheVersion}` ++ const cacheKey = `${workspaceId}-${url}-${workspaceCacheVersion}` + + if(this.schemaCache.has(cacheKey)) { + return this.schemaCache.get(cacheKey) @@ -116,7 +112,7 @@ index 1684394..32602b3 100644 + }); + + for (const key of this.schemaCache.keys()) { -+ if (key.startsWith(`${workspaceId}-${workspaceUserId}-${url}-`)) { ++ if (key.startsWith(`${workspaceId}-${url}-`)) { + this.schemaCache.delete(key); + } + } @@ -129,7 +125,7 @@ index 1684394..32602b3 100644 // disable logging by default // however, if `true` use fastify logger diff --git a/dist/esm/index.js b/dist/esm/index.js -index 7068c51..b8cbf9e 100644 +index 7068c51..8494b69 100644 --- a/dist/esm/index.js +++ b/dist/esm/index.js @@ -1,9 +1,13 @@ @@ -158,18 +154,16 @@ index 7068c51..b8cbf9e 100644 const app = this.httpAdapterHost.httpAdapter.getInstance(); preStartHook?.(app); // nest's logger doesnt have the info method -@@ -39,6 +43,47 @@ export class AbstractYogaDriver extends AbstractGraphQLDriver { +@@ -39,6 +43,45 @@ export class AbstractYogaDriver extends AbstractGraphQLDriver { } const yoga = createYoga({ ...options, + schema: async (request) => { + const workspaceId = request.req.workspace?.id ?? 'anonymous' + const workspaceCacheVersion = request.req.workspaceMetadataVersion ?? '0' -+ const workspaceUserId = request.req.user?.id ?? 'anonymous' -+ const apiKeyId = request.req.apiKey?.id ?? 'no-api-key' + const url = request.req.baseUrl + -+ const cacheKey = `${workspaceId}-${workspaceUserId}-${apiKeyId}-${url}-${workspaceCacheVersion}` ++ const cacheKey = `${workspaceId}-${url}-${workspaceCacheVersion}` + + if (this.schemaCache.has(cacheKey)) { + return this.schemaCache.get(cacheKey) @@ -194,7 +188,7 @@ index 7068c51..b8cbf9e 100644 + }); + + for (const key of this.schemaCache.keys()) { -+ if (key.startsWith(`${workspaceId}-${workspaceUserId}-${url}-`)) { ++ if (key.startsWith(`${workspaceId}-${url}-`)) { + this.schemaCache.delete(key); + } + } @@ -206,7 +200,7 @@ index 7068c51..b8cbf9e 100644 graphqlEndpoint: options.path, // disable logging by default // however, if `true` use nest logger -@@ -51,11 +95,52 @@ export class AbstractYogaDriver extends AbstractGraphQLDriver { +@@ -51,11 +94,50 @@ export class AbstractYogaDriver extends AbstractGraphQLDriver { this.yoga = yoga; app.use(yoga.graphqlEndpoint, (req, res) => yoga(req, res, { req, res })); } @@ -219,11 +213,9 @@ index 7068c51..b8cbf9e 100644 + schema: async (request) => { + const workspaceId = request.req.workspace?.id ?? 'anonymous' + const workspaceCacheVersion = request.req.workspaceMetadataVersion ?? '0' -+ const workspaceUserId = request.req.user?.id ?? 'anonymous' -+ const apiKeyId = request.req.apiKey?.id ?? 'no-api-key' + const url = request.req.baseUrl + -+ const cacheKey = `${workspaceId}-${workspaceUserId}-${apiKeyId}-${url}-${workspaceCacheVersion}` ++ const cacheKey = `${workspaceId}-${url}-${workspaceCacheVersion}` + + if (this.schemaCache.has(cacheKey)) { + return this.schemaCache.get(cacheKey) @@ -248,7 +240,7 @@ index 7068c51..b8cbf9e 100644 + }); + + for (const key of this.schemaCache.keys()) { -+ if (key.startsWith(`${workspaceId}-${workspaceUserId}-${url}-`)) { ++ if (key.startsWith(`${workspaceId}-${url}-`)) { + this.schemaCache.delete(key); + } + } @@ -338,7 +330,7 @@ index 2c6a965..fd86dac 100644 }): void; subscriptionWithFilter(instanceRef: unknown, filterFn: (payload: TPayload, variables: TVariables, context: TContext) => boolean | Promise, createSubscribeContext: Function): (args_0: TPayload, args_1: TVariables, args_2: TContext) => Promise>; diff --git a/src/index.ts b/src/index.ts -index ce142f6..10e17d2 100644 +index ce142f6..d3e7bab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,10 @@ @@ -413,18 +405,16 @@ index ce142f6..10e17d2 100644 { preStartHook }: { preStartHook?: (app: Express) => void } = {}, ) { const app: Express = this.httpAdapterHost.httpAdapter.getInstance(); -@@ -98,6 +109,41 @@ export abstract class AbstractYogaDriver< +@@ -98,6 +109,39 @@ export abstract class AbstractYogaDriver< const yoga = createYoga>({ ...options, + schema: async request => { + const workspaceId = request.req.workspace.id + const workspaceCacheVersion = request.req.workspaceMetadataVersion -+ const workspaceUserId = request.req.user?.id ?? 'anonymous' -+ const apiKeyId = request.req.apiKey?.id ?? 'no-api-key' + const url = request.req.baseUrl + -+ const cacheKey = `${workspaceId}-${workspaceUserId}-${apiKeyId}-${url}-${workspaceCacheVersion}` ++ const cacheKey = `${workspaceId}-${url}-${workspaceCacheVersion}` + + if (this.schemaCache.has(cacheKey)) { + return this.schemaCache.get(cacheKey) @@ -455,7 +445,7 @@ index ce142f6..10e17d2 100644 graphqlEndpoint: options.path, // disable logging by default // however, if `true` use nest logger -@@ -105,8 +150,8 @@ export abstract class AbstractYogaDriver< +@@ -105,8 +149,8 @@ export abstract class AbstractYogaDriver< options.logging == null ? false : options.logging @@ -466,7 +456,7 @@ index ce142f6..10e17d2 100644 }); this.yoga = yoga as YogaDriverServerInstance; -@@ -115,7 +160,7 @@ export abstract class AbstractYogaDriver< +@@ -115,7 +159,7 @@ export abstract class AbstractYogaDriver< } protected registerFastify( @@ -475,18 +465,16 @@ index ce142f6..10e17d2 100644 { preStartHook }: { preStartHook?: (app: FastifyInstance) => void } = {}, ) { const app: FastifyInstance = this.httpAdapterHost.httpAdapter.getInstance(); -@@ -124,6 +169,41 @@ export abstract class AbstractYogaDriver< +@@ -124,6 +168,39 @@ export abstract class AbstractYogaDriver< const yoga = createYoga>({ ...options, + schema: async request => { + const workspaceId = request.req.workspace.id + const workspaceCacheVersion = request.req.workspaceMetadataVersion -+ const workspaceUserId = request.req.user?.id ?? 'anonymous' -+ const apiKeyId = request.req.apiKey?.id ?? 'no-api-key' + const url = request.req.baseUrl + -+ const cacheKey = `${workspaceId}-${workspaceUserId}-${apiKeyId}-${url}-${workspaceCacheVersion}` ++ const cacheKey = `${workspaceId}-${url}-${workspaceCacheVersion}` + + if (this.schemaCache.has(cacheKey)) { + return this.schemaCache.get(cacheKey) @@ -517,7 +505,7 @@ index ce142f6..10e17d2 100644 graphqlEndpoint: options.path, // disable logging by default // however, if `true` use fastify logger -@@ -191,8 +270,8 @@ export class YogaDriver< +@@ -191,8 +268,8 @@ export class YogaDriver< const config: SubscriptionConfig = options.subscriptions === true ? { diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts index abaf2db881..67b3aec8cc 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts @@ -14,11 +14,11 @@ import { type YogaInitialContext, } from 'graphql-yoga'; import { JsonWebTokenError, TokenExpiredError } from 'jsonwebtoken'; +import { isDefined } from 'twenty-shared/utils'; import { NodeEnvironment } from 'src/engine/core-modules/twenty-config/interfaces/node-environment.interface'; import { WorkspaceSchemaFactory } from 'src/engine/api/graphql/workspace-schema.factory'; -import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; import { ApiConfig, Billing, @@ -107,31 +107,14 @@ export class GraphQLConfigService ], }, conditionalSchema: async (context) => { - let user: UserEntity | null | undefined; - let workspace: WorkspaceEntity | undefined; + const { workspace, user } = context.req; try { - const { - user, - workspace, - apiKey, - application, - workspaceMemberId, - userWorkspaceId, - } = context.req; - - if (!workspace) { + if (!isDefined(workspace)) { return new GraphQLSchema({}); } - return await this.createSchema(context, { - user, - workspace, - apiKey, - application, - workspaceMemberId, - userWorkspaceId, - }); + return await this.createSchema(context, workspace); } catch (error) { if (error instanceof UnauthorizedException) { throw new GraphQLError('Unauthenticated', { @@ -161,7 +144,7 @@ export class GraphQLConfigService throw handleExceptionAndConvertToGraphQLError( error, this.exceptionHandlerService, - user + isDefined(user) ? { id: user.id, email: user.email, @@ -169,7 +152,7 @@ export class GraphQLConfigService lastName: user.lastName, } : undefined, - workspace + isDefined(workspace) ? { id: workspace.id, displayName: workspace.displayName, @@ -197,7 +180,7 @@ export class GraphQLConfigService async createSchema( context: YogaDriverServerContext<'express'> & YogaInitialContext, - data: AuthContext, + workspace: WorkspaceEntity, ): Promise>> { // Create a new contextId for each request const contextId = ContextIdFactory.create(); @@ -216,6 +199,6 @@ export class GraphQLConfigService }, ); - return await workspaceFactory.createGraphQLSchema(data); + return await workspaceFactory.createGraphQLSchema(workspace); } } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-many-resolver.factory.ts index bd1296f080..fd8f29a37c 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-many-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-many-resolver.factory.ts @@ -14,6 +14,7 @@ import { CommonCreateManyQueryRunnerService } from 'src/engine/api/common/common import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class CreateManyResolverFactory @@ -30,26 +31,31 @@ export class CreateManyResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const records = await this.commonCreateManyQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return records.map((record: ObjectRecord) => typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }), diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-one-resolver.factory.ts index 6550acccc6..12864ed51e 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-one-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/create-one-resolver.factory.ts @@ -13,6 +13,7 @@ import { CommonCreateOneQueryRunnerService } from 'src/engine/api/common/common- import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class CreateOneResolverFactory @@ -29,25 +30,30 @@ export class CreateOneResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const record = await this.commonCreateOneQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-many-resolver.factory.ts index 608ccf5813..0b8946ad95 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-many-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-many-resolver.factory.ts @@ -14,6 +14,7 @@ import { CommonDeleteManyQueryRunnerService } from 'src/engine/api/common/common import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class DeleteManyResolverFactory @@ -30,26 +31,31 @@ export class DeleteManyResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const records = await this.commonDeleteManyQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return records.map((record: ObjectRecord) => typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }), diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-one-resolver.factory.ts index 1bc0ae1acf..d524535385 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-one-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/delete-one-resolver.factory.ts @@ -13,6 +13,7 @@ import { CommonDeleteOneQueryRunnerService } from 'src/engine/api/common/common- import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class DeleteOneResolverFactory @@ -29,25 +30,30 @@ export class DeleteOneResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const record = await this.commonDeleteOneQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-many-resolver.factory.ts index 46f57ecfc2..15486fa0ad 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-many-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-many-resolver.factory.ts @@ -14,6 +14,7 @@ import { CommonDestroyManyQueryRunnerService } from 'src/engine/api/common/commo import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class DestroyManyResolverFactory @@ -30,26 +31,31 @@ export class DestroyManyResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const records = await this.commonDestroyManyQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return records.map((record: ObjectRecord) => typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }), diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-one-resolver.factory.ts index d7afd06d55..132ac445f6 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-one-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/destroy-one-resolver.factory.ts @@ -13,6 +13,7 @@ import { CommonDestroyOneQueryRunnerService } from 'src/engine/api/common/common import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class DestroyOneResolverFactory @@ -29,25 +30,30 @@ export class DestroyOneResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const record = await this.commonDestroyOneQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-duplicates-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-duplicates-resolver.factory.ts index 15f6192899..0bbdc0e57f 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-duplicates-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-duplicates-resolver.factory.ts @@ -14,6 +14,7 @@ import { CommonFindDuplicatesQueryRunnerService } from 'src/engine/api/common/co import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class FindDuplicatesResolverFactory @@ -30,27 +31,32 @@ export class FindDuplicatesResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const paginatedDuplicates = await this.commonFindDuplicatesQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return paginatedDuplicates.map((duplicate) => typeORMObjectRecordsParser.createConnection({ objectRecords: duplicate.records, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: duplicate.records.length, totalCount: duplicate.totalCount, order: [{ id: OrderByDirection.AscNullsFirst }], diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-many-resolver.factory.ts index f9b173ace9..d66bbe3f14 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-many-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-many-resolver.factory.ts @@ -14,6 +14,7 @@ import { CommonFindManyQueryRunnerService } from 'src/engine/api/common/common-q import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class FindManyResolverFactory @@ -30,9 +31,14 @@ export class FindManyResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const { records, @@ -42,21 +48,21 @@ export class FindManyResolverFactory selectedFieldsResult, } = await this.commonFindManyQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return typeORMObjectRecordsParser.createConnection({ objectRecords: records, objectRecordsAggregatedValues: aggregatedValues, selectedAggregatedFields: selectedFieldsResult.aggregate, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: args.first ?? args.last ?? QUERY_MAX_RECORDS, totalCount, order: args.orderBy, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-one-resolver.factory.ts index fe8160001c..46ff8b36e0 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-one-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-one-resolver.factory.ts @@ -13,6 +13,7 @@ import { CommonFindOneQueryRunnerService } from 'src/engine/api/common/common-qu import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class FindOneResolverFactory @@ -29,25 +30,30 @@ export class FindOneResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { try { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + const record = await this.commonFindOneQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/group-by-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/group-by-resolver.factory.ts index 946b216c24..1595c6d73b 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/group-by-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/group-by-resolver.factory.ts @@ -14,6 +14,7 @@ import { CommonGroupByQueryRunnerService } from 'src/engine/api/common/common-qu import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class GroupByResolverFactory @@ -30,9 +31,14 @@ export class GroupByResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + const shouldIncludeRecords = isDefined(selectedFields.edges?.node) && Object.keys(selectedFields.edges?.node).length > 0; @@ -40,20 +46,20 @@ export class GroupByResolverFactory try { const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); const results = await this.commonGroupByQueryRunnerService.execute( { ...args, selectedFields, includeRecords: shouldIncludeRecords }, - internalContext, + resolverContext, ); const formattedResults = results.map((group) => { const formattedRecords = typeORMObjectRecordsParser.createConnection({ objectRecords: group.records ?? [], - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, objectRecordsAggregatedValues: {}, selectedAggregatedFields: {}, take: group.records?.length || 0, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/merge-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/merge-many-resolver.factory.ts index 86345942d5..e48688e3df 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/merge-many-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/merge-many-resolver.factory.ts @@ -13,6 +13,7 @@ import { CommonMergeManyQueryRunnerService } from 'src/engine/api/common/common- import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class MergeManyResolverFactory @@ -29,25 +30,30 @@ export class MergeManyResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const record = await this.commonMergeManyQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-many-resolver.factory.ts index 444fee1a9b..5d33bca725 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-many-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-many-resolver.factory.ts @@ -14,6 +14,7 @@ import { CommonRestoreManyQueryRunnerService } from 'src/engine/api/common/commo import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class RestoreManyResolverFactory @@ -30,26 +31,31 @@ export class RestoreManyResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const records = await this.commonRestoreManyQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return records.map((record: ObjectRecord) => typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }), diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-one-resolver.factory.ts index 3bf4b686c0..2c7cccde5d 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-one-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/restore-one-resolver.factory.ts @@ -13,6 +13,7 @@ import { CommonRestoreOneQueryRunnerService } from 'src/engine/api/common/common import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class RestoreOneResolverFactory @@ -29,25 +30,30 @@ export class RestoreOneResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const record = await this.commonRestoreOneQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory.ts index 90a0868826..c859601e32 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory.ts @@ -14,6 +14,7 @@ import { CommonUpdateManyQueryRunnerService } from 'src/engine/api/common/common import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class UpdateManyResolverFactory @@ -30,26 +31,31 @@ export class UpdateManyResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const records = await this.commonUpdateManyQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return records.map((record: ObjectRecord) => typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }), diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-one-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-one-resolver.factory.ts index c31aef9150..c45aec5b57 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-one-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/update-one-resolver.factory.ts @@ -13,6 +13,7 @@ import { CommonUpdateOneQueryRunnerService } from 'src/engine/api/common/common- import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper'; import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util'; import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names'; +import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util'; @Injectable() export class UpdateOneResolverFactory @@ -29,25 +30,30 @@ export class UpdateOneResolverFactory ): Resolver { const internalContext = context; - return async (_source, args, _context, info) => { + return async (_source, args, requestContext, info) => { const selectedFields = graphqlFields(info); + const resolverContext = createQueryRunnerContext({ + workspaceSchemaBuilderContext: internalContext, + request: requestContext.req, + }); + try { const record = await this.commonUpdateOneQueryRunnerService.execute( { ...args, selectedFields }, - internalContext, + resolverContext, ); const typeORMObjectRecordsParser = new ObjectRecordsToGraphqlConnectionHelper( - internalContext.flatObjectMetadataMaps, - internalContext.flatFieldMetadataMaps, - internalContext.objectIdByNameSingular, + resolverContext.flatObjectMetadataMaps, + resolverContext.flatFieldMetadataMaps, + resolverContext.objectIdByNameSingular, ); return typeORMObjectRecordsParser.processRecord({ objectRecord: record, - objectName: internalContext.flatObjectMetadata.nameSingular, + objectName: resolverContext.flatObjectMetadata.nameSingular, take: 1, totalCount: 1, }); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util.ts new file mode 100644 index 0000000000..5cca2656c9 --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util.ts @@ -0,0 +1,37 @@ +import { type WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface'; + +import { type CommonBaseQueryRunnerContext } from 'src/engine/api/common/types/common-base-query-runner-context.type'; +import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; + +export const createQueryRunnerContext = ({ + workspaceSchemaBuilderContext, + request, +}: { + workspaceSchemaBuilderContext: WorkspaceSchemaBuilderContext; + request: AuthContext; +}): CommonBaseQueryRunnerContext => { + const { + user, + workspace, + apiKey, + workspaceMemberId, + userWorkspaceId, + userWorkspace, + authProvider, + impersonationContext, + } = request; + + return { + ...workspaceSchemaBuilderContext, + authContext: { + user, + workspace, + apiKey, + workspaceMemberId, + userWorkspaceId, + userWorkspace, + authProvider, + impersonationContext, + }, + }; +}; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory.ts index 0db00351d5..d206f3a1f7 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory.ts @@ -12,11 +12,6 @@ import { RestoreManyResolverFactory } from 'src/engine/api/graphql/workspace-res import { RestoreOneResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/factories/restore-one-resolver.factory'; import { UpdateManyResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory'; import { WorkspaceResolverBuilderService } from 'src/engine/api/graphql/workspace-resolver-builder/workspace-resolver-builder.service'; -import { - AuthException, - AuthExceptionCode, -} from 'src/engine/core-modules/auth/auth.exception'; -import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; @@ -59,7 +54,6 @@ export class WorkspaceResolverFactory { ) {} async create( - authContext: AuthContext, flatObjectMetadataMaps: FlatEntityMaps, flatFieldMetadataMaps: FlatEntityMaps, objectIdByNameSingular: Record, @@ -90,15 +84,6 @@ export class WorkspaceResolverFactory { Mutation: {}, }; - const workspaceId = authContext.workspace?.id; - - if (!workspaceId) { - throw new AuthException( - 'Unauthenticated', - AuthExceptionCode.UNAUTHENTICATED, - ); - } - for (const flatObjectMetadata of Object.values( flatObjectMetadataMaps.byId, ).filter(isDefined)) { @@ -125,7 +110,6 @@ export class WorkspaceResolverFactory { ) { // @ts-expect-error legacy noImplicitAny resolvers.Query[resolverName] = resolverFactory.create({ - authContext, flatObjectMetadata, flatObjectMetadataMaps, flatFieldMetadataMaps, @@ -157,7 +141,6 @@ export class WorkspaceResolverFactory { ) { // @ts-expect-error legacy noImplicitAny resolvers.Mutation[resolverName] = resolverFactory.create({ - authContext, flatObjectMetadata, flatObjectMetadataMaps, flatFieldMetadataMaps, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface.ts index 1b7737ac38..10f8aa2cf2 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface.ts @@ -1,10 +1,8 @@ -import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; export interface WorkspaceSchemaBuilderContext { - authContext: AuthContext; flatObjectMetadata: FlatObjectMetadata; flatObjectMetadataMaps: FlatEntityMaps; flatFieldMetadataMaps: FlatEntityMaps; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema.factory.ts index 988dd0890a..5191edfa65 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema.factory.ts @@ -9,11 +9,7 @@ import { ScalarsExplorerService } from 'src/engine/api/graphql/services/scalars- import { workspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/factories/factories'; import { WorkspaceResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory'; import { WorkspaceGraphQLSchemaGenerator } from 'src/engine/api/graphql/workspace-schema-builder/workspace-graphql-schema.factory'; -import { - AuthException, - AuthExceptionCode, -} from 'src/engine/core-modules/auth/auth.exception'; -import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { FlatEntityMapsException, @@ -34,33 +30,22 @@ export class WorkspaceSchemaFactory { private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, ) {} - async createGraphQLSchema(authContext: AuthContext): Promise { - if (!authContext.workspace?.id) { - return new GraphQLSchema({}); - } - + async createGraphQLSchema( + workspace: WorkspaceEntity, + ): Promise { const dataSourcesMetadata = await this.dataSourceService.getDataSourcesMetadataFromWorkspaceId( - authContext.workspace.id, + workspace.id, ); if (!dataSourcesMetadata || dataSourcesMetadata.length === 0) { return new GraphQLSchema({}); } - const workspaceId = authContext.workspace.id; - - if (!workspaceId) { - throw new AuthException( - 'Unauthenticated', - AuthExceptionCode.UNAUTHENTICATED, - ); - } - const { flatObjectMetadataMaps, flatFieldMetadataMaps, flatIndexMaps } = await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( { - workspaceId, + workspaceId: workspace.id, flatMapsKeys: [ 'flatObjectMetadataMaps', 'flatFieldMetadataMaps', @@ -84,12 +69,14 @@ export class WorkspaceSchemaFactory { } let metadataVersion = - await this.workspaceCacheStorageService.getMetadataVersion(workspaceId); + await this.workspaceCacheStorageService.getMetadataVersion(workspace.id); if (!isDefined(metadataVersion)) { - metadataVersion = authContext.workspace.metadataVersion ?? 0; + metadataVersion = isDefined(workspace.metadataVersion) + ? workspace.metadataVersion + : 0; await this.workspaceCacheStorageService.setMetadataVersion( - workspaceId, + workspace.id, metadataVersion, ); } @@ -99,12 +86,12 @@ export class WorkspaceSchemaFactory { ); let typeDefs = await this.workspaceCacheStorageService.getGraphQLTypeDefs( - authContext.workspace.id, + workspace.id, metadataVersion, ); let usedScalarNames = await this.workspaceCacheStorageService.getGraphQLUsedScalarNames( - authContext.workspace.id, + workspace.id, metadataVersion, ); @@ -121,19 +108,18 @@ export class WorkspaceSchemaFactory { typeDefs = printSchema(autoGeneratedSchema); await this.workspaceCacheStorageService.setGraphQLTypeDefs( - authContext.workspace.id, + workspace.id, metadataVersion, typeDefs, ); await this.workspaceCacheStorageService.setGraphQLUsedScalarNames( - authContext.workspace.id, + workspace.id, metadataVersion, usedScalarNames, ); } const autoGeneratedResolvers = await this.workspaceResolverFactory.create( - authContext, flatObjectMetadataMaps, flatFieldMetadataMaps, idByNameSingular, diff --git a/yarn.lock b/yarn.lock index 7a3c53b0b5..92a2d08fa8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7659,14 +7659,14 @@ __metadata: "@graphql-yoga/nestjs@patch:@graphql-yoga/nestjs@2.1.0#./patches/@graphql-yoga+nestjs+2.1.0.patch::locator=twenty-server%40workspace%3Apackages%2Ftwenty-server": version: 2.1.0 - resolution: "@graphql-yoga/nestjs@patch:@graphql-yoga/nestjs@npm%3A2.1.0#./patches/@graphql-yoga+nestjs+2.1.0.patch::version=2.1.0&hash=971f26&locator=twenty-server%40workspace%3Apackages%2Ftwenty-server" + resolution: "@graphql-yoga/nestjs@patch:@graphql-yoga/nestjs@npm%3A2.1.0#./patches/@graphql-yoga+nestjs+2.1.0.patch::version=2.1.0&hash=d6801e&locator=twenty-server%40workspace%3Apackages%2Ftwenty-server" peerDependencies: "@nestjs/common": ^10.0.0 "@nestjs/core": ^10.0.0 "@nestjs/graphql": ^12.0.0 graphql: ^15.0.0 || ^16.0.0 graphql-yoga: ^4.0.4 - checksum: 10c0/68ebaf195c93a6d31e22f91e5474cfb51675eac44a6c1a2ef7c856539e704dd9e7f8ea7cfd930a0ad37894edbcab6502b642f202d9f31f8f38b36c7d4d5add43 + checksum: 10c0/929da1f7265003cb5f43291d6db96e752bd2ac5d81e21fb3af9b245e54e732f5862789d7e5941e893d85255919b4c6a5a37adb16ef6594fab606e8eec742891c languageName: node linkType: hard