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:
@ -21,4 +21,6 @@ export enum GraphqlQueryRunnerExceptionCode {
|
|||||||
INVALID_ARGS_LAST = 'INVALID_ARGS_LAST',
|
INVALID_ARGS_LAST = 'INVALID_ARGS_LAST',
|
||||||
METADATA_CACHE_VERSION_NOT_FOUND = 'METADATA_CACHE_VERSION_NOT_FOUND',
|
METADATA_CACHE_VERSION_NOT_FOUND = 'METADATA_CACHE_VERSION_NOT_FOUND',
|
||||||
METADATA_CACHE_FEATURE_FLAG_RECOMPUTATION_REQUIRED = 'METADATA_CACHE_FEATURE_FLAG_RECOMPUTATION_REQUIRED',
|
METADATA_CACHE_FEATURE_FLAG_RECOMPUTATION_REQUIRED = 'METADATA_CACHE_FEATURE_FLAG_RECOMPUTATION_REQUIRED',
|
||||||
|
RELATION_SETTINGS_NOT_FOUND = 'RELATION_SETTINGS_NOT_FOUND',
|
||||||
|
RELATION_TARGET_OBJECT_METADATA_NOT_FOUND = 'RELATION_TARGET_OBJECT_METADATA_NOT_FOUND',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
|
||||||
import { ObjectRecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
import { ObjectRecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||||
|
import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||||
|
|
||||||
import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map';
|
import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map';
|
||||||
|
|
||||||
@ -15,10 +16,14 @@ export class GraphqlQueryFilterConditionParser {
|
|||||||
private fieldMetadataMapByName: FieldMetadataMap;
|
private fieldMetadataMapByName: FieldMetadataMap;
|
||||||
private queryFilterFieldParser: GraphqlQueryFilterFieldParser;
|
private queryFilterFieldParser: GraphqlQueryFilterFieldParser;
|
||||||
|
|
||||||
constructor(fieldMetadataMapByName: FieldMetadataMap) {
|
constructor(
|
||||||
|
fieldMetadataMapByName: FieldMetadataMap,
|
||||||
|
featureFlagsMap: FeatureFlagMap,
|
||||||
|
) {
|
||||||
this.fieldMetadataMapByName = fieldMetadataMapByName;
|
this.fieldMetadataMapByName = fieldMetadataMapByName;
|
||||||
this.queryFilterFieldParser = new GraphqlQueryFilterFieldParser(
|
this.queryFilterFieldParser = new GraphqlQueryFilterFieldParser(
|
||||||
this.fieldMetadataMapByName,
|
this.fieldMetadataMapByName,
|
||||||
|
featureFlagsMap,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { capitalize } from 'twenty-shared';
|
import { capitalize } from 'twenty-shared';
|
||||||
import { WhereExpressionBuilder } from 'typeorm';
|
import { WhereExpressionBuilder } from 'typeorm';
|
||||||
|
|
||||||
|
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 { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -17,9 +18,14 @@ const ARRAY_OPERATORS = ['in', 'contains', 'notContains'];
|
|||||||
|
|
||||||
export class GraphqlQueryFilterFieldParser {
|
export class GraphqlQueryFilterFieldParser {
|
||||||
private fieldMetadataMapByName: FieldMetadataMap;
|
private fieldMetadataMapByName: FieldMetadataMap;
|
||||||
|
private featureFlagsMap: FeatureFlagMap;
|
||||||
|
|
||||||
constructor(fieldMetadataMapByName: FieldMetadataMap) {
|
constructor(
|
||||||
|
fieldMetadataMapByName: FieldMetadataMap,
|
||||||
|
featureFlagsMap: FeatureFlagMap,
|
||||||
|
) {
|
||||||
this.fieldMetadataMapByName = fieldMetadataMapByName;
|
this.fieldMetadataMapByName = fieldMetadataMapByName;
|
||||||
|
this.featureFlagsMap = featureFlagsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public parse(
|
public parse(
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
ObjectRecordOrderBy,
|
ObjectRecordOrderBy,
|
||||||
OrderByDirection,
|
OrderByDirection,
|
||||||
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.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 { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -16,9 +17,14 @@ import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metada
|
|||||||
import { CompositeFieldMetadataType } from 'src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory';
|
import { CompositeFieldMetadataType } from 'src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory';
|
||||||
export class GraphqlQueryOrderFieldParser {
|
export class GraphqlQueryOrderFieldParser {
|
||||||
private fieldMetadataMapByName: FieldMetadataMap;
|
private fieldMetadataMapByName: FieldMetadataMap;
|
||||||
|
private featureFlagsMap: FeatureFlagMap;
|
||||||
|
|
||||||
constructor(fieldMetadataMapByName: FieldMetadataMap) {
|
constructor(
|
||||||
|
fieldMetadataMapByName: FieldMetadataMap,
|
||||||
|
featureFlagsMap: FeatureFlagMap,
|
||||||
|
) {
|
||||||
this.fieldMetadataMapByName = fieldMetadataMapByName;
|
this.fieldMetadataMapByName = fieldMetadataMapByName;
|
||||||
|
this.featureFlagsMap = featureFlagsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(
|
parse(
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
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 { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -5,13 +6,20 @@ import {
|
|||||||
GraphqlQuerySelectedFieldsResult,
|
GraphqlQuerySelectedFieldsResult,
|
||||||
} from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-selected-fields/graphql-selected-fields.parser';
|
} from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-selected-fields/graphql-selected-fields.parser';
|
||||||
import { getRelationObjectMetadata } from 'src/engine/api/graphql/graphql-query-runner/utils/get-relation-object-metadata.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 { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||||
|
|
||||||
export class GraphqlQuerySelectedFieldsRelationParser {
|
export class GraphqlQuerySelectedFieldsRelationParser {
|
||||||
private objectMetadataMaps: ObjectMetadataMaps;
|
private objectMetadataMaps: ObjectMetadataMaps;
|
||||||
|
private featureFlagsMap: FeatureFlagMap;
|
||||||
|
|
||||||
constructor(objectMetadataMaps: ObjectMetadataMaps) {
|
constructor(
|
||||||
|
objectMetadataMaps: ObjectMetadataMaps,
|
||||||
|
featureFlagsMap: FeatureFlagMap,
|
||||||
|
) {
|
||||||
this.objectMetadataMaps = objectMetadataMaps;
|
this.objectMetadataMaps = objectMetadataMaps;
|
||||||
|
this.featureFlagsMap = featureFlagsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseRelationField(
|
parseRelationField(
|
||||||
@ -26,16 +34,19 @@ export class GraphqlQuerySelectedFieldsRelationParser {
|
|||||||
|
|
||||||
accumulator.relations[fieldKey] = true;
|
accumulator.relations[fieldKey] = true;
|
||||||
|
|
||||||
const referencedObjectMetadata = getRelationObjectMetadata(
|
const isNewRelationEnabled =
|
||||||
fieldMetadata,
|
this.featureFlagsMap[FeatureFlagKey.IsNewRelationEnabled];
|
||||||
this.objectMetadataMaps,
|
|
||||||
);
|
|
||||||
|
|
||||||
const relationFields = referencedObjectMetadata.fieldsByName;
|
const targetObjectMetadata = isNewRelationEnabled
|
||||||
|
? getTargetObjectMetadataOrThrow(fieldMetadata, this.objectMetadataMaps)
|
||||||
|
: getRelationObjectMetadata(fieldMetadata, this.objectMetadataMaps);
|
||||||
|
|
||||||
|
const targetFields = targetObjectMetadata.fieldsByName;
|
||||||
const fieldParser = new GraphqlQuerySelectedFieldsParser(
|
const fieldParser = new GraphqlQuerySelectedFieldsParser(
|
||||||
this.objectMetadataMaps,
|
this.objectMetadataMaps,
|
||||||
|
this.featureFlagsMap,
|
||||||
);
|
);
|
||||||
const relationAccumulator = fieldParser.parse(fieldValue, relationFields);
|
const relationAccumulator = fieldParser.parse(fieldValue, targetFields);
|
||||||
|
|
||||||
accumulator.select[fieldKey] = {
|
accumulator.select[fieldKey] = {
|
||||||
id: true,
|
id: true,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { capitalize } from 'twenty-shared';
|
import { capitalize } from 'twenty-shared';
|
||||||
|
|
||||||
|
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 { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||||
|
|
||||||
import { GraphqlQuerySelectedFieldsAggregateParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-selected-fields/graphql-selected-fields-aggregate.parser';
|
import { GraphqlQuerySelectedFieldsAggregateParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-selected-fields/graphql-selected-fields-aggregate.parser';
|
||||||
@ -20,9 +21,15 @@ export class GraphqlQuerySelectedFieldsParser {
|
|||||||
private graphqlQuerySelectedFieldsRelationParser: GraphqlQuerySelectedFieldsRelationParser;
|
private graphqlQuerySelectedFieldsRelationParser: GraphqlQuerySelectedFieldsRelationParser;
|
||||||
private aggregateParser: GraphqlQuerySelectedFieldsAggregateParser;
|
private aggregateParser: GraphqlQuerySelectedFieldsAggregateParser;
|
||||||
|
|
||||||
constructor(objectMetadataMaps: ObjectMetadataMaps) {
|
constructor(
|
||||||
|
objectMetadataMaps: ObjectMetadataMaps,
|
||||||
|
featureFlagsMap: FeatureFlagMap,
|
||||||
|
) {
|
||||||
this.graphqlQuerySelectedFieldsRelationParser =
|
this.graphqlQuerySelectedFieldsRelationParser =
|
||||||
new GraphqlQuerySelectedFieldsRelationParser(objectMetadataMaps);
|
new GraphqlQuerySelectedFieldsRelationParser(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
this.aggregateParser = new GraphqlQuerySelectedFieldsAggregateParser();
|
this.aggregateParser = new GraphqlQuerySelectedFieldsAggregateParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
ObjectRecordFilter,
|
ObjectRecordFilter,
|
||||||
ObjectRecordOrderBy,
|
ObjectRecordOrderBy,
|
||||||
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||||
|
import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||||
|
|
||||||
import { GraphqlQueryFilterConditionParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-condition.parser';
|
import { GraphqlQueryFilterConditionParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-condition.parser';
|
||||||
import { GraphqlQueryOrderFieldParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/graphql-query-order.parser';
|
import { GraphqlQueryOrderFieldParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/graphql-query-order.parser';
|
||||||
@ -26,18 +27,23 @@ export class GraphqlQueryParser {
|
|||||||
private objectMetadataMaps: ObjectMetadataMaps;
|
private objectMetadataMaps: ObjectMetadataMaps;
|
||||||
private filterConditionParser: GraphqlQueryFilterConditionParser;
|
private filterConditionParser: GraphqlQueryFilterConditionParser;
|
||||||
private orderFieldParser: GraphqlQueryOrderFieldParser;
|
private orderFieldParser: GraphqlQueryOrderFieldParser;
|
||||||
|
private featureFlagsMap: FeatureFlagMap;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
fieldMetadataMapByName: FieldMetadataMap,
|
fieldMetadataMapByName: FieldMetadataMap,
|
||||||
objectMetadataMaps: ObjectMetadataMaps,
|
objectMetadataMaps: ObjectMetadataMaps,
|
||||||
|
featureFlagsMap: FeatureFlagMap,
|
||||||
) {
|
) {
|
||||||
this.objectMetadataMaps = objectMetadataMaps;
|
this.objectMetadataMaps = objectMetadataMaps;
|
||||||
this.fieldMetadataMapByName = fieldMetadataMapByName;
|
this.fieldMetadataMapByName = fieldMetadataMapByName;
|
||||||
|
this.featureFlagsMap = featureFlagsMap;
|
||||||
this.filterConditionParser = new GraphqlQueryFilterConditionParser(
|
this.filterConditionParser = new GraphqlQueryFilterConditionParser(
|
||||||
this.fieldMetadataMapByName,
|
this.fieldMetadataMapByName,
|
||||||
|
featureFlagsMap,
|
||||||
);
|
);
|
||||||
this.orderFieldParser = new GraphqlQueryOrderFieldParser(
|
this.orderFieldParser = new GraphqlQueryOrderFieldParser(
|
||||||
this.fieldMetadataMapByName,
|
this.fieldMetadataMapByName,
|
||||||
|
featureFlagsMap,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +128,7 @@ export class GraphqlQueryParser {
|
|||||||
|
|
||||||
const selectedFieldsParser = new GraphqlQuerySelectedFieldsParser(
|
const selectedFieldsParser = new GraphqlQuerySelectedFieldsParser(
|
||||||
this.objectMetadataMaps,
|
this.objectMetadataMaps,
|
||||||
|
this.featureFlagsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
return selectedFieldsParser.parse(graphqlSelectedFields, parentFields);
|
return selectedFieldsParser.parse(graphqlSelectedFields, parentFields);
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
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 { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
||||||
import { GraphqlQueryCreateManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service';
|
import { GraphqlQueryCreateManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service';
|
||||||
import { GraphqlQueryCreateOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-one-resolver.service';
|
import { GraphqlQueryCreateOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-one-resolver.service';
|
||||||
import { GraphqlQueryDeleteManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-many-resolver.service';
|
import { GraphqlQueryDeleteManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-many-resolver.service';
|
||||||
@ -42,7 +45,13 @@ const graphqlQueryResolvers = [
|
|||||||
WorkspaceQueryRunnerModule,
|
WorkspaceQueryRunnerModule,
|
||||||
FeatureFlagModule,
|
FeatureFlagModule,
|
||||||
],
|
],
|
||||||
providers: [ApiEventEmitterService, ...graphqlQueryResolvers],
|
providers: [
|
||||||
|
ApiEventEmitterService,
|
||||||
|
ProcessNestedRelationsHelper,
|
||||||
|
ProcessNestedRelationsV2Helper,
|
||||||
|
ProcessAggregateHelper,
|
||||||
|
...graphqlQueryResolvers,
|
||||||
|
],
|
||||||
exports: [...graphqlQueryResolvers],
|
exports: [...graphqlQueryResolvers],
|
||||||
})
|
})
|
||||||
export class GraphqlQueryRunnerModule {}
|
export class GraphqlQueryRunnerModule {}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {
|
|||||||
ObjectRecordOrderBy,
|
ObjectRecordOrderBy,
|
||||||
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
} 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 { 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 { 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';
|
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';
|
} 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 { 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 { 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 { 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 { 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 { 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';
|
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 {
|
export class ObjectRecordsToGraphqlConnectionHelper {
|
||||||
private objectMetadataMaps: ObjectMetadataMaps;
|
private objectMetadataMaps: ObjectMetadataMaps;
|
||||||
|
private featureFlagsMap: FeatureFlagMap;
|
||||||
|
|
||||||
constructor(objectMetadataMaps: ObjectMetadataMaps) {
|
constructor(
|
||||||
|
objectMetadataMaps: ObjectMetadataMaps,
|
||||||
|
featureFlagsMap: FeatureFlagMap,
|
||||||
|
) {
|
||||||
this.objectMetadataMaps = objectMetadataMaps;
|
this.objectMetadataMaps = objectMetadataMaps;
|
||||||
|
this.featureFlagsMap = featureFlagsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createConnection<T extends ObjectRecord = ObjectRecord>({
|
public createConnection<T extends ObjectRecord = ObjectRecord>({
|
||||||
@ -146,6 +154,9 @@ export class ObjectRecordsToGraphqlConnectionHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isNewRelationEnabled =
|
||||||
|
this.featureFlagsMap[FeatureFlagKey.IsNewRelationEnabled];
|
||||||
|
|
||||||
const objectMetadata = getObjectMetadataMapItemByNameSingular(
|
const objectMetadata = getObjectMetadataMapItemByNameSingular(
|
||||||
this.objectMetadataMaps,
|
this.objectMetadataMaps,
|
||||||
objectName,
|
objectName,
|
||||||
@ -170,6 +181,13 @@ export class ObjectRecordsToGraphqlConnectionHelper {
|
|||||||
|
|
||||||
if (isRelationFieldMetadataType(fieldMetadata.type)) {
|
if (isRelationFieldMetadataType(fieldMetadata.type)) {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
|
const targetObjectMetadata = isNewRelationEnabled
|
||||||
|
? getTargetObjectMetadataOrThrow(
|
||||||
|
fieldMetadata,
|
||||||
|
this.objectMetadataMaps,
|
||||||
|
)
|
||||||
|
: getRelationObjectMetadata(fieldMetadata, this.objectMetadataMaps);
|
||||||
|
|
||||||
processedObjectRecord[key] = this.createConnection({
|
processedObjectRecord[key] = this.createConnection({
|
||||||
objectRecords: value,
|
objectRecords: value,
|
||||||
parentObjectRecord: objectRecord,
|
parentObjectRecord: objectRecord,
|
||||||
@ -177,10 +195,7 @@ export class ObjectRecordsToGraphqlConnectionHelper {
|
|||||||
objectRecordsAggregatedValues[fieldMetadata.name],
|
objectRecordsAggregatedValues[fieldMetadata.name],
|
||||||
selectedAggregatedFields:
|
selectedAggregatedFields:
|
||||||
selectedAggregatedFields[fieldMetadata.name],
|
selectedAggregatedFields[fieldMetadata.name],
|
||||||
objectName: getRelationObjectMetadata(
|
objectName: targetObjectMetadata.nameSingular,
|
||||||
fieldMetadata,
|
|
||||||
this.objectMetadataMaps,
|
|
||||||
).nameSingular,
|
|
||||||
take,
|
take,
|
||||||
totalCount:
|
totalCount:
|
||||||
objectRecordsAggregatedValues[fieldMetadata.name]?.totalCount ??
|
objectRecordsAggregatedValues[fieldMetadata.name]?.totalCount ??
|
||||||
@ -191,16 +206,20 @@ export class ObjectRecordsToGraphqlConnectionHelper {
|
|||||||
depth: depth + 1,
|
depth: depth + 1,
|
||||||
});
|
});
|
||||||
} else if (isPlainObject(value)) {
|
} else if (isPlainObject(value)) {
|
||||||
|
const targetObjectMetadata = isNewRelationEnabled
|
||||||
|
? getTargetObjectMetadataOrThrow(
|
||||||
|
fieldMetadata,
|
||||||
|
this.objectMetadataMaps,
|
||||||
|
)
|
||||||
|
: getRelationObjectMetadata(fieldMetadata, this.objectMetadataMaps);
|
||||||
|
|
||||||
processedObjectRecord[key] = this.processRecord({
|
processedObjectRecord[key] = this.processRecord({
|
||||||
objectRecord: value,
|
objectRecord: value,
|
||||||
objectRecordsAggregatedValues:
|
objectRecordsAggregatedValues:
|
||||||
objectRecordsAggregatedValues[fieldMetadata.name],
|
objectRecordsAggregatedValues[fieldMetadata.name],
|
||||||
selectedAggregatedFields:
|
selectedAggregatedFields:
|
||||||
selectedAggregatedFields[fieldMetadata.name],
|
selectedAggregatedFields[fieldMetadata.name],
|
||||||
objectName: getRelationObjectMetadata(
|
objectName: targetObjectMetadata.nameSingular,
|
||||||
fieldMetadata,
|
|
||||||
this.objectMetadataMaps,
|
|
||||||
).nameSingular,
|
|
||||||
take,
|
take,
|
||||||
totalCount,
|
totalCount,
|
||||||
order,
|
order,
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
import { SelectQueryBuilder } from 'typeorm';
|
import { SelectQueryBuilder } from 'typeorm';
|
||||||
|
|
||||||
import { AGGREGATE_OPERATIONS } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
|
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 { formatColumnNamesFromCompositeFieldAndSubfields } from 'src/engine/twenty-orm/utils/format-column-names-from-composite-field-and-subfield.util';
|
||||||
import { isDefined } from 'src/utils/is-defined';
|
import { isDefined } from 'src/utils/is-defined';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
export class ProcessAggregateHelper {
|
export class ProcessAggregateHelper {
|
||||||
public addSelectedAggregatedFieldsQueriesToQueryBuilder = ({
|
public addSelectedAggregatedFieldsQueriesToQueryBuilder = ({
|
||||||
selectedAggregatedFields,
|
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 {
|
import {
|
||||||
DataSource,
|
DataSource,
|
||||||
FindOptionsRelations,
|
FindOptionsRelations,
|
||||||
@ -12,23 +14,28 @@ import {
|
|||||||
GraphqlQueryRunnerExceptionCode,
|
GraphqlQueryRunnerExceptionCode,
|
||||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
} 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 { 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 {
|
import {
|
||||||
getRelationMetadata,
|
getRelationMetadata,
|
||||||
getRelationObjectMetadata,
|
getRelationObjectMetadata,
|
||||||
} from 'src/engine/api/graphql/graphql-query-runner/utils/get-relation-object-metadata.util';
|
} 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 { 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 { 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 { 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 { 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 { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
import { deduceRelationDirection } from 'src/engine/utils/deduce-relation-direction.util';
|
import { deduceRelationDirection } from 'src/engine/utils/deduce-relation-direction.util';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
export class ProcessNestedRelationsHelper {
|
export class ProcessNestedRelationsHelper {
|
||||||
private processAggregateHelper: ProcessAggregateHelper;
|
constructor(
|
||||||
|
private readonly processNestedRelationsV2Helper: ProcessNestedRelationsV2Helper,
|
||||||
constructor() {
|
private readonly processAggregateHelper: ProcessAggregateHelper,
|
||||||
this.processAggregateHelper = new ProcessAggregateHelper();
|
private readonly featureFlagService: FeatureFlagService,
|
||||||
}
|
) {}
|
||||||
|
|
||||||
public async processNestedRelations<T extends ObjectRecord = ObjectRecord>({
|
public async processNestedRelations<T extends ObjectRecord = ObjectRecord>({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
@ -48,9 +55,28 @@ export class ProcessNestedRelationsHelper {
|
|||||||
relations: Record<string, FindOptionsRelations<ObjectLiteral>>;
|
relations: Record<string, FindOptionsRelations<ObjectLiteral>>;
|
||||||
aggregate?: Record<string, AggregationField>;
|
aggregate?: Record<string, AggregationField>;
|
||||||
limit: number;
|
limit: number;
|
||||||
authContext: any;
|
authContext: AuthContext;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
}): Promise<void> {
|
}): 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(
|
const processRelationTasks = Object.entries(relations).map(
|
||||||
([relationName, nestedRelations]) =>
|
([relationName, nestedRelations]) =>
|
||||||
this.processRelation({
|
this.processRelation({
|
||||||
|
|||||||
@ -16,11 +16,13 @@ import {
|
|||||||
|
|
||||||
import { GraphqlQuerySelectedFieldsResult } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-selected-fields/graphql-selected-fields.parser';
|
import { GraphqlQuerySelectedFieldsResult } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-selected-fields/graphql-selected-fields.parser';
|
||||||
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
|
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
|
||||||
|
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
||||||
import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service';
|
import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service';
|
||||||
import { QueryResultGettersFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/query-result-getters.factory';
|
import { QueryResultGettersFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/query-result-getters.factory';
|
||||||
import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory';
|
import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory';
|
||||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||||
import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service';
|
import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service';
|
||||||
|
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||||
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||||
|
|
||||||
@ -52,6 +54,10 @@ export abstract class GraphqlQueryBaseResolverService<
|
|||||||
protected readonly apiEventEmitterService: ApiEventEmitterService;
|
protected readonly apiEventEmitterService: ApiEventEmitterService;
|
||||||
@Inject()
|
@Inject()
|
||||||
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager;
|
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager;
|
||||||
|
@Inject()
|
||||||
|
protected readonly processNestedRelationsHelper: ProcessNestedRelationsHelper;
|
||||||
|
@Inject()
|
||||||
|
protected readonly featureFlagService: FeatureFlagService;
|
||||||
|
|
||||||
public async execute(
|
public async execute(
|
||||||
args: Input,
|
args: Input,
|
||||||
@ -86,9 +92,15 @@ export abstract class GraphqlQueryBaseResolverService<
|
|||||||
objectMetadataItemWithFieldMaps.nameSingular,
|
objectMetadataItemWithFieldMaps.nameSingular,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const graphqlQueryParser = new GraphqlQueryParser(
|
const graphqlQueryParser = new GraphqlQueryParser(
|
||||||
objectMetadataItemWithFieldMaps.fieldsByName,
|
objectMetadataItemWithFieldMaps.fieldsByName,
|
||||||
options.objectMetadataMaps,
|
options.objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedFields = graphqlFields(options.info);
|
const selectedFields = graphqlFields(options.info);
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolve
|
|||||||
|
|
||||||
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
||||||
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
@ -58,10 +57,8 @@ export class GraphqlQueryCreateManyResolverService extends GraphqlQueryBaseResol
|
|||||||
objectMetadataItemWithFieldMaps,
|
objectMetadataItemWithFieldMaps,
|
||||||
);
|
);
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: upsertedRecords,
|
parentObjectRecords: upsertedRecords,
|
||||||
@ -72,8 +69,16 @@ export class GraphqlQueryCreateManyResolverService extends GraphqlQueryBaseResol
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return upsertedRecords.map((record: ObjectRecord) =>
|
return upsertedRecords.map((record: ObjectRecord) =>
|
||||||
typeORMObjectRecordsParser.processRecord({
|
typeORMObjectRecordsParser.processRecord({
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import { CreateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver
|
|||||||
|
|
||||||
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
||||||
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
@ -58,10 +57,8 @@ export class GraphqlQueryCreateOneResolverService extends GraphqlQueryBaseResolv
|
|||||||
objectMetadataItemWithFieldMaps,
|
objectMetadataItemWithFieldMaps,
|
||||||
);
|
);
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: upsertedRecords,
|
parentObjectRecords: upsertedRecords,
|
||||||
@ -72,8 +69,16 @@ export class GraphqlQueryCreateOneResolverService extends GraphqlQueryBaseResolv
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return typeORMObjectRecordsParser.processRecord({
|
return typeORMObjectRecordsParser.processRecord({
|
||||||
objectRecord: upsertedRecords[0],
|
objectRecord: upsertedRecords[0],
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import { DeleteManyResolverArgs } from 'src/engine/api/graphql/workspace-resolve
|
|||||||
|
|
||||||
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
||||||
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
@ -59,10 +58,8 @@ export class GraphqlQueryDeleteManyResolverService extends GraphqlQueryBaseResol
|
|||||||
objectMetadataItemWithFieldMaps,
|
objectMetadataItemWithFieldMaps,
|
||||||
);
|
);
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: formattedDeletedRecords,
|
parentObjectRecords: formattedDeletedRecords,
|
||||||
@ -73,8 +70,16 @@ export class GraphqlQueryDeleteManyResolverService extends GraphqlQueryBaseResol
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return formattedDeletedRecords.map((record: ObjectRecord) =>
|
return formattedDeletedRecords.map((record: ObjectRecord) =>
|
||||||
typeORMObjectRecordsParser.processRecord({
|
typeORMObjectRecordsParser.processRecord({
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import {
|
|||||||
GraphqlQueryRunnerExceptionCode,
|
GraphqlQueryRunnerExceptionCode,
|
||||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
||||||
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
@ -61,10 +60,8 @@ export class GraphqlQueryDeleteOneResolverService extends GraphqlQueryBaseResolv
|
|||||||
|
|
||||||
const deletedRecord = formattedDeletedRecords[0];
|
const deletedRecord = formattedDeletedRecords[0];
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: [deletedRecord],
|
parentObjectRecords: [deletedRecord],
|
||||||
@ -75,8 +72,16 @@ export class GraphqlQueryDeleteOneResolverService extends GraphqlQueryBaseResolv
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return typeORMObjectRecordsParser.processRecord({
|
return typeORMObjectRecordsParser.processRecord({
|
||||||
objectRecord: deletedRecord,
|
objectRecord: deletedRecord,
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import { DestroyManyResolverArgs } from 'src/engine/api/graphql/workspace-resolv
|
|||||||
|
|
||||||
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
import { computeTableName } from 'src/engine/utils/compute-table-name.util';
|
import { computeTableName } from 'src/engine/utils/compute-table-name.util';
|
||||||
|
|
||||||
@ -57,10 +56,8 @@ export class GraphqlQueryDestroyManyResolverService extends GraphqlQueryBaseReso
|
|||||||
objectMetadataItemWithFieldMaps,
|
objectMetadataItemWithFieldMaps,
|
||||||
);
|
);
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: deletedRecords,
|
parentObjectRecords: deletedRecords,
|
||||||
@ -71,8 +68,16 @@ export class GraphqlQueryDestroyManyResolverService extends GraphqlQueryBaseReso
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return deletedRecords.map((record: ObjectRecord) =>
|
return deletedRecords.map((record: ObjectRecord) =>
|
||||||
typeORMObjectRecordsParser.processRecord({
|
typeORMObjectRecordsParser.processRecord({
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import {
|
|||||||
GraphqlQueryRunnerExceptionCode,
|
GraphqlQueryRunnerExceptionCode,
|
||||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -57,10 +56,8 @@ export class GraphqlQueryDestroyOneResolverService extends GraphqlQueryBaseResol
|
|||||||
objectMetadataItemWithFieldMaps,
|
objectMetadataItemWithFieldMaps,
|
||||||
);
|
);
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: deletedRecords,
|
parentObjectRecords: deletedRecords,
|
||||||
@ -71,8 +68,16 @@ export class GraphqlQueryDestroyOneResolverService extends GraphqlQueryBaseResol
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return typeORMObjectRecordsParser.processRecord({
|
return typeORMObjectRecordsParser.processRecord({
|
||||||
objectRecord: deletedRecords[0],
|
objectRecord: deletedRecords[0],
|
||||||
|
|||||||
@ -37,7 +37,7 @@ export class GraphqlQueryFindDuplicatesResolverService extends GraphqlQueryBaseR
|
|||||||
async resolve(
|
async resolve(
|
||||||
executionArgs: GraphqlQueryResolverExecutionArgs<FindDuplicatesResolverArgs>,
|
executionArgs: GraphqlQueryResolverExecutionArgs<FindDuplicatesResolverArgs>,
|
||||||
): Promise<IConnection<ObjectRecord>[]> {
|
): Promise<IConnection<ObjectRecord>[]> {
|
||||||
const { objectMetadataItemWithFieldMaps, objectMetadataMaps } =
|
const { objectMetadataItemWithFieldMaps, objectMetadataMaps, authContext } =
|
||||||
executionArgs.options;
|
executionArgs.options;
|
||||||
|
|
||||||
const existingRecordsQueryBuilder =
|
const existingRecordsQueryBuilder =
|
||||||
@ -58,13 +58,22 @@ export class GraphqlQueryFindDuplicatesResolverService extends GraphqlQueryBaseR
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const graphqlQueryParser = new GraphqlQueryParser(
|
const graphqlQueryParser = new GraphqlQueryParser(
|
||||||
objectMetadataItemWithFieldsMaps?.fieldsByName,
|
objectMetadataItemWithFieldsMaps?.fieldsByName,
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
let objectRecords: Partial<ObjectRecord>[] = [];
|
let objectRecords: Partial<ObjectRecord>[] = [];
|
||||||
|
|
||||||
|
|||||||
@ -21,13 +21,11 @@ import {
|
|||||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-aggregate.helper';
|
import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-aggregate.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { computeCursorArgFilter } from 'src/engine/api/graphql/graphql-query-runner/utils/compute-cursor-arg-filter';
|
import { computeCursorArgFilter } from 'src/engine/api/graphql/graphql-query-runner/utils/compute-cursor-arg-filter';
|
||||||
import {
|
import {
|
||||||
getCursor,
|
getCursor,
|
||||||
getPaginationInfo,
|
getPaginationInfo,
|
||||||
} from 'src/engine/api/graphql/graphql-query-runner/utils/cursors.util';
|
} from 'src/engine/api/graphql/graphql-query-runner/utils/cursors.util';
|
||||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
import { isDefined } from 'src/utils/is-defined';
|
import { isDefined } from 'src/utils/is-defined';
|
||||||
|
|
||||||
@ -36,7 +34,7 @@ export class GraphqlQueryFindManyResolverService extends GraphqlQueryBaseResolve
|
|||||||
FindManyResolverArgs,
|
FindManyResolverArgs,
|
||||||
IConnection<ObjectRecord>
|
IConnection<ObjectRecord>
|
||||||
> {
|
> {
|
||||||
constructor(private readonly featureFlagService: FeatureFlagService) {
|
constructor(private readonly processAggregateHelper: ProcessAggregateHelper) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,13 +106,13 @@ export class GraphqlQueryFindManyResolverService extends GraphqlQueryBaseResolve
|
|||||||
appliedFilters,
|
appliedFilters,
|
||||||
);
|
);
|
||||||
|
|
||||||
const processAggregateHelper = new ProcessAggregateHelper();
|
this.processAggregateHelper.addSelectedAggregatedFieldsQueriesToQueryBuilder(
|
||||||
|
{
|
||||||
processAggregateHelper.addSelectedAggregatedFieldsQueriesToQueryBuilder({
|
selectedAggregatedFields:
|
||||||
selectedAggregatedFields:
|
executionArgs.graphqlQuerySelectedFieldsResult.aggregate,
|
||||||
executionArgs.graphqlQuerySelectedFieldsResult.aggregate,
|
queryBuilder: aggregateQueryBuilder,
|
||||||
queryBuilder: aggregateQueryBuilder,
|
},
|
||||||
});
|
);
|
||||||
|
|
||||||
const limit =
|
const limit =
|
||||||
executionArgs.args.first ?? executionArgs.args.last ?? QUERY_MAX_RECORDS;
|
executionArgs.args.first ?? executionArgs.args.last ?? QUERY_MAX_RECORDS;
|
||||||
@ -142,10 +140,8 @@ export class GraphqlQueryFindManyResolverService extends GraphqlQueryBaseResolve
|
|||||||
const parentObjectRecordsAggregatedValues =
|
const parentObjectRecordsAggregatedValues =
|
||||||
await aggregateQueryBuilder.getRawOne();
|
await aggregateQueryBuilder.getRawOne();
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: objectRecords,
|
parentObjectRecords: objectRecords,
|
||||||
@ -158,8 +154,16 @@ export class GraphqlQueryFindManyResolverService extends GraphqlQueryBaseResolve
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return typeORMObjectRecordsParser.createConnection({
|
return typeORMObjectRecordsParser.createConnection({
|
||||||
objectRecords,
|
objectRecords,
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import {
|
|||||||
GraphqlQueryRunnerExceptionCode,
|
GraphqlQueryRunnerExceptionCode,
|
||||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import {
|
import {
|
||||||
WorkspaceQueryRunnerException,
|
WorkspaceQueryRunnerException,
|
||||||
WorkspaceQueryRunnerExceptionCode,
|
WorkspaceQueryRunnerExceptionCode,
|
||||||
@ -65,12 +64,10 @@ export class GraphqlQueryFindOneResolverService extends GraphqlQueryBaseResolver
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
const objectRecords = [objectRecord];
|
const objectRecords = [objectRecord];
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: objectRecords,
|
parentObjectRecords: objectRecords,
|
||||||
@ -81,8 +78,16 @@ export class GraphqlQueryFindOneResolverService extends GraphqlQueryBaseResolver
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return typeORMObjectRecordsParser.processRecord({
|
return typeORMObjectRecordsParser.processRecord({
|
||||||
objectRecord: objectRecords[0],
|
objectRecord: objectRecords[0],
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import { RestoreManyResolverArgs } from 'src/engine/api/graphql/workspace-resolv
|
|||||||
|
|
||||||
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
||||||
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
@ -59,10 +58,8 @@ export class GraphqlQueryRestoreManyResolverService extends GraphqlQueryBaseReso
|
|||||||
objectMetadataItemWithFieldMaps,
|
objectMetadataItemWithFieldMaps,
|
||||||
);
|
);
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: formattedRestoredRecords,
|
parentObjectRecords: formattedRestoredRecords,
|
||||||
@ -73,8 +70,16 @@ export class GraphqlQueryRestoreManyResolverService extends GraphqlQueryBaseReso
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return formattedRestoredRecords.map((record: ObjectRecord) =>
|
return formattedRestoredRecords.map((record: ObjectRecord) =>
|
||||||
typeORMObjectRecordsParser.processRecord({
|
typeORMObjectRecordsParser.processRecord({
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import {
|
|||||||
GraphqlQueryRunnerExceptionCode,
|
GraphqlQueryRunnerExceptionCode,
|
||||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
||||||
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
@ -61,10 +60,8 @@ export class GraphqlQueryRestoreOneResolverService extends GraphqlQueryBaseResol
|
|||||||
|
|
||||||
const restoredRecord = formattedRestoredRecords[0];
|
const restoredRecord = formattedRestoredRecords[0];
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: [restoredRecord],
|
parentObjectRecords: [restoredRecord],
|
||||||
@ -75,8 +72,16 @@ export class GraphqlQueryRestoreOneResolverService extends GraphqlQueryBaseResol
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return typeORMObjectRecordsParser.processRecord({
|
return typeORMObjectRecordsParser.processRecord({
|
||||||
objectRecord: restoredRecord,
|
objectRecord: restoredRecord,
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import { SearchResolverArgs } from 'src/engine/api/graphql/workspace-resolver-bu
|
|||||||
|
|
||||||
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/constants/search-vector-field.constants';
|
import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/constants/search-vector-field.constants';
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
import { isDefined } from 'src/utils/is-defined';
|
import { isDefined } from 'src/utils/is-defined';
|
||||||
@ -33,8 +32,16 @@ export class GraphqlQuerySearchResolverService extends GraphqlQueryBaseResolverS
|
|||||||
const { authContext, objectMetadataMaps, objectMetadataItemWithFieldMaps } =
|
const { authContext, objectMetadataMaps, objectMetadataItemWithFieldMaps } =
|
||||||
executionArgs.options;
|
executionArgs.options;
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
if (!isDefined(executionArgs.args.searchInput)) {
|
if (!isDefined(executionArgs.args.searchInput)) {
|
||||||
return typeORMObjectRecordsParser.createConnection({
|
return typeORMObjectRecordsParser.createConnection({
|
||||||
@ -113,10 +120,8 @@ export class GraphqlQuerySearchResolverService extends GraphqlQueryBaseResolverS
|
|||||||
: 0;
|
: 0;
|
||||||
const order = undefined;
|
const order = undefined;
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: objectRecords,
|
parentObjectRecords: objectRecords,
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import { UpdateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolve
|
|||||||
|
|
||||||
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
||||||
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
||||||
import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
|
import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
|
||||||
@ -83,10 +82,8 @@ export class GraphqlQueryUpdateManyResolverService extends GraphqlQueryBaseResol
|
|||||||
objectMetadataItemWithFieldMaps,
|
objectMetadataItemWithFieldMaps,
|
||||||
);
|
);
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: formattedUpdatedRecords,
|
parentObjectRecords: formattedUpdatedRecords,
|
||||||
@ -97,8 +94,16 @@ export class GraphqlQueryUpdateManyResolverService extends GraphqlQueryBaseResol
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return formattedUpdatedRecords.map((record: ObjectRecord) =>
|
return formattedUpdatedRecords.map((record: ObjectRecord) =>
|
||||||
typeORMObjectRecordsParser.processRecord({
|
typeORMObjectRecordsParser.processRecord({
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import {
|
|||||||
GraphqlQueryRunnerExceptionCode,
|
GraphqlQueryRunnerExceptionCode,
|
||||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||||
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
|
||||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
|
|
||||||
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util';
|
||||||
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
||||||
import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
|
import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
|
||||||
@ -81,10 +80,8 @@ export class GraphqlQueryUpdateOneResolverService extends GraphqlQueryBaseResolv
|
|||||||
|
|
||||||
const updatedRecord = formattedUpdatedRecords[0];
|
const updatedRecord = formattedUpdatedRecords[0];
|
||||||
|
|
||||||
const processNestedRelationsHelper = new ProcessNestedRelationsHelper();
|
|
||||||
|
|
||||||
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
if (executionArgs.graphqlQuerySelectedFieldsResult.relations) {
|
||||||
await processNestedRelationsHelper.processNestedRelations({
|
await this.processNestedRelationsHelper.processNestedRelations({
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
parentObjectMetadataItem: objectMetadataItemWithFieldMaps,
|
||||||
parentObjectRecords: [updatedRecord],
|
parentObjectRecords: [updatedRecord],
|
||||||
@ -95,8 +92,16 @@ export class GraphqlQueryUpdateOneResolverService extends GraphqlQueryBaseResolv
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagsMap =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(
|
||||||
|
authContext.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
const typeORMObjectRecordsParser =
|
const typeORMObjectRecordsParser =
|
||||||
new ObjectRecordsToGraphqlConnectionHelper(objectMetadataMaps);
|
new ObjectRecordsToGraphqlConnectionHelper(
|
||||||
|
objectMetadataMaps,
|
||||||
|
featureFlagsMap,
|
||||||
|
);
|
||||||
|
|
||||||
return typeORMObjectRecordsParser.processRecord({
|
return typeORMObjectRecordsParser.processRecord({
|
||||||
objectRecord: updatedRecord,
|
objectRecord: updatedRecord,
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||||
|
|
||||||
|
import {
|
||||||
|
GraphqlQueryRunnerException,
|
||||||
|
GraphqlQueryRunnerExceptionCode,
|
||||||
|
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||||
|
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||||
|
|
||||||
|
export const getTargetObjectMetadataOrThrow = (
|
||||||
|
fieldMetadata: FieldMetadataInterface,
|
||||||
|
objectMetadataMaps: ObjectMetadataMaps,
|
||||||
|
) => {
|
||||||
|
if (!fieldMetadata.relationTargetObjectMetadataId) {
|
||||||
|
throw new GraphqlQueryRunnerException(
|
||||||
|
`Relation target object metadata id not found for field ${fieldMetadata.name}`,
|
||||||
|
GraphqlQueryRunnerExceptionCode.RELATION_TARGET_OBJECT_METADATA_NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetObjectMetadata =
|
||||||
|
objectMetadataMaps.byId[fieldMetadata.relationTargetObjectMetadataId];
|
||||||
|
|
||||||
|
if (!targetObjectMetadata) {
|
||||||
|
throw new GraphqlQueryRunnerException(
|
||||||
|
`Target object metadata not found for field ${fieldMetadata.name}`,
|
||||||
|
GraphqlQueryRunnerExceptionCode.RELATION_TARGET_OBJECT_METADATA_NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetObjectMetadata;
|
||||||
|
};
|
||||||
@ -16,10 +16,11 @@ 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 { 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 { WorkspaceMemberQueryResultGetterHandler } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/handlers/workspace-member-query-result-getter.handler';
|
||||||
import { CompositeInputTypeDefinitionFactory } from 'src/engine/api/graphql/workspace-schema-builder/factories/composite-input-type-definition.factory';
|
import { CompositeInputTypeDefinitionFactory } from 'src/engine/api/graphql/workspace-schema-builder/factories/composite-input-type-definition.factory';
|
||||||
|
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 { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||||
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
|
import { isRelationFieldMetadata } from 'src/engine/utils/is-relation-field-metadata.util';
|
||||||
import { isDefined } from 'src/utils/is-defined';
|
import { isDefined } from 'src/utils/is-defined';
|
||||||
|
|
||||||
// TODO: find a way to prevent conflict between handlers executing logic on object relations
|
// TODO: find a way to prevent conflict between handlers executing logic on object relations
|
||||||
@ -135,6 +136,11 @@ export class QueryResultGettersFactory {
|
|||||||
): Promise<ObjectRecord> {
|
): Promise<ObjectRecord> {
|
||||||
const objectMetadataMapItem = objectMetadataMaps.byId[objectMetadataItemId];
|
const objectMetadataMapItem = objectMetadataMaps.byId[objectMetadataItemId];
|
||||||
|
|
||||||
|
const isNewRelationEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsNewRelationEnabled,
|
||||||
|
workspaceId,
|
||||||
|
);
|
||||||
|
|
||||||
const handler = this.getHandler(objectMetadataMapItem.nameSingular);
|
const handler = this.getHandler(objectMetadataMapItem.nameSingular);
|
||||||
|
|
||||||
const relationFields = Object.keys(record)
|
const relationFields = Object.keys(record)
|
||||||
@ -143,9 +149,7 @@ export class QueryResultGettersFactory {
|
|||||||
objectMetadataMapItem.fieldsByName[recordFieldName],
|
objectMetadataMapItem.fieldsByName[recordFieldName],
|
||||||
)
|
)
|
||||||
.filter(isDefined)
|
.filter(isDefined)
|
||||||
.filter((fieldMetadata) =>
|
.filter((fieldMetadata) => isRelationFieldMetadata(fieldMetadata));
|
||||||
isRelationFieldMetadataType(fieldMetadata.type),
|
|
||||||
);
|
|
||||||
|
|
||||||
const relationFieldsProcessedMap = {} as Record<
|
const relationFieldsProcessedMap = {} as Record<
|
||||||
string,
|
string,
|
||||||
@ -153,38 +157,53 @@ export class QueryResultGettersFactory {
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
for (const relationField of relationFields) {
|
for (const relationField of relationFields) {
|
||||||
const relationMetadata =
|
if (!isNewRelationEnabled) {
|
||||||
relationField.fromRelationMetadata ?? relationField.toRelationMetadata;
|
const relationMetadata =
|
||||||
|
relationField.fromRelationMetadata ??
|
||||||
|
relationField.toRelationMetadata;
|
||||||
|
|
||||||
if (!isDefined(relationMetadata)) {
|
if (!isDefined(relationMetadata)) {
|
||||||
throw new Error('Relation metadata is not defined');
|
throw new Error('Relation metadata is not defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: computing this by taking the opposite of the current object metadata id
|
||||||
|
// is really less than ideal. This should be computed based on the relation metadata
|
||||||
|
// But right now it is too complex with the current structure and / or lack of utils
|
||||||
|
// around the possible combinations with relation metadata from / to + MANY_TO_ONE / ONE_TO_MANY
|
||||||
|
const relationObjectMetadataItemId =
|
||||||
|
relationMetadata.fromObjectMetadataId === objectMetadataItemId
|
||||||
|
? relationMetadata.toObjectMetadataId
|
||||||
|
: relationMetadata.fromObjectMetadataId;
|
||||||
|
|
||||||
|
const relationObjectMetadataItem =
|
||||||
|
objectMetadataMaps.byId[relationObjectMetadataItemId];
|
||||||
|
|
||||||
|
if (!isDefined(relationObjectMetadataItem)) {
|
||||||
|
throw new Error(
|
||||||
|
`Object metadata not found for id ${relationObjectMetadataItemId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
relationFieldsProcessedMap[relationField.name] =
|
||||||
|
await this.processQueryResultField(
|
||||||
|
record[relationField.name],
|
||||||
|
relationObjectMetadataItem.id,
|
||||||
|
objectMetadataMaps,
|
||||||
|
workspaceId,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (!isDefined(relationField.relationTargetObjectMetadataId)) {
|
||||||
|
throw new Error('Relation target object metadata id is not defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
relationFieldsProcessedMap[relationField.name] =
|
||||||
|
await this.processQueryResultField(
|
||||||
|
record[relationField.name],
|
||||||
|
relationField.relationTargetObjectMetadataId,
|
||||||
|
objectMetadataMaps,
|
||||||
|
workspaceId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: computing this by taking the opposite of the current object metadata id
|
|
||||||
// is really less than ideal. This should be computed based on the relation metadata
|
|
||||||
// But right now it is too complex with the current structure and / or lack of utils
|
|
||||||
// around the possible combinations with relation metadata from / to + MANY_TO_ONE / ONE_TO_MANY
|
|
||||||
const relationObjectMetadataItemId =
|
|
||||||
relationMetadata.fromObjectMetadataId === objectMetadataItemId
|
|
||||||
? relationMetadata.toObjectMetadataId
|
|
||||||
: relationMetadata.fromObjectMetadataId;
|
|
||||||
|
|
||||||
const relationObjectMetadataItem =
|
|
||||||
objectMetadataMaps.byId[relationObjectMetadataItemId];
|
|
||||||
|
|
||||||
if (!isDefined(relationObjectMetadataItem)) {
|
|
||||||
throw new Error(
|
|
||||||
`Object metadata not found for id ${relationObjectMetadataItemId}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
relationFieldsProcessedMap[relationField.name] =
|
|
||||||
await this.processQueryResultField(
|
|
||||||
record[relationField.name],
|
|
||||||
relationObjectMetadataItem.id,
|
|
||||||
objectMetadataMaps,
|
|
||||||
workspaceId,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const objectRecordProcessedWithoutRelationFields = await handler.handle(
|
const objectRecordProcessedWithoutRelationFields = await handler.handle(
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interface
|
|||||||
|
|
||||||
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
||||||
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
|
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
|
||||||
|
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 { 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 { 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 { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||||
@ -33,6 +34,7 @@ export class FindRecordsWorflowAction implements WorkflowAction {
|
|||||||
private readonly twentyORMManager: TwentyORMManager,
|
private readonly twentyORMManager: TwentyORMManager,
|
||||||
private readonly workspaceCacheStorageService: WorkspaceCacheStorageService,
|
private readonly workspaceCacheStorageService: WorkspaceCacheStorageService,
|
||||||
private readonly scopedWorkspaceContextFactory: ScopedWorkspaceContextFactory,
|
private readonly scopedWorkspaceContextFactory: ScopedWorkspaceContextFactory,
|
||||||
|
private readonly featureFlagService: FeatureFlagService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(
|
async execute(
|
||||||
@ -86,9 +88,13 @@ export class FindRecordsWorflowAction implements WorkflowAction {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFlagMaps =
|
||||||
|
await this.featureFlagService.getWorkspaceFeatureFlagsMap(workspaceId);
|
||||||
|
|
||||||
const graphqlQueryParser = new GraphqlQueryParser(
|
const graphqlQueryParser = new GraphqlQueryParser(
|
||||||
objectMetadataItemWithFieldsMaps.fieldsByName,
|
objectMetadataItemWithFieldsMaps.fieldsByName,
|
||||||
objectMetadataMaps,
|
objectMetadataMaps,
|
||||||
|
featureFlagMaps,
|
||||||
);
|
);
|
||||||
|
|
||||||
const objectRecords = await this.getObjectRecords(
|
const objectRecords = await this.getObjectRecords(
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
|
|||||||
|
|
||||||
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||||
|
|
||||||
|
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||||
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||||
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
||||||
@ -14,6 +15,7 @@ import { UpdateRecordWorkflowAction } from 'src/modules/workflow/workflow-execut
|
|||||||
imports: [
|
imports: [
|
||||||
WorkspaceCacheStorageModule,
|
WorkspaceCacheStorageModule,
|
||||||
NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
|
NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
|
||||||
|
FeatureFlagModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ScopedWorkspaceContextFactory,
|
ScopedWorkspaceContextFactory,
|
||||||
|
|||||||
Reference in New Issue
Block a user