Add count and percent aggregations to kanban headers (#9348)
Closes https://github.com/twentyhq/private-issues/issues/226 https://github.com/user-attachments/assets/cee78080-6dda-4102-9595-d32971cf9104
This commit is contained in:
@ -1,7 +1,8 @@
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { STANDARD_AGGREGATE_OPERATION_OPTIONS } from '@/object-record/record-table/record-table-footer/constants/standardAggregateOperationOptions';
|
||||
import { AggregateOperationsOmittingStandardOperations } from '@/object-record/types/AggregateOperationsOmittingStandardOperations';
|
||||
import { COUNT_AGGREGATE_OPERATION_OPTIONS } from '@/object-record/record-table/record-table-footer/constants/countAggregateOperationOptions';
|
||||
import { NON_STANDARD_AGGREGATE_OPERATION_OPTIONS } from '@/object-record/record-table/record-table-footer/constants/nonStandardAggregateOperationsOptions';
|
||||
import { PERCENT_AGGREGATE_OPERATION_OPTIONS } from '@/object-record/record-table/record-table-footer/constants/percentAggregateOperationOption';
|
||||
import { getAvailableFieldsIdsForAggregationFromObjectFields } from '@/object-record/utils/getAvailableFieldsIdsForAggregationFromObjectFields';
|
||||
import { FieldMetadataType } from '~/generated/graphql';
|
||||
|
||||
@ -9,59 +10,135 @@ const AMOUNT_FIELD_ID = '7d2d7b5e-7b3e-4b4a-8b0a-7b3e4b4a8b0a';
|
||||
const PRICE_FIELD_ID = '9d2d7b5e-7b3e-4b4a-8b0a-7b3e4b4a8b0b';
|
||||
const NAME_FIELD_ID = '5d2d7b5e-7b3e-4b4a-8b0a-7b3e4b4a8b0c';
|
||||
|
||||
describe('getAvailableFieldsIdsForAggregationFromObjectFields', () => {
|
||||
const mockFields = [
|
||||
{ id: AMOUNT_FIELD_ID, type: FieldMetadataType.Number, name: 'amount' },
|
||||
{ id: PRICE_FIELD_ID, type: FieldMetadataType.Currency, name: 'price' },
|
||||
{ id: NAME_FIELD_ID, type: FieldMetadataType.Text, name: 'name' },
|
||||
];
|
||||
const FIELDS_MOCKS = [
|
||||
{ id: AMOUNT_FIELD_ID, type: FieldMetadataType.Number, name: 'amount' },
|
||||
{ id: PRICE_FIELD_ID, type: FieldMetadataType.Currency, name: 'price' },
|
||||
{ id: NAME_FIELD_ID, type: FieldMetadataType.Text, name: 'name' },
|
||||
];
|
||||
|
||||
it('should correctly map fields to available aggregate operations', () => {
|
||||
jest.mock(
|
||||
'@/object-record/utils/getAvailableAggregationsFromObjectFields',
|
||||
() => ({
|
||||
getAvailableAggregationsFromObjectFields: jest.fn().mockReturnValue({
|
||||
amount: {
|
||||
[AGGREGATE_OPERATIONS.sum]: 'sumAmount',
|
||||
[AGGREGATE_OPERATIONS.avg]: 'avgAmount',
|
||||
[AGGREGATE_OPERATIONS.min]: 'minAmount',
|
||||
[AGGREGATE_OPERATIONS.max]: 'maxAmount',
|
||||
[AGGREGATE_OPERATIONS.count]: 'totalCount',
|
||||
[AGGREGATE_OPERATIONS.countUniqueValues]: 'countUniqueValuesAmount',
|
||||
[AGGREGATE_OPERATIONS.countEmpty]: 'countEmptyAmount',
|
||||
[AGGREGATE_OPERATIONS.countNotEmpty]: 'countNotEmptyAmount',
|
||||
[AGGREGATE_OPERATIONS.percentageEmpty]: 'percentageEmptyAmount',
|
||||
[AGGREGATE_OPERATIONS.percentageNotEmpty]: 'percentageNotEmptyAmount',
|
||||
},
|
||||
price: {
|
||||
[AGGREGATE_OPERATIONS.sum]: 'sumPriceAmountMicros',
|
||||
[AGGREGATE_OPERATIONS.avg]: 'avgPriceAmountMicros',
|
||||
[AGGREGATE_OPERATIONS.min]: 'minPriceAmountMicros',
|
||||
[AGGREGATE_OPERATIONS.max]: 'maxPriceAmountMicros',
|
||||
[AGGREGATE_OPERATIONS.count]: 'totalCount',
|
||||
[AGGREGATE_OPERATIONS.countUniqueValues]:
|
||||
'countUniqueValuesPriceAmountMicros',
|
||||
[AGGREGATE_OPERATIONS.countEmpty]: 'countEmptyPriceAmountMicros',
|
||||
[AGGREGATE_OPERATIONS.countNotEmpty]: 'countNotEmptyPriceAmountMicros',
|
||||
[AGGREGATE_OPERATIONS.percentageEmpty]:
|
||||
'percentageEmptyPriceAmountMicros',
|
||||
[AGGREGATE_OPERATIONS.percentageNotEmpty]:
|
||||
'percentageNotEmptyPriceAmountMicros',
|
||||
},
|
||||
name: {
|
||||
[AGGREGATE_OPERATIONS.count]: 'totalCount',
|
||||
[AGGREGATE_OPERATIONS.countUniqueValues]: 'countUniqueValuesName',
|
||||
[AGGREGATE_OPERATIONS.countEmpty]: 'countEmptyName',
|
||||
[AGGREGATE_OPERATIONS.countNotEmpty]: 'countNotEmptyName',
|
||||
[AGGREGATE_OPERATIONS.percentageEmpty]: 'percentageEmptyName',
|
||||
[AGGREGATE_OPERATIONS.percentageNotEmpty]: 'percentageNotEmptyName',
|
||||
},
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
describe('getAvailableFieldsIdsForAggregationFromObjectFields', () => {
|
||||
it('should handle empty fields array', () => {
|
||||
const result = getAvailableFieldsIdsForAggregationFromObjectFields(
|
||||
mockFields as FieldMetadataItem[],
|
||||
[],
|
||||
COUNT_AGGREGATE_OPERATION_OPTIONS,
|
||||
);
|
||||
|
||||
expect(result[AGGREGATE_OPERATIONS.sum]).toEqual([
|
||||
AMOUNT_FIELD_ID,
|
||||
PRICE_FIELD_ID,
|
||||
]);
|
||||
expect(result[AGGREGATE_OPERATIONS.avg]).toEqual([
|
||||
AMOUNT_FIELD_ID,
|
||||
PRICE_FIELD_ID,
|
||||
]);
|
||||
expect(result[AGGREGATE_OPERATIONS.min]).toEqual([
|
||||
AMOUNT_FIELD_ID,
|
||||
PRICE_FIELD_ID,
|
||||
]);
|
||||
expect(result[AGGREGATE_OPERATIONS.max]).toEqual([
|
||||
AMOUNT_FIELD_ID,
|
||||
PRICE_FIELD_ID,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should exclude non-numeric fields', () => {
|
||||
const result = getAvailableFieldsIdsForAggregationFromObjectFields([
|
||||
{ id: NAME_FIELD_ID, type: FieldMetadataType.Text } as FieldMetadataItem,
|
||||
]);
|
||||
|
||||
Object.values(AGGREGATE_OPERATIONS).forEach((operation) => {
|
||||
if (!STANDARD_AGGREGATE_OPERATION_OPTIONS.includes(operation)) {
|
||||
expect(
|
||||
result[operation as AggregateOperationsOmittingStandardOperations],
|
||||
).toEqual([]);
|
||||
}
|
||||
COUNT_AGGREGATE_OPERATION_OPTIONS.forEach((operation) => {
|
||||
expect(result[operation]).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty fields array', () => {
|
||||
const result = getAvailableFieldsIdsForAggregationFromObjectFields([]);
|
||||
describe('with count aggregate operations', () => {
|
||||
it('should include all fields', () => {
|
||||
const result = getAvailableFieldsIdsForAggregationFromObjectFields(
|
||||
FIELDS_MOCKS as FieldMetadataItem[],
|
||||
COUNT_AGGREGATE_OPERATION_OPTIONS,
|
||||
);
|
||||
|
||||
Object.values(AGGREGATE_OPERATIONS).forEach((operation) => {
|
||||
if (!STANDARD_AGGREGATE_OPERATION_OPTIONS.includes(operation)) {
|
||||
expect(
|
||||
result[operation as AggregateOperationsOmittingStandardOperations],
|
||||
).toEqual([]);
|
||||
}
|
||||
COUNT_AGGREGATE_OPERATION_OPTIONS.forEach((operation) => {
|
||||
expect(result[operation]).toEqual([
|
||||
AMOUNT_FIELD_ID,
|
||||
PRICE_FIELD_ID,
|
||||
NAME_FIELD_ID,
|
||||
]);
|
||||
});
|
||||
|
||||
PERCENT_AGGREGATE_OPERATION_OPTIONS.forEach((operation) => {
|
||||
expect(result[operation]).toBeUndefined();
|
||||
});
|
||||
|
||||
NON_STANDARD_AGGREGATE_OPERATION_OPTIONS.forEach((operation) => {
|
||||
expect(result[operation]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with percentage aggregate operations', () => {
|
||||
it('should include all fields', () => {
|
||||
const result = getAvailableFieldsIdsForAggregationFromObjectFields(
|
||||
FIELDS_MOCKS as FieldMetadataItem[],
|
||||
PERCENT_AGGREGATE_OPERATION_OPTIONS,
|
||||
);
|
||||
|
||||
PERCENT_AGGREGATE_OPERATION_OPTIONS.forEach((operation) => {
|
||||
expect(result[operation]).toEqual([
|
||||
AMOUNT_FIELD_ID,
|
||||
PRICE_FIELD_ID,
|
||||
NAME_FIELD_ID,
|
||||
]);
|
||||
});
|
||||
|
||||
COUNT_AGGREGATE_OPERATION_OPTIONS.forEach((operation) => {
|
||||
expect(result[operation]).toBeUndefined();
|
||||
});
|
||||
|
||||
NON_STANDARD_AGGREGATE_OPERATION_OPTIONS.forEach((operation) => {
|
||||
expect(result[operation]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with non standard aggregate operations', () => {
|
||||
it('should exclude non-numeric fields', () => {
|
||||
const result = getAvailableFieldsIdsForAggregationFromObjectFields(
|
||||
FIELDS_MOCKS as FieldMetadataItem[],
|
||||
NON_STANDARD_AGGREGATE_OPERATION_OPTIONS,
|
||||
);
|
||||
|
||||
COUNT_AGGREGATE_OPERATION_OPTIONS.forEach((operation) => {
|
||||
expect(result[operation]).toBeUndefined();
|
||||
});
|
||||
|
||||
PERCENT_AGGREGATE_OPERATION_OPTIONS.forEach((operation) => {
|
||||
expect(result[operation]).toBeUndefined();
|
||||
});
|
||||
|
||||
NON_STANDARD_AGGREGATE_OPERATION_OPTIONS.forEach((operation) => {
|
||||
expect(result[operation]).toEqual([AMOUNT_FIELD_ID, PRICE_FIELD_ID]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,26 +1,58 @@
|
||||
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION } from '@/object-record/record-table/constants/FieldsAvailableByAggregateOperation';
|
||||
import { FIELD_TYPES_AVAILABLE_FOR_NON_STANDARD_AGGREGATE_OPERATION } from '@/object-record/record-table/constants/FieldTypesAvailableForNonStandardAggregateOperation';
|
||||
import { COUNT_AGGREGATE_OPERATION_OPTIONS } from '@/object-record/record-table/record-table-footer/constants/countAggregateOperationOptions';
|
||||
import { PERCENT_AGGREGATE_OPERATION_OPTIONS } from '@/object-record/record-table/record-table-footer/constants/percentAggregateOperationOption';
|
||||
import { AggregateOperationsOmittingStandardOperations } from '@/object-record/types/AggregateOperationsOmittingStandardOperations';
|
||||
import { initializeAvailableFieldsForAggregateOperationMap } from '@/object-record/utils/initializeAvailableFieldsForAggregateOperationMap';
|
||||
|
||||
describe('initializeAvailableFieldsForAggregateOperationMap', () => {
|
||||
it('should initialize empty arrays for each aggregate operation', () => {
|
||||
const result = initializeAvailableFieldsForAggregateOperationMap();
|
||||
it('should initialize empty arrays for each non standard aggregate operation', () => {
|
||||
const result = initializeAvailableFieldsForAggregateOperationMap(
|
||||
Object.keys(
|
||||
FIELD_TYPES_AVAILABLE_FOR_NON_STANDARD_AGGREGATE_OPERATION,
|
||||
) as AGGREGATE_OPERATIONS[],
|
||||
);
|
||||
|
||||
expect(Object.keys(result)).toEqual(
|
||||
Object.keys(FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION),
|
||||
Object.keys(FIELD_TYPES_AVAILABLE_FOR_NON_STANDARD_AGGREGATE_OPERATION),
|
||||
);
|
||||
Object.values(result).forEach((array) => {
|
||||
expect(array).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not include count operation', () => {
|
||||
const result = initializeAvailableFieldsForAggregateOperationMap();
|
||||
it('should not include count operation when called with non standard aggregate operations', () => {
|
||||
const result = initializeAvailableFieldsForAggregateOperationMap(
|
||||
Object.keys(
|
||||
FIELD_TYPES_AVAILABLE_FOR_NON_STANDARD_AGGREGATE_OPERATION,
|
||||
) as AGGREGATE_OPERATIONS[],
|
||||
);
|
||||
expect(
|
||||
result[
|
||||
AGGREGATE_OPERATIONS.count as AggregateOperationsOmittingStandardOperations
|
||||
],
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should include count operation when called with count aggregate operations', () => {
|
||||
const result = initializeAvailableFieldsForAggregateOperationMap(
|
||||
COUNT_AGGREGATE_OPERATION_OPTIONS,
|
||||
);
|
||||
expect(result[AGGREGATE_OPERATIONS.count]).toEqual([]);
|
||||
expect(result[AGGREGATE_OPERATIONS.countEmpty]).toEqual([]);
|
||||
expect(result[AGGREGATE_OPERATIONS.countNotEmpty]).toEqual([]);
|
||||
expect(result[AGGREGATE_OPERATIONS.countUniqueValues]).toEqual([]);
|
||||
expect(result[AGGREGATE_OPERATIONS.min]).toBeUndefined();
|
||||
expect(result[AGGREGATE_OPERATIONS.percentageEmpty]).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should include percent operation when called with count aggregate operations', () => {
|
||||
const result = initializeAvailableFieldsForAggregateOperationMap(
|
||||
PERCENT_AGGREGATE_OPERATION_OPTIONS,
|
||||
);
|
||||
expect(result[AGGREGATE_OPERATIONS.percentageEmpty]).toEqual([]);
|
||||
expect(result[AGGREGATE_OPERATIONS.percentageNotEmpty]).toEqual([]);
|
||||
expect(result[AGGREGATE_OPERATIONS.count]).toBeUndefined();
|
||||
expect(result[AGGREGATE_OPERATIONS.min]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { getColumnNameForAggregateOperation } from 'twenty-shared';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
@ -16,6 +15,10 @@ export const getAvailableAggregationsFromObjectFields = (
|
||||
fields: FieldMetadataItem[],
|
||||
): Aggregations => {
|
||||
return fields.reduce<Record<string, NameForAggregation>>((acc, field) => {
|
||||
if (field.isSystem === true) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
if (field.type === FieldMetadataType.Relation) {
|
||||
acc[field.name] = {
|
||||
[AGGREGATE_OPERATIONS.count]: 'totalCount',
|
||||
@ -23,28 +26,15 @@ export const getAvailableAggregationsFromObjectFields = (
|
||||
return acc;
|
||||
}
|
||||
|
||||
const columnName = getColumnNameForAggregateOperation(
|
||||
field.name,
|
||||
field.type,
|
||||
);
|
||||
|
||||
acc[field.name] = {
|
||||
[AGGREGATE_OPERATIONS.countUniqueValues]: `countUniqueValues${capitalize(columnName)}`,
|
||||
[AGGREGATE_OPERATIONS.countEmpty]: `countEmpty${capitalize(columnName)}`,
|
||||
[AGGREGATE_OPERATIONS.countNotEmpty]: `countNotEmpty${capitalize(columnName)}`,
|
||||
[AGGREGATE_OPERATIONS.percentageEmpty]: `percentageEmpty${capitalize(columnName)}`,
|
||||
[AGGREGATE_OPERATIONS.percentageNotEmpty]: `percentageNotEmpty${capitalize(columnName)}`,
|
||||
[AGGREGATE_OPERATIONS.countUniqueValues]: `countUniqueValues${capitalize(field.name)}`,
|
||||
[AGGREGATE_OPERATIONS.countEmpty]: `countEmpty${capitalize(field.name)}`,
|
||||
[AGGREGATE_OPERATIONS.countNotEmpty]: `countNotEmpty${capitalize(field.name)}`,
|
||||
[AGGREGATE_OPERATIONS.percentageEmpty]: `percentageEmpty${capitalize(field.name)}`,
|
||||
[AGGREGATE_OPERATIONS.percentageNotEmpty]: `percentageNotEmpty${capitalize(field.name)}`,
|
||||
[AGGREGATE_OPERATIONS.count]: 'totalCount',
|
||||
};
|
||||
|
||||
if (field.type === FieldMetadataType.DateTime) {
|
||||
acc[field.name] = {
|
||||
...acc[field.name],
|
||||
[AGGREGATE_OPERATIONS.min]: `min${capitalize(field.name)}`,
|
||||
[AGGREGATE_OPERATIONS.max]: `max${capitalize(field.name)}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (field.type === FieldMetadataType.Number) {
|
||||
acc[field.name] = {
|
||||
...acc[field.name],
|
||||
|
||||
@ -1,32 +1,30 @@
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION } from '@/object-record/record-table/constants/FieldsAvailableByAggregateOperation';
|
||||
import { AggregateOperationsOmittingStandardOperations } from '@/object-record/types/AggregateOperationsOmittingStandardOperations';
|
||||
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { AvailableFieldsForAggregateOperation } from '@/object-record/types/AvailableFieldsForAggregateOperation';
|
||||
import { getAvailableAggregationsFromObjectFields } from '@/object-record/utils/getAvailableAggregationsFromObjectFields';
|
||||
import { initializeAvailableFieldsForAggregateOperationMap } from '@/object-record/utils/initializeAvailableFieldsForAggregateOperationMap';
|
||||
import { isFieldTypeValidForAggregateOperation } from '@/object-record/utils/isFieldTypeValidForAggregateOperation';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const getAvailableFieldsIdsForAggregationFromObjectFields = (
|
||||
fields: FieldMetadataItem[],
|
||||
targetAggregateOperations: AGGREGATE_OPERATIONS[],
|
||||
): AvailableFieldsForAggregateOperation => {
|
||||
const aggregationMap = initializeAvailableFieldsForAggregateOperationMap();
|
||||
const aggregationMap = initializeAvailableFieldsForAggregateOperationMap(
|
||||
targetAggregateOperations,
|
||||
);
|
||||
|
||||
const allAggregations = getAvailableAggregationsFromObjectFields(fields);
|
||||
|
||||
return fields.reduce((acc, field) => {
|
||||
Object.keys(FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION).forEach(
|
||||
(aggregateOperation) => {
|
||||
const typedAggregateOperation =
|
||||
aggregateOperation as AggregateOperationsOmittingStandardOperations;
|
||||
if (isDefined(allAggregations[field.name])) {
|
||||
Object.keys(allAggregations[field.name]).forEach((aggregation) => {
|
||||
const typedAggregateOperation = aggregation as AGGREGATE_OPERATIONS;
|
||||
|
||||
if (
|
||||
isFieldTypeValidForAggregateOperation(
|
||||
field.type,
|
||||
typedAggregateOperation,
|
||||
)
|
||||
) {
|
||||
if (targetAggregateOperations.includes(typedAggregateOperation)) {
|
||||
acc[typedAggregateOperation]?.push(field.id);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, aggregationMap);
|
||||
};
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import { FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION } from '@/object-record/record-table/constants/FieldsAvailableByAggregateOperation';
|
||||
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { AvailableFieldsForAggregateOperation } from '@/object-record/types/AvailableFieldsForAggregateOperation';
|
||||
|
||||
export const initializeAvailableFieldsForAggregateOperationMap =
|
||||
(): AvailableFieldsForAggregateOperation => {
|
||||
return Object.keys(FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION).reduce(
|
||||
(acc, operation) => ({
|
||||
...acc,
|
||||
[operation]: [],
|
||||
}),
|
||||
{},
|
||||
);
|
||||
};
|
||||
export const initializeAvailableFieldsForAggregateOperationMap = (
|
||||
aggregateOperations: AGGREGATE_OPERATIONS[],
|
||||
): AvailableFieldsForAggregateOperation => {
|
||||
return aggregateOperations.reduce(
|
||||
(acc, operation) => ({
|
||||
...acc,
|
||||
[operation]: [],
|
||||
}),
|
||||
{},
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION } from '@/object-record/record-table/constants/FieldsAvailableByAggregateOperation';
|
||||
import { FIELD_TYPES_AVAILABLE_FOR_NON_STANDARD_AGGREGATE_OPERATION } from '@/object-record/record-table/constants/FieldTypesAvailableForNonStandardAggregateOperation';
|
||||
import { AggregateOperationsOmittingStandardOperations } from '@/object-record/types/AggregateOperationsOmittingStandardOperations';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
@ -6,7 +6,7 @@ export const isFieldTypeValidForAggregateOperation = (
|
||||
fieldType: FieldMetadataType,
|
||||
aggregateOperation: AggregateOperationsOmittingStandardOperations,
|
||||
): boolean => {
|
||||
return FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION[aggregateOperation].includes(
|
||||
fieldType,
|
||||
);
|
||||
return FIELD_TYPES_AVAILABLE_FOR_NON_STANDARD_AGGREGATE_OPERATION[
|
||||
aggregateOperation
|
||||
].includes(fieldType);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user