Support full text searches across multiple search keys, not just the sort order key.

Signed-off-by: Aramis Sennyey <sennyeya@amazon.com>
This commit is contained in:
Aramis Sennyey
2023-03-16 17:17:41 -04:00
parent 893f69c8ba
commit ab31d8a7fd
2 changed files with 70 additions and 4 deletions
@@ -1119,6 +1119,64 @@ describe('DefaultEntitiesCatalog', () => {
},
);
it.each(databases.eachSupportedId())(
'should filter the text results when sortOrder is not provided, %p',
async databaseId => {
await createDatabase(databaseId);
const names = ['lion', 'cat', 'atcatss', 'dog', 'dogcat', 'aa', 's'];
const entities: Entity[] = names.map(name =>
// Need a stable search since default filtering is by uid, and those get generated on the fly
// during the test case.
entityFrom(name, { uid: name }),
);
const notFoundEntities: Entity[] = [
{
apiVersion: 'a',
kind: 'k',
metadata: { name: 'something' },
spec: {},
},
{
apiVersion: 'a',
kind: 'k',
metadata: { name: 'something else' },
spec: {},
},
];
await Promise.all(
entities.concat(notFoundEntities).map(e => addEntityToSearch(e)),
);
const catalog = new DefaultEntitiesCatalog({
database: knex,
logger: getVoidLogger(),
stitcher,
});
const filter = {
key: 'spec.should_include_this',
};
const request: QueryEntitiesInitialRequest = {
filter,
limit: 100,
fullTextFilter: { term: 'cAt ', fields: ['metadata.name'] },
};
const response = await catalog.queryEntities(request);
expect(response.items).toEqual([
entityFrom('atcatss', { uid: 'atcatss' }),
entityFrom('cat', { uid: 'cat' }),
entityFrom('dogcat', { uid: 'dogcat' }),
]);
expect(response.pageInfo.nextCursor).toBeUndefined();
expect(response.pageInfo.prevCursor).toBeUndefined();
expect(response.totalItems).toBe(3);
},
);
it.each(databases.eachSupportedId())(
'should include totalItems and empty entities in the response in case limit is zero, %p',
async databaseId => {
@@ -51,6 +51,7 @@ import {
} from '../database/tables';
import { Stitcher } from '../stitching/Stitcher';
import { parseFullTextFilterFields } from './request/parseFullTextFilterFields';
import {
isQueryEntitiesCursorRequest,
@@ -382,11 +383,18 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog {
}
const normalizedFullTextFilterTerm = cursor.fullTextFilter?.term?.trim();
const textFilterFields = cursor.fullTextFilter?.fields ?? [sortField.field];
if (normalizedFullTextFilterTerm) {
dbQuery.andWhereRaw(
'value like ?',
`%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`,
);
const matchQuery = db<DbSearchRow>('search')
.select('search.entity_id')
.whereIn('key', textFilterFields)
.andWhere(function keyFilter() {
this.andWhereRaw(
'value like ?',
`%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`,
);
});
dbQuery.andWhere('search.entity_id', 'in', matchQuery);
}
const countQuery = dbQuery.clone();