Deprecate object metadata maps in favor of flat entities (#16080)

## Context
Deprecating the old objectMetadataMap type in favour of split flat
entities to match with our new caching.
In the long run, trying to achieve:
- Better performance through caching
- Consistent data access patterns across the codebase
- Reduced database queries

Now that everything is based on flat entities, which are cached, we can
finish the refactoring of workspace context cache which should already
improve performances.
Then the last step will be to consume that new cache in the new global
datasource to get rid of the many workspace datasources stored in the
server
This commit is contained in:
Weiko
2025-11-27 13:43:34 +01:00
committed by GitHub
parent 978c0acb90
commit 1607aebcc6
281 changed files with 6510 additions and 6627 deletions
@@ -11,39 +11,43 @@ import { CommonSelectedFieldsResult } from 'src/engine/api/common/types/common-s
import { getAllSelectableFields } from 'src/engine/api/rest/core/rest-to-common-args-handlers/utils/get-all-selectable-fields.util';
import { MAX_DEPTH } from 'src/engine/api/rest/input-request-parsers/constants/max-depth.constant';
import { Depth } from 'src/engine/api/rest/input-request-parsers/types/depth.type';
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@Injectable()
export class CommonSelectedFieldsHandler {
computeFromDepth = ({
objectsPermissions,
objectMetadataMaps,
objectMetadataMapItem,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
depth,
}: {
objectsPermissions: ObjectsPermissions;
objectMetadataMaps: ObjectMetadataMaps;
objectMetadataMapItem: ObjectMetadataItemWithFieldMaps;
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
flatObjectMetadata: FlatObjectMetadata;
depth: Depth | undefined;
}): CommonSelectedFieldsResult => {
const restrictedFields =
objectsPermissions[objectMetadataMapItem.id].restrictedFields;
objectsPermissions[flatObjectMetadata.id].restrictedFields;
const { relations, relationsSelectFields } =
this.getRelationsAndRelationsSelectFields({
objectMetadataMaps,
objectMetadataMapItem,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
objectsPermissions,
depth,
});
const selectableFields = getAllSelectableFields({
restrictedFields,
objectMetadata: {
objectMetadataMapItem,
},
flatObjectMetadata,
flatFieldMetadataMaps,
});
return {
@@ -57,13 +61,15 @@ export class CommonSelectedFieldsHandler {
};
private getRelationsAndRelationsSelectFields({
objectMetadataMaps,
objectMetadataMapItem,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
objectsPermissions,
depth,
}: {
objectMetadataMaps: ObjectMetadataMaps;
objectMetadataMapItem: ObjectMetadataItemWithFieldMaps;
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
flatObjectMetadata: FlatObjectMetadata;
objectsPermissions: ObjectsPermissions;
depth: Depth | undefined;
}) {
@@ -82,12 +88,19 @@ export class CommonSelectedFieldsHandler {
| { [key: string]: boolean | { [key: string]: boolean } };
} = {};
for (const field of Object.values(objectMetadataMapItem.fieldsById)) {
if (!isFieldMetadataEntityOfType(field, FieldMetadataType.RELATION))
for (const fieldId of flatObjectMetadata.fieldMetadataIds) {
const field = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityMaps: flatFieldMetadataMaps,
flatEntityId: fieldId,
});
if (!isFlatFieldMetadataOfType(field, FieldMetadataType.RELATION))
continue;
if (!field.relationTargetObjectMetadataId) continue;
const relationTargetObjectMetadata =
objectMetadataMaps.byId[field.relationTargetObjectMetadataId];
flatObjectMetadataMaps.byId[field.relationTargetObjectMetadataId];
if (!isDefined(relationTargetObjectMetadata)) {
throw new CommonQueryRunnerException(
@@ -98,9 +111,8 @@ export class CommonSelectedFieldsHandler {
const relationFieldSelectFields = getAllSelectableFields({
restrictedFields:
objectsPermissions[relationTargetObjectMetadata.id].restrictedFields,
objectMetadata: {
objectMetadataMapItem: relationTargetObjectMetadata,
},
flatObjectMetadata: relationTargetObjectMetadata,
flatFieldMetadataMaps,
});
if (Object.keys(relationFieldSelectFields).length === 0) continue;
@@ -113,8 +125,9 @@ export class CommonSelectedFieldsHandler {
relations: depth2Relations,
relationsSelectFields: depth2RelationsSelectFields,
} = this.getRelationsAndRelationsSelectFields({
objectMetadataMaps,
objectMetadataMapItem: relationTargetObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata: relationTargetObjectMetadata,
objectsPermissions,
depth: 1,
}) as {
@@ -52,8 +52,10 @@ import { transformLinksValue } from 'src/engine/core-modules/record-transformer/
import { transformPhonesValue } from 'src/engine/core-modules/record-transformer/utils/transform-phones-value.util';
import { transformRichTextV2Value } from 'src/engine/core-modules/record-transformer/utils/transform-rich-text-v2.util';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@Injectable()
export class DataArgProcessor {
@@ -65,12 +67,14 @@ export class DataArgProcessor {
async process({
partialRecordInputs,
authContext,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
shouldBackfillPositionIfUndefined = true,
}: {
partialRecordInputs: Partial<ObjectRecord>[] | undefined;
authContext: AuthContext;
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
flatObjectMetadata: FlatObjectMetadata;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
shouldBackfillPositionIfUndefined?: boolean;
}): Promise<Partial<ObjectRecord>[]> {
if (!isDefined(partialRecordInputs)) {
@@ -87,6 +91,12 @@ export class DataArgProcessor {
workspace.id,
);
const { fieldIdByName, fieldIdByJoinColumnName } =
buildFieldMapsFromFlatObjectMetadata(
flatFieldMetadataMaps,
flatObjectMetadata,
);
const processedRecords: Partial<ObjectRecord>[] = [];
for (const record of partialRecordInputs) {
@@ -94,18 +104,23 @@ export class DataArgProcessor {
for (const [key, value] of Object.entries(record)) {
const fieldMetadataId =
objectMetadataItemWithFieldMaps.fieldIdByName[key] ||
objectMetadataItemWithFieldMaps.fieldIdByJoinColumnName[key];
fieldIdByName[key] || fieldIdByJoinColumnName[key];
if (!isDefined(fieldMetadataId)) {
throw new CommonQueryRunnerException(
`Object ${objectMetadataItemWithFieldMaps.nameSingular} doesn't have any "${key}" field.`,
`Object ${flatObjectMetadata.nameSingular} doesn't have any "${key}" field.`,
CommonQueryRunnerExceptionCode.INVALID_ARGS_DATA,
);
}
const fieldMetadata =
objectMetadataItemWithFieldMaps.fieldsById[fieldMetadataId];
const fieldMetadata = flatFieldMetadataMaps.byId[fieldMetadataId];
if (!fieldMetadata) {
throw new CommonQueryRunnerException(
`Field metadata not found for field ${key}`,
CommonQueryRunnerExceptionCode.INVALID_ARGS_DATA,
);
}
if (
!isDefined(fieldMetadata.defaultValue) &&
@@ -137,9 +152,9 @@ export class DataArgProcessor {
partialRecordInputs: processedRecords,
workspaceId: workspace.id,
objectMetadata: {
isCustom: objectMetadataItemWithFieldMaps.isCustom,
nameSingular: objectMetadataItemWithFieldMaps.nameSingular,
fieldIdByName: objectMetadataItemWithFieldMaps.fieldIdByName,
isCustom: flatObjectMetadata.isCustom,
nameSingular: flatObjectMetadata.nameSingular,
fieldIdByName,
},
shouldBackfillPositionIfUndefined,
});
@@ -148,7 +163,7 @@ export class DataArgProcessor {
}
private async processField(
fieldMetadata: FieldMetadataEntity,
fieldMetadata: FlatFieldMetadata,
key: string,
value: unknown,
isNullEquivalenceEnabled: boolean,
@@ -5,15 +5,15 @@ import { isDefined } from 'twenty-shared/utils';
import { type ObjectRecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
import { RecordInputTransformerService } from 'src/engine/core-modules/record-transformer/services/record-input-transformer.service';
import { type FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map';
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@Injectable()
export class QueryRunnerArgsFactory {
constructor(
private readonly recordPositionService: RecordPositionService,
private readonly recordInputTransformerService: RecordInputTransformerService,
) {}
@@ -21,12 +21,18 @@ export class QueryRunnerArgsFactory {
T extends ObjectRecordFilter | undefined,
>(
filter: T,
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps,
flatObjectMetadata: FlatObjectMetadata,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
): T {
if (!isDefined(filter)) {
return filter;
}
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
flatFieldMetadataMaps,
flatObjectMetadata,
);
const overrideFilter = (filterObject: ObjectRecordFilter) => {
return Object.entries(filterObject).reduce((acc, [key, value]) => {
if (key === 'and' || key === 'or') {
@@ -42,7 +48,8 @@ export class QueryRunnerArgsFactory {
acc[key] = this.transformFilterValueByType(
key,
value,
objectMetadataItemWithFieldMaps,
fieldIdByName,
flatFieldMetadataMaps,
);
}
@@ -57,11 +64,13 @@ export class QueryRunnerArgsFactory {
key: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value: any,
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps,
fieldIdByName: Record<string, string>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
) {
const fieldMetadataId = objectMetadataItemWithFieldMaps.fieldIdByName[key];
const fieldMetadata =
objectMetadataItemWithFieldMaps.fieldsById[fieldMetadataId];
const fieldMetadataId = fieldIdByName[key];
const fieldMetadata = fieldMetadataId
? flatFieldMetadataMaps.byId[fieldMetadataId]
: undefined;
if (!fieldMetadata) {
return value;
@@ -90,18 +99,22 @@ export class QueryRunnerArgsFactory {
key: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value: any,
fieldMetadataMapByName: FieldMetadataMap,
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps,
fieldIdByName: Record<string, string>,
flatObjectMetadata: FlatObjectMetadata,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
) {
const fieldMetadata = fieldMetadataMapByName[key];
const fieldMetadata = flatFieldMetadataMaps.byId[fieldIdByName[key]];
if (!fieldMetadata) {
return value;
}
return this.recordInputTransformerService.process({
const processed = await this.recordInputTransformerService.process({
recordInput: { [key]: value },
objectMetadataMapItem: objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
});
return processed[key] ?? value;
}
}
@@ -36,6 +36,9 @@ import { MetricsService } from 'src/engine/core-modules/metrics/metrics.service'
import { MetricsKeys } from 'src/engine/core-modules/metrics/types/metrics-keys.type';
import { ThrottlerService } from 'src/engine/core-modules/throttler/throttler.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import {
PermissionsException,
@@ -43,8 +46,6 @@ import {
PermissionsExceptionMessage,
} from 'src/engine/metadata-modules/permissions/permissions.exception';
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
@@ -93,8 +94,12 @@ export abstract class CommonBaseQueryRunnerService<
args: CommonInput<Args>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<Output> {
const { authContext, objectMetadataItemWithFieldMaps, objectMetadataMaps } =
queryRunnerContext;
const {
authContext,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
} = queryRunnerContext;
if (!isWorkspaceAuthContext(authContext)) {
throw new CommonQueryRunnerException(
@@ -107,7 +112,7 @@ export abstract class CommonBaseQueryRunnerService<
await this.validate(args, queryRunnerContext);
if (objectMetadataItemWithFieldMaps.isSystem === true) {
if (flatObjectMetadata.isSystem === true) {
await this.validateSettingsPermissionsOnObjectOrThrow(
authContext,
queryRunnerContext,
@@ -115,8 +120,9 @@ export abstract class CommonBaseQueryRunnerService<
}
const commonQueryParser = new GraphqlQueryParser(
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
);
const processedArgs = await this.processArgs(
@@ -172,8 +178,9 @@ export abstract class CommonBaseQueryRunnerService<
protected abstract processQueryResult(
queryResult: Output,
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<Output>;
@@ -187,14 +194,14 @@ export abstract class CommonBaseQueryRunnerService<
args.selectedFields,
);
const { authContext, objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { authContext, flatObjectMetadata } = queryRunnerContext;
const computedArgs = await this.computeArgs(args, queryRunnerContext);
const hookedArgs =
(await this.workspaceQueryHookService.executePreQueryHooks(
authContext,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
operationName,
computedArgs as WorkspacePreQueryHookPayload<CommonQueryNames>,
)) as CommonInput<Args>;
@@ -231,9 +238,9 @@ export abstract class CommonBaseQueryRunnerService<
results,
operationName: this.operationName,
authContext,
objectMetadataItemWithFieldMaps:
queryRunnerContext.objectMetadataItemWithFieldMaps,
objectMetadataMaps: queryRunnerContext.objectMetadataMaps,
flatObjectMetadata: queryRunnerContext.flatObjectMetadata,
flatObjectMetadataMaps: queryRunnerContext.flatObjectMetadataMaps,
flatFieldMetadataMaps: queryRunnerContext.flatFieldMetadataMaps,
});
}
@@ -241,25 +248,28 @@ export abstract class CommonBaseQueryRunnerService<
results,
operationName,
authContext,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
}: {
results: Output;
operationName: CommonQueryNames;
authContext: WorkspaceAuthContext;
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
objectMetadataMaps: ObjectMetadataMaps;
flatObjectMetadata: FlatObjectMetadata;
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
}): Promise<Output> {
const resultWithGetters = await this.processQueryResult(
results,
objectMetadataItemWithFieldMaps.id,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext,
);
await this.workspaceQueryHookService.executePostQueryHooks(
authContext,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
operationName,
resultWithGetters as QueryResultFieldValue,
);
@@ -271,18 +281,18 @@ export abstract class CommonBaseQueryRunnerService<
authContext: WorkspaceAuthContext,
queryRunnerContext: CommonBaseQueryRunnerContext,
) {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata } = queryRunnerContext;
const workspace = authContext.workspace;
if (
Object.keys(OBJECTS_WITH_SETTINGS_PERMISSIONS_REQUIREMENTS).includes(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
)
) {
const permissionRequired: PermissionFlagType =
OBJECTS_WITH_SETTINGS_PERMISSIONS_REQUIREMENTS[
objectMetadataItemWithFieldMaps.nameSingular as keyof typeof OBJECTS_WITH_SETTINGS_PERMISSIONS_REQUIREMENTS
flatObjectMetadata.nameSingular as keyof typeof OBJECTS_WITH_SETTINGS_PERMISSIONS_REQUIREMENTS
];
const userHasPermission =
@@ -368,7 +378,7 @@ export abstract class CommonBaseQueryRunnerService<
const rolePermissionConfig = { unionOf: [roleId] };
const repository = workspaceDataSource.getRepository(
queryRunnerContext.objectMetadataItemWithFieldMaps.nameSingular,
queryRunnerContext.flatObjectMetadata.nameSingular,
rolePermissionConfig,
authContext,
);
@@ -397,7 +407,7 @@ export abstract class CommonBaseQueryRunnerService<
const repository = await this.globalWorkspaceOrmManager.getRepository(
workspaceId,
queryRunnerContext.objectMetadataItemWithFieldMaps.nameSingular,
queryRunnerContext.flatObjectMetadata.nameSingular,
rolePermissionConfig,
);
@@ -31,9 +31,11 @@ import { buildColumnsToSelect } from 'src/engine/api/graphql/graphql-query-runne
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
import { getAllSelectableColumnNames } from 'src/engine/api/utils/get-all-selectable-column-names.utils';
import { 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 { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config';
@@ -62,22 +64,25 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
repository,
authContext,
rolePermissionConfig,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
workspaceDataSource,
} = queryRunnerContext;
const objectRecords = await this.insertOrUpsertRecords({
repository,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
args,
});
const upsertedRecords = await this.fetchUpsertedRecords({
objectRecords,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
repository,
selectedFieldsResult: args.selectedFieldsResult,
});
@@ -85,8 +90,9 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
await this.processNestedRelationsIfNeeded({
args,
records: upsertedRecords,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext,
workspaceDataSource,
rolePermissionConfig,
@@ -98,16 +104,18 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
private async processNestedRelationsIfNeeded({
args,
records,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext,
workspaceDataSource,
rolePermissionConfig,
}: {
args: CommonExtendedInput<CreateManyQueryArgs>;
records: ObjectRecord[];
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
objectMetadataMaps: ObjectMetadataMaps;
flatObjectMetadata: FlatObjectMetadata;
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
authContext: AuthContext;
workspaceDataSource: WorkspaceDataSource;
rolePermissionConfig?: RolePermissionConfig;
@@ -117,8 +125,9 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
}
await this.processNestedRelationsHelper.processNestedRelations({
objectMetadataMaps,
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
parentObjectMetadataItem: flatObjectMetadata,
parentObjectRecords: records,
relations: args.selectedFieldsResult.relations as Record<
string,
@@ -136,14 +145,16 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
args: CommonInput<CreateManyQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<CreateManyQueryArgs>> {
const { authContext, objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { authContext, flatObjectMetadata, flatFieldMetadataMaps } =
queryRunnerContext;
return {
...args,
data: await this.dataArgProcessor.process({
partialRecordInputs: args.data,
authContext,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
}),
};
}
@@ -152,9 +163,9 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
args: CommonInput<CreateManyQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<void> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(objectMetadataItemWithFieldMaps);
assertMutationNotOnRemoteObject(flatObjectMetadata);
args.data.forEach((record) => {
if (record?.id) {
@@ -165,13 +176,15 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
private async insertOrUpsertRecords({
repository,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
args,
}: {
repository: WorkspaceRepository<ObjectLiteral>;
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
objectMetadataMaps: ObjectMetadataMaps;
flatObjectMetadata: FlatObjectMetadata;
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
args: CommonExtendedInput<CreateManyQueryArgs>;
}): Promise<InsertResult> {
const { selectedFieldsResult } = args;
@@ -180,8 +193,9 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
const selectedColumns = buildColumnsToReturn({
select: selectedFieldsResult.select,
relations: selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
return await repository.insert(args.data, undefined, selectedColumns);
@@ -189,8 +203,9 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
return this.performUpsertOperation({
repository,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
args,
selectedFieldsResult,
});
@@ -198,23 +213,27 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
private async performUpsertOperation({
repository,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
args,
selectedFieldsResult,
}: {
repository: WorkspaceRepository<ObjectLiteral>;
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
objectMetadataMaps: ObjectMetadataMaps;
flatObjectMetadata: FlatObjectMetadata;
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
args: CreateManyQueryArgs;
selectedFieldsResult: CommonSelectedFieldsResult;
}): Promise<InsertResult> {
const conflictingFields = getConflictingFields(
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
);
const existingRecords = await this.findExistingRecords({
repository,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
args,
conflictingFields,
});
@@ -234,15 +253,17 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
const columnsToReturn = buildColumnsToReturn({
select: selectedFieldsResult.select,
relations: selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
if (recordsToUpdate.length > 0) {
await this.processRecordsToUpdate({
partialRecordsToUpdate: recordsToUpdate,
repository,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
result,
columnsToReturn,
});
@@ -260,12 +281,14 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
private async findExistingRecords({
repository,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
args,
conflictingFields,
}: {
repository: WorkspaceRepository<ObjectLiteral>;
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
flatObjectMetadata: FlatObjectMetadata;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
args: CreateManyQueryArgs;
conflictingFields: {
baseField: string;
@@ -274,7 +297,7 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
}[];
}): Promise<PartialObjectRecordWithId[]> {
const queryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
const whereConditions = buildWhereConditions(args.data, conflictingFields);
@@ -284,13 +307,14 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
});
const restrictedFields =
repository.objectRecordsPermissions?.[objectMetadataItemWithFieldMaps.id]
repository.objectRecordsPermissions?.[flatObjectMetadata.id]
?.restrictedFields;
const selectOptions = getAllSelectableColumnNames({
restrictedFields: restrictedFields ?? {},
objectMetadata: {
objectMetadataMapItem: objectMetadataItemWithFieldMaps,
objectMetadataMapItem: flatObjectMetadata,
flatFieldMetadataMaps,
},
});
@@ -305,19 +329,25 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
private async processRecordsToUpdate({
partialRecordsToUpdate,
repository,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
result,
columnsToReturn,
}: {
partialRecordsToUpdate: PartialObjectRecordWithId[];
repository: WorkspaceRepository<ObjectLiteral>;
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
flatObjectMetadata: FlatObjectMetadata;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
result: InsertResult;
columnsToReturn: string[];
}): Promise<void> {
const partialRecordsToUpdateWithoutCreatedByUpdate =
partialRecordsToUpdate.map((record) =>
this.getRecordWithoutCreatedBy(record, objectMetadataItemWithFieldMaps),
this.getRecordWithoutCreatedBy(
record,
flatObjectMetadata,
flatFieldMetadataMaps,
),
);
const savedRecords = await repository.updateMany(
@@ -363,26 +393,29 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
private async fetchUpsertedRecords({
objectRecords,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
repository,
selectedFieldsResult,
}: {
objectRecords: InsertResult;
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
objectMetadataMaps: ObjectMetadataMaps;
flatObjectMetadata: FlatObjectMetadata;
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
repository: WorkspaceRepository<ObjectLiteral>;
selectedFieldsResult: CommonSelectedFieldsResult;
}): Promise<ObjectRecord[]> {
const queryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
const columnsToSelect = buildColumnsToSelect({
select: selectedFieldsResult.select,
relations: selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
const upsertedRecords = await queryBuilder
@@ -401,32 +434,38 @@ export class CommonCreateManyQueryRunnerService extends CommonBaseQueryRunnerSer
async processQueryResult(
queryResult: ObjectRecord[],
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord[]> {
return await this.commonResultGettersService.processRecordArray(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
private getRecordWithoutCreatedBy(
record: PartialObjectRecordWithId,
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps,
flatObjectMetadata: FlatObjectMetadata,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
): Omit<PartialObjectRecordWithId, 'createdBy'> {
let recordWithoutCreatedByUpdate = record;
const createdByFieldMetadataId =
objectMetadataItemWithFieldMaps.fieldIdByName['createdBy'];
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
flatFieldMetadataMaps,
flatObjectMetadata,
);
const createdByFieldMetadata =
objectMetadataItemWithFieldMaps.fieldsById[createdByFieldMetadataId];
flatFieldMetadataMaps.byId[fieldIdByName['createdBy']];
if (!isDefined(createdByFieldMetadata)) {
throw new CommonQueryRunnerException(
`Missing createdBy field metadata for object ${objectMetadataItemWithFieldMaps.nameSingular}`,
`Missing createdBy field metadata for object ${flatObjectMetadata.nameSingular}`,
CommonQueryRunnerExceptionCode.MISSING_SYSTEM_FIELD,
);
}
@@ -1,87 +1,128 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { objectMetadataMapItemMock } from 'src/engine/api/__mocks__/object-metadata-item.mock';
import { getConflictingFields } from 'src/engine/api/common/common-query-runners/common-create-many-query-runner/utils/get-conflicting-fields.util';
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { getMockFieldMetadataEntity } from 'src/utils/__test__/get-field-metadata-entity.mock';
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';
describe('getConflictingFields', () => {
const workspaceId = 'workspaceId';
const objectMetadataId = 'objectMetadataId';
const idField = getMockFieldMetadataEntity({
workspaceId,
objectMetadataId,
const createMockField = (
overrides: Partial<FlatFieldMetadata> & {
id: string;
name: string;
type: FieldMetadataType;
},
): FlatFieldMetadata =>
({
workspaceId,
objectMetadataId,
isNullable: false,
isLabelSyncedWithName: true,
createdAt: new Date(),
updatedAt: new Date(),
universalIdentifier: overrides.id,
viewFieldIds: [],
viewFilterIds: [],
viewGroupIds: [],
kanbanAggregateOperationViewIds: [],
calendarViewIds: [],
applicationId: null,
label: overrides.name,
...overrides,
}) as FlatFieldMetadata;
const idField = createMockField({
id: 'id-field-id',
name: 'id',
type: FieldMetadataType.UUID,
isUnique: true,
});
const uniqueTextField = getMockFieldMetadataEntity({
workspaceId,
objectMetadataId,
const uniqueTextField = createMockField({
id: 'unique-text-id',
name: 'uniqueText',
type: FieldMetadataType.TEXT,
isUnique: true,
});
const emailsUniqueField = getMockFieldMetadataEntity({
workspaceId,
objectMetadataId,
const emailsUniqueField = createMockField({
id: 'emails-unique-id',
name: 'emailsField',
type: FieldMetadataType.EMAILS,
isUnique: true,
});
const phonesNotUniqueField = getMockFieldMetadataEntity({
workspaceId,
objectMetadataId,
const phonesNotUniqueField = createMockField({
id: 'phones-not-unique-id',
name: 'phonesField',
type: FieldMetadataType.PHONES,
isUnique: false,
});
const addressUniqueFieldNoIncludedProp = getMockFieldMetadataEntity({
workspaceId,
objectMetadataId,
const addressUniqueFieldNoIncludedProp = createMockField({
id: 'address-unique-id',
name: 'addressField',
type: FieldMetadataType.ADDRESS,
isUnique: true,
});
const buildObjectMetadataWithFields = (
fields: (typeof idField)[],
): ObjectMetadataItemWithFieldMaps => {
const fieldsById = fields.reduce<Record<string, typeof idField>>(
const buildFlatObjectMetadata = (
fields: FlatFieldMetadata[],
): FlatObjectMetadata =>
({
id: objectMetadataId,
workspaceId,
nameSingular: 'testObject',
namePlural: 'testObjects',
labelSingular: 'Test Object',
labelPlural: 'Test Objects',
isCustom: false,
isRemote: false,
isActive: true,
isSystem: false,
createdAt: new Date(),
updatedAt: new Date(),
universalIdentifier: objectMetadataId,
fieldMetadataIds: fields.map((f) => f.id),
indexMetadataIds: [],
viewIds: [],
applicationId: null,
}) as unknown as FlatObjectMetadata;
const buildFlatFieldMetadataMaps = (
fields: FlatFieldMetadata[],
): FlatEntityMaps<FlatFieldMetadata> => ({
byId: fields.reduce(
(acc, field) => {
acc[field.id] = field;
return acc;
},
{},
);
{} as Record<string, FlatFieldMetadata>,
),
idByUniversalIdentifier: fields.reduce(
(acc, field) => {
acc[field.universalIdentifier] = field.id;
return {
...objectMetadataMapItemMock,
fieldsById,
fieldIdByName: Object.fromEntries(
Object.values(fieldsById).map((f) => [f.name, f.id]),
),
} as ObjectMetadataItemWithFieldMaps;
};
return acc;
},
{} as Record<string, string>,
),
universalIdentifiersByApplicationId: {},
});
it('returns id and unique non-composite fields as conflicts', () => {
const objectMetadata = buildObjectMetadataWithFields([
idField,
uniqueTextField,
]);
const fields = [idField, uniqueTextField];
const flatObjectMetadata = buildFlatObjectMetadata(fields);
const flatFieldMetadataMaps = buildFlatFieldMetadataMaps(fields);
const result = getConflictingFields(objectMetadata);
const result = getConflictingFields(
flatObjectMetadata,
flatFieldMetadataMaps,
);
expect(result).toEqual(
expect.arrayContaining([
@@ -96,12 +137,14 @@ describe('getConflictingFields', () => {
});
it('returns composite field with included unique property using full path and computed column', () => {
const objectMetadata = buildObjectMetadataWithFields([
idField,
emailsUniqueField,
]);
const fields = [idField, emailsUniqueField];
const flatObjectMetadata = buildFlatObjectMetadata(fields);
const flatFieldMetadataMaps = buildFlatFieldMetadataMaps(fields);
const result = getConflictingFields(objectMetadata);
const result = getConflictingFields(
flatObjectMetadata,
flatFieldMetadataMaps,
);
expect(result).toEqual(
expect.arrayContaining([
@@ -116,23 +159,27 @@ describe('getConflictingFields', () => {
});
it('does not include composite fields without included unique property', () => {
const objectMetadata = buildObjectMetadataWithFields([
idField,
addressUniqueFieldNoIncludedProp,
]);
const fields = [idField, addressUniqueFieldNoIncludedProp];
const flatObjectMetadata = buildFlatObjectMetadata(fields);
const flatFieldMetadataMaps = buildFlatFieldMetadataMaps(fields);
const result = getConflictingFields(objectMetadata);
const result = getConflictingFields(
flatObjectMetadata,
flatFieldMetadataMaps,
);
expect(result).toEqual([{ baseField: 'id', fullPath: 'id', column: 'id' }]);
});
it('ignores non-unique fields', () => {
const objectMetadata = buildObjectMetadataWithFields([
idField,
phonesNotUniqueField,
]);
const fields = [idField, phonesNotUniqueField];
const flatObjectMetadata = buildFlatObjectMetadata(fields);
const flatFieldMetadataMaps = buildFlatFieldMetadataMaps(fields);
const result = getConflictingFields(objectMetadata);
const result = getConflictingFields(
flatObjectMetadata,
flatFieldMetadataMaps,
);
expect(result).toEqual([{ baseField: 'id', fullPath: 'id', column: 'id' }]);
});
@@ -1,16 +1,23 @@
import { capitalize } from 'twenty-shared/utils';
import { compositeTypeDefinitions } from 'twenty-shared/types';
import { capitalize } from 'twenty-shared/utils';
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util';
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 const getConflictingFields = (
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps,
flatObjectMetadata: FlatObjectMetadata,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
): {
baseField: string;
fullPath: string;
column: string;
}[] => {
return Object.values(objectMetadataItemWithFieldMaps.fieldsById)
return getFlatFieldsFromFlatObjectMetadata(
flatObjectMetadata,
flatFieldMetadataMaps,
)
.filter((field) => field.isUnique || field.name === 'id')
.flatMap((field) => {
const compositeType = compositeTypeDefinitions.get(field.type);
@@ -16,8 +16,10 @@ import {
CreateOneQueryArgs,
} from 'src/engine/api/common/types/common-query-args.type';
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
@Injectable()
export class CommonCreateOneQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -51,12 +53,14 @@ export class CommonCreateOneQueryRunnerService extends CommonBaseQueryRunnerServ
args: CommonInput<CreateOneQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<CreateOneQueryArgs>> {
const { authContext, objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { authContext, flatObjectMetadata, flatFieldMetadataMaps } =
queryRunnerContext;
const coercedData = await this.dataArgProcessor.process({
partialRecordInputs: [args.data],
authContext,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
});
return {
@@ -67,14 +71,16 @@ export class CommonCreateOneQueryRunnerService extends CommonBaseQueryRunnerServ
async processQueryResult(
queryResult: ObjectRecord,
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord> {
return this.commonResultGettersService.processRecord(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
@@ -83,9 +89,9 @@ export class CommonCreateOneQueryRunnerService extends CommonBaseQueryRunnerServ
args: CommonInput<CreateOneQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<void> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(objectMetadataItemWithFieldMaps);
assertMutationNotOnRemoteObject(flatObjectMetadata);
if (args.data?.id) {
assertIsValidUuid(args.data.id);
@@ -1,8 +1,8 @@
import { Injectable } from '@nestjs/common';
import { isDefined } from 'class-validator';
import { QUERY_MAX_RECORDS } from 'twenty-shared/constants';
import { ObjectRecord } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { FindOptionsRelations, ObjectLiteral } from 'typeorm';
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
@@ -22,8 +22,10 @@ import {
} from 'src/engine/api/common/types/common-query-args.type';
import { buildColumnsToReturn } from 'src/engine/api/graphql/graphql-query-runner/utils/build-columns-to-return';
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
@Injectable()
export class CommonDeleteManyQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -41,26 +43,28 @@ export class CommonDeleteManyQueryRunnerService extends CommonBaseQueryRunnerSer
authContext,
rolePermissionConfig,
workspaceDataSource,
objectMetadataMaps,
objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
commonQueryParser,
} = queryRunnerContext;
const queryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
commonQueryParser.applyFilterToBuilder(
queryBuilder,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
args.filter,
);
const columnsToReturn = buildColumnsToReturn({
select: args.selectedFieldsResult.select,
relations: args.selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
const deletedObjectRecords = await queryBuilder
@@ -72,10 +76,10 @@ export class CommonDeleteManyQueryRunnerService extends CommonBaseQueryRunnerSer
if (isDefined(args.selectedFieldsResult.relations)) {
await this.processNestedRelationsHelper.processNestedRelations({
objectMetadataMaps,
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
parentObjectMetadataItem: flatObjectMetadata,
parentObjectRecords: deletedRecords,
//TODO : Refacto-common - Typing to fix when switching processNestedRelationsHelper to Common
relations: args.selectedFieldsResult.relations as Record<
string,
FindOptionsRelations<ObjectLiteral>
@@ -95,39 +99,43 @@ export class CommonDeleteManyQueryRunnerService extends CommonBaseQueryRunnerSer
args: CommonInput<DeleteManyQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<DeleteManyQueryArgs>> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata, flatFieldMetadataMaps } = queryRunnerContext;
return {
...args,
filter: this.queryRunnerArgsFactory.overrideFilterByFieldMetadata(
args.filter,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
),
};
}
async processQueryResult(
queryResult: ObjectRecord[],
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord[]> {
return this.commonResultGettersService.processRecordArray(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
async validate(
args: DeleteManyQueryArgs,
args: CommonInput<DeleteManyQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
) {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
): Promise<void> {
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(objectMetadataItemWithFieldMaps);
if (!args.filter) {
assertMutationNotOnRemoteObject(flatObjectMetadata);
if (!isDefined(args.filter)) {
throw new CommonQueryRunnerException(
'Filter is required',
CommonQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
@@ -20,8 +20,10 @@ import {
DeleteOneQueryArgs,
} from 'src/engine/api/common/types/common-query-args.type';
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
@Injectable()
export class CommonDeleteOneQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -67,14 +69,16 @@ export class CommonDeleteOneQueryRunnerService extends CommonBaseQueryRunnerServ
async processQueryResult(
queryResult: ObjectRecord,
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord> {
return this.commonResultGettersService.processRecord(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
@@ -83,9 +87,9 @@ export class CommonDeleteOneQueryRunnerService extends CommonBaseQueryRunnerServ
args: CommonInput<DeleteOneQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<void> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(objectMetadataItemWithFieldMaps);
assertMutationNotOnRemoteObject(flatObjectMetadata);
assertIsValidUuid(args.id);
}
}
@@ -21,7 +21,11 @@ import {
DestroyManyQueryArgs,
} from 'src/engine/api/common/types/common-query-args.type';
import { buildColumnsToReturn } from 'src/engine/api/graphql/graphql-query-runner/utils/build-columns-to-return';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
@Injectable()
export class CommonDestroyManyQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -39,41 +43,44 @@ export class CommonDestroyManyQueryRunnerService extends CommonBaseQueryRunnerSe
authContext,
rolePermissionConfig,
workspaceDataSource,
objectMetadataMaps,
objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
commonQueryParser,
} = queryRunnerContext;
const queryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
commonQueryParser.applyFilterToBuilder(
queryBuilder,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
args.filter,
);
const columnsToReturn = buildColumnsToReturn({
select: args.selectedFieldsResult.select,
relations: args.selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
const deletedObjectRecords = await queryBuilder
const destroyedObjectRecords = await queryBuilder
.delete()
.returning(columnsToReturn)
.execute();
const deletedRecords = deletedObjectRecords.generatedMaps as ObjectRecord[];
const destroyedRecords =
destroyedObjectRecords.generatedMaps as ObjectRecord[];
if (isDefined(args.selectedFieldsResult.relations)) {
await this.processNestedRelationsHelper.processNestedRelations({
objectMetadataMaps,
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
parentObjectRecords: deletedRecords,
//TODO : Refacto-common - Typing to fix when switching processNestedRelationsHelper to Common
flatObjectMetadataMaps,
flatFieldMetadataMaps,
parentObjectMetadataItem: flatObjectMetadata,
parentObjectRecords: destroyedRecords,
relations: args.selectedFieldsResult.relations as Record<
string,
FindOptionsRelations<ObjectLiteral>
@@ -86,47 +93,56 @@ export class CommonDestroyManyQueryRunnerService extends CommonBaseQueryRunnerSe
});
}
return deletedRecords;
return destroyedRecords;
}
async computeArgs(
args: CommonInput<DestroyManyQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<DestroyManyQueryArgs>> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata, flatFieldMetadataMaps } = queryRunnerContext;
return {
...args,
filter: this.queryRunnerArgsFactory.overrideFilterByFieldMetadata(
args.filter,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
),
};
}
async processQueryResult(
queryResult: ObjectRecord[],
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord[]> {
return this.commonResultGettersService.processRecordArray(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
async validate(
args: CommonInput<DestroyManyQueryArgs>,
_queryRunnerContext: CommonBaseQueryRunnerContext,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<void> {
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(flatObjectMetadata);
if (!isDefined(args.filter)) {
throw new CommonQueryRunnerException(
'Filter is required',
CommonQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
);
}
args.filter.id?.in?.forEach((id: string) => assertIsValidUuid(id));
}
}
@@ -19,7 +19,9 @@ import {
CommonQueryNames,
DestroyOneQueryArgs,
} from 'src/engine/api/common/types/common-query-args.type';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@Injectable()
export class CommonDestroyOneQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -65,14 +67,16 @@ export class CommonDestroyOneQueryRunnerService extends CommonBaseQueryRunnerSer
async processQueryResult(
queryResult: ObjectRecord,
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord> {
return this.commonResultGettersService.processRecord(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
@@ -25,7 +25,10 @@ import {
import { getPageInfo } from 'src/engine/api/common/utils/get-page-info.util';
import { buildColumnsToSelect } from 'src/engine/api/graphql/graphql-query-runner/utils/build-columns-to-select';
import { buildDuplicateConditions } from 'src/engine/api/utils/build-duplicate-conditions.utils';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@Injectable()
export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -40,8 +43,9 @@ export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunne
): Promise<CommonFindDuplicatesOutputItem[]> {
const {
repository,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
commonQueryParser,
authContext,
workspaceDataSource,
@@ -49,7 +53,7 @@ export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunne
} = queryRunnerContext;
const existingRecordsQueryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
let objectRecords: Partial<ObjectRecord>[] = [];
@@ -57,8 +61,9 @@ export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunne
const columnsToSelect = buildColumnsToSelect({
select: args.selectedFieldsResult.select,
relations: args.selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
if (isDefined(args.ids) && args.ids.length > 0) {
@@ -76,7 +81,9 @@ export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunne
await Promise.all(
objectRecords.map(async (record) => {
const duplicateConditions = buildDuplicateConditions(
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
[record],
record.id,
);
@@ -93,12 +100,12 @@ export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunne
}
const duplicateRecordsQueryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
commonQueryParser.applyFilterToBuilder(
duplicateRecordsQueryBuilder,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
duplicateConditions,
);
@@ -132,8 +139,9 @@ export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunne
if (isDefined(args.selectedFieldsResult.relations)) {
await this.processNestedRelationsHelper.processNestedRelations({
objectMetadataMaps,
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
parentObjectMetadataItem: flatObjectMetadata,
parentObjectRecords: findDuplicatesOutput.flatMap(
(item) => item.records,
),
@@ -157,7 +165,13 @@ export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunne
args: CommonInput<FindDuplicatesQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<FindDuplicatesQueryArgs>> {
const { authContext, objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { authContext, flatObjectMetadata, flatFieldMetadataMaps } =
queryRunnerContext;
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
flatFieldMetadataMaps,
flatObjectMetadata,
);
return {
...args,
@@ -166,15 +180,17 @@ export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunne
this.queryRunnerArgsFactory.overrideValueByFieldMetadata(
'id',
id,
objectMetadataItemWithFieldMaps.fieldsById,
objectMetadataItemWithFieldMaps,
fieldIdByName,
flatObjectMetadata,
flatFieldMetadataMaps,
),
) ?? [],
),
data: await this.dataArgProcessor.process({
partialRecordInputs: args.data,
authContext,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
shouldBackfillPositionIfUndefined: false,
}),
};
@@ -182,8 +198,9 @@ export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunne
async processQueryResult(
queryResult: CommonFindDuplicatesOutputItem[],
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<CommonFindDuplicatesOutputItem[]> {
const processedResults = await Promise.all(
@@ -192,8 +209,9 @@ export class CommonFindDuplicatesQueryRunnerService extends CommonBaseQueryRunne
...result,
records: await this.commonResultGettersService.processRecordArray(
result.records,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
),
};
@@ -30,7 +30,9 @@ import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-run
import { buildColumnsToSelect } from 'src/engine/api/graphql/graphql-query-runner/utils/build-columns-to-select';
import { getCursor } from 'src/engine/api/graphql/graphql-query-runner/utils/cursors.util';
import { computeCursorArgFilter } from 'src/engine/api/utils/compute-cursor-arg-filter.utils';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@Injectable()
export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -47,14 +49,15 @@ export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerServi
repository,
authContext,
rolePermissionConfig,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
workspaceDataSource,
commonQueryParser,
} = queryRunnerContext;
const queryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
const aggregateQueryBuilder = queryBuilder.clone();
@@ -63,7 +66,7 @@ export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerServi
commonQueryParser.applyFilterToBuilder(
aggregateQueryBuilder,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
appliedFilters,
);
@@ -85,7 +88,8 @@ export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerServi
const cursorArgFilter = computeCursorArgFilter(
cursor,
orderByWithIdCondition,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
isForwardPagination,
);
@@ -98,14 +102,14 @@ export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerServi
commonQueryParser.applyFilterToBuilder(
queryBuilder,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
appliedFilters,
);
commonQueryParser.applyOrderToBuilder(
queryBuilder,
orderByWithIdCondition,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
isForwardPagination,
);
@@ -114,7 +118,7 @@ export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerServi
ProcessAggregateHelper.addSelectedAggregatedFieldsQueriesToQueryBuilder({
selectedAggregatedFields: args.selectedFieldsResult.aggregate,
queryBuilder: aggregateQueryBuilder,
objectMetadataNameSingular: objectMetadataItemWithFieldMaps.nameSingular,
objectMetadataNameSingular: flatObjectMetadata.nameSingular,
});
const limit = args.first ?? args.last ?? QUERY_MAX_RECORDS;
@@ -122,8 +126,9 @@ export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerServi
const columnsToSelect = buildColumnsToSelect({
select: args.selectedFieldsResult.select,
relations: args.selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
if (isDefined(args.offset)) {
@@ -153,11 +158,11 @@ export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerServi
if (isDefined(args.selectedFieldsResult.relations)) {
await this.processNestedRelationsHelper.processNestedRelations({
objectMetadataMaps,
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
parentObjectMetadataItem: flatObjectMetadata,
parentObjectRecords: objectRecords,
parentObjectRecordsAggregatedValues,
//TODO : Refacto-common - Typing to fix when switching processNestedRelationsHelper to Common
relations: args.selectedFieldsResult.relations as Record<
string,
FindOptionsRelations<ObjectLiteral>
@@ -184,28 +189,31 @@ export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerServi
args: CommonInput<FindManyQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<FindManyQueryArgs>> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata, flatFieldMetadataMaps } = queryRunnerContext;
return {
...args,
filter: this.queryRunnerArgsFactory.overrideFilterByFieldMetadata(
args.filter,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
),
};
}
async processQueryResult(
queryResult: CommonFindManyOutput,
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<CommonFindManyOutput> {
const processedRecords =
await this.commonResultGettersService.processRecordArray(
queryResult.records,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
@@ -22,7 +22,9 @@ import {
FindOneQueryArgs,
} from 'src/engine/api/common/types/common-query-args.type';
import { buildColumnsToSelect } from 'src/engine/api/graphql/graphql-query-runner/utils/build-columns-to-select';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@Injectable()
export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -40,18 +42,19 @@ export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerServic
authContext,
rolePermissionConfig,
workspaceDataSource,
objectMetadataMaps,
objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
commonQueryParser,
} = queryRunnerContext;
const queryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
commonQueryParser.applyFilterToBuilder(
queryBuilder,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
args.filter ?? ({} as ObjectRecordFilter),
);
@@ -63,8 +66,9 @@ export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerServic
const columnsToSelect = buildColumnsToSelect({
select: args.selectedFieldsResult.select,
relations: args.selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
const objectRecord = await queryBuilder
@@ -84,10 +88,10 @@ export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerServic
if (isDefined(args.selectedFieldsResult.relations)) {
await this.processNestedRelationsHelper.processNestedRelations({
objectMetadataMaps,
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
parentObjectMetadataItem: flatObjectMetadata,
parentObjectRecords: objectRecords,
//TODO : Refacto-common - To fix when switching processNestedRelationsHelper to Common
relations: args.selectedFieldsResult.relations as Record<
string,
FindOptionsRelations<ObjectLiteral>
@@ -107,27 +111,30 @@ export class CommonFindOneQueryRunnerService extends CommonBaseQueryRunnerServic
args: CommonInput<FindOneQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<FindOneQueryArgs>> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata, flatFieldMetadataMaps } = queryRunnerContext;
return {
...args,
filter: this.queryRunnerArgsFactory.overrideFilterByFieldMetadata(
args.filter,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
),
};
}
async processQueryResult(
queryResult: ObjectRecord,
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord> {
return this.commonResultGettersService.processRecord(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
@@ -44,9 +44,11 @@ import { parseGroupByArgs } from 'src/engine/api/graphql/graphql-query-runner/gr
import { GroupByWithRecordsService } from 'src/engine/api/graphql/graphql-query-runner/group-by/services/group-by-with-records.service';
import { getGroupLimit } from 'src/engine/api/graphql/graphql-query-runner/group-by/utils/get-group-limit.util';
import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-aggregate.helper';
import { isFieldMetadataRelationOrMorphRelation } from 'src/engine/api/graphql/workspace-schema-builder/utils/is-field-metadata-relation-or-morph-relation.utils';
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { ViewFilterGroupService } from 'src/engine/metadata-modules/view-filter-group/services/view-filter-group.service';
import { ViewFilterService } from 'src/engine/metadata-modules/view-filter/services/view-filter.service';
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
@@ -77,12 +79,13 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
const {
repository,
commonQueryParser,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext,
} = queryRunnerContext;
const objectMetadataNameSingular =
objectMetadataItemWithFieldMaps.nameSingular;
const objectMetadataNameSingular = flatObjectMetadata.nameSingular;
let queryBuilder = repository.createQueryBuilder(
objectMetadataNameSingular,
@@ -90,11 +93,12 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
const groupByFields = parseGroupByArgs(
args,
objectMetadataItemWithFieldMaps,
queryRunnerContext.objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
);
const objectAlias = getObjectAlias(objectMetadataItemWithFieldMaps);
const objectAlias = getObjectAlias(flatObjectMetadata);
this.addJoinForGroupByOnRelationFields({
queryBuilder,
@@ -108,7 +112,8 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
args,
appliedFilters,
queryBuilder,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
workspaceId: authContext.workspace.id,
commonQueryParser,
});
@@ -166,8 +171,9 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
async processQueryResult(
queryResult: CommonGroupByOutputItem[],
_objectMetadataItemId: string,
_objectMetadataMaps: ObjectMetadataMaps,
_flatObjectMetadata: FlatObjectMetadata,
_flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
_flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
_authContext: WorkspaceAuthContext,
): Promise<CommonGroupByOutputItem[]> {
return queryResult;
@@ -175,12 +181,14 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
private async addFiltersFromView({
args,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
appliedFilters,
workspaceId,
}: {
args: GroupByQueryArgs;
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
flatObjectMetadata: FlatObjectMetadata;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
appliedFilters: ObjectRecordFilter;
workspaceId: string;
}): Promise<ObjectRecordFilter> {
@@ -197,14 +205,21 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
);
const recordFilters = viewFilters.map((viewFilter) => {
const fieldMetadataItem =
objectMetadataItemWithFieldMaps.fieldsById[viewFilter.fieldMetadataId];
const fieldMetadata =
flatFieldMetadataMaps.byId[viewFilter.fieldMetadataId];
if (!fieldMetadata) {
throw new CommonQueryRunnerException(
`Field metadata not found for field ${viewFilter.fieldMetadataId}`,
CommonQueryRunnerExceptionCode.INTERNAL_SERVER_ERROR,
);
}
return {
id: viewFilter.id,
fieldMetadataId: viewFilter.fieldMetadataId,
value: convertViewFilterValueToString(viewFilter.value),
type: getFilterTypeFromFieldType(fieldMetadataItem.type),
type: getFilterTypeFromFieldType(fieldMetadata.type),
operand: viewFilter.operand,
recordFilterGroupId: viewFilter.viewFilterGroupId,
positionInRecordFilterGroup: viewFilter.positionInViewFilterGroup,
@@ -221,8 +236,9 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
};
});
const fields = Object.values(
objectMetadataItemWithFieldMaps.fieldsById,
const fields = getFlatFieldsFromFlatObjectMetadata(
flatObjectMetadata,
flatFieldMetadataMaps,
).map((field) => ({
id: field.id,
name: field.name,
@@ -263,24 +279,26 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
args,
appliedFilters,
queryBuilder,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
workspaceId,
commonQueryParser,
}: {
args: GroupByQueryArgs;
appliedFilters: ObjectRecordFilter;
queryBuilder: WorkspaceSelectQueryBuilder<ObjectLiteral>;
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
flatObjectMetadata: FlatObjectMetadata;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
workspaceId: string;
commonQueryParser: GraphqlQueryParser;
}): Promise<void> {
const objectMetadataNameSingular =
objectMetadataItemWithFieldMaps.nameSingular;
const objectMetadataNameSingular = flatObjectMetadata.nameSingular;
if (args.viewId) {
appliedFilters = await this.addFiltersFromView({
args,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
appliedFilters,
workspaceId,
});
@@ -336,7 +354,7 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
if (
!groupByField.fieldMetadata.settings ||
!isFieldMetadataRelationOrMorphRelation(groupByField.fieldMetadata)
!isMorphOrRelationFlatFieldMetadata(groupByField.fieldMetadata)
) {
throw new CommonQueryRunnerException(
`Field metadata settings are missing or invalid for field ${groupByField.fieldMetadata.name}`,
@@ -370,13 +388,14 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
args: CommonInput<GroupByQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<GroupByQueryArgs>> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata, flatFieldMetadataMaps } = queryRunnerContext;
return {
...args,
filter: this.queryRunnerArgsFactory.overrideFilterByFieldMetadata(
args.filter,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
),
};
}
@@ -33,10 +33,12 @@ import { buildColumnsToReturn } from 'src/engine/api/graphql/graphql-query-runne
import { buildColumnsToSelect } from 'src/engine/api/graphql/graphql-query-runner/utils/build-columns-to-select';
import { hasRecordFieldValue } from 'src/engine/api/graphql/graphql-query-runner/utils/has-record-field-value.util';
import { mergeFieldValues } from 'src/engine/api/graphql/graphql-query-runner/utils/merge-field-values.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
@Injectable()
export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -50,8 +52,11 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
args: CommonExtendedInput<MergeManyQueryArgs>,
queryRunnerContext: CommonExtendedQueryRunnerContext,
): Promise<ObjectRecord> {
const { objectMetadataMaps, objectMetadataItemWithFieldMaps } =
queryRunnerContext;
const {
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
} = queryRunnerContext;
const recordsToMerge = await this.fetchRecordsToMerge(
queryRunnerContext,
@@ -67,7 +72,8 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
const mergedData = this.performDeepMerge(
recordsToMerge,
priorityRecord.id,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
args.dryRun ?? false,
);
@@ -84,14 +90,15 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
);
const queryBuilder = queryRunnerContext.repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
const columnsToReturn = buildColumnsToReturn({
select: args.selectedFieldsResult.select,
relations: args.selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
await queryBuilder
@@ -123,8 +130,9 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
const columnsToSelect = buildColumnsToSelect({
select: args.selectedFieldsResult.select,
relations: args.selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps: context.objectMetadataItemWithFieldMaps,
objectMetadataMaps: context.objectMetadataMaps,
flatObjectMetadata: context.flatObjectMetadata,
flatObjectMetadataMaps: context.flatObjectMetadataMaps,
flatFieldMetadataMaps: context.flatFieldMetadataMaps,
});
const recordsToMerge = await context.repository.find({
@@ -141,8 +149,9 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
if (args.dryRun && args.selectedFieldsResult.relations) {
await this.processNestedRelationsHelper.processNestedRelations({
objectMetadataMaps: context.objectMetadataMaps,
parentObjectMetadataItem: context.objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps: context.flatObjectMetadataMaps,
flatFieldMetadataMaps: context.flatFieldMetadataMaps,
parentObjectMetadataItem: context.flatObjectMetadata,
parentObjectRecords: recordsToMerge as ObjectRecord[],
relations: args.selectedFieldsResult.relations as Record<
string,
@@ -182,7 +191,8 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
private performDeepMerge(
recordsToMerge: ObjectRecord[],
priorityRecordId: string,
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps,
flatObjectMetadata: FlatObjectMetadata,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
isDryRun = false,
): Partial<ObjectRecord> {
const mergedResult: Partial<ObjectRecord> = {};
@@ -194,7 +204,8 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
if (
!this.shouldExcludeFieldFromMerge(
fieldName,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
)
) {
allFieldNames.add(fieldName);
@@ -218,9 +229,12 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
} else if (recordsWithValues.length === 1) {
mergedResult[fieldName] = recordsWithValues[0].value;
} else {
const fieldMetadata = Object.values(
objectMetadataItemWithFieldMaps.fieldsById,
).find((field) => field?.name === fieldName);
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
flatFieldMetadataMaps,
flatObjectMetadata,
);
const fieldMetadata =
flatFieldMetadataMaps.byId[fieldIdByName[fieldName]];
if (!fieldMetadata) {
return;
@@ -247,11 +261,14 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
private shouldExcludeFieldFromMerge(
fieldName: string,
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps,
flatObjectMetadata: FlatObjectMetadata,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
): boolean {
const fieldMetadata = Object.values(
objectMetadataItemWithFieldMaps.fieldsById,
).find((field) => field?.name === fieldName);
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
flatFieldMetadataMaps,
flatObjectMetadata,
);
const fieldMetadata = flatFieldMetadataMaps.byId[fieldIdByName[fieldName]];
return fieldMetadata?.isSystem ?? false;
}
@@ -276,18 +293,23 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
priorityRecordId: string,
mergedData: Partial<ObjectRecord>,
): Promise<ObjectRecord> {
const { objectMetadataItemWithFieldMaps, objectMetadataMaps, repository } =
queryRunnerContext;
const {
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
repository,
} = queryRunnerContext;
const queryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
const columnsToReturn = buildColumnsToReturn({
select: args.selectedFieldsResult.select,
relations: args.selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
const updatedObjectRecords = await queryBuilder
@@ -314,46 +336,54 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
fromIds: string[],
toId: string,
): Promise<void> {
const { objectMetadataMaps, objectMetadataItemWithFieldMaps } = context;
const {
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
} = context;
const relationFieldsPointingToCurrentObject = Object.values(
objectMetadataMaps.byId,
)
.filter(isDefined)
.flatMap((metadata) => {
const relationFields = Object.values(metadata.fieldsById)
.filter(isDefined)
.filter((field) =>
isFieldMetadataEntityOfType(field, FieldMetadataType.RELATION),
)
.filter(
(field) =>
field.relationTargetObjectMetadataId ===
objectMetadataItemWithFieldMaps.id && field.isActive,
);
const relationFieldsPointingToCurrentObject: Array<{
objectMetadata: FlatObjectMetadata;
fieldName: string;
fieldId: string;
joinColumnName: string | undefined;
}> = [];
return relationFields
.filter((field) => {
const relationSettings =
field.settings as FieldMetadataRelationSettings;
for (const field of Object.values(flatFieldMetadataMaps.byId).filter(
isDefined,
)) {
if (
!isFlatFieldMetadataOfType(field, FieldMetadataType.RELATION) ||
field.relationTargetObjectMetadataId !== flatObjectMetadata.id ||
!field.isActive
) {
continue;
}
return (
relationSettings?.relationType === RelationType.MANY_TO_ONE &&
relationSettings?.joinColumnName
);
})
.map((field) => {
const relationSettings =
field.settings as FieldMetadataRelationSettings;
const relationSettings = field.settings as
| FieldMetadataRelationSettings
| undefined;
return {
objectMetadata: metadata,
fieldName: field.name,
fieldId: field.id,
joinColumnName: relationSettings.joinColumnName,
};
});
if (
relationSettings?.relationType !== RelationType.MANY_TO_ONE ||
!relationSettings?.joinColumnName
) {
continue;
}
const objMetadata = flatObjectMetadataMaps.byId[field.objectMetadataId];
if (!objMetadata) {
continue;
}
relationFieldsPointingToCurrentObject.push({
objectMetadata: objMetadata,
fieldName: field.name,
fieldId: field.id,
joinColumnName: relationSettings.joinColumnName,
});
}
for (const relationField of relationFieldsPointingToCurrentObject) {
if (!relationField.joinColumnName) {
@@ -396,8 +426,9 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
updatedRecords: ObjectRecord[];
}): Promise<void> {
const {
objectMetadataMaps,
objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
authContext,
workspaceDataSource,
rolePermissionConfig,
@@ -405,8 +436,9 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
if (args.selectedFieldsResult.relations) {
await this.processNestedRelationsHelper.processNestedRelations({
objectMetadataMaps,
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
parentObjectMetadataItem: flatObjectMetadata,
parentObjectRecords: updatedRecords,
relations: args.selectedFieldsResult.relations as Record<
string,
@@ -430,8 +462,9 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
async processQueryResult(
queryResult: ObjectRecord,
_objectMetadataItemId: string,
_objectMetadataMaps: ObjectMetadataMaps,
_flatObjectMetadata: FlatObjectMetadata,
_flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
_flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
_authContext: WorkspaceAuthContext,
): Promise<ObjectRecord> {
return queryResult;
@@ -441,13 +474,13 @@ export class CommonMergeManyQueryRunnerService extends CommonBaseQueryRunnerServ
args: CommonInput<MergeManyQueryArgs>,
queryRunnerContext: CommonExtendedQueryRunnerContext,
): Promise<void> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(objectMetadataItemWithFieldMaps);
assertMutationNotOnRemoteObject(flatObjectMetadata);
if (!isDefined(objectMetadataItemWithFieldMaps.duplicateCriteria)) {
if (!isDefined(flatObjectMetadata.duplicateCriteria)) {
throw new CommonQueryRunnerException(
`Merge is only available for objects with duplicate criteria. Object '${objectMetadataItemWithFieldMaps.nameSingular}' does not have duplicate criteria defined.`,
`Merge is only available for objects with duplicate criteria. Object '${flatObjectMetadata.nameSingular}' does not have duplicate criteria defined.`,
CommonQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
);
}
@@ -22,8 +22,10 @@ import {
} from 'src/engine/api/common/types/common-query-args.type';
import { buildColumnsToReturn } from 'src/engine/api/graphql/graphql-query-runner/utils/build-columns-to-return';
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
@Injectable()
export class CommonRestoreManyQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -41,26 +43,28 @@ export class CommonRestoreManyQueryRunnerService extends CommonBaseQueryRunnerSe
authContext,
rolePermissionConfig,
workspaceDataSource,
objectMetadataMaps,
objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
commonQueryParser,
} = queryRunnerContext;
const queryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
commonQueryParser.applyFilterToBuilder(
queryBuilder,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
args.filter,
);
const columnsToReturn = buildColumnsToReturn({
select: args.selectedFieldsResult.select,
relations: args.selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
const restoredObjectRecords = await queryBuilder
@@ -73,10 +77,10 @@ export class CommonRestoreManyQueryRunnerService extends CommonBaseQueryRunnerSe
if (isDefined(args.selectedFieldsResult.relations)) {
await this.processNestedRelationsHelper.processNestedRelations({
objectMetadataMaps,
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
parentObjectMetadataItem: flatObjectMetadata,
parentObjectRecords: restoredRecords,
//TODO : Refacto-common - Typing to fix when switching processNestedRelationsHelper to Common
relations: args.selectedFieldsResult.relations as Record<
string,
FindOptionsRelations<ObjectLiteral>
@@ -96,27 +100,30 @@ export class CommonRestoreManyQueryRunnerService extends CommonBaseQueryRunnerSe
args: CommonInput<RestoreManyQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<RestoreManyQueryArgs>> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata, flatFieldMetadataMaps } = queryRunnerContext;
return {
...args,
filter: this.queryRunnerArgsFactory.overrideFilterByFieldMetadata(
args.filter,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
),
};
}
async processQueryResult(
queryResult: ObjectRecord[],
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord[]> {
return this.commonResultGettersService.processRecordArray(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
@@ -125,9 +132,9 @@ export class CommonRestoreManyQueryRunnerService extends CommonBaseQueryRunnerSe
args: RestoreManyQueryArgs,
queryRunnerContext: CommonBaseQueryRunnerContext,
) {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(objectMetadataItemWithFieldMaps);
assertMutationNotOnRemoteObject(flatObjectMetadata);
if (!isDefined(args.filter)) {
throw new CommonQueryRunnerException(
'Filter is required',
@@ -20,8 +20,10 @@ import {
RestoreOneQueryArgs,
} from 'src/engine/api/common/types/common-query-args.type';
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
@Injectable()
export class CommonRestoreOneQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -67,14 +69,16 @@ export class CommonRestoreOneQueryRunnerService extends CommonBaseQueryRunnerSer
async processQueryResult(
queryResult: ObjectRecord,
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord> {
return this.commonResultGettersService.processRecord(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
@@ -83,9 +87,9 @@ export class CommonRestoreOneQueryRunnerService extends CommonBaseQueryRunnerSer
args: CommonInput<RestoreOneQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<void> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(objectMetadataItemWithFieldMaps);
assertMutationNotOnRemoteObject(flatObjectMetadata);
assertIsValidUuid(args.id);
}
}
@@ -22,8 +22,10 @@ import {
} from 'src/engine/api/common/types/common-query-args.type';
import { buildColumnsToReturn } from 'src/engine/api/graphql/graphql-query-runner/utils/build-columns-to-return';
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
@Injectable()
export class CommonUpdateManyQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -41,26 +43,28 @@ export class CommonUpdateManyQueryRunnerService extends CommonBaseQueryRunnerSer
authContext,
rolePermissionConfig,
workspaceDataSource,
objectMetadataMaps,
objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatObjectMetadata,
commonQueryParser,
} = queryRunnerContext;
const queryBuilder = repository.createQueryBuilder(
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
);
commonQueryParser.applyFilterToBuilder(
queryBuilder,
objectMetadataItemWithFieldMaps.nameSingular,
flatObjectMetadata.nameSingular,
args.filter,
);
const columnsToReturn = buildColumnsToReturn({
select: args.selectedFieldsResult.select,
relations: args.selectedFieldsResult.relations,
objectMetadataItemWithFieldMaps,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
});
const updatedObjectRecords = await queryBuilder
@@ -73,10 +77,10 @@ export class CommonUpdateManyQueryRunnerService extends CommonBaseQueryRunnerSer
if (isDefined(args.selectedFieldsResult.relations)) {
await this.processNestedRelationsHelper.processNestedRelations({
objectMetadataMaps,
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
parentObjectMetadataItem: flatObjectMetadata,
parentObjectRecords: updatedRecords,
//TODO : Refacto-common - Typing to fix when switching processNestedRelationsHelper to Common
relations: args.selectedFieldsResult.relations as Record<
string,
FindOptionsRelations<ObjectLiteral>
@@ -96,20 +100,22 @@ export class CommonUpdateManyQueryRunnerService extends CommonBaseQueryRunnerSer
args: CommonInput<UpdateManyQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<UpdateManyQueryArgs>> {
const { authContext, objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { authContext, flatObjectMetadata, flatFieldMetadataMaps } =
queryRunnerContext;
return {
...args,
filter:
this.queryRunnerArgsFactory.overrideFilterByFieldMetadata(
args.filter,
objectMetadataItemWithFieldMaps,
) || {},
filter: this.queryRunnerArgsFactory.overrideFilterByFieldMetadata(
args.filter,
flatObjectMetadata,
flatFieldMetadataMaps,
),
data: (
await this.dataArgProcessor.process({
partialRecordInputs: [args.data],
authContext,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
shouldBackfillPositionIfUndefined: false,
})
)[0],
@@ -120,9 +126,9 @@ export class CommonUpdateManyQueryRunnerService extends CommonBaseQueryRunnerSer
args: CommonInput<UpdateManyQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<void> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(objectMetadataItemWithFieldMaps);
assertMutationNotOnRemoteObject(flatObjectMetadata);
if (!args.filter) {
throw new CommonQueryRunnerException(
'Filter is required',
@@ -135,14 +141,16 @@ export class CommonUpdateManyQueryRunnerService extends CommonBaseQueryRunnerSer
async processQueryResult(
queryResult: ObjectRecord[],
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord[]> {
return await this.commonResultGettersService.processRecordArray(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
@@ -19,8 +19,10 @@ import {
UpdateOneQueryArgs,
} from 'src/engine/api/common/types/common-query-args.type';
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
@Injectable()
export class CommonUpdateOneQueryRunnerService extends CommonBaseQueryRunnerService<
@@ -60,7 +62,8 @@ export class CommonUpdateOneQueryRunnerService extends CommonBaseQueryRunnerServ
args: CommonInput<UpdateOneQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<CommonInput<UpdateOneQueryArgs>> {
const { authContext, objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { authContext, flatObjectMetadata, flatFieldMetadataMaps } =
queryRunnerContext;
return {
...args,
@@ -68,7 +71,8 @@ export class CommonUpdateOneQueryRunnerService extends CommonBaseQueryRunnerServ
await this.dataArgProcessor.process({
partialRecordInputs: [args.data],
authContext,
objectMetadataItemWithFieldMaps,
flatObjectMetadata,
flatFieldMetadataMaps,
shouldBackfillPositionIfUndefined: false,
})
)[0],
@@ -77,14 +81,16 @@ export class CommonUpdateOneQueryRunnerService extends CommonBaseQueryRunnerServ
async processQueryResult(
queryResult: ObjectRecord,
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
authContext: WorkspaceAuthContext,
): Promise<ObjectRecord> {
return this.commonResultGettersService.processRecord(
queryResult,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
authContext.workspace.id,
);
}
@@ -93,9 +99,9 @@ export class CommonUpdateOneQueryRunnerService extends CommonBaseQueryRunnerServ
args: CommonInput<UpdateOneQueryArgs>,
queryRunnerContext: CommonBaseQueryRunnerContext,
): Promise<void> {
const { objectMetadataItemWithFieldMaps } = queryRunnerContext;
const { flatObjectMetadata } = queryRunnerContext;
assertMutationNotOnRemoteObject(objectMetadataItemWithFieldMaps);
assertMutationNotOnRemoteObject(flatObjectMetadata);
assertIsValidUuid(args.id);
}
}
@@ -1,7 +1,7 @@
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
export const getObjectAlias = (
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps,
flatObjectMetadata: FlatObjectMetadata,
): string => {
return objectMetadataItemWithFieldMaps.nameSingular;
return flatObjectMetadata.nameSingular;
};
@@ -15,8 +15,12 @@ import { AttachmentQueryResultGetterHandler } from 'src/engine/api/graphql/works
import { PersonQueryResultGetterHandler } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/handlers/person-query-result-getter.handler';
import { WorkspaceMemberQueryResultGetterHandler } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/handlers/workspace-member-query-result-getter.handler';
import { FileService } from 'src/engine/core-modules/file/services/file.service';
import { type ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
// TODO: find a way to prevent conflict between handlers executing logic on object relations
// And this factory that is also executing logic on object relations
@@ -45,8 +49,9 @@ export class CommonResultGettersService {
public async processRecordArray(
recordArray: ObjectRecord[],
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
workspaceId: string,
) {
return await Promise.all(
@@ -54,8 +59,9 @@ export class CommonResultGettersService {
async (record: ObjectRecord) =>
await this.processRecord(
record,
objectMetadataItemId,
objectMetadataMaps,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
workspaceId,
),
),
@@ -64,28 +70,26 @@ export class CommonResultGettersService {
public async processRecord(
record: ObjectRecord,
objectMetadataItemId: string,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadata: FlatObjectMetadata,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
workspaceId: string,
): Promise<ObjectRecord> {
const objectMetadataMapItem = objectMetadataMaps.byId[objectMetadataItemId];
const handler = this.getHandler(flatObjectMetadata.nameSingular);
if (!isDefined(objectMetadataMapItem)) {
throw new Error('Object metadata map item is not defined');
}
const handler = this.getHandler(objectMetadataMapItem.nameSingular);
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
flatFieldMetadataMaps,
flatObjectMetadata,
);
const relationFields = Object.keys(record)
.map(
(recordFieldName) =>
objectMetadataMapItem.fieldsById[
objectMetadataMapItem.fieldIdByName[recordFieldName]
],
flatFieldMetadataMaps.byId[fieldIdByName[recordFieldName]],
)
.filter(isDefined)
.filter((fieldMetadata) =>
isFieldMetadataEntityOfType(fieldMetadata, FieldMetadataType.RELATION),
isFlatFieldMetadataOfType(fieldMetadata, FieldMetadataType.RELATION),
);
const relationFieldsProcessedMap = {} as Record<
@@ -104,18 +108,26 @@ export class CommonResultGettersService {
continue;
}
const targetFlatObjectMetadata =
findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId: relationField.relationTargetObjectMetadataId,
flatEntityMaps: flatObjectMetadataMaps,
});
relationFieldsProcessedMap[relationField.name] =
relationField.settings?.relationType === RelationType.ONE_TO_MANY
? await this.processRecordArray(
record[relationField.name],
relationField.relationTargetObjectMetadataId,
objectMetadataMaps,
targetFlatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
workspaceId,
)
: await this.processRecord(
record[relationField.name],
relationField.relationTargetObjectMetadataId,
objectMetadataMaps,
targetFlatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
workspaceId,
);
}
@@ -1,9 +1,12 @@
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { type ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
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 type CommonBaseQueryRunnerContext = {
authContext: AuthContext;
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps;
objectMetadataMaps: ObjectMetadataMaps;
flatObjectMetadata: FlatObjectMetadata;
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
objectIdByNameSingular: Record<string, string>;
};