Update searchVector at label identifier update for custom fields (#7588)
By default, when custom fields are created, a searchVector field is created based on the "name" field, which is also the label identifier by default. When this label identifier is updated, we want to update the searchVector field to use this field as searchable field instead, if it is of "searchable type" (today it is only possible to select a text or number field as label identifier, while number fields are not searchable).
This commit is contained in:
@ -7,6 +7,7 @@ import { DataSeedDemoWorkspaceCommand } from 'src/database/commands/data-seed-de
|
||||
import { DataSeedDemoWorkspaceModule } from 'src/database/commands/data-seed-demo-workspace/data-seed-demo-workspace.module';
|
||||
import { DataSeedWorkspaceCommand } from 'src/database/commands/data-seed-dev-workspace.command';
|
||||
import { ConfirmationQuestion } from 'src/database/commands/questions/confirmation.question';
|
||||
import { SimplifySearchVectorExpressionCommandModule } from 'src/database/commands/upgrade-version/0-31/0-32/0-32-simplify-search-vector-expression.module';
|
||||
import { UpgradeTo0_32CommandModule } from 'src/database/commands/upgrade-version/0-32/0-32-upgrade-version.module';
|
||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||
@ -46,6 +47,7 @@ import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/worksp
|
||||
DataSeedDemoWorkspaceModule,
|
||||
WorkspaceCacheStorageModule,
|
||||
WorkspaceMetadataVersionModule,
|
||||
SimplifySearchVectorExpressionCommandModule,
|
||||
UpgradeTo0_32CommandModule,
|
||||
FeatureFlagModule,
|
||||
],
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { SimplifySearchVectorExpressionCommand } from 'src/database/commands/upgrade-version/0-31/0-32/0-32-simplify-search-vector-expression';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { SearchModule } from 'src/engine/metadata-modules/search/search.module';
|
||||
import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module';
|
||||
import { WorkspaceSyncMetadataCommandsModule } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Workspace], 'core'),
|
||||
TypeOrmModule.forFeature([FieldMetadataEntity], 'metadata'),
|
||||
WorkspaceSyncMetadataCommandsModule,
|
||||
SearchModule,
|
||||
WorkspaceMigrationRunnerModule,
|
||||
],
|
||||
providers: [SimplifySearchVectorExpressionCommand],
|
||||
})
|
||||
export class SimplifySearchVectorExpressionCommandModule {}
|
||||
@ -0,0 +1,115 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import chalk from 'chalk';
|
||||
import { Command } from 'nest-commander';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
ActiveWorkspacesCommandOptions,
|
||||
ActiveWorkspacesCommandRunner,
|
||||
} from 'src/database/commands/active-workspaces.command';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import {
|
||||
FieldMetadataEntity,
|
||||
FieldMetadataType,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { SearchService } from 'src/engine/metadata-modules/search/search.service';
|
||||
import { SEARCH_FIELDS_FOR_CUSTOM_OBJECT } from 'src/engine/twenty-orm/custom.workspace-entity';
|
||||
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service';
|
||||
import {
|
||||
COMPANY_STANDARD_FIELD_IDS,
|
||||
CUSTOM_OBJECT_STANDARD_FIELD_IDS,
|
||||
OPPORTUNITY_STANDARD_FIELD_IDS,
|
||||
PERSON_STANDARD_FIELD_IDS,
|
||||
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
|
||||
import { FieldTypeAndNameMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
|
||||
import { SEARCH_FIELDS_FOR_COMPANY } from 'src/modules/company/standard-objects/company.workspace-entity';
|
||||
import { SEARCH_FIELDS_FOR_OPPORTUNITY } from 'src/modules/opportunity/standard-objects/opportunity.workspace-entity';
|
||||
import { SEARCH_FIELDS_FOR_PERSON } from 'src/modules/person/standard-objects/person.workspace-entity';
|
||||
|
||||
@Command({
|
||||
name: 'fix-0.32:simplify-search-vector-expression',
|
||||
description: 'Replace searchVector with simpler expression',
|
||||
})
|
||||
export class SimplifySearchVectorExpressionCommand extends ActiveWorkspacesCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(Workspace, 'core')
|
||||
protected readonly workspaceRepository: Repository<Workspace>,
|
||||
@InjectRepository(FieldMetadataEntity, 'metadata')
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
private readonly searchService: SearchService,
|
||||
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
|
||||
) {
|
||||
super(workspaceRepository);
|
||||
}
|
||||
|
||||
async executeActiveWorkspacesCommand(
|
||||
_passedParam: string[],
|
||||
_options: ActiveWorkspacesCommandOptions,
|
||||
workspaceIds: string[],
|
||||
): Promise<void> {
|
||||
this.logger.log('Running command to fix migration');
|
||||
|
||||
for (const workspaceId of workspaceIds) {
|
||||
this.logger.log(`Running command for workspace ${workspaceId}`);
|
||||
|
||||
try {
|
||||
const searchVectorFields = await this.fieldMetadataRepository.findBy({
|
||||
workspaceId: workspaceId,
|
||||
type: FieldMetadataType.TS_VECTOR,
|
||||
});
|
||||
|
||||
for (const searchVectorField of searchVectorFields) {
|
||||
let fieldsUsedForSearch: FieldTypeAndNameMetadata[] = [];
|
||||
|
||||
switch (searchVectorField.standardId) {
|
||||
case CUSTOM_OBJECT_STANDARD_FIELD_IDS.searchVector: {
|
||||
fieldsUsedForSearch = SEARCH_FIELDS_FOR_CUSTOM_OBJECT;
|
||||
break;
|
||||
}
|
||||
case PERSON_STANDARD_FIELD_IDS.searchVector: {
|
||||
fieldsUsedForSearch = SEARCH_FIELDS_FOR_PERSON;
|
||||
break;
|
||||
}
|
||||
case COMPANY_STANDARD_FIELD_IDS.searchVector: {
|
||||
fieldsUsedForSearch = SEARCH_FIELDS_FOR_COMPANY;
|
||||
break;
|
||||
}
|
||||
case OPPORTUNITY_STANDARD_FIELD_IDS.searchVector: {
|
||||
fieldsUsedForSearch = SEARCH_FIELDS_FOR_OPPORTUNITY;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new Error(
|
||||
`search vector has unexpected standardId: ${searchVectorField.standardId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await this.searchService.updateSearchVector(
|
||||
searchVectorField.objectMetadataId,
|
||||
fieldsUsedForSearch,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.log(
|
||||
chalk.red(
|
||||
`Running command on workspace ${workspaceId} failed with error: ${error}`,
|
||||
),
|
||||
);
|
||||
continue;
|
||||
} finally {
|
||||
this.logger.log(
|
||||
chalk.green(`Finished running command for workspace ${workspaceId}.`),
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(chalk.green(`Command completed!`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,16 +55,6 @@ export const seedFeatureFlags = async (
|
||||
workspaceId: workspaceId,
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IsSearchEnabled,
|
||||
workspaceId: workspaceId,
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IsWorkspaceMigratedForSearch,
|
||||
workspaceId: workspaceId,
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IsAnalyticsV2Enabled,
|
||||
workspaceId: workspaceId,
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddConstraintOnIndex1728999374151 implements MigrationInterface {
|
||||
name = 'AddConstraintOnIndexMetadata1728999374151';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."indexMetadata" ADD CONSTRAINT "IndexOnNameAndWorkspaceIdAndObjectMetadataUnique" UNIQUE ("name", "workspaceId", "objectMetadataId")`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."indexMetadata" DROP CONSTRAINT "IndexOnNameAndWorkspaceIdAndObjectMetadataUnique"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user