11import { Inject , Injectable } from '@nestjs/common' ;
22
3- import { type ObjectRecord } from 'twenty-shared/types' ;
43import { isDefined } from 'twenty-shared/utils' ;
4+ import { Omit } from 'zod/v4/core/util.cjs' ;
55
66import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface' ;
7+ import { QueryResultFieldValue } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/interfaces/query-result-field-value' ;
78
89import { CommonSelectedFieldsHandler } from 'src/engine/api/common/common-args-handlers/common-query-selected-fields/common-selected-fields.handler' ;
10+ import {
11+ CommonQueryRunnerException ,
12+ CommonQueryRunnerExceptionCode ,
13+ } from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception' ;
914import { CommonResultGettersService } from 'src/engine/api/common/common-result-getters/common-result-getters.service' ;
10- import { CommonQueryNames } from 'src/engine/api/common/types/common-query-args.type' ;
15+ import { CommonBaseQueryRunnerContext } from 'src/engine/api/common/types/common-base-query-runner-context.type' ;
16+ import { CommonExtendedQueryRunnerContext } from 'src/engine/api/common/types/common-extended-query-runner-context.type' ;
17+ import {
18+ CommonExtendedInput ,
19+ CommonInput ,
20+ CommonQueryArgs ,
21+ CommonQueryNames ,
22+ } from 'src/engine/api/common/types/common-query-args.type' ;
23+ import { CommonQueryResult } from 'src/engine/api/common/types/common-query-result.type' ;
24+ import { isWorkspaceAuthContext } from 'src/engine/api/common/utils/is-workspace-auth-context.util' ;
1125import { OBJECTS_WITH_SETTINGS_PERMISSIONS_REQUIREMENTS } from 'src/engine/api/graphql/graphql-query-runner/constants/objects-with-settings-permissions-requirements' ;
26+ import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser' ;
1227import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper' ;
1328import { QueryResultGettersFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/query-result-getters.factory' ;
1429import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory' ;
30+ import { WorkspacePreQueryHookPayload } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type' ;
1531import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service' ;
1632import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/api-key-role.service' ;
1733import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type' ;
@@ -29,7 +45,10 @@ import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/wo
2945import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager' ;
3046
3147@Injectable ( )
32- export abstract class CommonBaseQueryRunnerService {
48+ export abstract class CommonBaseQueryRunnerService <
49+ Args extends CommonQueryArgs ,
50+ Output extends CommonQueryResult ,
51+ > {
3352 @Inject ( )
3453 protected readonly workspaceQueryHookService : WorkspaceQueryHookService ;
3554 @Inject ( )
@@ -53,60 +72,117 @@ export abstract class CommonBaseQueryRunnerService {
5372 @Inject ( )
5473 protected readonly commonResultGettersService : CommonResultGettersService ;
5574
56- public async prepareQueryRunnerContext ( {
57- authContext,
58- objectMetadataItemWithFieldMaps,
59- } : {
60- authContext : WorkspaceAuthContext ;
61- objectMetadataItemWithFieldMaps : ObjectMetadataItemWithFieldMaps ;
62- } ) {
75+ public async execute (
76+ args : CommonInput < Args > ,
77+ queryRunnerContext : CommonBaseQueryRunnerContext ,
78+ operationName : CommonQueryNames ,
79+ ) : Promise < Output > {
80+ const { authContext, objectMetadataItemWithFieldMaps, objectMetadataMaps } =
81+ queryRunnerContext ;
82+
83+ if ( ! isWorkspaceAuthContext ( authContext ) ) {
84+ throw new CommonQueryRunnerException (
85+ 'Invalid auth context' ,
86+ CommonQueryRunnerExceptionCode . INVALID_AUTH_CONTEXT ,
87+ ) ;
88+ }
89+
90+ await this . validate ( args , queryRunnerContext ) ;
91+
6392 if ( objectMetadataItemWithFieldMaps . isSystem === true ) {
6493 await this . validateSettingsPermissionsOnObjectOrThrow (
6594 authContext ,
66- objectMetadataItemWithFieldMaps ,
95+ queryRunnerContext ,
6796 ) ;
6897 }
6998
70- const workspace = authContext . workspace ;
71-
72- const workspaceDataSource =
73- await this . twentyORMGlobalManager . getDataSourceForWorkspace ( {
74- workspaceId : workspace . id ,
75- } ) ;
99+ const commonQueryParser = new GraphqlQueryParser (
100+ objectMetadataItemWithFieldMaps ,
101+ objectMetadataMaps ,
102+ ) ;
76103
77- const { roleId } = await this . getRoleIdAndObjectsPermissions (
78- authContext ,
79- workspace . id ,
104+ const processedArgs = await this . processArgs (
105+ args ,
106+ queryRunnerContext ,
107+ operationName ,
108+ commonQueryParser ,
80109 ) ;
81110
82- const rolePermissionConfig = { unionOf : [ roleId ] } ;
111+ const extendedQueryRunnerContext =
112+ await this . prepareExtendedQueryRunnerContext (
113+ authContext ,
114+ queryRunnerContext ,
115+ ) ;
83116
84- const repository = workspaceDataSource . getRepository (
85- objectMetadataItemWithFieldMaps . nameSingular ,
86- rolePermissionConfig ,
117+ const results = await this . run ( processedArgs , {
118+ ...extendedQueryRunnerContext ,
119+ commonQueryParser,
120+ } ) ;
121+
122+ return this . enrichResultsWithGettersAndHooks ( {
123+ results,
124+ operationName,
87125 authContext,
126+ objectMetadataItemWithFieldMaps,
127+ objectMetadataMaps,
128+ } ) ;
129+ }
130+
131+ protected abstract run (
132+ args : CommonExtendedInput < Args > ,
133+ queryRunnerContext : CommonExtendedQueryRunnerContext ,
134+ ) : Promise < Output > ;
135+
136+ protected abstract validate (
137+ args : CommonInput < Args > ,
138+ queryRunnerContext : CommonBaseQueryRunnerContext ,
139+ ) : Promise < void > ;
140+
141+ protected abstract computeArgs (
142+ args : CommonInput < Args > ,
143+ queryRunnerContext : CommonBaseQueryRunnerContext ,
144+ ) : Promise < CommonInput < Args > > ;
145+
146+ private async processArgs (
147+ args : CommonInput < Args > ,
148+ queryRunnerContext : CommonBaseQueryRunnerContext ,
149+ operationName : CommonQueryNames ,
150+ commonQueryParser : GraphqlQueryParser ,
151+ ) : Promise < CommonExtendedInput < Args > > {
152+ const selectedFieldsResult = commonQueryParser . parseSelectedFields (
153+ args . selectedFields ,
88154 ) ;
89155
156+ const { authContext, objectMetadataItemWithFieldMaps } = queryRunnerContext ;
157+ const hookedArgs =
158+ ( await this . workspaceQueryHookService . executePreQueryHooks (
159+ authContext ,
160+ objectMetadataItemWithFieldMaps . nameSingular ,
161+ operationName ,
162+ args as WorkspacePreQueryHookPayload < CommonQueryNames > ,
163+ ) ) as CommonInput < Args > ;
164+
165+ const computedArgs = await this . computeArgs ( hookedArgs , queryRunnerContext ) ;
166+
90167 return {
91- workspaceDataSource,
92- repository,
93- rolePermissionConfig,
168+ ...computedArgs ,
169+ selectedFieldsResult,
94170 } ;
95171 }
96172
97- public async enrichResultsWithGettersAndHooks ( {
173+ private async enrichResultsWithGettersAndHooks ( {
98174 results,
99175 operationName,
100176 authContext,
101177 objectMetadataItemWithFieldMaps,
102178 objectMetadataMaps,
103179 } : {
104- results : ObjectRecord [ ] ;
180+ results : Output ;
105181 operationName : CommonQueryNames ;
106182 authContext : WorkspaceAuthContext ;
107183 objectMetadataItemWithFieldMaps : ObjectMetadataItemWithFieldMaps ;
108184 objectMetadataMaps : ObjectMetadataMaps ;
109- } ) : Promise < ObjectRecord [ ] > {
185+ } ) : Promise < Output > {
110186 const resultWithGetters =
111187 await this . commonResultGettersService . processQueryResult (
112188 results ,
@@ -119,16 +195,18 @@ export abstract class CommonBaseQueryRunnerService {
119195 authContext ,
120196 objectMetadataItemWithFieldMaps . nameSingular ,
121197 operationName ,
122- resultWithGetters ,
198+ resultWithGetters as QueryResultFieldValue ,
123199 ) ;
124200
125- return resultWithGetters ;
201+ return resultWithGetters as Output ;
126202 }
127203
128204 private async validateSettingsPermissionsOnObjectOrThrow (
129205 authContext : WorkspaceAuthContext ,
130- objectMetadataItemWithFieldMaps : ObjectMetadataItemWithFieldMaps ,
206+ queryRunnerContext : CommonBaseQueryRunnerContext ,
131207 ) {
208+ const { objectMetadataItemWithFieldMaps } = queryRunnerContext ;
209+
132210 const workspace = authContext . workspace ;
133211
134212 if (
@@ -206,4 +284,35 @@ export abstract class CommonBaseQueryRunnerService {
206284
207285 return { roleId, objectsPermissions : objectMetadataPermissions [ roleId ] } ;
208286 }
287+
288+ private async prepareExtendedQueryRunnerContext (
289+ authContext : WorkspaceAuthContext ,
290+ queryRunnerContext : CommonBaseQueryRunnerContext ,
291+ ) : Promise < Omit < CommonExtendedQueryRunnerContext , 'commonQueryParser' > > {
292+ const workspaceDataSource =
293+ await this . twentyORMGlobalManager . getDataSourceForWorkspace ( {
294+ workspaceId : authContext . workspace . id ,
295+ } ) ;
296+
297+ const { roleId } = await this . getRoleIdAndObjectsPermissions (
298+ authContext ,
299+ authContext . workspace . id ,
300+ ) ;
301+
302+ const rolePermissionConfig = { unionOf : [ roleId ] } ;
303+
304+ const repository = workspaceDataSource . getRepository (
305+ queryRunnerContext . objectMetadataItemWithFieldMaps . nameSingular ,
306+ rolePermissionConfig ,
307+ authContext ,
308+ ) ;
309+
310+ return {
311+ ...queryRunnerContext ,
312+ authContext,
313+ workspaceDataSource,
314+ rolePermissionConfig,
315+ repository,
316+ } ;
317+ }
209318}
0 commit comments