Merge pull request #7726 from szubster/lunr-filter-single-item-array

Handle single-item array filter in Lunr search engine
This commit is contained in:
Camila Belo
2021-10-22 08:32:17 +02:00
committed by GitHub
3 changed files with 43 additions and 1 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-search-backend-node': patch
---
Handle special case when filter array has single value optimizing Lunr search behaviour.
@@ -192,6 +192,37 @@ describe('LunrSearchEngine', () => {
});
});
it('should handle single-item array filter as scalar value', async () => {
const inspectableSearchEngine = new LunrSearchEngineForTranslatorTests({
logger: getVoidLogger(),
});
const translatorUnderTest = inspectableSearchEngine.getTranslator();
const actualTranslatedQuery = translatorUnderTest({
term: 'testTerm',
filters: { kind: ['testKind'] },
}) as ConcreteLunrQuery;
expect(actualTranslatedQuery).toMatchObject({
documentTypes: undefined,
lunrQueryBuilder: expect.any(Function),
});
const query: jest.Mocked<lunr.Query> = {
allFields: ['kind'],
clauses: [],
term: jest.fn(),
clause: jest.fn(),
};
actualTranslatedQuery.lunrQueryBuilder.bind(query)(query);
expect(query.term).toBeCalledWith(lunr.tokenizer('testKind'), {
fields: ['kind'],
presence: lunr.Query.presence.REQUIRED,
});
});
it('should return translated query with multiple filters', async () => {
const inspectableSearchEngine = new LunrSearchEngineForTranslatorTests({
logger: getVoidLogger(),
@@ -80,11 +80,17 @@ export class LunrSearchEngine implements SearchEngine {
});
if (filters) {
Object.entries(filters).forEach(([field, value]) => {
Object.entries(filters).forEach(([field, fieldValue]) => {
if (!q.allFields.includes(field)) {
// Throw for unknown field, as this will be a non match
throw new Error(`unrecognised field ${field}`);
}
// Arrays are poorly supported, but we can make it better for single-item arrays,
// which should be a common case
const value =
Array.isArray(fieldValue) && fieldValue.length === 1
? fieldValue[0]
: fieldValue;
// Require that the given field has the given value
if (['string', 'number', 'boolean'].includes(typeof value)) {