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:
+38
-25
@@ -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 {
|
||||
|
||||
+28
-13
@@ -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,
|
||||
|
||||
+28
-15
@@ -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
-26
@@ -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,
|
||||
);
|
||||
|
||||
|
||||
+100
-61
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
+99
-52
@@ -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' }]);
|
||||
});
|
||||
|
||||
+11
-4
@@ -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);
|
||||
|
||||
+15
-9
@@ -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);
|
||||
|
||||
+30
-22
@@ -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,
|
||||
|
||||
+11
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+37
-21
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
+9
-5
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
+37
-19
@@ -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,
|
||||
),
|
||||
};
|
||||
|
||||
+28
-20
@@ -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,
|
||||
);
|
||||
|
||||
|
||||
+23
-16
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
+46
-27
@@ -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,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
+105
-72
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
+25
-18
@@ -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',
|
||||
|
||||
+11
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+31
-23
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
+15
-9
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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;
|
||||
};
|
||||
|
||||
+34
-22
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
+7
-4
@@ -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>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user