Fix flat entity maps date serialization (#16420)

Changes:
- as we store date in redis as serialized, let's make all flatEntity
dates as string. This requires changing FlatEntity types and making sure
that entity are converted to flatEntity and flatEntity to dtos
This commit is contained in:
Charles Bochet
2025-12-09 16:41:50 +01:00
committed by GitHub
parent 608e5751a9
commit a18203934c
94 changed files with 357 additions and 204 deletions
@@ -1,9 +1,9 @@
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
export const createEmptyFlatEntityMaps = () =>
({
byId: {},
idByUniversalIdentifier: {},
universalIdentifiersByApplicationId: {},
}) as const satisfies FlatEntityMaps<FlatEntity>;
}) as const satisfies FlatEntityMaps<SyncableFlatEntity>;
@@ -1,8 +1,8 @@
import { type Expect } from 'twenty-shared/testing';
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type Expect } from 'twenty-shared/testing';
import { type AllFlatEntityTypesByMetadataName } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-types-by-metadata-name';
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type WorkspaceMigrationActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2';
type ExpectedGenericFlatEntityInformation = {
@@ -11,7 +11,7 @@ type ExpectedGenericFlatEntityInformation = {
deleted: WorkspaceMigrationActionV2 | WorkspaceMigrationActionV2[];
updated: WorkspaceMigrationActionV2 | WorkspaceMigrationActionV2[];
};
flatEntity: FlatEntity;
flatEntity: SyncableFlatEntity;
};
type ExpectedGenericAllFlatEntityInformationByMetadataEngine = {
@@ -1,6 +1,6 @@
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
export type FlatEntityMaps<T extends FlatEntity> = {
export type FlatEntityMaps<T extends SyncableFlatEntity> = {
byId: Partial<Record<string, T>>;
idByUniversalIdentifier: Partial<Record<string, string>>;
universalIdentifiersByApplicationId: Partial<Record<string, string[]>>;
@@ -1,22 +1,33 @@
import { type SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/interfaces/syncable-entity.interface';
import { type ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
import { type ExtractRecordTypeOrmNonNullableDateProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-non-nullable-date-properties.type';
import { type ExtractRecordTypeOrmNullableDateProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-nullable-date-properties.type';
import { type NonNullableProperties } from 'src/types/non-nullable-properties.type';
export type SyncableEntityRelationProperties =
ExtractRecordTypeOrmRelationProperties<SyncableEntity, ApplicationEntity>;
export interface FlatEntity
extends NonNullableProperties<
Omit<SyncableEntity, SyncableEntityRelationProperties | 'applicationId'>
> {
export type SyncableFlatEntity = NonNullableProperties<
Omit<SyncableEntity, 'application' | 'applicationId'>
> & {
id: string;
applicationId: string | null;
}
};
export type EntityNullableDateProperties<TEntity> =
ExtractRecordTypeOrmNullableDateProperties<TEntity>;
export type EntityNonNullableDateProperties<TEntity> =
ExtractRecordTypeOrmNonNullableDateProperties<TEntity>;
export type FlatEntityFrom<
TEntity extends SyncableEntity,
TEntity,
TEntityRelationProperties extends keyof TEntity,
> = FlatEntity &
Omit<TEntity, TEntityRelationProperties | SyncableEntityRelationProperties>;
> = Omit<
TEntity,
| TEntityRelationProperties
| EntityNonNullableDateProperties<TEntity>
| EntityNullableDateProperties<TEntity>
| 'application'
> & {
[P in EntityNonNullableDateProperties<TEntity>]: string;
} & {
[P in EntityNullableDateProperties<TEntity>]: string | null;
};
@@ -50,8 +50,8 @@ describe('deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThr
viewGroupIds: [],
workspaceId,
calendarFieldMetadataId: mockFieldMetadata.id,
createdAt: new Date('2024-01-01'),
updatedAt: new Date('2024-01-01'),
createdAt: new Date('2024-01-01').toISOString(),
updatedAt: new Date('2024-01-01').toISOString(),
icon: 'icon',
isCompact: false,
name: 'View Name',
@@ -5,14 +5,16 @@ import {
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
type AddFlatEntityToFlatEntityMapsOrThrowArgs<T extends FlatEntity> = {
type AddFlatEntityToFlatEntityMapsOrThrowArgs<T extends SyncableFlatEntity> = {
flatEntity: T;
flatEntityMaps: FlatEntityMaps<T>;
};
export const addFlatEntityToFlatEntityMapsOrThrow = <T extends FlatEntity>({
export const addFlatEntityToFlatEntityMapsOrThrow = <
T extends SyncableFlatEntity,
>({
flatEntity,
flatEntityMaps,
}: AddFlatEntityToFlatEntityMapsOrThrowArgs<T>): FlatEntityMaps<T> => {
@@ -6,17 +6,17 @@ import {
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
export type DeleteFlatEntityFromFlatEntityMapsOrThrowArgs<
T extends FlatEntity,
T extends SyncableFlatEntity,
> = {
entityToDeleteId: string;
flatEntityMaps: FlatEntityMaps<T>;
};
export const deleteFlatEntityFromFlatEntityMapsOrThrow = <
T extends FlatEntity,
T extends SyncableFlatEntity,
>({
flatEntityMaps,
entityToDeleteId,
@@ -6,16 +6,16 @@ import {
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
export type FindFlatEntityByIdInFlatEntityMapsOrThrowArgs<
T extends FlatEntity,
T extends SyncableFlatEntity,
> = {
flatEntityMaps: FlatEntityMaps<T>;
flatEntityId: string;
};
export const findFlatEntityByIdInFlatEntityMapsOrThrow = <
T extends FlatEntity,
T extends SyncableFlatEntity,
>({
flatEntityMaps,
flatEntityId,
@@ -1,10 +1,12 @@
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import {
findFlatEntityByIdInFlatEntityMapsOrThrow,
type FindFlatEntityByIdInFlatEntityMapsOrThrowArgs,
} from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
export const findFlatEntityByIdInFlatEntityMaps = <T extends FlatEntity>(
export const findFlatEntityByIdInFlatEntityMaps = <
T extends SyncableFlatEntity,
>(
args: FindFlatEntityByIdInFlatEntityMapsOrThrowArgs<T>,
): T | undefined => {
try {
@@ -1,17 +1,17 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { getSubFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/get-sub-flat-entity-maps-or-throw.util';
export type FindManyFlatEntityByIdInFlatEntityMapsOrThrowArgs<
T extends FlatEntity,
T extends SyncableFlatEntity,
> = {
flatEntityMaps: FlatEntityMaps<T>;
flatEntityIds: string[];
};
export const findManyFlatEntityByIdInFlatEntityMapsOrThrow = <
T extends FlatEntity,
T extends SyncableFlatEntity,
>({
flatEntityMaps,
flatEntityIds,
@@ -1,9 +1,9 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
export const getFlatEntitiesByApplicationId = <T extends FlatEntity>(
export const getFlatEntitiesByApplicationId = <T extends SyncableFlatEntity>(
maps: FlatEntityMaps<T>,
applicationId: string,
): T[] => {
@@ -1,9 +1,11 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
export const getFlatEntityByUniversalIdentifier = <T extends FlatEntity>(
export const getFlatEntityByUniversalIdentifier = <
T extends SyncableFlatEntity,
>(
maps: FlatEntityMaps<T>,
universalIdentifier: string,
): T | undefined => {
@@ -1,10 +1,10 @@
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
export const getSubFlatEntityMapsOrThrow = <T extends FlatEntity>({
export const getSubFlatEntityMapsOrThrow = <T extends SyncableFlatEntity>({
flatEntityIds,
flatEntityMaps,
}: {
@@ -1,15 +1,18 @@
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
import { deleteFlatEntityFromFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/delete-flat-entity-from-flat-entity-maps-or-throw.util';
export type ReplaceFlatEntityInFlatEntityMapsOrThrowArgs<T extends FlatEntity> =
{
flatEntity: T;
flatEntityMaps: FlatEntityMaps<T>;
};
export type ReplaceFlatEntityInFlatEntityMapsOrThrowArgs<
T extends SyncableFlatEntity,
> = {
flatEntity: T;
flatEntityMaps: FlatEntityMaps<T>;
};
export const replaceFlatEntityInFlatEntityMapsOrThrow = <T extends FlatEntity>({
export const replaceFlatEntityInFlatEntityMapsOrThrow = <
T extends SyncableFlatEntity,
>({
flatEntity,
flatEntityMaps,
}: ReplaceFlatEntityInFlatEntityMapsOrThrowArgs<T>): FlatEntityMaps<T> => {
@@ -1,8 +1,8 @@
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
import { orderObjectProperties } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/order-object-properties.util';
export function transformFlatEntityForComparison<
TFlatEntity extends FlatEntity,
TFlatEntity extends SyncableFlatEntity,
PToCompare extends keyof TFlatEntity,
PJsonB extends PToCompare,
>({