[AI] Add group_by_* database tools and centralize groupBy validation (#19406)
closes https://discord.com/channels/1130383047699738754/1488990242873806868 https://github.com/user-attachments/assets/2b2bbfba-3fa6-4114-9a26-96a61599d748 <img width="729" height="1283" alt="CleanShot 2026-04-07 at 20 43 06" src="https://github.com/user-attachments/assets/815efb97-81a0-44ea-8d79-b3ce7d5b00b6" /> <img width="708" height="1266" alt="CleanShot 2026-04-07 at 20 40 13" src="https://github.com/user-attachments/assets/692366bc-b629-4d9f-b6b8-ab670d5ad046" /> <img width="665" height="3524" alt="CleanShot 2026-04-07 at 20 42 00" src="https://github.com/user-attachments/assets/5e844e0f-7835-47a8-9d20-a5baddc0992d" />
This commit is contained in:
-1
@@ -1 +0,0 @@
|
||||
export type CompositeFieldGroupByDefinition = Record<string, boolean>;
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
import {
|
||||
type ObjectRecordGroupByDateGranularity,
|
||||
type FirstDayOfTheWeek,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
export type DateFieldGroupByDefinition = {
|
||||
granularity: ObjectRecordGroupByDateGranularity;
|
||||
weekStartDay?: FirstDayOfTheWeek;
|
||||
timeZone?: string;
|
||||
};
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
import { type CompositeFieldGroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/composite-field-group-by-definition.type';
|
||||
import { type DateFieldGroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/date-field-group-by-definition.type';
|
||||
|
||||
export type FieldGroupByDefinition =
|
||||
| boolean
|
||||
| CompositeFieldGroupByDefinition
|
||||
| DateFieldGroupByDefinition
|
||||
| undefined;
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
import { isDefined } from 'class-validator';
|
||||
import { ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
|
||||
|
||||
import { type FieldGroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/field-group-by-definition.type';
|
||||
|
||||
export const isGroupByDateFieldDefinition = (
|
||||
fieldGroupByDefinition: FieldGroupByDefinition,
|
||||
): fieldGroupByDefinition is {
|
||||
granularity: ObjectRecordGroupByDateGranularity;
|
||||
} => {
|
||||
if (
|
||||
typeof fieldGroupByDefinition !== 'object' ||
|
||||
!isDefined(fieldGroupByDefinition)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (!('granularity' in fieldGroupByDefinition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const granularity = fieldGroupByDefinition.granularity;
|
||||
|
||||
return (
|
||||
isDefined(granularity) &&
|
||||
typeof granularity === 'string' &&
|
||||
Object.values(ObjectRecordGroupByDateGranularity).includes(
|
||||
granularity as ObjectRecordGroupByDateGranularity,
|
||||
)
|
||||
);
|
||||
};
|
||||
-141
@@ -1,141 +0,0 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type GroupByResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||
|
||||
import { type GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types';
|
||||
import { isGroupByDateFieldDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-date-field-definition.util';
|
||||
import { parseGroupByRelationField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-relation-field.util';
|
||||
import { validateSingleKeyForGroupByOrThrow } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/validate-single-key-for-group-by-or-throw.util';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
|
||||
export const parseGroupByArgs = (
|
||||
args: GroupByResolverArgs,
|
||||
flatObjectMetadata: FlatObjectMetadata,
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
|
||||
): GroupByField[] => {
|
||||
const groupByFieldNames = args.groupBy;
|
||||
|
||||
const groupByFields: GroupByField[] = [];
|
||||
|
||||
const { fieldIdByName, fieldIdByJoinColumnName } =
|
||||
buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata,
|
||||
);
|
||||
|
||||
for (const fieldNames of groupByFieldNames) {
|
||||
validateSingleKeyForGroupByOrThrow({
|
||||
groupByKeys: Object.keys(fieldNames),
|
||||
errorMessage:
|
||||
'You cannot provide multiple fields in one GroupByInput, split them into multiple GroupByInput',
|
||||
});
|
||||
|
||||
for (const fieldName of Object.keys(fieldNames)) {
|
||||
const fieldMetadataId =
|
||||
fieldIdByName[fieldName] || fieldIdByJoinColumnName[fieldName];
|
||||
const fieldMetadata = fieldMetadataId
|
||||
? findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: fieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
if (!isDefined(fieldMetadata) || !isDefined(fieldMetadataId)) {
|
||||
throw new Error(`Unidentified field in groupBy: ${fieldName}`);
|
||||
}
|
||||
|
||||
const isGroupByRelationField =
|
||||
isMorphOrRelationFlatFieldMetadata(fieldMetadata) &&
|
||||
typeof fieldNames[fieldName] === 'object' &&
|
||||
fieldNames[fieldName] !== null &&
|
||||
!isGroupByDateFieldDefinition(fieldNames[fieldName]);
|
||||
|
||||
// Handle relation fields
|
||||
if (isGroupByRelationField) {
|
||||
parseGroupByRelationField({
|
||||
fieldNames,
|
||||
fieldName,
|
||||
fieldMetadata,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
groupByFields,
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle date fields
|
||||
if (
|
||||
fieldMetadata.type === FieldMetadataType.DATE ||
|
||||
fieldMetadata.type === FieldMetadataType.DATE_TIME
|
||||
) {
|
||||
const fieldGroupByDefinition = fieldNames[fieldName];
|
||||
|
||||
const shouldGroupByDateGranularity = isGroupByDateFieldDefinition(
|
||||
fieldGroupByDefinition,
|
||||
);
|
||||
|
||||
if (shouldGroupByDateGranularity) {
|
||||
groupByFields.push({
|
||||
fieldMetadata,
|
||||
dateGranularity: fieldGroupByDefinition.granularity,
|
||||
weekStartDay: fieldGroupByDefinition.weekStartDay,
|
||||
timeZone: fieldGroupByDefinition.timeZone,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle array unnest fields
|
||||
if (
|
||||
typeof fieldNames[fieldName] === 'object' &&
|
||||
fieldNames[fieldName] !== null &&
|
||||
'unnest' in fieldNames[fieldName]
|
||||
) {
|
||||
groupByFields.push({
|
||||
fieldMetadata,
|
||||
subFieldName: undefined,
|
||||
shouldUnnest: true,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle regular fields and composite fields
|
||||
if (fieldNames[fieldName] === true) {
|
||||
groupByFields.push({
|
||||
fieldMetadata,
|
||||
subFieldName: undefined,
|
||||
});
|
||||
continue;
|
||||
} else if (typeof fieldNames[fieldName] === 'object') {
|
||||
validateSingleKeyForGroupByOrThrow({
|
||||
groupByKeys: Object.keys(fieldNames[fieldName]),
|
||||
errorMessage:
|
||||
'You cannot provide multiple subfields in one GroupByInput, split them into multiple GroupByInput',
|
||||
});
|
||||
|
||||
for (const subFieldName of Object.keys(fieldNames[fieldName])) {
|
||||
if (
|
||||
(fieldNames[fieldName] as Record<string, boolean>)[subFieldName] ===
|
||||
true
|
||||
) {
|
||||
groupByFields.push({
|
||||
fieldMetadata,
|
||||
subFieldName,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupByFields;
|
||||
};
|
||||
-210
@@ -1,210 +0,0 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { STANDARD_ERROR_MESSAGE } from 'src/engine/api/common/common-query-runners/errors/standard-error-message.constant';
|
||||
import {
|
||||
GraphqlQueryRunnerException,
|
||||
GraphqlQueryRunnerExceptionCode,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { type CompositeFieldGroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/composite-field-group-by-definition.type';
|
||||
import { type DateFieldGroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/date-field-group-by-definition.type';
|
||||
import { type GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types';
|
||||
import { isGroupByDateFieldDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-date-field-definition.util';
|
||||
import { validateSingleKeyForGroupByOrThrow } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/validate-single-key-for-group-by-or-throw.util';
|
||||
import { UserInputError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
|
||||
const getNestedFieldMetadataDetails = ({
|
||||
fieldNames,
|
||||
fieldName,
|
||||
fieldMetadata,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
}: {
|
||||
fieldNames: Record<string, unknown>;
|
||||
fieldName: string;
|
||||
fieldMetadata: FlatFieldMetadata;
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
}) => {
|
||||
const nestedFieldGroupByDefinitions = fieldNames[fieldName] as
|
||||
| Record<string, boolean>
|
||||
| Record<string, CompositeFieldGroupByDefinition>
|
||||
| Record<string, DateFieldGroupByDefinition>;
|
||||
|
||||
if (!isDefined(fieldMetadata.relationTargetObjectMetadataId)) {
|
||||
throw new UserInputError(
|
||||
`Relation target object metadata id not found for field ${fieldMetadata.name}`,
|
||||
);
|
||||
}
|
||||
|
||||
const targetObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: fieldMetadata.relationTargetObjectMetadataId,
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const nestedFieldNames = Object.keys(nestedFieldGroupByDefinitions);
|
||||
|
||||
validateSingleKeyForGroupByOrThrow({
|
||||
groupByKeys: nestedFieldNames,
|
||||
errorMessage:
|
||||
'You cannot provide multiple nested fields in one relation GroupByInput, split them into multiple GroupByInput',
|
||||
});
|
||||
|
||||
const nestedFieldName = nestedFieldNames[0];
|
||||
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
targetObjectMetadata,
|
||||
);
|
||||
|
||||
const nestedFieldMetadataId = fieldIdByName[nestedFieldName];
|
||||
const nestedFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: nestedFieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(nestedFieldMetadata) || !isDefined(nestedFieldMetadataId)) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
`Nested field "${nestedFieldName}" not found in target object "${targetObjectMetadata.nameSingular}"`,
|
||||
GraphqlQueryRunnerExceptionCode.FIELD_NOT_FOUND,
|
||||
{ userFriendlyMessage: STANDARD_ERROR_MESSAGE },
|
||||
);
|
||||
}
|
||||
|
||||
if (nestedFieldMetadata.type === FieldMetadataType.RELATION) {
|
||||
throw new UserInputError(
|
||||
`Cannot group by a relation field of the relation field: "${nestedFieldName}" is a relation field of "${targetObjectMetadata.nameSingular}"`,
|
||||
);
|
||||
}
|
||||
|
||||
const nestedFieldGroupByDefinition =
|
||||
nestedFieldGroupByDefinitions[nestedFieldName];
|
||||
|
||||
return {
|
||||
nestedFieldGroupByDefinition,
|
||||
nestedFieldMetadata,
|
||||
nestedFieldName,
|
||||
};
|
||||
};
|
||||
|
||||
const handleNestedCompositeField = ({
|
||||
nestedFieldGroupByDefinition,
|
||||
nestedFieldName,
|
||||
fieldMetadata,
|
||||
nestedFieldMetadata,
|
||||
groupByFields,
|
||||
}: {
|
||||
nestedFieldGroupByDefinition: CompositeFieldGroupByDefinition;
|
||||
nestedFieldName: string;
|
||||
fieldMetadata: FlatFieldMetadata;
|
||||
nestedFieldMetadata: FlatFieldMetadata;
|
||||
groupByFields: GroupByField[];
|
||||
}) => {
|
||||
if (
|
||||
typeof nestedFieldGroupByDefinition === 'object' &&
|
||||
nestedFieldGroupByDefinition !== null
|
||||
) {
|
||||
const compositeSubFields = Object.keys(
|
||||
nestedFieldGroupByDefinition as Record<string, unknown>,
|
||||
);
|
||||
|
||||
validateSingleKeyForGroupByOrThrow({
|
||||
groupByKeys: compositeSubFields,
|
||||
errorMessage:
|
||||
'You cannot provide multiple composite subfields in one GroupByInput, split them into multiple GroupByInput',
|
||||
});
|
||||
|
||||
const nestedSubFieldName = compositeSubFields[0];
|
||||
|
||||
if (
|
||||
(nestedFieldGroupByDefinition as Record<string, boolean>)[
|
||||
nestedSubFieldName
|
||||
] === true
|
||||
) {
|
||||
groupByFields.push({
|
||||
fieldMetadata,
|
||||
nestedFieldMetadata,
|
||||
nestedSubFieldName,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new GraphqlQueryRunnerException(
|
||||
`Composite field "${nestedFieldName}" requires a subfield to be specified`,
|
||||
GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
|
||||
{ userFriendlyMessage: STANDARD_ERROR_MESSAGE },
|
||||
);
|
||||
};
|
||||
|
||||
export const parseGroupByRelationField = ({
|
||||
fieldNames,
|
||||
fieldName,
|
||||
fieldMetadata,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
groupByFields,
|
||||
}: {
|
||||
fieldNames: Record<string, unknown>;
|
||||
fieldName: string;
|
||||
fieldMetadata: FlatFieldMetadata;
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
groupByFields: GroupByField[];
|
||||
}) => {
|
||||
const { nestedFieldGroupByDefinition, nestedFieldMetadata, nestedFieldName } =
|
||||
getNestedFieldMetadataDetails({
|
||||
fieldNames,
|
||||
fieldName,
|
||||
fieldMetadata,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
// Handle date fields in nested relations
|
||||
if (
|
||||
(nestedFieldMetadata.type === FieldMetadataType.DATE ||
|
||||
nestedFieldMetadata.type === FieldMetadataType.DATE_TIME) &&
|
||||
isGroupByDateFieldDefinition(nestedFieldGroupByDefinition)
|
||||
) {
|
||||
const dateFieldDefinition = nestedFieldGroupByDefinition;
|
||||
|
||||
groupByFields.push({
|
||||
fieldMetadata,
|
||||
nestedFieldMetadata,
|
||||
dateGranularity: dateFieldDefinition.granularity,
|
||||
weekStartDay: dateFieldDefinition.weekStartDay,
|
||||
timeZone: dateFieldDefinition.timeZone,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle composite fields in nested relations
|
||||
if (isCompositeFieldMetadataType(nestedFieldMetadata.type)) {
|
||||
handleNestedCompositeField({
|
||||
nestedFieldGroupByDefinition:
|
||||
nestedFieldGroupByDefinition as CompositeFieldGroupByDefinition,
|
||||
nestedFieldName,
|
||||
fieldMetadata,
|
||||
nestedFieldMetadata,
|
||||
groupByFields,
|
||||
});
|
||||
}
|
||||
|
||||
// Handle regular nested fields
|
||||
if (nestedFieldGroupByDefinition === true) {
|
||||
groupByFields.push({
|
||||
fieldMetadata,
|
||||
nestedFieldMetadata,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
import { STANDARD_ERROR_MESSAGE } from 'src/engine/api/common/common-query-runners/errors/standard-error-message.constant';
|
||||
import {
|
||||
GraphqlQueryRunnerException,
|
||||
GraphqlQueryRunnerExceptionCode,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
|
||||
export const validateSingleKeyForGroupByOrThrow = ({
|
||||
groupByKeys,
|
||||
errorMessage,
|
||||
}: {
|
||||
groupByKeys: string[];
|
||||
errorMessage: string;
|
||||
}): void => {
|
||||
if (groupByKeys.length > 1) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
errorMessage,
|
||||
GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
|
||||
{ userFriendlyMessage: STANDARD_ERROR_MESSAGE },
|
||||
);
|
||||
}
|
||||
};
|
||||
+2
-2
@@ -12,6 +12,7 @@ import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-sch
|
||||
import { TypeMapperService } from 'src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service';
|
||||
import { GqlTypesStorage } from 'src/engine/api/graphql/workspace-schema-builder/storages/gql-types.storage';
|
||||
import { computeCompositeFieldInputTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-input-type-key.util';
|
||||
import { isCompositePropertySupportedInGroupBy } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-property-supported-in-group-by.util';
|
||||
import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or-relation-field-metadata-type.util';
|
||||
|
||||
@Injectable()
|
||||
@@ -54,8 +55,7 @@ export class CompositeFieldMetadataGroupByGqlInputTypeGenerator {
|
||||
throw new Error('Relation fields are not supported in composite types');
|
||||
}
|
||||
|
||||
// Skip hidden fields
|
||||
if (property.hidden === true) {
|
||||
if (!isCompositePropertySupportedInGroupBy(property)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -20,6 +20,7 @@ import { type SchemaGenerationContext } from 'src/engine/api/graphql/workspace-s
|
||||
import { computeCompositeFieldInputTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-input-type-key.util';
|
||||
import { computeObjectMetadataInputTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-input-type.util';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { isFlatFieldMetadataSupportedInGroupBy } from 'src/engine/metadata-modules/field-metadata/utils/is-supported-in-group-by.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
@@ -62,6 +63,10 @@ export class ObjectMetadataGroupByGqlInputTypeGenerator {
|
||||
const allGeneratedFields: GraphQLInputFieldConfigMap = {};
|
||||
|
||||
for (const fieldMetadata of fields) {
|
||||
if (!isFlatFieldMetadataSupportedInGroupBy(fieldMetadata)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const generatedField = isMorphOrRelationFlatFieldMetadata(fieldMetadata)
|
||||
? this.relationFieldMetadataGqlInputTypeGenerator.generateSimpleRelationFieldGroupByInputType(
|
||||
fieldMetadata,
|
||||
|
||||
Reference in New Issue
Block a user