[groupBy][Requires cache flush] Add WEEK date granularity (#16099)
Closes https://github.com/twentyhq/core-team-issues/issues/1921 https://github.com/user-attachments/assets/bf400ec1-ce25-4d9e-b875-774168452514
This commit is contained in:
+2
@@ -1,5 +1,7 @@
|
||||
import { type ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
|
||||
import { type FirstDayOfTheWeek } from 'twenty-shared/utils';
|
||||
|
||||
export type DateFieldGroupByDefinition = {
|
||||
granularity: ObjectRecordGroupByDateGranularity;
|
||||
weekStartDay?: FirstDayOfTheWeek;
|
||||
};
|
||||
|
||||
+3
@@ -1,4 +1,5 @@
|
||||
import { type ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
|
||||
import { type FirstDayOfTheWeek } from 'twenty-shared/utils';
|
||||
|
||||
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
|
||||
@@ -10,12 +11,14 @@ export type GroupByDateField = {
|
||||
fieldMetadata: FieldMetadataEntity;
|
||||
subFieldName?: string;
|
||||
dateGranularity: ObjectRecordGroupByDateGranularity;
|
||||
weekStartDay?: FirstDayOfTheWeek;
|
||||
};
|
||||
export type GroupByRelationField = {
|
||||
fieldMetadata: FieldMetadataEntity;
|
||||
nestedFieldMetadata: FieldMetadataEntity;
|
||||
nestedSubFieldName?: string;
|
||||
dateGranularity?: ObjectRecordGroupByDateGranularity;
|
||||
weekStartDay?: FirstDayOfTheWeek;
|
||||
};
|
||||
export type GroupByField =
|
||||
| GroupByRegularField
|
||||
|
||||
+15
-1
@@ -33,11 +33,25 @@ export const getGroupByExpression = ({
|
||||
return `TRIM(TO_CHAR(${columnNameWithQuotes}, 'TMMonth'))`;
|
||||
case ObjectRecordGroupByDateGranularity.QUARTER_OF_THE_YEAR:
|
||||
return `TRIM(TO_CHAR(${columnNameWithQuotes}, '"Q"Q'))`;
|
||||
case ObjectRecordGroupByDateGranularity.WEEK: {
|
||||
const weekStartDay = groupByField.weekStartDay;
|
||||
let shiftedExpression = `DATE_TRUNC('week', ${columnNameWithQuotes})`;
|
||||
|
||||
if (isDefined(weekStartDay)) {
|
||||
if (weekStartDay === 'SUNDAY') {
|
||||
shiftedExpression = `DATE_TRUNC('week', ${columnNameWithQuotes} + INTERVAL '1 day') - INTERVAL '1 day'`;
|
||||
} else if (weekStartDay === 'SATURDAY') {
|
||||
shiftedExpression = `DATE_TRUNC('week', ${columnNameWithQuotes} + INTERVAL '2 days') - INTERVAL '2 days'`;
|
||||
}
|
||||
}
|
||||
|
||||
return `TO_CHAR(${shiftedExpression}, 'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM')`;
|
||||
}
|
||||
case ObjectRecordGroupByDateGranularity.DAY:
|
||||
case ObjectRecordGroupByDateGranularity.MONTH:
|
||||
case ObjectRecordGroupByDateGranularity.QUARTER:
|
||||
case ObjectRecordGroupByDateGranularity.YEAR:
|
||||
return `DATE_TRUNC('${dateGranularity}', ${columnNameWithQuotes})`;
|
||||
return `TO_CHAR(DATE_TRUNC('${dateGranularity}', ${columnNameWithQuotes}), 'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM')`;
|
||||
default:
|
||||
assertUnreachable(dateGranularity);
|
||||
}
|
||||
|
||||
+1
@@ -72,6 +72,7 @@ export const parseGroupByArgs = (
|
||||
groupByFields.push({
|
||||
fieldMetadata,
|
||||
dateGranularity: fieldGroupByDefinition.granularity,
|
||||
weekStartDay: fieldGroupByDefinition.weekStartDay,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
+6
-9
@@ -1,9 +1,6 @@
|
||||
import { UserInputError } from 'apollo-server-core';
|
||||
import { isDefined } from 'class-validator';
|
||||
import {
|
||||
FieldMetadataType,
|
||||
type ObjectRecordGroupByDateGranularity,
|
||||
} from 'twenty-shared/types';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import {
|
||||
GraphqlQueryRunnerException,
|
||||
@@ -153,14 +150,14 @@ export const parseGroupByRelationField = ({
|
||||
nestedFieldMetadata.type === FieldMetadataType.DATE_TIME) &&
|
||||
isGroupByDateFieldDefinition(nestedFieldGroupByDefinition)
|
||||
) {
|
||||
const dateFieldDefinition =
|
||||
nestedFieldGroupByDefinition as DateFieldGroupByDefinition;
|
||||
|
||||
groupByFields.push({
|
||||
fieldMetadata,
|
||||
nestedFieldMetadata,
|
||||
dateGranularity: (
|
||||
nestedFieldGroupByDefinition as {
|
||||
granularity: ObjectRecordGroupByDateGranularity;
|
||||
}
|
||||
).granularity,
|
||||
dateGranularity: dateFieldDefinition.granularity,
|
||||
weekStartDay: dateFieldDefinition.weekStartDay,
|
||||
});
|
||||
|
||||
return;
|
||||
|
||||
+2
@@ -4,6 +4,7 @@ import {
|
||||
type ObjectRecordOrderByForCompositeField,
|
||||
type ObjectRecordOrderByForScalarField,
|
||||
} from 'twenty-shared/types';
|
||||
import { type FirstDayOfTheWeek } from 'twenty-shared/utils';
|
||||
|
||||
export type ObjectRecordFilter = Partial<{
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -27,6 +28,7 @@ export type ObjectRecordGroupByForCompositeField = Partial<{
|
||||
export type ObjectRecordGroupByForDateField = Partial<{
|
||||
[Property in keyof ObjectRecord]: {
|
||||
granularity: ObjectRecordGroupByDateGranularity;
|
||||
weekStartDay?: FirstDayOfTheWeek;
|
||||
};
|
||||
}>;
|
||||
|
||||
|
||||
+26
-3
@@ -1,7 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { GraphQLEnumType, GraphQLInputObjectType } from 'graphql';
|
||||
import { ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
|
||||
import {
|
||||
FirstDayOfTheWeek,
|
||||
ObjectRecordGroupByDateGranularity,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { OrderByDirectionType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/enum';
|
||||
@@ -30,7 +33,7 @@ export class GroupByDateGranularityInputTypeGenerator {
|
||||
{} as Record<string, { value: string }>,
|
||||
),
|
||||
description:
|
||||
'Date granularity (e.g. day, month, quarter, year, day of the week, quarter of the year, month of the year)',
|
||||
'Date granularity (e.g. day, month, quarter, year, week, day of the week, quarter of the year, month of the year)',
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -42,13 +45,33 @@ export class GroupByDateGranularityInputTypeGenerator {
|
||||
throw new Error('DateGranularityEnum not found');
|
||||
}
|
||||
|
||||
const firstDayOfWeekEnum = new GraphQLEnumType({
|
||||
name: 'FirstDayOfTheWeek',
|
||||
values: Object.values(FirstDayOfTheWeek).reduce(
|
||||
(acc, option) => {
|
||||
acc[option] = { value: option };
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, { value: string }>,
|
||||
),
|
||||
description: 'First day of the week (MONDAY, SUNDAY, SATURDAY)',
|
||||
});
|
||||
|
||||
this.gqlTypesStorage.addGqlType('FirstDayOfTheWeek', firstDayOfWeekEnum);
|
||||
|
||||
const groupByDateField = new GraphQLInputObjectType({
|
||||
name: GROUP_BY_DATE_GRANULARITY_INPUT_KEY,
|
||||
fields: {
|
||||
granularity: {
|
||||
type: dateGranularityEnum,
|
||||
description:
|
||||
'Date granularity (e.g. day, month, quarter, year, day of the week, quarter of the year, month of the year)',
|
||||
'Date granularity (e.g. day, month, quarter, year, week, day of the week, quarter of the year, month of the year)',
|
||||
},
|
||||
weekStartDay: {
|
||||
type: firstDayOfWeekEnum,
|
||||
description:
|
||||
'First day of the week (only applicable when granularity is WEEK). Defaults to MONDAY if not specified.',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user