feat: new relation in graphql-query-runner (#9883)
Fix https://github.com/twentyhq/core-team-issues/issues/300 Within GraphQLQueryRunner the new relation format will be used when the feature flag `IsNewRelationEnabled` is set to true.
This commit is contained in:
@ -5,6 +5,7 @@ import {
|
||||
ObjectRecordOrderBy,
|
||||
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||
import { IConnection } from 'src/engine/api/graphql/workspace-query-runner/interfaces/connection.interface';
|
||||
import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||
|
||||
import { CONNECTION_MAX_DEPTH } from 'src/engine/api/graphql/graphql-query-runner/constants/connection-max-depth.constant';
|
||||
@ -14,7 +15,9 @@ import {
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { encodeCursor } from 'src/engine/api/graphql/graphql-query-runner/utils/cursors.util';
|
||||
import { getRelationObjectMetadata } from 'src/engine/api/graphql/graphql-query-runner/utils/get-relation-object-metadata.util';
|
||||
import { getTargetObjectMetadataOrThrow } from 'src/engine/api/graphql/graphql-query-runner/utils/get-target-object-metadata.util';
|
||||
import { AggregationField } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-available-aggregations-from-object-fields.util';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
@ -26,9 +29,14 @@ import { isPlainObject } from 'src/utils/is-plain-object';
|
||||
|
||||
export class ObjectRecordsToGraphqlConnectionHelper {
|
||||
private objectMetadataMaps: ObjectMetadataMaps;
|
||||
private featureFlagsMap: FeatureFlagMap;
|
||||
|
||||
constructor(objectMetadataMaps: ObjectMetadataMaps) {
|
||||
constructor(
|
||||
objectMetadataMaps: ObjectMetadataMaps,
|
||||
featureFlagsMap: FeatureFlagMap,
|
||||
) {
|
||||
this.objectMetadataMaps = objectMetadataMaps;
|
||||
this.featureFlagsMap = featureFlagsMap;
|
||||
}
|
||||
|
||||
public createConnection<T extends ObjectRecord = ObjectRecord>({
|
||||
@ -146,6 +154,9 @@ export class ObjectRecordsToGraphqlConnectionHelper {
|
||||
);
|
||||
}
|
||||
|
||||
const isNewRelationEnabled =
|
||||
this.featureFlagsMap[FeatureFlagKey.IsNewRelationEnabled];
|
||||
|
||||
const objectMetadata = getObjectMetadataMapItemByNameSingular(
|
||||
this.objectMetadataMaps,
|
||||
objectName,
|
||||
@ -170,6 +181,13 @@ export class ObjectRecordsToGraphqlConnectionHelper {
|
||||
|
||||
if (isRelationFieldMetadataType(fieldMetadata.type)) {
|
||||
if (Array.isArray(value)) {
|
||||
const targetObjectMetadata = isNewRelationEnabled
|
||||
? getTargetObjectMetadataOrThrow(
|
||||
fieldMetadata,
|
||||
this.objectMetadataMaps,
|
||||
)
|
||||
: getRelationObjectMetadata(fieldMetadata, this.objectMetadataMaps);
|
||||
|
||||
processedObjectRecord[key] = this.createConnection({
|
||||
objectRecords: value,
|
||||
parentObjectRecord: objectRecord,
|
||||
@ -177,10 +195,7 @@ export class ObjectRecordsToGraphqlConnectionHelper {
|
||||
objectRecordsAggregatedValues[fieldMetadata.name],
|
||||
selectedAggregatedFields:
|
||||
selectedAggregatedFields[fieldMetadata.name],
|
||||
objectName: getRelationObjectMetadata(
|
||||
fieldMetadata,
|
||||
this.objectMetadataMaps,
|
||||
).nameSingular,
|
||||
objectName: targetObjectMetadata.nameSingular,
|
||||
take,
|
||||
totalCount:
|
||||
objectRecordsAggregatedValues[fieldMetadata.name]?.totalCount ??
|
||||
@ -191,16 +206,20 @@ export class ObjectRecordsToGraphqlConnectionHelper {
|
||||
depth: depth + 1,
|
||||
});
|
||||
} else if (isPlainObject(value)) {
|
||||
const targetObjectMetadata = isNewRelationEnabled
|
||||
? getTargetObjectMetadataOrThrow(
|
||||
fieldMetadata,
|
||||
this.objectMetadataMaps,
|
||||
)
|
||||
: getRelationObjectMetadata(fieldMetadata, this.objectMetadataMaps);
|
||||
|
||||
processedObjectRecord[key] = this.processRecord({
|
||||
objectRecord: value,
|
||||
objectRecordsAggregatedValues:
|
||||
objectRecordsAggregatedValues[fieldMetadata.name],
|
||||
selectedAggregatedFields:
|
||||
selectedAggregatedFields[fieldMetadata.name],
|
||||
objectName: getRelationObjectMetadata(
|
||||
fieldMetadata,
|
||||
this.objectMetadataMaps,
|
||||
).nameSingular,
|
||||
objectName: targetObjectMetadata.nameSingular,
|
||||
take,
|
||||
totalCount,
|
||||
order,
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { SelectQueryBuilder } from 'typeorm';
|
||||
|
||||
import { AGGREGATE_OPERATIONS } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
|
||||
@ -5,6 +7,7 @@ import { AggregationField } from 'src/engine/api/graphql/workspace-schema-builde
|
||||
import { formatColumnNamesFromCompositeFieldAndSubfields } from 'src/engine/twenty-orm/utils/format-column-names-from-composite-field-and-subfield.util';
|
||||
import { isDefined } from 'src/utils/is-defined';
|
||||
|
||||
@Injectable()
|
||||
export class ProcessAggregateHelper {
|
||||
public addSelectedAggregatedFieldsQueriesToQueryBuilder = ({
|
||||
selectedAggregatedFields,
|
||||
|
||||
@ -0,0 +1,347 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
DataSource,
|
||||
FindOptionsRelations,
|
||||
ObjectLiteral,
|
||||
SelectQueryBuilder,
|
||||
} from 'typeorm';
|
||||
|
||||
import { ObjectRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
|
||||
import {
|
||||
GraphqlQueryRunnerException,
|
||||
GraphqlQueryRunnerExceptionCode,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-aggregate.helper';
|
||||
import { getTargetObjectMetadataOrThrow } from 'src/engine/api/graphql/graphql-query-runner/utils/get-target-object-metadata.util';
|
||||
import { AggregationField } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-available-aggregations-from-object-fields.util';
|
||||
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.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 { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||
import { isRelationFieldMetadata } from 'src/engine/utils/is-relation-field-metadata.util';
|
||||
|
||||
@Injectable()
|
||||
export class ProcessNestedRelationsV2Helper {
|
||||
constructor(
|
||||
private readonly processAggregateHelper: ProcessAggregateHelper,
|
||||
) {}
|
||||
|
||||
public async processNestedRelations<T extends ObjectRecord = ObjectRecord>({
|
||||
objectMetadataMaps,
|
||||
parentObjectMetadataItem,
|
||||
parentObjectRecords,
|
||||
parentObjectRecordsAggregatedValues = {},
|
||||
relations,
|
||||
aggregate = {},
|
||||
limit,
|
||||
authContext,
|
||||
dataSource,
|
||||
}: {
|
||||
objectMetadataMaps: ObjectMetadataMaps;
|
||||
parentObjectMetadataItem: ObjectMetadataItemWithFieldMaps;
|
||||
parentObjectRecords: T[];
|
||||
parentObjectRecordsAggregatedValues?: Record<string, any>;
|
||||
relations: Record<string, FindOptionsRelations<ObjectLiteral>>;
|
||||
aggregate?: Record<string, AggregationField>;
|
||||
limit: number;
|
||||
authContext: AuthContext;
|
||||
dataSource: DataSource;
|
||||
}): Promise<void> {
|
||||
const processRelationTasks = Object.entries(relations).map(
|
||||
([sourceFieldName, nestedRelations]) =>
|
||||
this.processRelation({
|
||||
objectMetadataMaps,
|
||||
parentObjectMetadataItem,
|
||||
parentObjectRecords,
|
||||
parentObjectRecordsAggregatedValues,
|
||||
sourceFieldName,
|
||||
nestedRelations,
|
||||
aggregate,
|
||||
limit,
|
||||
authContext,
|
||||
dataSource,
|
||||
}),
|
||||
);
|
||||
|
||||
await Promise.all(processRelationTasks);
|
||||
}
|
||||
|
||||
private async processRelation<T extends ObjectRecord = ObjectRecord>({
|
||||
objectMetadataMaps,
|
||||
parentObjectMetadataItem,
|
||||
parentObjectRecords,
|
||||
parentObjectRecordsAggregatedValues,
|
||||
sourceFieldName,
|
||||
nestedRelations,
|
||||
aggregate,
|
||||
limit,
|
||||
authContext,
|
||||
dataSource,
|
||||
}: {
|
||||
objectMetadataMaps: ObjectMetadataMaps;
|
||||
parentObjectMetadataItem: ObjectMetadataItemWithFieldMaps;
|
||||
parentObjectRecords: T[];
|
||||
parentObjectRecordsAggregatedValues: Record<string, any>;
|
||||
sourceFieldName: string;
|
||||
nestedRelations: FindOptionsRelations<ObjectLiteral>;
|
||||
aggregate: Record<string, AggregationField>;
|
||||
limit: number;
|
||||
authContext: AuthContext;
|
||||
dataSource: DataSource;
|
||||
}): Promise<void> {
|
||||
const sourceFieldMetadata =
|
||||
parentObjectMetadataItem.fieldsByName[sourceFieldName];
|
||||
|
||||
if (!isRelationFieldMetadata(sourceFieldMetadata)) {
|
||||
// TODO: Maybe we should throw an error here ?
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sourceFieldMetadata.settings) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
`Relation settings not found for field ${sourceFieldName}`,
|
||||
GraphqlQueryRunnerExceptionCode.RELATION_SETTINGS_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const relationType = sourceFieldMetadata.settings?.relationType;
|
||||
const { targetRelationName, targetObjectMetadata } =
|
||||
this.getTargetObjectMetadata({
|
||||
objectMetadataMaps,
|
||||
parentObjectMetadataItem,
|
||||
sourceFieldName,
|
||||
});
|
||||
|
||||
const targetObjectRepository = dataSource.getRepository(
|
||||
targetObjectMetadata.nameSingular,
|
||||
);
|
||||
const targetObjectQueryBuilder = targetObjectRepository.createQueryBuilder(
|
||||
targetObjectMetadata.nameSingular,
|
||||
);
|
||||
|
||||
const relationIds = this.getUniqueIds({
|
||||
records: parentObjectRecords,
|
||||
idField:
|
||||
relationType === RelationType.ONE_TO_MANY
|
||||
? 'id'
|
||||
: `${sourceFieldName}Id`,
|
||||
});
|
||||
|
||||
const { relationResults, relationAggregatedFieldsResult } =
|
||||
await this.findRelations({
|
||||
referenceQueryBuilder: targetObjectQueryBuilder,
|
||||
column:
|
||||
relationType === RelationType.ONE_TO_MANY
|
||||
? `"${targetRelationName}Id"`
|
||||
: 'id',
|
||||
ids: relationIds,
|
||||
limit,
|
||||
objectMetadataMaps,
|
||||
targetObjectMetadata,
|
||||
aggregate,
|
||||
sourceFieldName,
|
||||
});
|
||||
|
||||
this.assignRelationResults({
|
||||
parentRecords: parentObjectRecords,
|
||||
parentObjectRecordsAggregatedValues,
|
||||
relationResults,
|
||||
relationAggregatedFieldsResult,
|
||||
sourceFieldName,
|
||||
joinField:
|
||||
relationType === RelationType.ONE_TO_MANY
|
||||
? `${targetRelationName}Id`
|
||||
: 'id',
|
||||
relationType,
|
||||
});
|
||||
|
||||
const targetObjectMetadataItemWithFieldsMaps =
|
||||
getObjectMetadataMapItemByNameSingular(
|
||||
objectMetadataMaps,
|
||||
targetObjectMetadata.nameSingular,
|
||||
);
|
||||
|
||||
if (!targetObjectMetadataItemWithFieldsMaps) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
`Object ${targetObjectMetadata.nameSingular} not found`,
|
||||
GraphqlQueryRunnerExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
if (Object.keys(nestedRelations).length > 0) {
|
||||
await this.processNestedRelations({
|
||||
objectMetadataMaps,
|
||||
parentObjectMetadataItem: targetObjectMetadataItemWithFieldsMaps,
|
||||
parentObjectRecords: relationResults as ObjectRecord[],
|
||||
parentObjectRecordsAggregatedValues: relationAggregatedFieldsResult,
|
||||
relations: nestedRelations as Record<
|
||||
string,
|
||||
FindOptionsRelations<ObjectLiteral>
|
||||
>,
|
||||
aggregate,
|
||||
limit,
|
||||
authContext,
|
||||
dataSource,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private getTargetObjectMetadata({
|
||||
objectMetadataMaps,
|
||||
parentObjectMetadataItem,
|
||||
sourceFieldName,
|
||||
}: {
|
||||
objectMetadataMaps: ObjectMetadataMaps;
|
||||
parentObjectMetadataItem: ObjectMetadataItemWithFieldMaps;
|
||||
sourceFieldName: string;
|
||||
}) {
|
||||
const targetFieldMetadata =
|
||||
parentObjectMetadataItem.fieldsByName[sourceFieldName];
|
||||
const targetObjectMetadata = getTargetObjectMetadataOrThrow(
|
||||
targetFieldMetadata,
|
||||
objectMetadataMaps,
|
||||
);
|
||||
|
||||
if (
|
||||
!targetFieldMetadata.relationTargetObjectMetadataId ||
|
||||
!targetFieldMetadata.relationTargetFieldMetadataId
|
||||
) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
`Relation target object metadata id or field metadata id not found for field ${sourceFieldName}`,
|
||||
GraphqlQueryRunnerExceptionCode.RELATION_TARGET_OBJECT_METADATA_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const targetRelationName =
|
||||
objectMetadataMaps.byId[
|
||||
targetFieldMetadata.relationTargetObjectMetadataId
|
||||
]?.fieldsById[targetFieldMetadata.relationTargetFieldMetadataId]?.name;
|
||||
|
||||
return { targetRelationName, targetObjectMetadata };
|
||||
}
|
||||
|
||||
private getUniqueIds({
|
||||
records,
|
||||
idField,
|
||||
}: {
|
||||
records: ObjectRecord[];
|
||||
idField: string;
|
||||
}): any[] {
|
||||
return [...new Set(records.map((item) => item[idField]))];
|
||||
}
|
||||
|
||||
private async findRelations({
|
||||
referenceQueryBuilder,
|
||||
column,
|
||||
ids,
|
||||
limit,
|
||||
objectMetadataMaps,
|
||||
targetObjectMetadata,
|
||||
aggregate,
|
||||
sourceFieldName,
|
||||
}: {
|
||||
referenceQueryBuilder: SelectQueryBuilder<any>;
|
||||
column: string;
|
||||
ids: any[];
|
||||
limit: number;
|
||||
objectMetadataMaps: ObjectMetadataMaps;
|
||||
targetObjectMetadata: ObjectMetadataItemWithFieldMaps;
|
||||
aggregate: Record<string, any>;
|
||||
sourceFieldName: string;
|
||||
}): Promise<{ relationResults: any[]; relationAggregatedFieldsResult: any }> {
|
||||
if (ids.length === 0) {
|
||||
return { relationResults: [], relationAggregatedFieldsResult: {} };
|
||||
}
|
||||
|
||||
const aggregateForRelation = aggregate[sourceFieldName];
|
||||
let relationAggregatedFieldsResult: Record<string, any> = {};
|
||||
|
||||
if (aggregateForRelation) {
|
||||
const aggregateQueryBuilder = referenceQueryBuilder.clone();
|
||||
|
||||
this.processAggregateHelper.addSelectedAggregatedFieldsQueriesToQueryBuilder(
|
||||
{
|
||||
selectedAggregatedFields: aggregateForRelation,
|
||||
queryBuilder: aggregateQueryBuilder,
|
||||
},
|
||||
);
|
||||
|
||||
const aggregatedFieldsValues = await aggregateQueryBuilder
|
||||
.addSelect(column)
|
||||
.where(`${column} IN (:...ids)`, {
|
||||
ids,
|
||||
})
|
||||
.groupBy(column)
|
||||
.getRawMany();
|
||||
|
||||
relationAggregatedFieldsResult = aggregatedFieldsValues.reduce(
|
||||
(acc, item) => {
|
||||
const columnWithoutQuotes = column.replace(/["']/g, '');
|
||||
const key = item[columnWithoutQuotes];
|
||||
const { [column]: _, ...itemWithoutColumn } = item;
|
||||
|
||||
acc[key] = itemWithoutColumn;
|
||||
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
const result = await referenceQueryBuilder
|
||||
.where(`${column} IN (:...ids)`, {
|
||||
ids,
|
||||
})
|
||||
.take(limit)
|
||||
.getMany();
|
||||
|
||||
const relationResults = formatResult<ObjectRecord[]>(
|
||||
result,
|
||||
targetObjectMetadata,
|
||||
objectMetadataMaps,
|
||||
);
|
||||
|
||||
return { relationResults, relationAggregatedFieldsResult };
|
||||
}
|
||||
|
||||
private assignRelationResults({
|
||||
parentRecords,
|
||||
parentObjectRecordsAggregatedValues,
|
||||
relationResults,
|
||||
relationAggregatedFieldsResult,
|
||||
sourceFieldName,
|
||||
joinField,
|
||||
relationType,
|
||||
}: {
|
||||
parentRecords: ObjectRecord[];
|
||||
parentObjectRecordsAggregatedValues: Record<string, any>;
|
||||
relationResults: any[];
|
||||
relationAggregatedFieldsResult: Record<string, any>;
|
||||
sourceFieldName: string;
|
||||
joinField: string;
|
||||
relationType: RelationType;
|
||||
}): void {
|
||||
parentRecords.forEach((item) => {
|
||||
if (relationType === RelationType.ONE_TO_MANY) {
|
||||
item[sourceFieldName] = relationResults.filter(
|
||||
(rel) => rel[joinField] === item.id,
|
||||
);
|
||||
} else {
|
||||
if (relationResults.length === 0) {
|
||||
item[`${sourceFieldName}Id`] = null;
|
||||
}
|
||||
item[sourceFieldName] =
|
||||
relationResults.find(
|
||||
(rel) => rel.id === item[`${sourceFieldName}Id`],
|
||||
) ?? null;
|
||||
}
|
||||
});
|
||||
|
||||
parentObjectRecordsAggregatedValues[sourceFieldName] =
|
||||
relationAggregatedFieldsResult;
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
DataSource,
|
||||
FindOptionsRelations,
|
||||
@ -12,23 +14,28 @@ import {
|
||||
GraphqlQueryRunnerExceptionCode,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-aggregate.helper';
|
||||
import { ProcessNestedRelationsV2Helper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations-v2.helper';
|
||||
import {
|
||||
getRelationMetadata,
|
||||
getRelationObjectMetadata,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/utils/get-relation-object-metadata.util';
|
||||
import { AggregationField } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-available-aggregations-from-object-fields.util';
|
||||
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.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 { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||
import { deduceRelationDirection } from 'src/engine/utils/deduce-relation-direction.util';
|
||||
|
||||
@Injectable()
|
||||
export class ProcessNestedRelationsHelper {
|
||||
private processAggregateHelper: ProcessAggregateHelper;
|
||||
|
||||
constructor() {
|
||||
this.processAggregateHelper = new ProcessAggregateHelper();
|
||||
}
|
||||
constructor(
|
||||
private readonly processNestedRelationsV2Helper: ProcessNestedRelationsV2Helper,
|
||||
private readonly processAggregateHelper: ProcessAggregateHelper,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
) {}
|
||||
|
||||
public async processNestedRelations<T extends ObjectRecord = ObjectRecord>({
|
||||
objectMetadataMaps,
|
||||
@ -48,9 +55,28 @@ export class ProcessNestedRelationsHelper {
|
||||
relations: Record<string, FindOptionsRelations<ObjectLiteral>>;
|
||||
aggregate?: Record<string, AggregationField>;
|
||||
limit: number;
|
||||
authContext: any;
|
||||
authContext: AuthContext;
|
||||
dataSource: DataSource;
|
||||
}): Promise<void> {
|
||||
const isNewRelationEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsNewRelationEnabled,
|
||||
authContext.workspace.id,
|
||||
);
|
||||
|
||||
if (isNewRelationEnabled) {
|
||||
return this.processNestedRelationsV2Helper.processNestedRelations({
|
||||
objectMetadataMaps,
|
||||
parentObjectMetadataItem,
|
||||
parentObjectRecords,
|
||||
parentObjectRecordsAggregatedValues,
|
||||
relations,
|
||||
aggregate,
|
||||
limit,
|
||||
authContext,
|
||||
dataSource,
|
||||
});
|
||||
}
|
||||
|
||||
const processRelationTasks = Object.entries(relations).map(
|
||||
([relationName, nestedRelations]) =>
|
||||
this.processRelation({
|
||||
|
||||
Reference in New Issue
Block a user