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,82 +72,147 @@ 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+ protected abstract processQueryResult (
147+ queryResult : Output ,
148+ objectMetadataItemId : string ,
149+ objectMetadataMaps : ObjectMetadataMaps ,
150+ authContext : WorkspaceAuthContext ,
151+ ) : Promise < Output > ;
152+
153+ private async processArgs (
154+ args : CommonInput < Args > ,
155+ queryRunnerContext : CommonBaseQueryRunnerContext ,
156+ operationName : CommonQueryNames ,
157+ commonQueryParser : GraphqlQueryParser ,
158+ ) : Promise < CommonExtendedInput < Args > > {
159+ const selectedFieldsResult = commonQueryParser . parseSelectedFields (
160+ args . selectedFields ,
88161 ) ;
89162
163+ const { authContext, objectMetadataItemWithFieldMaps } = queryRunnerContext ;
164+ const hookedArgs =
165+ ( await this . workspaceQueryHookService . executePreQueryHooks (
166+ authContext ,
167+ objectMetadataItemWithFieldMaps . nameSingular ,
168+ operationName ,
169+ args as WorkspacePreQueryHookPayload < CommonQueryNames > ,
170+ ) ) as CommonInput < Args > ;
171+
172+ const computedArgs = await this . computeArgs ( hookedArgs , queryRunnerContext ) ;
173+
90174 return {
91- workspaceDataSource,
92- repository,
93- rolePermissionConfig,
175+ ...computedArgs ,
176+ selectedFieldsResult,
94177 } ;
95178 }
96179
97- public async enrichResultsWithGettersAndHooks ( {
180+ private async enrichResultsWithGettersAndHooks ( {
98181 results,
99182 operationName,
100183 authContext,
101184 objectMetadataItemWithFieldMaps,
102185 objectMetadataMaps,
103186 } : {
104- results : ObjectRecord [ ] ;
187+ results : Output ;
105188 operationName : CommonQueryNames ;
106189 authContext : WorkspaceAuthContext ;
107190 objectMetadataItemWithFieldMaps : ObjectMetadataItemWithFieldMaps ;
108191 objectMetadataMaps : ObjectMetadataMaps ;
109- } ) : Promise < ObjectRecord [ ] > {
110- const resultWithGetters =
111- await this . commonResultGettersService . processQueryResult (
112- results ,
113- objectMetadataItemWithFieldMaps . id ,
114- objectMetadataMaps ,
115- authContext . workspace . id ,
116- ) ;
192+ } ) : Promise < Output > {
193+ const resultWithGetters = await this . processQueryResult (
194+ results ,
195+ objectMetadataItemWithFieldMaps . id ,
196+ objectMetadataMaps ,
197+ authContext ,
198+ ) ;
117199
118200 await this . workspaceQueryHookService . executePostQueryHooks (
119201 authContext ,
120202 objectMetadataItemWithFieldMaps . nameSingular ,
121203 operationName ,
122- resultWithGetters ,
204+ resultWithGetters as QueryResultFieldValue ,
123205 ) ;
124206
125- return resultWithGetters ;
207+ return resultWithGetters as Output ;
126208 }
127209
128210 private async validateSettingsPermissionsOnObjectOrThrow (
129211 authContext : WorkspaceAuthContext ,
130- objectMetadataItemWithFieldMaps : ObjectMetadataItemWithFieldMaps ,
212+ queryRunnerContext : CommonBaseQueryRunnerContext ,
131213 ) {
214+ const { objectMetadataItemWithFieldMaps } = queryRunnerContext ;
215+
132216 const workspace = authContext . workspace ;
133217
134218 if (
@@ -206,4 +290,35 @@ export abstract class CommonBaseQueryRunnerService {
206290
207291 return { roleId, objectsPermissions : objectMetadataPermissions [ roleId ] } ;
208292 }
293+
294+ private async prepareExtendedQueryRunnerContext (
295+ authContext : WorkspaceAuthContext ,
296+ queryRunnerContext : CommonBaseQueryRunnerContext ,
297+ ) : Promise < Omit < CommonExtendedQueryRunnerContext , 'commonQueryParser' > > {
298+ const workspaceDataSource =
299+ await this . twentyORMGlobalManager . getDataSourceForWorkspace ( {
300+ workspaceId : authContext . workspace . id ,
301+ } ) ;
302+
303+ const { roleId } = await this . getRoleIdAndObjectsPermissions (
304+ authContext ,
305+ authContext . workspace . id ,
306+ ) ;
307+
308+ const rolePermissionConfig = { unionOf : [ roleId ] } ;
309+
310+ const repository = workspaceDataSource . getRepository (
311+ queryRunnerContext . objectMetadataItemWithFieldMaps . nameSingular ,
312+ rolePermissionConfig ,
313+ authContext ,
314+ ) ;
315+
316+ return {
317+ ...queryRunnerContext ,
318+ authContext,
319+ workspaceDataSource,
320+ rolePermissionConfig,
321+ repository,
322+ } ;
323+ }
209324}
0 commit comments