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:
@ -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,
|
||||
|
||||
Reference in New Issue
Block a user