Fix index renaming (#8771)

Fixes https://github.com/twentyhq/twenty/issues/8760

## Context
Index names are based on table names and column names, which means
renaming an object (or a field) should also trigger a recompute of index
names. As of today it raises a bug where you can't create an object with
a name that was previously used.

I also took the occasion to refactor a bit the part where we create and
update (after renaming) relations. Basically the only relations we want
to affect are standard relations so I've aligned the logic with
sync-metadata which uses standardId as a source of truth to simplify the
code.

Note: We don't create index for custom relations
Next step should be to do that and update that code to update the index
name as well. Also note that we need to update the sync-metadata logic
for that as well
This commit is contained in:
Weiko
2024-11-28 10:21:03 +01:00
committed by GitHub
parent 2fab2266d5
commit c9fd194695
5 changed files with 487 additions and 313 deletions

View File

@ -10,6 +10,7 @@ import { FindManyOptions, FindOneOptions, In, Not, Repository } from 'typeorm';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { IndexMetadataService } from 'src/engine/metadata-modules/index-metadata/index-metadata.service';
import { DeleteOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/delete-object.input';
import { UpdateOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input';
import {
@ -26,7 +27,6 @@ import {
validateObjectMetadataInputOrThrow,
} from 'src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util';
import { RemoteTableRelationsService } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table-relations/remote-table-relations.service';
import { mapUdtNameToFieldType } from 'src/engine/metadata-modules/remote-server/remote-table/utils/udt-name-mapper.util';
import { SearchService } from 'src/engine/metadata-modules/search/search.service';
import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
@ -55,6 +55,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
private readonly objectMetadataRelationService: ObjectMetadataRelationService,
private readonly objectMetadataMigrationService: ObjectMetadataMigrationService,
private readonly objectMetadataRelatedRecordsService: ObjectMetadataRelatedRecordsService,
private readonly indexMetadataService: IndexMetadataService,
) {
super(objectMetadataRepository);
}
@ -142,18 +143,29 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
objectMetadataInput.primaryKeyColumnType,
);
} else {
await this.objectMetadataMigrationService.createObjectMigration(
await this.objectMetadataMigrationService.createTableMigration(
createdObjectMetadata,
);
await this.objectMetadataMigrationService.createFieldMigrations(
await this.objectMetadataMigrationService.createColumnsMigrations(
createdObjectMetadata,
createdObjectMetadata.fields,
);
await this.createRelationsMetadataAndMigrations(
objectMetadataInput,
const createdRelatedObjectMetadataCollection =
await this.objectMetadataRelationService.createRelationsAndForeignKeysMetadata(
objectMetadataInput.workspaceId,
createdObjectMetadata,
{
primaryKeyFieldMetadataSettings:
objectMetadataInput.primaryKeyFieldMetadataSettings,
primaryKeyColumnType: objectMetadataInput.primaryKeyColumnType,
},
);
await this.objectMetadataMigrationService.createRelationMigrations(
createdObjectMetadata,
createdRelatedObjectMetadataCollection,
);
await this.searchService.createSearchVectorFieldForObject(
@ -194,26 +206,29 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
);
}
const fullObjectMetadataAfterUpdate = {
const existingObjectMetadataCombinedWithUpdateInput = {
...existingObjectMetadata,
...input.update,
};
await this.validatesNoOtherObjectWithSameNameExistsOrThrows({
objectMetadataNameSingular: fullObjectMetadataAfterUpdate.nameSingular,
objectMetadataNamePlural: fullObjectMetadataAfterUpdate.namePlural,
objectMetadataNameSingular:
existingObjectMetadataCombinedWithUpdateInput.nameSingular,
objectMetadataNamePlural:
existingObjectMetadataCombinedWithUpdateInput.namePlural,
workspaceId: workspaceId,
existingObjectMetadataId: fullObjectMetadataAfterUpdate.id,
existingObjectMetadataId:
existingObjectMetadataCombinedWithUpdateInput.id,
});
if (fullObjectMetadataAfterUpdate.isLabelSyncedWithName) {
if (existingObjectMetadataCombinedWithUpdateInput.isLabelSyncedWithName) {
validateNameAndLabelAreSyncOrThrow(
fullObjectMetadataAfterUpdate.labelSingular,
fullObjectMetadataAfterUpdate.nameSingular,
existingObjectMetadataCombinedWithUpdateInput.labelSingular,
existingObjectMetadataCombinedWithUpdateInput.nameSingular,
);
validateNameAndLabelAreSyncOrThrow(
fullObjectMetadataAfterUpdate.labelPlural,
fullObjectMetadataAfterUpdate.namePlural,
existingObjectMetadataCombinedWithUpdateInput.labelPlural,
existingObjectMetadataCombinedWithUpdateInput.namePlural,
);
}
@ -222,8 +237,8 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
isDefined(input.update.namePlural)
) {
validateNameSingularAndNamePluralAreDifferentOrThrow(
fullObjectMetadataAfterUpdate.nameSingular,
fullObjectMetadataAfterUpdate.namePlural,
existingObjectMetadataCombinedWithUpdateInput.nameSingular,
existingObjectMetadataCombinedWithUpdateInput.namePlural,
);
}
@ -231,12 +246,12 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
await this.handleObjectNameAndLabelUpdates(
existingObjectMetadata,
fullObjectMetadataAfterUpdate,
existingObjectMetadataCombinedWithUpdateInput,
input,
);
if (input.update.isActive !== undefined) {
await this.objectMetadataRelationService.updateObjectRelationships(
await this.objectMetadataRelationService.updateObjectRelationshipsActivationStatus(
input.id,
input.update.isActive,
);
@ -396,38 +411,6 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
);
}
private async createRelationsMetadataAndMigrations(
objectMetadataInput: CreateObjectInput,
createdObjectMetadata: ObjectMetadataEntity,
) {
const relatedObjectTypes = [
'timelineActivity',
'favorite',
'attachment',
'noteTarget',
'taskTarget',
];
const createdRelatedObjectMetadata = await Promise.all(
relatedObjectTypes.map(async (relationType) =>
this.objectMetadataRelationService.createMetadata(
objectMetadataInput.workspaceId,
createdObjectMetadata,
mapUdtNameToFieldType(
objectMetadataInput.primaryKeyColumnType ?? 'uuid',
),
objectMetadataInput.primaryKeyFieldMetadataSettings,
relationType,
),
),
);
await this.objectMetadataMigrationService.createRelationMigrations(
createdObjectMetadata,
createdRelatedObjectMetadata,
);
}
private async handleObjectNameAndLabelUpdates(
existingObjectMetadata: ObjectMetadataEntity,
objectMetadataForUpdate: ObjectMetadataEntity,
@ -447,17 +430,37 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
objectMetadataForUpdate.workspaceId,
);
await this.objectMetadataMigrationService.createStandardRelationsUpdatesMigrations(
const relationsAndForeignKeysMetadata =
await this.objectMetadataRelationService.updateRelationsAndForeignKeysMetadata(
objectMetadataForUpdate.workspaceId,
objectMetadataForUpdate,
);
await this.objectMetadataMigrationService.createUpdateForeignKeysMigrations(
existingObjectMetadata,
objectMetadataForUpdate,
relationsAndForeignKeysMetadata,
objectMetadataForUpdate.workspaceId,
);
}
if (input.update.labelPlural || input.update.icon) {
const recomputedIndexes =
await this.indexMetadataService.recomputeIndexMetadataForObject(
objectMetadataForUpdate.workspaceId,
objectMetadataForUpdate,
);
// TODO: recompute foreign keys indexes as well (in the related object and not objectMetadataForUpdate)
await this.indexMetadataService.createIndexRecomputeMigrations(
objectMetadataForUpdate.workspaceId,
objectMetadataForUpdate,
recomputedIndexes,
);
if (
!(input.update.labelPlural === existingObjectMetadata.labelPlural) ||
!(input.update.icon === existingObjectMetadata.icon)
(input.update.labelPlural || input.update.icon) &&
(input.update.labelPlural !== existingObjectMetadata.labelPlural ||
input.update.icon !== existingObjectMetadata.icon)
) {
await this.objectMetadataRelatedRecordsService.updateObjectViews(
objectMetadataForUpdate,