mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-23 20:13:21 +03:00
Fix custom index creation missing indexFieldMetadatas (#7832)
## Context Regression on custom index creation where indexFieldMetadatas were not saved properly in the DB. This is because we recently changed save() to upsert() in the indexMetadataService and upsert does not handle nesting insert properly. I'm suggesting another fix where we separate indexMetadata creation and index migration creation in 2 different functions. Since the goal was to be able to recreate the index after being deleted when we changed the tsvector expression and indexMetadata was actually not deleted, we didn't need to recreate that part (hence the upsert) and only needed to run a migration to create the actual index in the workspace schema. I've updated the different services and now only call createIndexMigration when we update a search vector expression. Note: this is also fixing the sync-metadata command when running on a workspace with a custom object (including the seeded workspace which has the 'rocket' custom object), failing due to the missing 'searchVector' indexFieldMetadata
This commit is contained in:
parent
17b934e22b
commit
d4457d756c
@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { isDefined } from 'class-validator';
|
||||
import { InsertResult, Repository } from 'typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import {
|
||||
@ -28,7 +28,7 @@ export class IndexMetadataService {
|
||||
private readonly workspaceMigrationService: WorkspaceMigrationService,
|
||||
) {}
|
||||
|
||||
async createIndex(
|
||||
async createIndexMetadata(
|
||||
workspaceId: string,
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
fieldMetadataToIndex: Partial<FieldMetadataEntity>[],
|
||||
@ -45,42 +45,76 @@ export class IndexMetadataService {
|
||||
|
||||
const indexName = `IDX_${generateDeterministicIndexName([tableName, ...columnNames])}`;
|
||||
|
||||
let result: InsertResult;
|
||||
let result: IndexMetadataEntity;
|
||||
|
||||
const existingIndex = await this.indexMetadataRepository.findOne({
|
||||
where: {
|
||||
name: indexName,
|
||||
workspaceId,
|
||||
objectMetadataId: objectMetadata.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingIndex) {
|
||||
throw new Error(
|
||||
`Index ${indexName} on object metadata ${objectMetadata.nameSingular} already exists`,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
result = await this.indexMetadataRepository.upsert(
|
||||
{
|
||||
name: indexName,
|
||||
indexFieldMetadatas: fieldMetadataToIndex.map(
|
||||
(fieldMetadata, index) => {
|
||||
return {
|
||||
fieldMetadataId: fieldMetadata.id,
|
||||
order: index,
|
||||
};
|
||||
},
|
||||
),
|
||||
workspaceId,
|
||||
objectMetadataId: objectMetadata.id,
|
||||
...(isDefined(indexType) ? { indexType: indexType } : {}),
|
||||
isCustom: isCustom,
|
||||
},
|
||||
{
|
||||
conflictPaths: ['workspaceId', 'name', 'objectMetadataId'],
|
||||
skipUpdateIfNoValuesChanged: true,
|
||||
},
|
||||
);
|
||||
result = await this.indexMetadataRepository.save({
|
||||
name: indexName,
|
||||
indexFieldMetadatas: fieldMetadataToIndex.map(
|
||||
(fieldMetadata, index) => ({
|
||||
fieldMetadataId: fieldMetadata.id,
|
||||
order: index,
|
||||
}),
|
||||
),
|
||||
workspaceId,
|
||||
objectMetadataId: objectMetadata.id,
|
||||
...(isDefined(indexType) ? { indexType } : {}),
|
||||
isCustom,
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to create index ${indexName} on object metadata ${objectMetadata.nameSingular}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!result.identifiers.length) {
|
||||
if (!result) {
|
||||
throw new Error(
|
||||
`Failed to return saved index ${indexName} on object metadata ${objectMetadata.nameSingular}`,
|
||||
);
|
||||
}
|
||||
|
||||
await this.createIndexCreationMigration(
|
||||
workspaceId,
|
||||
objectMetadata,
|
||||
fieldMetadataToIndex,
|
||||
isUnique,
|
||||
isCustom,
|
||||
indexType,
|
||||
indexWhereClause,
|
||||
);
|
||||
}
|
||||
|
||||
async createIndexCreationMigration(
|
||||
workspaceId: string,
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
fieldMetadataToIndex: Partial<FieldMetadataEntity>[],
|
||||
isUnique: boolean,
|
||||
isCustom: boolean,
|
||||
indexType?: IndexType,
|
||||
indexWhereClause?: string,
|
||||
) {
|
||||
const tableName = computeObjectTargetTable(objectMetadata);
|
||||
|
||||
const columnNames: string[] = fieldMetadataToIndex.map(
|
||||
(fieldMetadata) => fieldMetadata.name as string,
|
||||
);
|
||||
|
||||
const indexName = `IDX_${generateDeterministicIndexName([tableName, ...columnNames])}`;
|
||||
|
||||
const migration = {
|
||||
name: tableName,
|
||||
action: WorkspaceMigrationTableActionType.ALTER_INDEXES,
|
||||
|
@ -149,7 +149,7 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
|
||||
);
|
||||
}
|
||||
|
||||
await this.indexMetadataService.createIndex(
|
||||
await this.indexMetadataService.createIndexMetadata(
|
||||
relationMetadataInput.workspaceId,
|
||||
toObjectMetadata,
|
||||
[foreignKeyFieldMetadata, deletedFieldMetadata],
|
||||
|
@ -105,7 +105,7 @@ export class SearchService {
|
||||
],
|
||||
);
|
||||
|
||||
await this.indexMetadataService.createIndex(
|
||||
await this.indexMetadataService.createIndexMetadata(
|
||||
objectMetadataInput.workspaceId,
|
||||
createdObjectMetadata,
|
||||
[searchVectorFieldMetadata],
|
||||
@ -157,7 +157,7 @@ export class SearchService {
|
||||
);
|
||||
|
||||
// index needs to be recreated as typeorm deletes then recreates searchVector column at alter
|
||||
await this.indexMetadataService.createIndex(
|
||||
await this.indexMetadataService.createIndexCreationMigration(
|
||||
workspaceId,
|
||||
objectMetadata,
|
||||
[existingSearchVectorFieldMetadata],
|
||||
|
Loading…
Reference in New Issue
Block a user