Migrate view filter group to v2 (#16876)
## Introduction On the side hanlded PR with a // agents on another repo Made several iterations to fix behavior and direction Find below auto-generated PR description closes https://github.com/twentyhq/core-team-issues/issues/2037 Created generic tooling for entity circular dep checking, will be useful for permissions validation too @Weiko ## Migrate `viewFilterGroup` entity to v2 flat architecture ### Summary Migrates the `viewFilterGroup` entity from v1 to the v2 flat entity architecture, following the established patterns for other v2 entities like `viewFilter`, `view`, and `viewField`. ### Changes **Types & Constants** - Added `FlatViewFilterGroup` and `FlatViewFilterGroupMaps` types - Added editable properties constant for `viewFilterGroup` - Registered `viewFilterGroup` in `ALL_METADATA_NAME`, `ALL_METADATA_RELATION_PROPERTIES`, `ALL_METADATA_MANY_TO_ONE_RELATIONS`, and related constants **Cache Service** - Created `WorkspaceFlatViewFilterGroupMapCacheService` with proper relation loading for `viewFilters` and `childViewFilterGroups` - Updated `WorkspaceFlatViewMapCacheService` to load `viewFilterGroups` relation **Builder & Validator** - Created `WorkspaceMigrationV2ViewFilterGroupActionsBuilderService` - Created `FlatViewFilterGroupValidatorService` with creation, update, and deletion validation - Integrated validation into the orchestrator service (runs before `viewFilter` validation) **Action Handlers** - Created create, update, and delete action handlers for `viewFilterGroup` **Service Migration** - Rewrote `ViewFilterGroupService` to use v2 migration pattern with `WorkspaceMigrationValidateBuildAndRunService` - Created utility functions for transforming DTOs to flat entities **Database Migration** - Added migration to make `parentViewFilterGroupId` foreign key deferrable (handles self-referential parent/child insertions) **ViewFilter Integration** - Added `viewFilterGroupId` validation in `FlatViewFilterValidatorService` - Updated `viewFilter` many-to-one relations to include `viewFilterGroup` **Tests** - Added integration tests for successful creation, update, deletion, and destruction - Added failing test cases for non-existent entities and invalid references - Added failing test for `viewFilter` creation with non-existent `viewFilterGroupId` ### Breaking Changes None - existing API contracts are preserved.
This commit is contained in:
@@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { WorkspaceFlatViewMapCacheService } from 'src/engine/metadata-modules/flat-view/services/workspace-flat-view-map-cache.service';
|
||||
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
|
||||
import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity';
|
||||
import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
@@ -14,6 +15,7 @@ import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entit
|
||||
ViewFieldEntity,
|
||||
ViewFilterEntity,
|
||||
ViewGroupEntity,
|
||||
ViewFilterGroupEntity,
|
||||
]),
|
||||
],
|
||||
providers: [WorkspaceFlatViewMapCacheService],
|
||||
|
||||
+42
-23
@@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
import { type Repository } from 'typeorm';
|
||||
|
||||
import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service';
|
||||
|
||||
@@ -9,6 +9,7 @@ import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-enti
|
||||
import { type FlatViewMaps } from 'src/engine/metadata-modules/flat-view/types/flat-view-maps.type';
|
||||
import { fromViewEntityToFlatView } from 'src/engine/metadata-modules/flat-view/utils/from-view-entity-to-flat-view.util';
|
||||
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
|
||||
import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity';
|
||||
import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
@@ -28,34 +29,47 @@ export class WorkspaceFlatViewMapCacheService extends WorkspaceCacheProvider<Fla
|
||||
private readonly viewFilterRepository: Repository<ViewFilterEntity>,
|
||||
@InjectRepository(ViewGroupEntity)
|
||||
private readonly viewGroupRepository: Repository<ViewGroupEntity>,
|
||||
@InjectRepository(ViewFilterGroupEntity)
|
||||
private readonly viewFilterGroupRepository: Repository<ViewFilterGroupEntity>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async computeForCache(workspaceId: string): Promise<FlatViewMaps> {
|
||||
const [views, viewFields, viewFilters, viewGroups] = await Promise.all([
|
||||
this.viewRepository.find({
|
||||
where: { workspaceId },
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.viewFieldRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'viewId'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.viewFilterRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'viewId'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.viewGroupRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'viewId'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
]);
|
||||
const [views, viewFields, viewFilters, viewGroups, viewFilterGroups] =
|
||||
await Promise.all([
|
||||
this.viewRepository.find({
|
||||
where: { workspaceId },
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.viewFieldRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'viewId'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.viewFilterRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'viewId'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.viewGroupRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'viewId'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.viewFilterGroupRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'viewId'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
]);
|
||||
|
||||
const [viewFieldsByViewId, viewFiltersByViewId, viewGroupsByViewId] = (
|
||||
const [
|
||||
viewFieldsByViewId,
|
||||
viewFiltersByViewId,
|
||||
viewGroupsByViewId,
|
||||
viewFilterGroupsByViewId,
|
||||
] = (
|
||||
[
|
||||
{
|
||||
entities: viewFields,
|
||||
@@ -69,6 +83,10 @@ export class WorkspaceFlatViewMapCacheService extends WorkspaceCacheProvider<Fla
|
||||
entities: viewGroups,
|
||||
foreignKey: 'viewId',
|
||||
},
|
||||
{
|
||||
entities: viewFilterGroups,
|
||||
foreignKey: 'viewId',
|
||||
},
|
||||
] as const
|
||||
).map(regroupEntitiesByRelatedEntityId);
|
||||
|
||||
@@ -80,6 +98,7 @@ export class WorkspaceFlatViewMapCacheService extends WorkspaceCacheProvider<Fla
|
||||
viewFields: viewFieldsByViewId.get(viewEntity.id) || [],
|
||||
viewFilters: viewFiltersByViewId.get(viewEntity.id) || [],
|
||||
viewGroups: viewGroupsByViewId.get(viewEntity.id) || [],
|
||||
viewFilterGroups: viewFilterGroupsByViewId.get(viewEntity.id) || [],
|
||||
} as ViewEntity);
|
||||
|
||||
addFlatEntityToFlatEntityMapsThroughMutationOrThrow({
|
||||
|
||||
+2
-2
@@ -2,6 +2,6 @@ import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/typ
|
||||
import { type ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
|
||||
export type FlatView = FlatEntityFrom<
|
||||
// TODO remove once viewSorts and viewFilterGroups have been migrated to v2
|
||||
Omit<ViewEntity, 'viewSorts' | 'viewFilterGroups'>
|
||||
// TODO remove once viewSorts has been migrated to v2
|
||||
Omit<ViewEntity, 'viewSorts'>
|
||||
>;
|
||||
|
||||
+1
@@ -68,6 +68,7 @@ export const fromCreateViewInputToFlatViewToCreate = ({
|
||||
viewFieldIds: [],
|
||||
viewFilterIds: [],
|
||||
viewGroupIds: [],
|
||||
viewFilterGroupIds: [],
|
||||
applicationId: workspaceCustomApplicationId,
|
||||
};
|
||||
|
||||
|
||||
+4
@@ -23,5 +23,9 @@ export const fromViewEntityToFlatView = (viewEntity: ViewEntity): FlatView => {
|
||||
viewFieldIds: viewEntity.viewFields.map((viewField) => viewField.id),
|
||||
viewFilterIds: viewEntity.viewFilters.map((viewFilter) => viewFilter.id),
|
||||
viewGroupIds: viewEntity.viewGroups.map((viewGroup) => viewGroup.id),
|
||||
viewFilterGroupIds:
|
||||
viewEntity.viewFilterGroups?.map(
|
||||
(viewFilterGroup) => viewFilterGroup.id,
|
||||
) ?? [],
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user