Steps to test

1. Run metadata migrations
2. Run sync-metadata on your workspace
3. Enable the following feature flags: 
IS_SEARCH_ENABLED
IS_QUERY_RUNNER_TWENTY_ORM_ENABLED
IS_WORKSPACE_MIGRATED_FOR_SEARCH
4. Type Cmd + K and search anything
This commit is contained in:
Marie
2024-10-03 17:18:49 +02:00
committed by GitHub
parent 4c250dd811
commit 5f9435c718
71 changed files with 1517 additions and 209 deletions

View File

@ -10,9 +10,11 @@ import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { IndexMetadataModule } from 'src/engine/metadata-modules/index-metadata/index-metadata.module';
import { BeforeUpdateOneObject } from 'src/engine/metadata-modules/object-metadata/hooks/before-update-one-object.hook';
import { ObjectMetadataGraphqlApiExceptionInterceptor } from 'src/engine/metadata-modules/object-metadata/interceptors/object-metadata-graphql-api-exception.interceptor';
import { ObjectMetadataResolver } from 'src/engine/metadata-modules/object-metadata/object-metadata.resolver';
@ -44,6 +46,8 @@ import { UpdateObjectPayload } from './dtos/update-object.input';
WorkspaceMigrationRunnerModule,
WorkspaceMetadataVersionModule,
RemoteTableRelationsModule,
IndexMetadataModule,
FeatureFlagModule,
],
services: [ObjectMetadataService],
resolvers: [

View File

@ -5,19 +5,30 @@ import console from 'console';
import { Query, QueryOptions } from '@ptc-org/nestjs-query-core';
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { isDefined } from 'class-validator';
import { FindManyOptions, FindOneOptions, In, Repository } from 'typeorm';
import { FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/constants/search-vector-field.constants';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import {
FieldMetadataEntity,
FieldMetadataType,
} from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import {
computeColumnName,
FieldTypeAndNameMetadata,
} from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/index-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 { DEFAULT_LABEL_IDENTIFIER_FIELD_NAME } from 'src/engine/metadata-modules/object-metadata/object-metadata.constants';
import {
ObjectMetadataException,
ObjectMetadataExceptionCode,
@ -33,6 +44,7 @@ import { RelationToDelete } from 'src/engine/metadata-modules/relation-metadata/
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 { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service';
import { TsVectorColumnActionFactory } from 'src/engine/metadata-modules/workspace-migration/factories/ts-vector-column-action.factory';
import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util';
import {
WorkspaceMigrationColumnActionType,
@ -58,6 +70,7 @@ import {
createForeignKeyDeterministicUuid,
createRelationDeterministicUuid,
} from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity';
import { ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.workspace-entity';
@ -79,9 +92,14 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
private readonly remoteTableRelationsService: RemoteTableRelationsService,
private readonly tsVectorColumnActionFactory: TsVectorColumnActionFactory,
private readonly dataSourceService: DataSourceService,
private readonly typeORMService: TypeORMService,
private readonly workspaceMigrationService: WorkspaceMigrationService,
private readonly indexMetadataService: IndexMetadataService,
private readonly featureFlagService: FeatureFlagService,
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
@ -350,6 +368,18 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
objectMetadataInput,
createdObjectMetadata,
);
const isSearchEnabled = await this.featureFlagService.isFeatureEnabled(
FeatureFlagKey.IsSearchEnabled,
objectMetadataInput.workspaceId,
);
if (isSearchEnabled) {
await this.createSearchVectorField(
objectMetadataInput,
createdObjectMetadata,
);
}
} else {
await this.remoteTableRelationsService.createForeignKeysMetadataAndMigrations(
objectMetadataInput.workspaceId,
@ -548,6 +578,70 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
);
}
private async createSearchVectorField(
objectMetadataInput: CreateObjectInput,
createdObjectMetadata: ObjectMetadataEntity,
) {
const searchVectorFieldMetadata = await this.fieldMetadataRepository.save({
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.searchVector,
objectMetadataId: createdObjectMetadata.id,
workspaceId: objectMetadataInput.workspaceId,
isCustom: false,
isActive: false,
isSystem: true,
type: FieldMetadataType.TS_VECTOR,
name: SEARCH_VECTOR_FIELD.name,
label: SEARCH_VECTOR_FIELD.label,
description: SEARCH_VECTOR_FIELD.description,
isNullable: true,
});
const searchableFieldForCustomObject =
createdObjectMetadata.labelIdentifierFieldMetadataId
? createdObjectMetadata.fields.find(
(field) =>
field.id === createdObjectMetadata.labelIdentifierFieldMetadataId,
)
: createdObjectMetadata.fields.find(
(field) => field.name === DEFAULT_LABEL_IDENTIFIER_FIELD_NAME,
);
if (!isDefined(searchableFieldForCustomObject)) {
throw new Error('No searchable field found for custom object');
}
this.workspaceMigrationService.createCustomMigration(
generateMigrationName(`create-${createdObjectMetadata.nameSingular}`),
createdObjectMetadata.workspaceId,
[
{
name: computeTableName(
createdObjectMetadata.nameSingular,
createdObjectMetadata.isCustom,
),
action: WorkspaceMigrationTableActionType.ALTER,
columns: this.tsVectorColumnActionFactory.handleCreateAction({
...searchVectorFieldMetadata,
defaultValue: undefined,
generatedType: 'STORED',
asExpression: getTsVectorColumnExpressionFromFields([
searchableFieldForCustomObject as FieldTypeAndNameMetadata,
]),
options: undefined,
} as FieldMetadataInterface<FieldMetadataType.TS_VECTOR>),
},
],
);
await this.indexMetadataService.createIndex(
objectMetadataInput.workspaceId,
createdObjectMetadata,
[searchVectorFieldMetadata],
false,
IndexType.GIN,
);
}
private async createActivityTargetRelation(
workspaceId: string,
createdObjectMetadata: ObjectMetadataEntity,