From 6860f1a26fe8936d4f672619a614fc40d6394367 Mon Sep 17 00:00:00 2001 From: prathamesh0 <42446521+prathamesh0@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:15:31 +0530 Subject: [PATCH] Handle tsvector type columns when forming the db query (#459) * Support full text search queries * Handle text search for all query types --- packages/util/src/database.ts | 36 ++++++++++++++++++++++++++++- packages/util/src/graph/database.ts | 20 ++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/util/src/database.ts b/packages/util/src/database.ts index 01b01d30..56cf51fa 100644 --- a/packages/util/src/database.ts +++ b/packages/util/src/database.ts @@ -42,7 +42,8 @@ export const OPERATOR_MAP = { contains_nocase: 'ILIKE', starts_nocase: 'ILIKE', ends_nocase: 'ILIKE', - nested: '' + nested: '', + match: '@@' }; const INSERT_EVENTS_BATCH = 100; @@ -66,6 +67,8 @@ export interface QueryOptions { skip?: number; orderBy?: string; orderDirection?: OrderDirection; + tsRankBy?: string; + tsRankValue?: string; } export interface Filter { @@ -943,6 +946,8 @@ export class Database { value = this._transformBigValues(value); if (operator === 'in') { whereClause += '(:...'; + } else if (columnMetadata.type === 'tsvector' && operator === 'match') { + whereClause += 'to_tsquery(:'; } else { whereClause += ':'; } @@ -958,6 +963,10 @@ export class Database { } } + if (operator === 'match') { + whereClause += ')'; + } + if (!columnIsArray) { if (['contains', 'contains_nocase', 'ends', 'ends_nocase'].some(el => el === operator)) { value = `%${value}`; @@ -1173,6 +1182,31 @@ export class Database { ); } + orderTsQuery ( + repo: Repository, + selectQueryBuilder: SelectQueryBuilder, + tsOrderOptions: { tsRankBy?: string, tsRankValue?: string }, + columnPrefix = '', + alias?: string + ): SelectQueryBuilder { + if (!alias) { + alias = selectQueryBuilder.alias; + } + + const { tsRankBy, tsRankValue } = tsOrderOptions; + assert(tsRankBy); + + const columnMetadata = repo.metadata.findColumnWithPropertyName(tsRankBy); + assert(columnMetadata); + + const tsOrderBy = `ts_rank("${alias}"."${columnPrefix}${columnMetadata.databaseName}", to_tsquery('${tsRankValue ?? ''}'))`; + + return selectQueryBuilder.addOrderBy( + tsOrderBy, + 'ASC' + ); + } + async applyBlockHeightFilter ( queryRunner: QueryRunner, queryBuilder: SelectQueryBuilder, diff --git a/packages/util/src/graph/database.ts b/packages/util/src/graph/database.ts index b2eca9de..3a17ba08 100644 --- a/packages/util/src/graph/database.ts +++ b/packages/util/src/graph/database.ts @@ -454,6 +454,10 @@ export class GraphDatabase { selectQueryBuilder = this._baseDatabase.buildQuery(repo, selectQueryBuilder, where, relationsMap.get(entityType), block); + if (queryOptions.tsRankBy) { + selectQueryBuilder = this._baseDatabase.orderTsQuery(repo, selectQueryBuilder, queryOptions); + } + if (queryOptions.orderBy) { selectQueryBuilder = await this._baseDatabase.orderQuery(repo, selectQueryBuilder, queryOptions, relationsMap.get(entityType), block); } @@ -508,6 +512,10 @@ export class GraphDatabase { .from(`(${subQuery.getQuery()})`, 'latestEntities') .setParameters(subQuery.getParameters()) as SelectQueryBuilder; + if (queryOptions.tsRankBy) { + selectQueryBuilder = this._baseDatabase.orderTsQuery(repo, selectQueryBuilder, queryOptions, 'subTable_'); + } + if (queryOptions.orderBy) { selectQueryBuilder = await this._baseDatabase.orderQuery(repo, selectQueryBuilder, queryOptions, relationsMap.get(entityType), block, 'subTable_'); if (queryOptions.orderBy !== 'id') { @@ -582,6 +590,10 @@ export class GraphDatabase { selectQueryBuilder = this._baseDatabase.buildQuery(repo, selectQueryBuilder, where, relationsMap.get(entityType), block); + if (queryOptions.tsRankBy) { + selectQueryBuilder = this._baseDatabase.orderTsQuery(repo, selectQueryBuilder, queryOptions); + } + if (queryOptions.orderBy) { selectQueryBuilder = await this._baseDatabase.orderQuery(repo, selectQueryBuilder, queryOptions, relationsMap.get(entityType), block); } @@ -644,6 +656,10 @@ export class GraphDatabase { selectQueryBuilder = this._baseDatabase.buildQuery(repo, selectQueryBuilder, where, relationsMap.get(entityType), {}, 'latest'); + if (queryOptions.tsRankBy) { + selectQueryBuilder = this._baseDatabase.orderTsQuery(repo, selectQueryBuilder, queryOptions, '', 'latest'); + } + if (queryOptions.orderBy) { selectQueryBuilder = await this._baseDatabase.orderQuery(repo, selectQueryBuilder, queryOptions, relationsMap.get(entityType), {}, '', 'latest'); } @@ -700,6 +716,10 @@ export class GraphDatabase { selectQueryBuilder = this._baseDatabase.buildQuery(latestEntityRepo, selectQueryBuilder, where, relationsMap.get(entityType), block, 'latest'); + if (queryOptions.tsRankBy) { + selectQueryBuilder = this._baseDatabase.orderTsQuery(latestEntityRepo, selectQueryBuilder, queryOptions, '', 'latest'); + } + if (queryOptions.orderBy) { selectQueryBuilder = await this._baseDatabase.orderQuery(latestEntityRepo, selectQueryBuilder, queryOptions, relationsMap.get(entityType), block, '', 'latest'); }