Aggregate count variations (#9304)

Closes https://github.com/twentyhq/private-issues/issues/222

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
Co-authored-by: Weiko <corentin@twenty.com>
This commit is contained in:
Marie
2025-01-02 17:35:05 +01:00
committed by GitHub
parent 0f1458cbe9
commit 5d857fbfb5
43 changed files with 650 additions and 203 deletions

View File

@ -1,5 +1,7 @@
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 { getAvailableFieldsIdsForAggregationFromObjectFields } from '@/object-record/utils/getAvailableFieldsIdsForAggregationFromObjectFields';
import { FieldMetadataType } from '~/generated/graphql';
@ -43,8 +45,10 @@ describe('getAvailableFieldsIdsForAggregationFromObjectFields', () => {
]);
Object.values(AGGREGATE_OPERATIONS).forEach((operation) => {
if (operation !== AGGREGATE_OPERATIONS.count) {
expect(result[operation]).toEqual([]);
if (!STANDARD_AGGREGATE_OPERATION_OPTIONS.includes(operation)) {
expect(
result[operation as AggregateOperationsOmittingStandardOperations],
).toEqual([]);
}
});
});
@ -53,8 +57,10 @@ describe('getAvailableFieldsIdsForAggregationFromObjectFields', () => {
const result = getAvailableFieldsIdsForAggregationFromObjectFields([]);
Object.values(AGGREGATE_OPERATIONS).forEach((operation) => {
if (operation !== AGGREGATE_OPERATIONS.count) {
expect(result[operation]).toEqual([]);
if (!STANDARD_AGGREGATE_OPERATION_OPTIONS.includes(operation)) {
expect(
result[operation as AggregateOperationsOmittingStandardOperations],
).toEqual([]);
}
});
});

View File

@ -1,6 +1,6 @@
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
import { FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION } from '@/object-record/record-table/constants/FieldsAvailableByAggregateOperation';
import { AggregateOperationsOmittingCount } from '@/object-record/types/AggregateOperationsOmittingCount';
import { AggregateOperationsOmittingStandardOperations } from '@/object-record/types/AggregateOperationsOmittingStandardOperations';
import { initializeAvailableFieldsForAggregateOperationMap } from '@/object-record/utils/initializeAvailableFieldsForAggregateOperationMap';
describe('initializeAvailableFieldsForAggregateOperationMap', () => {
@ -18,7 +18,9 @@ describe('initializeAvailableFieldsForAggregateOperationMap', () => {
it('should not include count operation', () => {
const result = initializeAvailableFieldsForAggregateOperationMap();
expect(
result[AGGREGATE_OPERATIONS.count as AggregateOperationsOmittingCount],
result[
AGGREGATE_OPERATIONS.count as AggregateOperationsOmittingStandardOperations
],
).toBeUndefined();
});
});

View File

@ -1,5 +1,5 @@
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
import { AggregateOperationsOmittingCount } from '@/object-record/types/AggregateOperationsOmittingCount';
import { AggregateOperationsOmittingStandardOperations } from '@/object-record/types/AggregateOperationsOmittingStandardOperations';
import { isFieldTypeValidForAggregateOperation } from '@/object-record/utils/isFieldTypeValidForAggregateOperation';
import { FieldMetadataType } from '~/generated/graphql';
@ -49,7 +49,7 @@ describe('isFieldTypeValidForAggregateOperation', () => {
expect(
isFieldTypeValidForAggregateOperation(
numericField,
operation as AggregateOperationsOmittingCount,
operation as AggregateOperationsOmittingStandardOperations,
),
).toBe(true);
});

View File

@ -1,5 +1,6 @@
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';
@ -15,8 +16,30 @@ export const getAvailableAggregationsFromObjectFields = (
fields: FieldMetadataItem[],
): Aggregations => {
return fields.reduce<Record<string, NameForAggregation>>((acc, field) => {
if (field.type === FieldMetadataType.Relation) {
acc[field.name] = {
[AGGREGATE_OPERATIONS.count]: 'totalCount',
};
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.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)}`,
};
@ -24,6 +47,7 @@ export const getAvailableAggregationsFromObjectFields = (
if (field.type === FieldMetadataType.Number) {
acc[field.name] = {
...acc[field.name],
[AGGREGATE_OPERATIONS.min]: `min${capitalize(field.name)}`,
[AGGREGATE_OPERATIONS.max]: `max${capitalize(field.name)}`,
[AGGREGATE_OPERATIONS.avg]: `avg${capitalize(field.name)}`,
@ -33,6 +57,7 @@ export const getAvailableAggregationsFromObjectFields = (
if (field.type === FieldMetadataType.Currency) {
acc[field.name] = {
...acc[field.name],
[AGGREGATE_OPERATIONS.min]: `min${capitalize(field.name)}AmountMicros`,
[AGGREGATE_OPERATIONS.max]: `max${capitalize(field.name)}AmountMicros`,
[AGGREGATE_OPERATIONS.avg]: `avg${capitalize(field.name)}AmountMicros`,
@ -44,8 +69,6 @@ export const getAvailableAggregationsFromObjectFields = (
acc[field.name] = {};
}
acc[field.name][AGGREGATE_OPERATIONS.count] = 'totalCount';
return acc;
}, {});
};

View File

@ -1,6 +1,6 @@
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION } from '@/object-record/record-table/constants/FieldsAvailableByAggregateOperation';
import { AggregateOperationsOmittingCount } from '@/object-record/types/AggregateOperationsOmittingCount';
import { AggregateOperationsOmittingStandardOperations } from '@/object-record/types/AggregateOperationsOmittingStandardOperations';
import { AvailableFieldsForAggregateOperation } from '@/object-record/types/AvailableFieldsForAggregateOperation';
import { initializeAvailableFieldsForAggregateOperationMap } from '@/object-record/utils/initializeAvailableFieldsForAggregateOperationMap';
import { isFieldTypeValidForAggregateOperation } from '@/object-record/utils/isFieldTypeValidForAggregateOperation';
@ -14,7 +14,7 @@ export const getAvailableFieldsIdsForAggregationFromObjectFields = (
Object.keys(FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION).forEach(
(aggregateOperation) => {
const typedAggregateOperation =
aggregateOperation as AggregateOperationsOmittingCount;
aggregateOperation as AggregateOperationsOmittingStandardOperations;
if (
isFieldTypeValidForAggregateOperation(

View File

@ -1,10 +1,10 @@
import { FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION } from '@/object-record/record-table/constants/FieldsAvailableByAggregateOperation';
import { AggregateOperationsOmittingCount } from '@/object-record/types/AggregateOperationsOmittingCount';
import { AggregateOperationsOmittingStandardOperations } from '@/object-record/types/AggregateOperationsOmittingStandardOperations';
import { FieldMetadataType } from '~/generated-metadata/graphql';
export const isFieldTypeValidForAggregateOperation = (
fieldType: FieldMetadataType,
aggregateOperation: AggregateOperationsOmittingCount,
aggregateOperation: AggregateOperationsOmittingStandardOperations,
): boolean => {
return FIELDS_AVAILABLE_BY_AGGREGATE_OPERATION[aggregateOperation].includes(
fieldType,