Skip to content

Commit 3966eae

Browse files
committed
compute selected fields before common
1 parent 469233b commit 3966eae

20 files changed

+314
-121
lines changed

packages/twenty-server/src/engine/api/common/common-query-runners/common-base-query-runner.service.ts

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Inject, Injectable } from '@nestjs/common';
22

3-
import { ObjectsPermissions } from 'twenty-shared/types';
43
import { isDefined } from 'twenty-shared/utils';
54

65
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
@@ -9,13 +8,8 @@ import { type IConnection } from 'src/engine/api/graphql/workspace-query-runner/
98
import { type IEdge } from 'src/engine/api/graphql/workspace-query-runner/interfaces/edge.interface';
109

1110
import { CommonSelectedFieldsHandler } from 'src/engine/api/common/common-args-handlers/common-query-selected-fields/common-selected-fields.handler';
12-
import {
13-
CommonQueryNames,
14-
RawSelectedFields,
15-
} from 'src/engine/api/common/types/common-query-args.type';
16-
import { CommonSelectedFieldsResult } from 'src/engine/api/common/types/common-selected-fields-result.type';
11+
import { CommonQueryNames } from 'src/engine/api/common/types/common-query-args.type';
1712
import { OBJECTS_WITH_SETTINGS_PERMISSIONS_REQUIREMENTS } from 'src/engine/api/graphql/graphql-query-runner/constants/objects-with-settings-permissions-requirements';
18-
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
1913
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
2014
import { QueryResultGettersFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/query-result-getters.factory';
2115
import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory';
@@ -85,8 +79,10 @@ export abstract class CommonBaseQueryRunnerService<
8579
workspaceId: workspace.id,
8680
});
8781

88-
const { roleId, objectsPermissions } =
89-
await this.getRoleIdAndObjectsPermissions(authContext, workspace.id);
82+
const { roleId } = await this.getRoleIdAndObjectsPermissions(
83+
authContext,
84+
workspace.id,
85+
);
9086

9187
const repository = workspaceDataSource.getRepository(
9288
objectMetadataItemWithFieldMaps.nameSingular,
@@ -101,43 +97,9 @@ export abstract class CommonBaseQueryRunnerService<
10197
isExecutedByApiKey: isDefined(authContext.apiKey),
10298
roleId,
10399
shouldBypassPermissionChecks: false,
104-
objectsPermissions,
105100
};
106101
}
107102

108-
public async computeSelectedFields({
109-
rawSelectedFields,
110-
objectMetadataItemWithFieldMaps,
111-
objectMetadataMaps,
112-
objectsPermissions,
113-
}: {
114-
rawSelectedFields: RawSelectedFields;
115-
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
116-
objectMetadataMaps: ObjectMetadataMaps;
117-
objectsPermissions: ObjectsPermissions;
118-
}): Promise<CommonSelectedFieldsResult> {
119-
if (isDefined(rawSelectedFields.graphqlSelectedFields)) {
120-
const graphqlQueryParser = new GraphqlQueryParser(
121-
objectMetadataItemWithFieldMaps,
122-
objectMetadataMaps,
123-
);
124-
125-
//TODO : Refacto-common - QueryParser should be moved to selected fields handler
126-
return graphqlQueryParser.parseSelectedFields(
127-
objectMetadataItemWithFieldMaps,
128-
rawSelectedFields.graphqlSelectedFields,
129-
objectMetadataMaps,
130-
);
131-
}
132-
133-
return this.selectedFieldsHandler.computeFromDepth({
134-
objectsPermissions,
135-
objectMetadataMaps,
136-
objectMetadataMapItem: objectMetadataItemWithFieldMaps,
137-
depth: rawSelectedFields.depth,
138-
});
139-
}
140-
141103
public async enrichResultsWithGettersAndHooks({
142104
results,
143105
operationName,

packages/twenty-server/src/engine/api/common/common-query-runners/common-find-one-query-runner.service.ts

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Injectable } from '@nestjs/common';
22

33
import { QUERY_MAX_RECORDS } from 'twenty-shared/constants';
4+
import { isDefined } from 'twenty-shared/utils';
45
import { FindOptionsRelations, ObjectLiteral } from 'typeorm';
56

67
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
@@ -17,7 +18,6 @@ import {
1718
import {
1819
CommonQueryNames,
1920
FindOneQueryArgs,
20-
RawSelectedFields,
2121
} from 'src/engine/api/common/types/common-query-args.type';
2222
import { isWorkspaceAuthContext } from 'src/engine/api/common/utils/is-workspace-auth-context.util';
2323
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
@@ -30,13 +30,11 @@ import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-met
3030
@Injectable()
3131
export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerService<ObjectRecord> {
3232
async run({
33-
rawSelectedFields,
3433
args,
3534
authContext: toValidateAuthContext,
3635
objectMetadataMaps,
3736
objectMetadataItemWithFieldMaps,
3837
}: {
39-
rawSelectedFields: RawSelectedFields;
4038
args: FindOneQueryArgs;
4139
authContext: AuthContext;
4240
objectMetadataMaps: ObjectMetadataMaps;
@@ -56,19 +54,11 @@ export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerServic
5654
repository,
5755
roleId,
5856
shouldBypassPermissionChecks,
59-
objectsPermissions,
6057
} = await this.prepareQueryRunnerContext({
6158
authContext,
6259
objectMetadataItemWithFieldMaps,
6360
});
6461

65-
const selectedFieldsResult = await this.computeSelectedFields({
66-
rawSelectedFields,
67-
objectMetadataItemWithFieldMaps,
68-
objectMetadataMaps,
69-
objectsPermissions,
70-
});
71-
7262
const processedArgs = await this.processQueryArgs({
7363
authContext,
7464
objectMetadataItemWithFieldMaps,
@@ -107,8 +97,8 @@ export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerServic
10797
);
10898

10999
const columnsToSelect = buildColumnsToSelect({
110-
select: selectedFieldsResult.select,
111-
relations: selectedFieldsResult.relations,
100+
select: args.selectedFieldsResult.select,
101+
relations: args.selectedFieldsResult.relations,
112102
objectMetadataItemWithFieldMaps,
113103
objectMetadataMaps,
114104
});
@@ -128,13 +118,13 @@ export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerServic
128118

129119
const objectRecords = [objectRecord] as ObjectRecord[];
130120

131-
if (selectedFieldsResult.relations) {
121+
if (isDefined(args.selectedFieldsResult.relations)) {
132122
await this.processNestedRelationsHelper.processNestedRelations({
133123
objectMetadataMaps,
134124
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
135125
parentObjectRecords: objectRecords,
136126
//TODO : Refacto-common - To fix when switching processNestedRelationsHelper to Common
137-
relations: selectedFieldsResult.relations as Record<
127+
relations: args.selectedFieldsResult.relations as Record<
138128
string,
139129
FindOptionsRelations<ObjectLiteral>
140130
>,
@@ -143,7 +133,7 @@ export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerServic
143133
workspaceDataSource,
144134
roleId,
145135
shouldBypassPermissionChecks,
146-
selectedFields: selectedFieldsResult.select,
136+
selectedFields: args.selectedFieldsResult.select,
147137
});
148138
}
149139

@@ -176,14 +166,16 @@ export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerServic
176166
args: FindOneQueryArgs;
177167
}): Promise<FindOneQueryArgs> {
178168
const hookedArgs =
179-
await this.workspaceQueryHookService.executePreQueryHooks(
169+
(await this.workspaceQueryHookService.executePreQueryHooks(
180170
authContext,
181171
objectMetadataItemWithFieldMaps.nameSingular,
182172
CommonQueryNames.findOne,
183173
args,
184-
);
174+
//TODO : Refacto-common - To fix when updating workspaceQueryHookService, removing gql typing dependency
175+
)) as FindOneQueryArgs;
185176

186177
return {
178+
...hookedArgs,
187179
filter: this.queryRunnerArgsFactory.overrideFilterByFieldMetadata(
188180
hookedArgs.filter,
189181
objectMetadataItemWithFieldMaps,

packages/twenty-server/src/engine/api/common/common-query-runners/utils/common-query-runner-to-rest-api-exception-handler.util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313

1414
export const commonQueryRunnerToRestApiExceptionHandler = (
1515
error: CommonQueryRunnerException,
16-
) => {
16+
): never => {
1717
switch (error.code) {
1818
case CommonQueryRunnerExceptionCode.INVALID_QUERY_INPUT:
1919
throw new BadRequestException(error.message);

packages/twenty-server/src/engine/api/common/types/common-query-args.type.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import { type ObjectRecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
22

3-
import { type Depth } from 'src/engine/api/rest/input-factories/depth-input.factory';
3+
import { type CommonSelectedFieldsResult } from 'src/engine/api/common/types/common-selected-fields-result.type';
44

55
export enum CommonQueryNames {
66
findOne = 'findOne',
77
}
88

9-
export type RawSelectedFields = {
10-
graphqlSelectedFields?: Record<string, boolean>;
11-
depth?: Depth;
12-
};
13-
149
export interface FindOneQueryArgs {
10+
selectedFieldsResult: CommonSelectedFieldsResult;
1511
filter?: ObjectRecordFilter;
1612
}
1713

packages/twenty-server/src/engine/api/graphql/workspace-resolver-builder/factories/find-one-resolver.factory.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
1111

1212
import { CommonFindOneQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-find-one-query-runner.service';
13+
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
1314
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
1415
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
1516

@@ -29,12 +30,20 @@ export class FindOneResolverFactory
2930
const internalContext = context;
3031

3132
return async (_source, args, _context, info) => {
32-
const selectedFields = graphqlFields(info);
33-
3433
try {
34+
const graphqlQueryParser = new GraphqlQueryParser(
35+
internalContext.objectMetadataItemWithFieldMaps,
36+
internalContext.objectMetadataMaps,
37+
);
38+
39+
const selectedFieldsResult = graphqlQueryParser.parseSelectedFields(
40+
internalContext.objectMetadataItemWithFieldMaps,
41+
graphqlFields(info),
42+
internalContext.objectMetadataMaps,
43+
);
44+
3545
return await this.commonFindOneQueryRunnerService.run({
36-
rawSelectedFields: { graphqlSelectedFields: selectedFields },
37-
args,
46+
args: { ...args, selectedFieldsResult },
3847
authContext: internalContext.authContext,
3948
objectMetadataMaps: internalContext.objectMetadataMaps,
4049
objectMetadataItemWithFieldMaps:

packages/twenty-server/src/engine/api/rest/core/controllers/rest-api-core.controller.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ import {
1414

1515
import { Response } from 'express';
1616

17-
import { AuthenticatedRequest } from 'src/engine/api/rest/core/interfaces/authenticated-request.interface';
18-
1917
import { RestApiCoreService } from 'src/engine/api/rest/core/services/rest-api-core.service';
2018
import { RestApiExceptionFilter } from 'src/engine/api/rest/rest-api-exception.filter';
19+
import { AuthenticatedRequest } from 'src/engine/api/rest/types/authenticated-request';
2120
import { JwtAuthGuard } from 'src/engine/guards/jwt-auth.guard';
2221
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
2322

@@ -33,6 +32,9 @@ export class RestApiCoreController {
3332
@Req() request: AuthenticatedRequest,
3433
@Res() res: Response,
3534
) {
35+
this.logger.log(
36+
`[REST API] Processing BATCH request to ${request.path} on workspace ${request.workspaceId}`,
37+
);
3638
const result = await this.restApiCoreService.createMany(request);
3739

3840
res.status(200).send(result);
@@ -43,6 +45,9 @@ export class RestApiCoreController {
4345
@Req() request: AuthenticatedRequest,
4446
@Res() res: Response,
4547
) {
48+
this.logger.log(
49+
`[REST API] Processing DUPLICATES request to ${request.path} on workspace ${request.workspaceId}`,
50+
);
4651
const result = await this.restApiCoreService.findDuplicates(request);
4752

4853
res.status(200).send(result);
@@ -53,6 +58,9 @@ export class RestApiCoreController {
5358
@Req() request: AuthenticatedRequest,
5459
@Res() res: Response,
5560
) {
61+
this.logger.log(
62+
`[REST API] Processing POST request to ${request.path} on workspace ${request.workspaceId}`,
63+
);
5664
const result = await this.restApiCoreService.createOne(request);
5765

5866
res.status(201).send(result);
@@ -63,6 +71,9 @@ export class RestApiCoreController {
6371
@Req() request: AuthenticatedRequest,
6472
@Res() res: Response,
6573
) {
74+
this.logger.log(
75+
`[REST API] Processing GET request to ${request.path} on workspace ${request.workspaceId}`,
76+
);
6677
const result = await this.restApiCoreService.get(request);
6778

6879
res.status(200).send(result);
@@ -73,6 +84,9 @@ export class RestApiCoreController {
7384
@Req() request: AuthenticatedRequest,
7485
@Res() res: Response,
7586
) {
87+
this.logger.log(
88+
`[REST API] Processing DELETE request to ${request.path} on workspace ${request.workspaceId}`,
89+
);
7690
const result = await this.restApiCoreService.delete(request);
7791

7892
res.status(200).send(result);
@@ -83,6 +97,9 @@ export class RestApiCoreController {
8397
@Req() request: AuthenticatedRequest,
8498
@Res() res: Response,
8599
) {
100+
this.logger.log(
101+
`[REST API] Processing PATCH request to ${request.path} on workspace ${request.workspaceId}`,
102+
);
86103
const result = await this.restApiCoreService.update(request);
87104

88105
res.status(200).send(result);
@@ -96,6 +113,9 @@ export class RestApiCoreController {
96113
@Req() request: AuthenticatedRequest,
97114
@Res() res: Response,
98115
) {
116+
this.logger.log(
117+
`[REST API] Processing PUT request to ${request.path} on workspace ${request.workspaceId}`,
118+
);
99119
const result = await this.restApiCoreService.update(request);
100120

101121
res.status(200).send(result);

packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-create-many.handler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ import {
44
InternalServerErrorException,
55
} from '@nestjs/common';
66

7-
import { Request } from 'express';
87
import isEmpty from 'lodash.isempty';
98
import { isDefined } from 'twenty-shared/utils';
109

1110
import { RestApiBaseHandler } from 'src/engine/api/rest/core/interfaces/rest-api-base.handler';
1211

12+
import { AuthenticatedRequest } from 'src/engine/api/rest/types/authenticated-request';
1313
import { getAllSelectableFields } from 'src/engine/api/utils/get-all-selectable-fields.utils';
1414

1515
@Injectable()
1616
export class RestApiCreateManyHandler extends RestApiBaseHandler {
17-
async handle(request: Request) {
17+
async handle(request: AuthenticatedRequest) {
1818
const { objectMetadata, repository, restrictedFields } =
1919
await this.getRepositoryAndMetadataOrFail(request);
2020

packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-create-one.handler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ import {
44
InternalServerErrorException,
55
} from '@nestjs/common';
66

7-
import { Request } from 'express';
87
import isEmpty from 'lodash.isempty';
98
import { isDefined } from 'twenty-shared/utils';
109

1110
import { RestApiBaseHandler } from 'src/engine/api/rest/core/interfaces/rest-api-base.handler';
1211

12+
import { AuthenticatedRequest } from 'src/engine/api/rest/types/authenticated-request';
1313
import { getAllSelectableFields } from 'src/engine/api/utils/get-all-selectable-fields.utils';
1414

1515
@Injectable()
1616
export class RestApiCreateOneHandler extends RestApiBaseHandler {
17-
async handle(request: Request) {
17+
async handle(request: AuthenticatedRequest) {
1818
const { objectMetadata, repository, restrictedFields } =
1919
await this.getRepositoryAndMetadataOrFail(request);
2020

packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-delete-one.handler.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import { BadRequestException, Injectable } from '@nestjs/common';
22

3-
import { Request } from 'express';
4-
53
import { RestApiBaseHandler } from 'src/engine/api/rest/core/interfaces/rest-api-base.handler';
64

75
import { parseCorePath } from 'src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-path.utils';
6+
import { AuthenticatedRequest } from 'src/engine/api/rest/types/authenticated-request';
87
import { getAllSelectableFields } from 'src/engine/api/utils/get-all-selectable-fields.utils';
98

109
@Injectable()
1110
export class RestApiDeleteOneHandler extends RestApiBaseHandler {
12-
async handle(request: Request) {
11+
async handle(request: AuthenticatedRequest) {
1312
const { id: recordId } = parseCorePath(request);
1413

1514
if (!recordId) {

packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-find-duplicates.handler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import {
1010
RestApiBaseHandler,
1111
} from 'src/engine/api/rest/core/interfaces/rest-api-base.handler';
1212

13+
import { AuthenticatedRequest } from 'src/engine/api/rest/types/authenticated-request';
1314
import { buildDuplicateConditions } from 'src/engine/api/utils/build-duplicate-conditions.utils';
1415

1516
@Injectable()
1617
export class RestApiFindDuplicatesHandler extends RestApiBaseHandler {
17-
async handle(request: Request) {
18+
async handle(request: AuthenticatedRequest) {
1819
this.validate(request);
1920

2021
const {

0 commit comments

Comments
 (0)