Refactor validate build and run for configuration to be less verbose and more reliable (#16343)

# Introduction
Refactored the api `validateBuildAndRunWorkspaceMigration` to be require
less configuration but to infer required args dynamically depending on
provided metadata maps to compare

## `inferDeletionFromMissingEntities`
Is not dynamically computed avoiding any miss configuration issue and
any missleading devxp

## Maps computation

Making only one call to redis to build both dependency and to be
compared entity maps. It does not matter to avoid passing a about to
compared flat entity maps to could also be a depedency, it's handled
directly in the builder setup optimistic cache logic

Please note that the flat maps used for the service input transpilation
might differ from the one that we will dynamically compute and inject in
the builder. Leading to do 2 redis calls but also race condition prone
validation error
We prefer that this occurs at the builder rather than at the runner
level as the pg instance is not cache and reflect the real state of a
given workspace
In a nutshell, there's a possible race condition between cache
invalidation and computation in both service input transpilers and
builder but we're totally ok with that
This commit is contained in:
Paul Rastoin
2025-12-05 16:41:56 +01:00
committed by GitHub
parent fee3e6b7a1
commit c8f541618d
22 changed files with 554 additions and 976 deletions
@@ -26,10 +26,8 @@ import { DatabaseEventTriggerV2Service } from 'src/engine/metadata-modules/datab
import { FlatDatabaseEventTrigger } from 'src/engine/metadata-modules/database-event-trigger/types/flat-database-event-trigger.type';
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service';
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { getFlatEntitiesByApplicationId } from 'src/engine/metadata-modules/flat-entity/utils/get-flat-entities-by-application-id.util';
import { getSubFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/get-sub-flat-entity-maps-or-throw.util';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
import { RouteTriggerV2Service } from 'src/engine/metadata-modules/route-trigger/services/route-trigger-v2.service';
@@ -990,54 +988,37 @@ export class ApplicationSyncService {
application.id,
);
const fromFlatObjectMetadataMaps = getSubFlatEntityMapsOrThrow({
flatEntityIds: flatObjectMetadataMapsByApplicationId.map((obj) => obj.id),
flatEntityMaps: existingFlatObjectMetadataMaps,
});
const flatIndexMetadataMapsByApplicationId = getFlatEntitiesByApplicationId(
existingFlatIndexMetadataMaps,
application.id,
);
const fromFlatIndexMetadataMaps = getSubFlatEntityMapsOrThrow({
flatEntityIds: flatIndexMetadataMapsByApplicationId.map(
(field) => field.id,
),
flatEntityMaps: existingFlatIndexMetadataMaps,
});
const flatFieldMetadataMapsByApplicationId = getFlatEntitiesByApplicationId(
existingFlatFieldMetadataMaps,
application.id,
);
const fromFlatFieldMetadataMaps = getSubFlatEntityMapsOrThrow({
flatEntityIds: flatFieldMetadataMapsByApplicationId.map((idx) => idx.id),
flatEntityMaps: existingFlatFieldMetadataMaps,
});
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatObjectMetadataMaps: {
from: fromFlatObjectMetadataMaps,
to: createEmptyFlatEntityMaps(),
allFlatEntityOperationByMetadataName: {
objectMetadata: {
flatEntityToCreate: [],
flatEntityToDelete: flatObjectMetadataMapsByApplicationId,
flatEntityToUpdate: [],
},
flatIndexMaps: {
from: fromFlatIndexMetadataMaps,
to: createEmptyFlatEntityMaps(),
index: {
flatEntityToCreate: [],
flatEntityToDelete: flatIndexMetadataMapsByApplicationId,
flatEntityToUpdate: [],
},
flatFieldMetadataMaps: {
from: fromFlatFieldMetadataMaps,
to: createEmptyFlatEntityMaps(),
fieldMetadata: {
flatEntityToCreate: [],
flatEntityToDelete: flatFieldMetadataMapsByApplicationId,
flatEntityToUpdate: [],
},
},
workspaceId,
buildOptions: {
isSystemBuild: true,
inferDeletionFromMissingEntities: true,
},
isSystemBuild: true,
},
);
@@ -10,7 +10,6 @@ import { type UpdateAgentInput } from 'src/engine/metadata-modules/ai/ai-agent/d
import { fromCreateAgentInputToFlatAgent } from 'src/engine/metadata-modules/ai/ai-agent/utils/from-create-agent-input-to-flat-agent.util';
import { fromUpdateAgentInputToFlatAgentToUpdate } from 'src/engine/metadata-modules/ai/ai-agent/utils/from-update-agent-input-to-flat-agent-to-update.util';
import { FlatAgentWithRoleId } from 'src/engine/metadata-modules/flat-agent/types/flat-agent.type';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
@@ -107,16 +106,6 @@ export class AgentService {
input: CreateAgentInput & { isCustom: boolean },
workspaceId: string,
): Promise<FlatAgentWithRoleId> {
const {
flatAgentMaps: existingFlatAgentMaps,
flatRoleTargetMaps: existingFlatRoleTargetMaps,
flatRoleMaps: existingFlatRoleMaps,
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
'flatAgentMaps',
'flatRoleTargetMaps',
'flatRoleMaps',
]);
const { workspaceCustomFlatApplication } =
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
{
@@ -137,27 +126,22 @@ export class AgentService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatAgentMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatAgentMaps,
allFlatEntityOperationByMetadataName: {
agent: {
flatEntityToCreate: [flatAgentToCreate],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
flatRoleTargetMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatRoleTargetMaps,
},
roleTarget: {
flatEntityToCreate: isDefined(flatRoleTargetToCreate)
? [flatRoleTargetToCreate]
: [],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: { flatRoleMaps: existingFlatRoleMaps },
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -191,17 +175,11 @@ export class AgentService {
input: UpdateAgentInput;
workspaceId: string;
}): Promise<FlatAgentWithRoleId> {
const {
flatAgentMaps: existingFlatAgentMaps,
flatRoleTargetMaps: existingFlatRoleTargetMaps,
flatRoleMaps: existingFlatRoleMaps,
flatRoleTargetByAgentIdMaps,
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
'flatAgentMaps',
'flatRoleTargetMaps',
'flatRoleMaps',
'flatRoleTargetByAgentIdMaps',
]);
const { flatRoleTargetByAgentIdMaps, flatAgentMaps } =
await this.workspaceCacheService.getOrRecompute(workspaceId, [
'flatRoleTargetByAgentIdMaps',
'flatAgentMaps',
]);
const {
flatAgentToUpdate,
@@ -210,22 +188,20 @@ export class AgentService {
flatRoleTargetToUpdate,
} = fromUpdateAgentInputToFlatAgentToUpdate({
updateAgentInput: input,
flatAgentMaps: existingFlatAgentMaps,
flatAgentMaps,
flatRoleTargetByAgentIdMaps,
});
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatAgentMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatAgentMaps,
allFlatEntityOperationByMetadataName: {
agent: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [flatAgentToUpdate],
}),
flatRoleTargetMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatRoleTargetMaps,
},
roleTarget: {
flatEntityToCreate: isDefined(flatRoleTargetToCreate)
? [flatRoleTargetToCreate]
: [],
@@ -235,16 +211,10 @@ export class AgentService {
flatEntityToUpdate: isDefined(flatRoleTargetToUpdate)
? [flatRoleTargetToUpdate]
: [],
}),
},
dependencyAllFlatEntityMaps: { flatRoleMaps: existingFlatRoleMaps },
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
roleTarget: isDefined(flatRoleTargetToDelete),
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -306,21 +276,15 @@ export class AgentService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatAgentMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatAgentMaps,
allFlatEntityOperationByMetadataName: {
agent: {
flatEntityToCreate: [],
flatEntityToDelete: [agentToDelete],
flatEntityToUpdate: [],
}),
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
agent: true,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -14,7 +14,6 @@ import { FlatCronTrigger } from 'src/engine/metadata-modules/cron-trigger/types/
import { fromCreateCronTriggerInputToFlatCronTrigger } from 'src/engine/metadata-modules/cron-trigger/utils/from-create-cron-trigger-input-to-flat-cron-trigger.util';
import { fromUpdateCronTriggerInputToFlatCronTriggerToUpdateOrThrow } from 'src/engine/metadata-modules/cron-trigger/utils/from-update-cron-trigger-input-to-flat-cron-trigger-to-update-or-throw.util';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service';
@@ -43,16 +42,6 @@ export class CronTriggerV2Service {
},
);
const flatEntityMaps =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatCronTriggerMaps', 'flatServerlessFunctionMaps'],
},
);
const existingFlatCronTriggerMaps = flatEntityMaps.flatCronTriggerMaps;
const flatCronTriggerToCreate = fromCreateCronTriggerInputToFlatCronTrigger(
{
createCronTriggerInput: cronTriggerInput,
@@ -65,22 +54,15 @@ export class CronTriggerV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
workspaceId,
fromToAllFlatEntityMaps: {
flatCronTriggerMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatCronTriggerMaps,
allFlatEntityOperationByMetadataName: {
cronTrigger: {
flatEntityToCreate: [flatCronTriggerToCreate],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatServerlessFunctionMaps:
flatEntityMaps.flatServerlessFunctionMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -109,41 +91,32 @@ export class CronTriggerV2Service {
cronTriggerInput: UpdateCronTriggerInput,
workspaceId: string,
) {
const flatEntityMaps =
const { flatCronTriggerMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatCronTriggerMaps', 'flatServerlessFunctionMaps'],
flatMapsKeys: ['flatCronTriggerMaps'],
},
);
const existingFlatCronTriggerMaps = flatEntityMaps.flatCronTriggerMaps;
const optimisticallyUpdatedFlatCronTrigger =
fromUpdateCronTriggerInputToFlatCronTriggerToUpdateOrThrow({
flatCronTriggerMaps: existingFlatCronTriggerMaps,
flatCronTriggerMaps,
updateCronTriggerInput: cronTriggerInput,
});
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
workspaceId,
fromToAllFlatEntityMaps: {
flatCronTriggerMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatCronTriggerMaps,
allFlatEntityOperationByMetadataName: {
cronTrigger: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [optimisticallyUpdatedFlatCronTrigger],
}),
},
dependencyAllFlatEntityMaps: {
flatServerlessFunctionMaps:
flatEntityMaps.flatServerlessFunctionMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -175,19 +148,16 @@ export class CronTriggerV2Service {
destroyCronTriggerInput: CronTriggerIdInput;
workspaceId: string;
}): Promise<FlatCronTrigger> {
const {
flatCronTriggerMaps: existingFlatCronTriggerMaps,
flatServerlessFunctionMaps: existingFlatServerlessFunctionMaps,
} =
const { flatCronTriggerMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatCronTriggerMaps', 'flatServerlessFunctionMaps'],
flatMapsKeys: ['flatCronTriggerMaps'],
},
);
const existingFlatCronTrigger =
existingFlatCronTriggerMaps.byId[destroyCronTriggerInput.id];
flatCronTriggerMaps.byId[destroyCronTriggerInput.id];
if (!isDefined(existingFlatCronTrigger)) {
throw new CronTriggerException(
@@ -199,24 +169,15 @@ export class CronTriggerV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatCronTriggerMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatCronTriggerMaps,
allFlatEntityOperationByMetadataName: {
cronTrigger: {
flatEntityToCreate: [],
flatEntityToDelete: [existingFlatCronTrigger],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatServerlessFunctionMaps: existingFlatServerlessFunctionMaps,
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
cronTrigger: true,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -14,7 +14,6 @@ import { FlatDatabaseEventTrigger } from 'src/engine/metadata-modules/database-e
import { fromCreateDatabaseEventTriggerInputToFlatDatabaseEventTrigger } from 'src/engine/metadata-modules/database-event-trigger/utils/from-create-database-event-trigger-input-to-flat-database-event-trigger.util';
import { fromUpdateDatabaseEventTriggerInputToFlatDatabaseEventTriggerToUpdateOrThrow } from 'src/engine/metadata-modules/database-event-trigger/utils/from-update-database-event-trigger-input-to-flat-database-event-trigger-to-update-or-throw.util';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service';
@@ -43,20 +42,6 @@ export class DatabaseEventTriggerV2Service {
},
);
const flatEntityMaps =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatDatabaseEventTriggerMaps',
'flatServerlessFunctionMaps',
],
},
);
const existingFlatDatabaseEventTriggerMaps =
flatEntityMaps.flatDatabaseEventTriggerMaps;
const flatDatabaseEventTriggerToCreate =
fromCreateDatabaseEventTriggerInputToFlatDatabaseEventTrigger({
createDatabaseEventTriggerInput: databaseEventTriggerInput,
@@ -68,22 +53,15 @@ export class DatabaseEventTriggerV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
workspaceId,
fromToAllFlatEntityMaps: {
flatDatabaseEventTriggerMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatDatabaseEventTriggerMaps,
allFlatEntityOperationByMetadataName: {
databaseEventTrigger: {
flatEntityToCreate: [flatDatabaseEventTriggerToCreate],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatServerlessFunctionMaps:
flatEntityMaps.flatServerlessFunctionMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -115,24 +93,18 @@ export class DatabaseEventTriggerV2Service {
databaseEventTriggerInput: UpdateDatabaseEventTriggerInput,
workspaceId: string,
) {
const flatEntityMaps =
const { flatDatabaseEventTriggerMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatDatabaseEventTriggerMaps',
'flatServerlessFunctionMaps',
],
flatMapsKeys: ['flatDatabaseEventTriggerMaps'],
},
);
const existingFlatDatabaseEventTriggerMaps =
flatEntityMaps.flatDatabaseEventTriggerMaps;
const optimisticallyUpdatedFlatDatabaseEventTrigger =
fromUpdateDatabaseEventTriggerInputToFlatDatabaseEventTriggerToUpdateOrThrow(
{
flatDatabaseEventTriggerMaps: existingFlatDatabaseEventTriggerMaps,
flatDatabaseEventTriggerMaps,
updateDatabaseEventTriggerInput: databaseEventTriggerInput,
},
);
@@ -140,24 +112,17 @@ export class DatabaseEventTriggerV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
workspaceId,
fromToAllFlatEntityMaps: {
flatDatabaseEventTriggerMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatDatabaseEventTriggerMaps,
allFlatEntityOperationByMetadataName: {
databaseEventTrigger: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [
optimisticallyUpdatedFlatDatabaseEventTrigger,
],
}),
},
dependencyAllFlatEntityMaps: {
flatServerlessFunctionMaps:
flatEntityMaps.flatServerlessFunctionMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -192,24 +157,16 @@ export class DatabaseEventTriggerV2Service {
destroyDatabaseEventTriggerInput: DatabaseEventTriggerIdInput;
workspaceId: string;
}): Promise<FlatDatabaseEventTrigger> {
const {
flatDatabaseEventTriggerMaps: existingFlatDatabaseEventTriggerMaps,
flatServerlessFunctionMaps: existingFlatServerlessFunctionMaps,
} =
const { flatDatabaseEventTriggerMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatDatabaseEventTriggerMaps',
'flatServerlessFunctionMaps',
],
flatMapsKeys: ['flatDatabaseEventTriggerMaps'],
},
);
const existingFlatDatabaseEventTrigger =
existingFlatDatabaseEventTriggerMaps.byId[
destroyDatabaseEventTriggerInput.id
];
flatDatabaseEventTriggerMaps.byId[destroyDatabaseEventTriggerInput.id];
if (!isDefined(existingFlatDatabaseEventTrigger)) {
throw new DatabaseEventTriggerException(
@@ -221,24 +178,15 @@ export class DatabaseEventTriggerV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatDatabaseEventTriggerMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatDatabaseEventTriggerMaps,
allFlatEntityOperationByMetadataName: {
databaseEventTrigger: {
flatEntityToCreate: [],
flatEntityToDelete: [existingFlatDatabaseEventTrigger],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatServerlessFunctionMaps: existingFlatServerlessFunctionMaps,
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
databaseEventTrigger: true,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -15,7 +15,6 @@ import {
FieldMetadataExceptionCode,
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
@@ -105,31 +104,20 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
dependencyAllFlatEntityMaps: {
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
},
buildOptions: {
isSystemBuild,
inferDeletionFromMissingEntities: {
fieldMetadata: true,
index: true,
},
},
fromToAllFlatEntityMaps: {
flatFieldMetadataMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatFieldMetadataMaps,
allFlatEntityOperationByMetadataName: {
fieldMetadata: {
flatEntityToCreate: [],
flatEntityToDelete: flatFieldMetadatasToDelete,
flatEntityToUpdate: [],
}),
flatIndexMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatIndexMaps,
},
index: {
flatEntityToCreate: [],
flatEntityToDelete: flatIndexesToDelete,
flatEntityToUpdate: flatIndexesToUpdate,
}),
},
},
workspaceId,
isSystemBuild,
},
);
@@ -224,58 +212,40 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
dependencyAllFlatEntityMaps: {
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
flatViewMaps: existingFlatViewMaps,
},
fromToAllFlatEntityMaps: {
flatFieldMetadataMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatFieldMetadataMaps,
allFlatEntityOperationByMetadataName: {
fieldMetadata: {
flatEntityToCreate: flatFieldMetadatasToCreate,
flatEntityToDelete: [],
flatEntityToUpdate: flatFieldMetadatasToUpdate,
}),
flatIndexMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatIndexMaps,
},
index: {
flatEntityToCreate: flatIndexMetadatasToCreate,
flatEntityToDelete: flatIndexMetadatasToDelete,
flatEntityToUpdate: flatIndexMetadatasToUpdate,
}),
flatViewFilterMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFilterMaps,
},
viewFilter: {
flatEntityToCreate: [],
flatEntityToDelete: flatViewFiltersToDelete,
flatEntityToUpdate: flatViewFiltersToUpdate,
}),
flatViewGroupMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewGroupMaps,
},
viewGroup: {
flatEntityToCreate: flatViewGroupsToCreate,
flatEntityToDelete: flatViewGroupsToDelete,
flatEntityToUpdate: flatViewGroupsToUpdate,
}),
flatViewMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewMaps,
},
view: {
flatEntityToCreate: [],
flatEntityToDelete: flatViewsToDelete,
flatEntityToUpdate: flatViewsToUpdate,
}),
flatViewFieldMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFieldMaps,
},
viewField: {
flatEntityToCreate: [],
flatEntityToDelete: flatViewFieldsToDelete,
flatEntityToUpdate: [],
}),
},
buildOptions: {
isSystemBuild,
inferDeletionFromMissingEntities: {
index: true,
viewGroup: true,
viewFilter: true,
view: true,
},
},
workspaceId,
isSystemBuild,
},
);
@@ -324,20 +294,13 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
},
);
const {
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
flatIndexMaps: existingFlatIndexMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatObjectMetadataMaps',
'flatIndexMaps',
'flatFieldMetadataMaps',
],
},
);
const { flatObjectMetadataMaps: existingFlatObjectMetadataMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatObjectMetadataMaps'],
},
);
const allTranspiledTranspilationInputs: Awaited<
ReturnType<typeof fromCreateFieldInputToFlatFieldMetadatasToCreate>
@@ -377,27 +340,20 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
dependencyAllFlatEntityMaps: {
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
},
fromToAllFlatEntityMaps: {
flatFieldMetadataMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatFieldMetadataMaps,
allFlatEntityOperationByMetadataName: {
fieldMetadata: {
flatEntityToCreate: flatFieldMetadatasToCreate,
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
flatIndexMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatIndexMaps,
},
index: {
flatEntityToCreate: flatIndexMetadatasToCreate,
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -0,0 +1,9 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
export type FlatEntityToCreateDeleteUpdate<T extends AllMetadataName> = {
flatEntityToUpdate: MetadataFlatEntity<T>[];
flatEntityToCreate: MetadataFlatEntity<T>[];
flatEntityToDelete: MetadataFlatEntity<T>[];
};
@@ -1,24 +1,23 @@
import { type AllFlatEntities } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entities.type';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FlatEntityToCreateDeleteUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-to-create-delete-update.type';
import { type MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.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';
import { getSubFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/get-sub-flat-entity-maps-or-throw.util';
import { replaceFlatEntityInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/replace-flat-entity-in-flat-entity-maps-or-throw.util';
type ComputeFlatEntityMapsFromToArgs<T extends AllFlatEntities> = {
flatEntityMaps: FlatEntityMaps<T>;
flatEntityToUpdate: T[];
flatEntityToCreate: T[];
flatEntityToDelete: T[];
};
export const computeFlatEntityMapsFromTo = <T extends AllFlatEntities>({
export type ComputeFlatEntityMapsFromToArgs<T extends AllMetadataName> = {
flatEntityMaps: MetadataFlatEntityMaps<T>;
} & FlatEntityToCreateDeleteUpdate<T>;
export const computeFlatEntityMapsFromTo = <T extends AllMetadataName>({
flatEntityMaps,
flatEntityToCreate,
flatEntityToDelete,
flatEntityToUpdate,
}: ComputeFlatEntityMapsFromToArgs<T>): {
from: FlatEntityMaps<T>;
to: FlatEntityMaps<T>;
from: MetadataFlatEntityMaps<T>;
to: MetadataFlatEntityMaps<T>;
} => {
const fromFlatEntityMaps =
flatEntityToDelete.length > 0
@@ -6,9 +6,11 @@ import { fromArrayToUniqueKeyRecord, isDefined } from 'twenty-shared/utils';
import { FindManyOptions, FindOneOptions, Repository } from 'typeorm';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type';
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
@@ -94,39 +96,30 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatObjectMetadataMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatObjectMetadataMaps,
allFlatEntityOperationByMetadataName: {
objectMetadata: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [flatObjectMetadataToUpdate],
}),
flatIndexMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatIndexMaps,
},
index: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: flatIndexMetadatasToUpdate,
}),
flatFieldMetadataMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatFieldMetadataMaps,
},
fieldMetadata: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: otherObjectFlatFieldMetadatasToUpdate,
}),
flatViewFieldMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFieldMaps,
},
viewField: {
flatEntityToCreate: flatViewFieldsToCreate,
flatEntityToDelete: [],
flatEntityToUpdate: flatViewFieldsToUpdate,
}),
},
dependencyAllFlatEntityMaps: {
flatViewMaps: existingFlatViewMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -279,35 +272,25 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatObjectMetadataMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: flatObjectMetadataMaps,
allFlatEntityOperationByMetadataName: {
objectMetadata: {
flatEntityToCreate: [],
flatEntityToDelete: flatObjectMetadatasToDelete,
flatEntityToUpdate: [],
}),
flatIndexMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: flatIndexMaps,
},
index: {
flatEntityToCreate: [],
flatEntityToDelete: flatIndexToDelete,
flatEntityToUpdate: [],
}),
flatFieldMetadataMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: flatFieldMetadataMaps,
},
fieldMetadata: {
flatEntityToCreate: [],
flatEntityToDelete: flatFieldMetadatasToDelete,
flatEntityToUpdate: [],
}),
},
buildOptions: {
inferDeletionFromMissingEntities: {
objectMetadata: true,
fieldMetadata: true,
index: true,
},
isSystemBuild,
},
workspaceId,
isSystemBuild,
},
);
@@ -340,24 +323,13 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
workspaceId,
},
);
const {
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
flatViewMaps: existingFlatViewMaps,
flatViewFieldMaps: existingFlatViewFieldMaps,
flatIndexMaps: existingFlatIndexMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatObjectMetadataMaps',
'flatViewMaps',
'flatViewFieldMaps',
'flatIndexMaps',
'flatFieldMetadataMaps',
],
},
);
const { flatObjectMetadataMaps: existingFlatObjectMetadataMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatObjectMetadataMaps'],
},
);
const {
flatObjectMetadataToCreate,
@@ -372,34 +344,29 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
});
const flatFieldMetadataMapsFromTo = computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatFieldMetadataMaps,
flatEntityToCreate: [
...flatFieldMetadataToCreateOnObject,
...relationTargetFlatFieldMetadataToCreate,
],
flatEntityToDelete: [],
flatEntityToUpdate: [],
});
const optimisticFlatFieldMetadataMaps = [
...flatFieldMetadataToCreateOnObject,
...relationTargetFlatFieldMetadataToCreate,
].reduce<MetadataFlatEntityMaps<'fieldMetadata'>>(
(flatEntityMaps, flatFieldMetadata) =>
addFlatEntityToFlatEntityMapsOrThrow({
flatEntity: flatFieldMetadata,
flatEntityMaps,
}),
createEmptyFlatEntityMaps(),
);
const flatDefaultViewToCreate = await this.computeFlatViewToCreate({
objectMetadata: flatObjectMetadataToCreate,
workspaceId,
workspaceCustomApplicationId: workspaceCustomFlatApplication.id,
flatFieldMetadataMaps: flatFieldMetadataMapsFromTo.to,
flatFieldMetadataMaps: optimisticFlatFieldMetadataMaps,
});
const flatDefaultViewFieldsToCreate =
await this.computeFlatViewFieldsToCreate({
workspaceCustomApplicationId: workspaceCustomFlatApplication.id,
objectFlatFieldMetadatas: findManyFlatEntityByIdInFlatEntityMapsOrThrow(
{
flatEntityMaps: flatFieldMetadataMapsFromTo.to,
flatEntityIds: flatFieldMetadataToCreateOnObject.map(
({ id }) => id,
),
},
),
objectFlatFieldMetadatas: flatFieldMetadataToCreateOnObject,
viewId: flatDefaultViewToCreate.id,
workspaceId,
});
@@ -407,37 +374,38 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatObjectMetadataMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatObjectMetadataMaps,
allFlatEntityOperationByMetadataName: {
objectMetadata: {
flatEntityToCreate: [flatObjectMetadataToCreate],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
flatViewMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewMaps,
},
view: {
flatEntityToCreate: [flatDefaultViewToCreate],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
flatViewFieldMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFieldMaps,
},
viewField: {
flatEntityToCreate: flatDefaultViewFieldsToCreate,
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
flatFieldMetadataMaps: flatFieldMetadataMapsFromTo,
flatIndexMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatIndexMaps,
},
fieldMetadata: {
flatEntityToCreate: [
...flatFieldMetadataToCreateOnObject,
...relationTargetFlatFieldMetadataToCreate,
],
flatEntityToDelete: [],
flatEntityToUpdate: [],
},
index: {
flatEntityToCreate: flatIndexMetadataToCreate,
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -4,7 +4,6 @@ import { isDefined } from 'twenty-shared/utils';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { FlatRoleTarget } from 'src/engine/metadata-modules/flat-role-target/types/flat-role-target.type';
import { CreateRoleTargetInput } from 'src/engine/metadata-modules/role-target/types/create-role-target.input';
@@ -56,11 +55,11 @@ export class RoleTargetService {
return [];
}
const { flatRoleTargetMaps, flatRoleMaps } =
const { flatRoleTargetMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatRoleTargetMaps', 'flatRoleMaps'],
flatMapsKeys: ['flatRoleTargetMaps'],
},
);
@@ -94,24 +93,15 @@ export class RoleTargetService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatRoleTargetMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: flatRoleTargetMaps,
allFlatEntityOperationByMetadataName: {
roleTarget: {
flatEntityToCreate: allFlatRoleTargetsToCreate,
flatEntityToDelete: allFlatRoleTargetsToDelete,
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatRoleMaps,
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
roleTarget: true,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -155,21 +145,15 @@ export class RoleTargetService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatRoleTargetMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatRoleTargetMaps,
allFlatEntityOperationByMetadataName: {
roleTarget: {
flatEntityToCreate: [],
flatEntityToDelete: [roleTargetToDelete],
flatEntityToUpdate: [],
}),
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
roleTarget: true,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -7,7 +7,6 @@ import { Repository } from 'typeorm';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { fromCreateRoleInputToFlatRoleToCreate } from 'src/engine/metadata-modules/flat-role/utils/from-create-role-input-to-flat-role-to-create.util';
import { fromDeleteRoleInputToFlatRoleOrThrow } from 'src/engine/metadata-modules/flat-role/utils/from-delete-role-input-to-flat-role-or-throw.util';
@@ -80,14 +79,6 @@ export class RoleService {
workspaceId: string;
applicationId: string;
}): Promise<RoleDTO> {
const { flatRoleMaps: existingFlatRoleMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatRoleMaps'],
},
);
const flatRoleToCreate = fromCreateRoleInputToFlatRoleToCreate({
createRoleInput: input,
workspaceId,
@@ -97,19 +88,15 @@ export class RoleService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatRoleMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatRoleMaps,
allFlatEntityOperationByMetadataName: {
role: {
flatEntityToCreate: [flatRoleToCreate],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -159,19 +146,15 @@ export class RoleService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatRoleMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatRoleMaps,
allFlatEntityOperationByMetadataName: {
role: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [flatRoleToUpdate],
}),
},
dependencyAllFlatEntityMaps: {},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -255,22 +238,15 @@ export class RoleService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatRoleMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatRoleMaps,
allFlatEntityOperationByMetadataName: {
role: {
flatEntityToCreate: [],
flatEntityToDelete: [flatRoleToDelete],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {},
buildOptions: {
inferDeletionFromMissingEntities: {
role: true,
},
isSystemBuild: false,
},
workspaceId,
isSystemBuild: false,
},
);
@@ -4,7 +4,6 @@ import { isDefined } from 'twenty-shared/utils';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { CreateRouteTriggerInput } from 'src/engine/metadata-modules/route-trigger/dtos/create-route-trigger.input';
import { RouteTriggerIdInput } from 'src/engine/metadata-modules/route-trigger/dtos/route-trigger-id.input';
@@ -43,16 +42,6 @@ export class RouteTriggerV2Service {
},
);
const flatEntityMaps =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatRouteTriggerMaps', 'flatServerlessFunctionMaps'],
},
);
const existingFlatRouteMaps = flatEntityMaps.flatRouteTriggerMaps;
const flatRouteTriggerToCreate =
fromCreateRouteTriggerInputToFlatRouteTrigger({
createRouteTriggerInput: routeTriggerInput,
@@ -64,22 +53,15 @@ export class RouteTriggerV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
workspaceId,
fromToAllFlatEntityMaps: {
flatRouteTriggerMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatRouteMaps,
allFlatEntityOperationByMetadataName: {
routeTrigger: {
flatEntityToCreate: [flatRouteTriggerToCreate],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatServerlessFunctionMaps:
flatEntityMaps.flatServerlessFunctionMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -108,41 +90,32 @@ export class RouteTriggerV2Service {
routeTriggerInput: UpdateRouteTriggerInput,
workspaceId: string,
) {
const flatEntityMaps =
const { flatRouteTriggerMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatRouteTriggerMaps', 'flatServerlessFunctionMaps'],
flatMapsKeys: ['flatRouteTriggerMaps'],
},
);
const existingFlatRouteMaps = flatEntityMaps.flatRouteTriggerMaps;
const optimisticallyUpdatedFlatRouteTrigger =
fromUpdateRouteTriggerInputToFlatRouteTriggerToUpdateOrThrow({
flatRouteTriggerMaps: existingFlatRouteMaps,
flatRouteTriggerMaps,
updateRouteTriggerInput: routeTriggerInput,
});
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
workspaceId,
fromToAllFlatEntityMaps: {
flatRouteTriggerMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatRouteMaps,
allFlatEntityOperationByMetadataName: {
routeTrigger: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [optimisticallyUpdatedFlatRouteTrigger],
}),
},
dependencyAllFlatEntityMaps: {
flatServerlessFunctionMaps:
flatEntityMaps.flatServerlessFunctionMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -174,19 +147,16 @@ export class RouteTriggerV2Service {
destroyRouteTriggerInput: RouteTriggerIdInput;
workspaceId: string;
}): Promise<FlatRouteTrigger> {
const {
flatRouteTriggerMaps: existingFlatRouteMaps,
flatServerlessFunctionMaps: existingFlatServerlessFunctionMaps,
} =
const { flatRouteTriggerMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatRouteTriggerMaps', 'flatServerlessFunctionMaps'],
flatMapsKeys: ['flatRouteTriggerMaps'],
},
);
const existingFlatRoute =
existingFlatRouteMaps.byId[destroyRouteTriggerInput.id];
flatRouteTriggerMaps.byId[destroyRouteTriggerInput.id];
if (!isDefined(existingFlatRoute)) {
throw new RouteTriggerException(
@@ -198,24 +168,15 @@ export class RouteTriggerV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatRouteTriggerMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatRouteMaps,
allFlatEntityOperationByMetadataName: {
routeTrigger: {
flatEntityToCreate: [],
flatEntityToDelete: [existingFlatRoute],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatServerlessFunctionMaps: existingFlatServerlessFunctionMaps,
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
routeTrigger: true,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -4,7 +4,6 @@ import { isDefined } from 'twenty-shared/utils';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import type { CreateServerlessFunctionInput } from 'src/engine/metadata-modules/serverless-function/dtos/create-serverless-function.input';
import { ServerlessFunctionIdInput } from 'src/engine/metadata-modules/serverless-function/dtos/serverless-function-id.input';
@@ -49,17 +48,6 @@ export class ServerlessFunctionV2Service {
},
);
const flatEntityMaps =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatServerlessFunctionMaps'],
},
);
const existingFlatServerlessFunctionMaps =
flatEntityMaps.flatServerlessFunctionMaps;
const flatServerlessFunctionToCreate =
fromCreateServerlessFunctionInputToFlatServerlessFunction({
createServerlessFunctionInput,
@@ -71,18 +59,15 @@ export class ServerlessFunctionV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
workspaceId,
fromToAllFlatEntityMaps: {
flatServerlessFunctionMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatServerlessFunctionMaps,
allFlatEntityOperationByMetadataName: {
serverlessFunction: {
flatEntityToCreate: [flatServerlessFunctionToCreate],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -113,7 +98,7 @@ export class ServerlessFunctionV2Service {
serverlessFunctionInput: UpdateServerlessFunctionInput,
workspaceId: string,
) {
const flatEntityMaps =
const { flatServerlessFunctionMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
@@ -121,30 +106,24 @@ export class ServerlessFunctionV2Service {
},
);
const existingFlatServerlessFunctionMaps =
flatEntityMaps.flatServerlessFunctionMaps;
const optimisticallyUpdatedFlatServerlessFunction =
fromUpdateServerlessFunctionInputToFlatServerlessFunctionToUpdateOrThrow({
flatServerlessFunctionMaps: existingFlatServerlessFunctionMaps,
flatServerlessFunctionMaps,
updateServerlessFunctionInput: serverlessFunctionInput,
});
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
workspaceId,
fromToAllFlatEntityMaps: {
flatServerlessFunctionMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatServerlessFunctionMaps,
allFlatEntityOperationByMetadataName: {
serverlessFunction: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [optimisticallyUpdatedFlatServerlessFunction],
}),
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -206,20 +185,17 @@ export class ServerlessFunctionV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatServerlessFunctionMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatServerlessFunctionMaps,
allFlatEntityOperationByMetadataName: {
serverlessFunction: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [
optimisticallyUpdatedFlatServerlessFunctionWithDeletedAt,
],
}),
},
buildOptions: {
isSystemBuild,
},
},
workspaceId,
isSystemBuild,
},
);
@@ -278,21 +254,15 @@ export class ServerlessFunctionV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatServerlessFunctionMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatServerlessFunctionMaps,
allFlatEntityOperationByMetadataName: {
serverlessFunction: {
flatEntityToCreate: [],
flatEntityToDelete: [existingFlatServerlessFunction],
flatEntityToUpdate: [],
}),
},
buildOptions: {
isSystemBuild,
inferDeletionFromMissingEntities: {
serverlessFunction: true,
},
},
workspaceId,
isSystemBuild,
},
);
@@ -6,7 +6,6 @@ import { IsNull, Repository } from 'typeorm';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { fromCreateViewFieldInputToFlatViewFieldToCreate } from 'src/engine/metadata-modules/flat-view-field/utils/from-create-view-field-input-to-flat-view-field-to-create.util';
@@ -76,23 +75,6 @@ export class ViewFieldV2Service {
},
);
const {
flatViewFieldMaps: existingFlatViewFieldMaps,
flatViewMaps,
flatFieldMetadataMaps,
flatObjectMetadataMaps,
} = await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewFieldMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
'flatObjectMetadataMaps',
],
},
);
const flatViewFieldsToCreate = createViewFieldInputs.map(
(createViewFieldInput) =>
fromCreateViewFieldInputToFlatViewFieldToCreate({
@@ -105,23 +87,15 @@ export class ViewFieldV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewFieldMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFieldMaps,
allFlatEntityOperationByMetadataName: {
viewField: {
flatEntityToCreate: flatViewFieldsToCreate,
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatFieldMetadataMaps,
flatViewMaps,
flatObjectMetadataMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -153,20 +127,13 @@ export class ViewFieldV2Service {
workspaceId: string;
updateViewFieldInput: UpdateViewFieldInput;
}): Promise<ViewFieldDTO> {
const {
flatViewFieldMaps: existingFlatViewFieldMaps,
flatObjectMetadataMaps,
flatViewMaps,
} = await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewFieldMaps',
'flatObjectMetadataMaps',
'flatViewMaps',
],
},
);
const { flatViewFieldMaps: existingFlatViewFieldMaps } =
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewFieldMaps'],
},
);
const optimisticallyUpdatedFlatView =
fromUpdateViewFieldInputToFlatViewFieldToUpdateOrThrow({
@@ -177,22 +144,15 @@ export class ViewFieldV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewFieldMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFieldMaps,
allFlatEntityOperationByMetadataName: {
viewField: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [optimisticallyUpdatedFlatView],
}),
},
dependencyAllFlatEntityMaps: {
flatObjectMetadataMaps,
flatViewMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -224,20 +184,13 @@ export class ViewFieldV2Service {
deleteViewFieldInput: DeleteViewFieldInput;
workspaceId: string;
}): Promise<ViewFieldDTO> {
const {
flatViewFieldMaps: existingFlatViewFieldMaps,
flatObjectMetadataMaps,
flatViewMaps,
} = await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewFieldMaps',
'flatObjectMetadataMaps',
'flatViewMaps',
],
},
);
const { flatViewFieldMaps: existingFlatViewFieldMaps } =
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewFieldMaps'],
},
);
const optimisticallyUpdatedFlatViewWithDeletedAt =
fromDeleteViewFieldInputToFlatViewFieldOrThrow({
@@ -248,22 +201,15 @@ export class ViewFieldV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewFieldMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFieldMaps,
allFlatEntityOperationByMetadataName: {
viewField: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [optimisticallyUpdatedFlatViewWithDeletedAt],
}),
},
dependencyAllFlatEntityMaps: {
flatObjectMetadataMaps,
flatViewMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -295,22 +241,13 @@ export class ViewFieldV2Service {
destroyViewFieldInput: DestroyViewFieldInput;
workspaceId: string;
}): Promise<ViewFieldDTO> {
const {
flatViewFieldMaps: existingFlatViewFieldMaps,
flatViewMaps: existingFlatViewMaps,
flatFieldMetadataMaps,
flatObjectMetadataMaps,
} = await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewFieldMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
'flatObjectMetadataMaps',
],
},
);
const { flatViewFieldMaps: existingFlatViewFieldMaps } =
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewFieldMaps'],
},
);
const existingViewFieldToDelete =
fromDestroyViewFieldInputToFlatViewFieldOrThrow({
@@ -321,26 +258,15 @@ export class ViewFieldV2Service {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewFieldMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFieldMaps,
allFlatEntityOperationByMetadataName: {
viewField: {
flatEntityToCreate: [],
flatEntityToDelete: [existingViewFieldToDelete],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatViewMaps: existingFlatViewMaps,
flatFieldMetadataMaps,
flatObjectMetadataMaps,
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
viewField: true,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -6,7 +6,6 @@ import { IsNull, Repository } from 'typeorm';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { fromCreateViewFilterInputToFlatViewFilterToCreate } from 'src/engine/metadata-modules/flat-view-filter/utils/from-create-view-filter-input-to-flat-view-filter-to-create.util';
import { fromDeleteViewFilterInputToFlatViewFilterOrThrow } from 'src/engine/metadata-modules/flat-view-filter/utils/from-delete-view-filter-input-to-flat-view-filter-or-throw.util';
@@ -45,23 +44,6 @@ export class ViewFilterService {
},
);
const {
flatViewFilterMaps: existingFlatViewFilterMaps,
flatViewMaps,
flatFieldMetadataMaps,
flatObjectMetadataMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewFilterMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
'flatObjectMetadataMaps',
],
},
);
const flatViewFilterToCreate =
fromCreateViewFilterInputToFlatViewFilterToCreate({
createViewFilterInput,
@@ -72,23 +54,15 @@ export class ViewFilterService {
const buildAndRunResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewFilterMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFilterMaps,
allFlatEntityOperationByMetadataName: {
viewFilter: {
flatEntityToCreate: [flatViewFilterToCreate],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatFieldMetadataMaps,
flatViewMaps,
flatObjectMetadataMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -125,20 +99,13 @@ export class ViewFilterService {
workspaceId: string;
updateViewFilterInput: UpdateViewFilterInput;
}): Promise<ViewFilterDTO> {
const {
flatViewFilterMaps: existingFlatViewFilterMaps,
flatViewMaps,
flatFieldMetadataMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewFilterMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
],
},
);
const { flatViewFilterMaps: existingFlatViewFilterMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewFilterMaps'],
},
);
const optimisticallyUpdatedFlatViewFilter =
fromUpdateViewFilterInputToFlatViewFilterToUpdateOrThrow({
@@ -149,22 +116,15 @@ export class ViewFilterService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewFilterMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFilterMaps,
allFlatEntityOperationByMetadataName: {
viewFilter: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [optimisticallyUpdatedFlatViewFilter],
}),
},
dependencyAllFlatEntityMaps: {
flatViewMaps,
flatFieldMetadataMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -196,20 +156,13 @@ export class ViewFilterService {
deleteViewFilterInput: DeleteViewFilterInput;
workspaceId: string;
}): Promise<ViewFilterDTO> {
const {
flatViewFilterMaps: existingFlatViewFilterMaps,
flatViewMaps,
flatFieldMetadataMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewFilterMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
],
},
);
const { flatViewFilterMaps: existingFlatViewFilterMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewFilterMaps'],
},
);
const optimisticallyUpdatedFlatViewFilterWithDeletedAt =
fromDeleteViewFilterInputToFlatViewFilterOrThrow({
@@ -220,24 +173,17 @@ export class ViewFilterService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewFilterMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFilterMaps,
allFlatEntityOperationByMetadataName: {
viewFilter: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [
optimisticallyUpdatedFlatViewFilterWithDeletedAt,
],
}),
},
dependencyAllFlatEntityMaps: {
flatFieldMetadataMaps,
flatViewMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -269,20 +215,13 @@ export class ViewFilterService {
destroyViewFilterInput: DestroyViewFilterInput;
workspaceId: string;
}): Promise<ViewFilterDTO> {
const {
flatViewFilterMaps: existingFlatViewFilterMaps,
flatViewMaps: existingFlatViewMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewFilterMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
],
},
);
const { flatViewFilterMaps: existingFlatViewFilterMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewFilterMaps'],
},
);
const existingViewFilterToDelete =
fromDestroyViewFilterInputToFlatViewFilterOrThrow({
@@ -293,25 +232,15 @@ export class ViewFilterService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewFilterMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewFilterMaps,
allFlatEntityOperationByMetadataName: {
viewFilter: {
flatEntityToCreate: [],
flatEntityToDelete: [existingViewFilterToDelete],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatViewMaps: existingFlatViewMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
viewFilter: true,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -6,7 +6,6 @@ import { IsNull, Repository } from 'typeorm';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { fromCreateViewGroupInputToFlatViewGroupToCreate } from 'src/engine/metadata-modules/flat-view-group/utils/from-create-view-group-input-to-flat-view-group-to-create.util';
@@ -76,20 +75,13 @@ export class ViewGroupService {
},
);
const {
flatViewGroupMaps: existingFlatViewGroupMaps,
flatViewMaps,
flatFieldMetadataMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewGroupMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
],
},
);
const { flatViewMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewMaps'],
},
);
const flatViewGroupsToCreate = createViewGroupInputs.map(
(createViewGroupInput) => {
@@ -116,22 +108,15 @@ export class ViewGroupService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewGroupMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewGroupMaps,
allFlatEntityOperationByMetadataName: {
viewGroup: {
flatEntityToCreate: flatViewGroupsToCreate,
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatFieldMetadataMaps,
flatViewMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -163,20 +148,13 @@ export class ViewGroupService {
workspaceId: string;
updateViewGroupInput: UpdateViewGroupInput;
}): Promise<ViewGroupDTO> {
const {
flatViewGroupMaps: existingFlatViewGroupMaps,
flatViewMaps,
flatFieldMetadataMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewGroupMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
],
},
);
const { flatViewGroupMaps: existingFlatViewGroupMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewGroupMaps'],
},
);
const optimisticallyUpdatedFlatViewGroup =
fromUpdateViewGroupInputToFlatViewGroupToUpdateOrThrow({
@@ -187,22 +165,15 @@ export class ViewGroupService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewGroupMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewGroupMaps,
allFlatEntityOperationByMetadataName: {
viewGroup: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [optimisticallyUpdatedFlatViewGroup],
}),
},
dependencyAllFlatEntityMaps: {
flatViewMaps,
flatFieldMetadataMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -234,20 +205,13 @@ export class ViewGroupService {
deleteViewGroupInput: DeleteViewGroupInput;
workspaceId: string;
}): Promise<ViewGroupDTO> {
const {
flatViewGroupMaps: existingFlatViewGroupMaps,
flatViewMaps,
flatFieldMetadataMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewGroupMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
],
},
);
const { flatViewGroupMaps: existingFlatViewGroupMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewGroupMaps'],
},
);
const optimisticallyUpdatedFlatViewGroupWithDeletedAt =
fromDeleteViewGroupInputToFlatViewGroupOrThrow({
@@ -258,24 +222,17 @@ export class ViewGroupService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewGroupMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewGroupMaps,
allFlatEntityOperationByMetadataName: {
viewGroup: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [
optimisticallyUpdatedFlatViewGroupWithDeletedAt,
],
}),
},
dependencyAllFlatEntityMaps: {
flatFieldMetadataMaps,
flatViewMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -307,20 +264,13 @@ export class ViewGroupService {
destroyViewGroupInput: DestroyViewGroupInput;
workspaceId: string;
}): Promise<ViewGroupDTO> {
const {
flatViewGroupMaps: existingFlatViewGroupMaps,
flatViewMaps: existingFlatViewMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatViewGroupMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
],
},
);
const { flatViewGroupMaps: existingFlatViewGroupMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewGroupMaps'],
},
);
const existingViewGroupToDelete =
fromDestroyViewGroupInputToFlatViewGroupOrThrow({
@@ -331,25 +281,15 @@ export class ViewGroupService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewGroupMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewGroupMaps,
allFlatEntityOperationByMetadataName: {
viewGroup: {
flatEntityToCreate: [],
flatEntityToDelete: [existingViewGroupToDelete],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatViewMaps: existingFlatViewMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
viewGroup: true,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -9,7 +9,6 @@ import { ApplicationService } from 'src/engine/core-modules/application/applicat
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { fromCreateViewInputToFlatViewToCreate } from 'src/engine/metadata-modules/flat-view/utils/from-create-view-input-to-flat-view-to-create.util';
import { fromDeleteViewInputToFlatViewOrThrow } from 'src/engine/metadata-modules/flat-view/utils/from-delete-view-input-to-flat-view-or-throw.util';
@@ -52,22 +51,13 @@ export class ViewService {
},
);
const {
flatObjectMetadataMaps,
flatViewMaps: existingFlatViewMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
flatViewGroupMaps: existingFlatViewGroupMaps,
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: [
'flatObjectMetadataMaps',
'flatViewMaps',
'flatFieldMetadataMaps',
'flatViewGroupMaps',
],
},
);
const { flatFieldMetadataMaps: existingFlatFieldMetadataMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatFieldMetadataMaps'],
},
);
const { flatViewToCreate, flatViewGroupsToCreate } =
fromCreateViewInputToFlatViewToCreate({
@@ -81,28 +71,21 @@ export class ViewService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewMaps,
allFlatEntityOperationByMetadataName: {
view: {
flatEntityToCreate: [flatViewToCreate],
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
flatViewGroupMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewGroupMaps,
},
viewGroup: {
flatEntityToCreate: flatViewGroupsToCreate,
flatEntityToDelete: [],
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatObjectMetadataMaps: flatObjectMetadataMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -163,30 +146,20 @@ export class ViewService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewMaps,
allFlatEntityOperationByMetadataName: {
view: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [flatViewToUpdate],
}),
flatViewGroupMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewGroupMaps,
},
viewGroup: {
flatEntityToCreate: flatViewGroupsToCreate,
flatEntityToDelete: flatViewGroupsToDelete,
flatEntityToUpdate: [],
}),
},
dependencyAllFlatEntityMaps: {
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
viewGroup: true,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -218,14 +191,11 @@ export class ViewService {
deleteViewInput: DeleteViewInput;
workspaceId: string;
}): Promise<ViewDTO> {
const {
flatViewMaps: existingFlatViewMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
} =
const { flatViewMaps: existingFlatViewMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewMaps', 'flatFieldMetadataMaps'],
flatMapsKeys: ['flatViewMaps'],
},
);
@@ -238,21 +208,15 @@ export class ViewService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewMaps,
allFlatEntityOperationByMetadataName: {
view: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: [optimisticallyUpdatedFlatViewWithDeletedAt],
}),
},
dependencyAllFlatEntityMaps: {
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
},
buildOptions: {
isSystemBuild: false,
},
},
workspaceId,
isSystemBuild: false,
},
);
@@ -284,14 +248,11 @@ export class ViewService {
destroyViewInput: DestroyViewInput;
workspaceId: string;
}): Promise<ViewDTO> {
const {
flatViewMaps: existingFlatViewMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
} =
const { flatViewMaps: existingFlatViewMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatViewMaps', 'flatFieldMetadataMaps'],
flatMapsKeys: ['flatViewMaps'],
},
);
@@ -303,24 +264,15 @@ export class ViewService {
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
fromToAllFlatEntityMaps: {
flatViewMaps: computeFlatEntityMapsFromTo({
flatEntityMaps: existingFlatViewMaps,
allFlatEntityOperationByMetadataName: {
view: {
flatEntityToCreate: [],
flatEntityToDelete: [flatViewFromDestroyInput],
flatEntityToUpdate: [],
}),
},
buildOptions: {
isSystemBuild: false,
inferDeletionFromMissingEntities: {
view: true,
},
},
dependencyAllFlatEntityMaps: {
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
},
workspaceId,
isSystemBuild: false,
},
);
@@ -1,8 +1,8 @@
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type';
import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util';
import { createStandardObjectFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-object-flat-metadata.util';
import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util';
export type BuildStandardFlatObjectMetadatasArgs = {
createdAt: Date;
@@ -14,11 +14,6 @@ export type StandardFlatObjectMetadataBuilder = (
args: BuildStandardFlatObjectMetadatasArgs,
) => FlatObjectMetadata;
/**
* Record mapping each standard object name to its corresponding object metadata builder.
* Using `satisfies` ensures type safety: if a new standard object is added to STANDARD_OBJECTS,
* TypeScript will error until a builder is added here.
*/
export const STANDARD_FLAT_OBJECT_METADATA_BUILDERS_BY_OBJECT_NAME = {
attachment: (args: BuildStandardFlatObjectMetadatasArgs) =>
createStandardObjectFlatMetadata({
@@ -15,12 +15,12 @@ import {
} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { aggregateOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/utils/aggregate-orchestrator-actions-report.util';
import { WorkspaceMigrationV2AgentActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/agent/workspace-migration-v2-agent-actions-builder.service';
import { WorkspaceMigrationV2PageLayoutTabActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/page-layout-tab/workspace-migration-v2-page-layout-tab-actions-builder.service';
import { WorkspaceMigrationV2CronTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/cron-trigger/workspace-migration-v2-cron-trigger-action-builder.service';
import { WorkspaceMigrationV2DatabaseEventTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/database-event-trigger/workspace-migration-v2-database-event-trigger-actions-builder.service';
import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/workspace-migration-v2-field-actions-builder.service';
import { WorkspaceMigrationV2IndexActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/index/workspace-migration-v2-index-actions-builder.service';
import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/workspace-migration-v2-object-actions-builder.service';
import { WorkspaceMigrationV2PageLayoutTabActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/page-layout-tab/workspace-migration-v2-page-layout-tab-actions-builder.service';
import { WorkspaceMigrationV2RoleTargetActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/role-target/workspace-migration-v2-role-target-actions-builder.service';
import { WorkspaceMigrationV2RoleActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/role/workspace-migration-v2-role-actions-builder.service';
import { WorkspaceMigrationV2RouteTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/route-trigger/workspace-migration-v2-route-trigger-actions-builder.service';
@@ -65,7 +65,10 @@ export class WorkspaceMigrationBuildOrchestratorService {
(allFlatEntityMaps, currFlatMaps) => {
const fromToOccurence = fromToAllFlatEntityMaps[currFlatMaps];
if (!isDefined(fromToOccurence)) {
if (
!isDefined(fromToOccurence) ||
isDefined(allFlatEntityMaps[currFlatMaps])
) {
return allFlatEntityMaps;
}
@@ -1,15 +1,35 @@
import { Injectable, Logger } from '@nestjs/common';
import { WorkspaceMigrationV2ExceptionCode } from 'twenty-shared/metadata';
import {
AllMetadataName,
WorkspaceMigrationV2ExceptionCode,
} from 'twenty-shared/metadata';
import { isDefined } from 'twenty-shared/utils';
import { ALL_METADATA_REQUIRED_METADATA_FOR_VALIDATION } from 'src/engine/metadata-modules/flat-entity/constant/all-metadata-required-metadata-for-validation.constant';
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import { AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { FlatEntityToCreateDeleteUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-to-create-delete-update.type';
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
import { WorkspaceMigrationBuildOrchestratorService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-build-orchestrator.service';
import {
WorkspaceMigrationOrchestratorBuildArgs,
WorkspaceMigrationOrchestratorFailedResult,
} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { InferDeletionFromMissingEntities } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/infer-deletion-from-missing-entities.type';
import { WorkspaceMigrationRunnerV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/services/workspace-migration-runner-v2.service';
import { WorkspaceMigrationV2Exception } from 'src/engine/workspace-manager/workspace-migration.exception';
type ValidateBuildAndRunWorkspaceMigrationFromMatriceArgs = {
workspaceId: string;
allFlatEntityOperationByMetadataName: {
[P in AllMetadataName]?: FlatEntityToCreateDeleteUpdate<P>;
};
isSystemBuild?: boolean;
};
@Injectable()
export class WorkspaceMigrationValidateBuildAndRunService {
private readonly logger = new Logger(
@@ -19,14 +39,144 @@ export class WorkspaceMigrationValidateBuildAndRunService {
constructor(
private readonly workspaceMigrationRunnerV2Service: WorkspaceMigrationRunnerV2Service,
private readonly workspaceMigrationBuildOrchestratorService: WorkspaceMigrationBuildOrchestratorService,
private readonly workspaceCacheService: WorkspaceCacheService,
) {}
public async validateBuildAndRunWorkspaceMigration(
builderArgs: WorkspaceMigrationOrchestratorBuildArgs,
): Promise<WorkspaceMigrationOrchestratorFailedResult | undefined> {
private async computeAllRelatedFlatEntityMaps({
allFlatEntityOperationByMetadataName,
workspaceId,
}: ValidateBuildAndRunWorkspaceMigrationFromMatriceArgs) {
const allMetadataNameToCompare = Object.keys(
allFlatEntityOperationByMetadataName,
) as AllMetadataName[];
const allDependencyMetadataName = allMetadataNameToCompare.flatMap(
(metadataName) =>
Object.keys(
ALL_METADATA_REQUIRED_METADATA_FOR_VALIDATION[metadataName],
) as AllMetadataName[],
);
const allMetadataNameCacheToCompute = [
...new Set([...allMetadataNameToCompare, ...allDependencyMetadataName]),
];
const allFlatEntityMapsCacheKeysToCompute =
allMetadataNameCacheToCompute.map(getMetadataFlatEntityMapsKey);
const allRelatedFlatEntityMaps =
await this.workspaceCacheService.getOrRecompute(
workspaceId,
allFlatEntityMapsCacheKeysToCompute,
);
const initialAccumulator = allDependencyMetadataName.reduce<
Partial<AllFlatEntityMaps>
>(
(allFlatEntityMaps, metadataName) => ({
...allFlatEntityMaps,
[getMetadataFlatEntityMapsKey(metadataName)]:
createEmptyFlatEntityMaps(),
}),
{},
);
const dependencyAllFlatEntityMaps = allDependencyMetadataName.reduce(
(allFlatEntityMaps, metadataName) => {
const metadataFlatEntityMapsKey =
getMetadataFlatEntityMapsKey(metadataName);
return {
...allFlatEntityMaps,
[metadataFlatEntityMapsKey]:
allRelatedFlatEntityMaps[metadataFlatEntityMapsKey],
};
},
initialAccumulator,
);
return {
allRelatedFlatEntityMaps,
dependencyAllFlatEntityMaps,
};
}
private async computeFromToAllFlatEntityMapsAndBuildOptions({
allFlatEntityOperationByMetadataName,
workspaceId,
}: ValidateBuildAndRunWorkspaceMigrationFromMatriceArgs): Promise<{
fromToAllFlatEntityMaps: WorkspaceMigrationOrchestratorBuildArgs['fromToAllFlatEntityMaps'];
inferDeletionFromMissingEntities: InferDeletionFromMissingEntities;
dependencyAllFlatEntityMaps: Partial<AllFlatEntityMaps>;
}> {
const { allRelatedFlatEntityMaps, dependencyAllFlatEntityMaps } =
await this.computeAllRelatedFlatEntityMaps({
allFlatEntityOperationByMetadataName,
workspaceId,
});
const fromToAllFlatEntityMaps: WorkspaceMigrationOrchestratorBuildArgs['fromToAllFlatEntityMaps'] =
{};
const inferDeletionFromMissingEntities: InferDeletionFromMissingEntities =
{};
const allMetadataNameToCompare = Object.keys(
allFlatEntityOperationByMetadataName,
) as AllMetadataName[];
for (const metadataName of allMetadataNameToCompare) {
const tmp = allFlatEntityOperationByMetadataName[metadataName];
if (!isDefined(tmp)) {
throw new Error('Should never occurs');
}
const { flatEntityToCreate, flatEntityToDelete, flatEntityToUpdate } =
tmp;
const flatEntityMapsKey = getMetadataFlatEntityMapsKey(metadataName);
const flatEntityMaps = allRelatedFlatEntityMaps[flatEntityMapsKey];
// @ts-expect-error Metadata flat entity maps cache key and metadataName colliding
fromToAllFlatEntityMaps[flatEntityMapsKey] = computeFlatEntityMapsFromTo({
flatEntityMaps,
flatEntityToCreate,
flatEntityToDelete,
flatEntityToUpdate,
});
if (flatEntityToDelete.length > 0) {
inferDeletionFromMissingEntities[metadataName] = true;
}
}
return {
fromToAllFlatEntityMaps,
inferDeletionFromMissingEntities,
dependencyAllFlatEntityMaps,
};
}
public async validateBuildAndRunWorkspaceMigration({
allFlatEntityOperationByMetadataName: allFlatEntities,
workspaceId,
isSystemBuild = false,
}: ValidateBuildAndRunWorkspaceMigrationFromMatriceArgs): Promise<
WorkspaceMigrationOrchestratorFailedResult | undefined
> {
const {
fromToAllFlatEntityMaps,
inferDeletionFromMissingEntities,
dependencyAllFlatEntityMaps,
} = await this.computeFromToAllFlatEntityMapsAndBuildOptions({
allFlatEntityOperationByMetadataName: allFlatEntities,
workspaceId,
});
const validateAndBuildResult =
await this.workspaceMigrationBuildOrchestratorService
.buildWorkspaceMigration(builderArgs)
.buildWorkspaceMigration({
buildOptions: {
isSystemBuild,
inferDeletionFromMissingEntities,
},
fromToAllFlatEntityMaps,
workspaceId,
dependencyAllFlatEntityMaps,
})
.catch((error) => {
this.logger.error(error);
throw new WorkspaceMigrationV2Exception(
@@ -0,0 +1,6 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
export type InferDeletionFromMissingEntities =
| true
| Partial<Record<AllMetadataName, boolean>>
| undefined;
@@ -1,8 +1,6 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type InferDeletionFromMissingEntities } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/infer-deletion-from-missing-entities.type';
export type WorkspaceMigrationBuilderOptions = {
inferDeletionFromMissingEntities?:
| true
| Partial<Record<AllMetadataName, boolean>>;
inferDeletionFromMissingEntities?: InferDeletionFromMissingEntities;
isSystemBuild: boolean;
};
@@ -1,5 +1,6 @@
import { Module } from '@nestjs/common';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
import { WorkspaceMigrationBuildOrchestratorService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-build-orchestrator.service';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service';
import { WorkspaceMigrationBuilderV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.module';
@@ -9,6 +10,7 @@ import { WorkspaceMigrationRunnerV2Module } from 'src/engine/workspace-manager/w
imports: [
WorkspaceMigrationBuilderV2Module,
WorkspaceMigrationRunnerV2Module,
WorkspaceCacheModule,
],
providers: [
WorkspaceMigrationValidateBuildAndRunService,