[BREAKING_CHANGE_VIEW_SORT] Refactor view sort to v2 (#17609)
Fixes https://github.com/twentyhq/core-team-issues/issues/2187 --------- Co-authored-by: prastoin <paul@twenty.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
+5
@@ -0,0 +1,5 @@
|
||||
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
|
||||
|
||||
export const FLAT_VIEW_SORT_EDITABLE_PROPERTIES = [
|
||||
'direction',
|
||||
] as const satisfies MetadataEntityPropertyName<'viewSort'>[];
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service';
|
||||
|
||||
import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator';
|
||||
import { FlatViewSortMaps } from 'src/engine/metadata-modules/flat-view-sort/types/flat-view-sort-maps.type';
|
||||
import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
|
||||
import { fromViewSortEntityToFlatViewSort } from 'src/engine/metadata-modules/flat-view-sort/utils/from-view-sort-entity-to-flat-view-sort.util';
|
||||
import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util';
|
||||
|
||||
@Injectable()
|
||||
@WorkspaceCache('flatViewSortMaps')
|
||||
export class WorkspaceFlatViewSortMapCacheService extends WorkspaceCacheProvider<FlatViewSortMaps> {
|
||||
constructor(
|
||||
@InjectRepository(ViewSortEntity)
|
||||
private readonly viewSortRepository: Repository<ViewSortEntity>,
|
||||
@InjectRepository(ViewEntity)
|
||||
private readonly viewRepository: Repository<ViewEntity>,
|
||||
@InjectRepository(ApplicationEntity)
|
||||
private readonly applicationRepository: Repository<ApplicationEntity>,
|
||||
@InjectRepository(FieldMetadataEntity)
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async computeForCache(workspaceId: string): Promise<FlatViewSortMaps> {
|
||||
const [existingViewSorts, applications, views, fieldMetadatas] =
|
||||
await Promise.all([
|
||||
this.viewSortRepository.find({
|
||||
where: { workspaceId },
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.applicationRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'universalIdentifier'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.viewRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'universalIdentifier'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.fieldMetadataRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'universalIdentifier'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
]);
|
||||
|
||||
const applicationIdToUniversalIdentifierMap =
|
||||
createIdToUniversalIdentifierMap(applications);
|
||||
const viewIdToUniversalIdentifierMap =
|
||||
createIdToUniversalIdentifierMap(views);
|
||||
const fieldMetadataIdToUniversalIdentifierMap =
|
||||
createIdToUniversalIdentifierMap(fieldMetadatas);
|
||||
|
||||
const flatViewSortMaps = createEmptyFlatEntityMaps();
|
||||
|
||||
for (const viewSort of existingViewSorts) {
|
||||
const flatViewSort = fromViewSortEntityToFlatViewSort({
|
||||
entity: viewSort,
|
||||
applicationIdToUniversalIdentifierMap,
|
||||
viewIdToUniversalIdentifierMap,
|
||||
fieldMetadataIdToUniversalIdentifierMap,
|
||||
});
|
||||
|
||||
addFlatEntityToFlatEntityMapsThroughMutationOrThrow({
|
||||
flatEntity: flatViewSort,
|
||||
flatEntityMapsToMutate: flatViewSortMaps,
|
||||
});
|
||||
}
|
||||
|
||||
return flatViewSortMaps;
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { type FlatViewSort } from 'src/engine/metadata-modules/flat-view-sort/types/flat-view-sort.type';
|
||||
|
||||
export type FlatViewSortMaps = FlatEntityMaps<FlatViewSort>;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
|
||||
import { type ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity';
|
||||
|
||||
export type FlatViewSort = FlatEntityFrom<ViewSortEntity>;
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
import { trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type CreateViewSortInput } from 'src/engine/metadata-modules/view-sort/dtos/inputs/create-view-sort.input';
|
||||
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { type UniversalFlatViewSort } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-sort.type';
|
||||
import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-modules/flat-entity/utils/resolve-entity-relation-universal-identifiers.util';
|
||||
|
||||
export const fromCreateViewSortInputToFlatViewSortToCreate = ({
|
||||
createViewSortInput: rawCreateViewSortInput,
|
||||
flatApplication,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewMaps,
|
||||
}: {
|
||||
createViewSortInput: CreateViewSortInput;
|
||||
flatApplication: FlatApplication;
|
||||
} & Pick<
|
||||
AllFlatEntityMaps,
|
||||
'flatViewMaps' | 'flatFieldMetadataMaps'
|
||||
>): UniversalFlatViewSort & {
|
||||
id: string;
|
||||
} => {
|
||||
const { viewId, fieldMetadataId, ...createViewSortInput } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawCreateViewSortInput,
|
||||
['fieldMetadataId', 'id', 'viewId'],
|
||||
);
|
||||
|
||||
const createdAt = new Date().toISOString();
|
||||
const viewSortId = createViewSortInput.id ?? v4();
|
||||
|
||||
const { fieldMetadataUniversalIdentifier, viewUniversalIdentifier } =
|
||||
resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'viewSort',
|
||||
foreignKeyValues: {
|
||||
fieldMetadataId,
|
||||
viewId,
|
||||
},
|
||||
flatEntityMaps: {
|
||||
flatFieldMetadataMaps,
|
||||
flatViewMaps,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
id: viewSortId,
|
||||
fieldMetadataUniversalIdentifier,
|
||||
viewUniversalIdentifier,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
universalIdentifier: createViewSortInput.universalIdentifier ?? v4(),
|
||||
direction: createViewSortInput.direction ?? ViewSortDirection.ASC,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
};
|
||||
};
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatViewSortMaps } from 'src/engine/metadata-modules/flat-view-sort/types/flat-view-sort-maps.type';
|
||||
import { type DeleteViewSortInput } from 'src/engine/metadata-modules/view-sort/dtos/inputs/delete-view-sort.input';
|
||||
import {
|
||||
ViewSortException,
|
||||
ViewSortExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view-sort/exceptions/view-sort.exception';
|
||||
import { type UniversalFlatViewSort } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-sort.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
|
||||
export const fromDeleteViewSortInputToFlatViewSortOrThrow = ({
|
||||
deleteViewSortInput: rawDeleteViewSortInput,
|
||||
flatViewSortMaps,
|
||||
}: {
|
||||
deleteViewSortInput: DeleteViewSortInput;
|
||||
flatViewSortMaps: FlatViewSortMaps;
|
||||
}): UniversalFlatViewSort => {
|
||||
const { id: viewSortId } = extractAndSanitizeObjectStringFields(
|
||||
rawDeleteViewSortInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatViewSortToDelete = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: viewSortId,
|
||||
flatEntityMaps: flatViewSortMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(existingFlatViewSortToDelete)) {
|
||||
throw new ViewSortException(
|
||||
t`View sort not found`,
|
||||
ViewSortExceptionCode.VIEW_SORT_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...existingFlatViewSortToDelete,
|
||||
deletedAt: new Date().toISOString(),
|
||||
};
|
||||
};
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatViewSortMaps } from 'src/engine/metadata-modules/flat-view-sort/types/flat-view-sort-maps.type';
|
||||
import { type DestroyViewSortInput } from 'src/engine/metadata-modules/view-sort/dtos/inputs/destroy-view-sort.input';
|
||||
import {
|
||||
ViewSortException,
|
||||
ViewSortExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view-sort/exceptions/view-sort.exception';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type UniversalFlatViewSort } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-sort.type';
|
||||
|
||||
export const fromDestroyViewSortInputToFlatViewSortOrThrow = ({
|
||||
destroyViewSortInput,
|
||||
flatViewSortMaps,
|
||||
}: {
|
||||
destroyViewSortInput: DestroyViewSortInput;
|
||||
flatViewSortMaps: FlatViewSortMaps;
|
||||
}): UniversalFlatViewSort => {
|
||||
const { id: viewSortId } = extractAndSanitizeObjectStringFields(
|
||||
destroyViewSortInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatViewSortToDestroy = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: viewSortId,
|
||||
flatEntityMaps: flatViewSortMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(existingFlatViewSortToDestroy)) {
|
||||
throw new ViewSortException(
|
||||
t`View sort not found`,
|
||||
ViewSortExceptionCode.VIEW_SORT_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return existingFlatViewSortToDestroy;
|
||||
};
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { FLAT_VIEW_SORT_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-view-sort/constants/flat-view-sort-editable-properties.constant';
|
||||
import { type UpdateViewSortInput } from 'src/engine/metadata-modules/view-sort/dtos/inputs/update-view-sort.input';
|
||||
import {
|
||||
ViewSortException,
|
||||
ViewSortExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view-sort/exceptions/view-sort.exception';
|
||||
import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-record.util';
|
||||
import { type UniversalFlatViewSort } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-sort.type';
|
||||
import { type FlatViewSortMaps } from 'src/engine/metadata-modules/flat-view-sort/types/flat-view-sort-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
|
||||
export const fromUpdateViewSortInputToFlatViewSortToUpdateOrThrow = ({
|
||||
updateViewSortInput: rawUpdateViewSortInput,
|
||||
flatViewSortMaps,
|
||||
}: {
|
||||
updateViewSortInput: UpdateViewSortInput;
|
||||
flatViewSortMaps: FlatViewSortMaps;
|
||||
}): UniversalFlatViewSort => {
|
||||
const { id: viewSortToUpdateId } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawUpdateViewSortInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatViewSortToUpdate = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: viewSortToUpdateId,
|
||||
flatEntityMaps: flatViewSortMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(existingFlatViewSortToUpdate)) {
|
||||
throw new ViewSortException(
|
||||
t`View sort not found`,
|
||||
ViewSortExceptionCode.VIEW_SORT_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const updatedEditableSortProperties = extractAndSanitizeObjectStringFields(
|
||||
rawUpdateViewSortInput.update,
|
||||
FLAT_VIEW_SORT_EDITABLE_PROPERTIES,
|
||||
);
|
||||
|
||||
return mergeUpdateInExistingRecord({
|
||||
existing: existingFlatViewSortToUpdate,
|
||||
properties: FLAT_VIEW_SORT_EDITABLE_PROPERTIES,
|
||||
update: updatedEditableSortProperties,
|
||||
});
|
||||
};
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
|
||||
|
||||
import type { FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
|
||||
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
|
||||
import {
|
||||
FlatEntityMapsException,
|
||||
FlatEntityMapsExceptionCode,
|
||||
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
|
||||
import { type FlatViewSort } from 'src/engine/metadata-modules/flat-view-sort/types/flat-view-sort.type';
|
||||
|
||||
export const fromViewSortEntityToFlatViewSort = ({
|
||||
entity: viewSortEntity,
|
||||
applicationIdToUniversalIdentifierMap,
|
||||
viewIdToUniversalIdentifierMap,
|
||||
fieldMetadataIdToUniversalIdentifierMap,
|
||||
}: FromEntityToFlatEntityArgs<'viewSort'>): FlatViewSort => {
|
||||
const viewSortEntityWithoutRelations = removePropertiesFromRecord(
|
||||
viewSortEntity,
|
||||
getMetadataEntityRelationProperties('viewSort'),
|
||||
);
|
||||
|
||||
const applicationUniversalIdentifier =
|
||||
applicationIdToUniversalIdentifierMap.get(viewSortEntity.applicationId);
|
||||
|
||||
if (!isDefined(applicationUniversalIdentifier)) {
|
||||
throw new FlatEntityMapsException(
|
||||
`Application with id ${viewSortEntity.applicationId} not found for viewSort ${viewSortEntity.id}`,
|
||||
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const viewUniversalIdentifier = viewIdToUniversalIdentifierMap.get(
|
||||
viewSortEntity.viewId,
|
||||
);
|
||||
|
||||
if (!isDefined(viewUniversalIdentifier)) {
|
||||
throw new FlatEntityMapsException(
|
||||
`View with id ${viewSortEntity.viewId} not found for viewSort ${viewSortEntity.id}`,
|
||||
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const fieldMetadataUniversalIdentifier =
|
||||
fieldMetadataIdToUniversalIdentifierMap.get(viewSortEntity.fieldMetadataId);
|
||||
|
||||
if (!isDefined(fieldMetadataUniversalIdentifier)) {
|
||||
throw new FlatEntityMapsException(
|
||||
`Field metadata with id ${viewSortEntity.fieldMetadataId} not found for viewSort ${viewSortEntity.id}`,
|
||||
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...viewSortEntityWithoutRelations,
|
||||
createdAt: viewSortEntity.createdAt.toISOString(),
|
||||
updatedAt: viewSortEntity.updatedAt.toISOString(),
|
||||
deletedAt: viewSortEntity.deletedAt?.toISOString() ?? null,
|
||||
universalIdentifier: viewSortEntityWithoutRelations.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
viewUniversalIdentifier,
|
||||
fieldMetadataUniversalIdentifier,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user