Make the QueryTranslator a more integral part of the SearchEngine API

Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
Eric Peterson
2021-06-01 11:48:04 +02:00
parent 455b97b127
commit 8cb45d747a
3 changed files with 58 additions and 12 deletions
@@ -18,6 +18,15 @@ import { getVoidLogger } from '@backstage/backend-common';
import { LunrSearchEngine } from './LunrSearchEngine';
import { SearchEngine } from '../types';
/**
* Just used to test the default translator shipped with LunrSearchEngine.
*/
class LunrSearchEngineForTranslatorTests extends LunrSearchEngine {
getTranslator() {
return this.translator;
}
}
describe('LunrSearchEngine', () => {
let testLunrSearchEngine: SearchEngine;
@@ -27,16 +36,21 @@ describe('LunrSearchEngine', () => {
describe('translator', () => {
it('query translator invoked', async () => {
const translatorSpy = jest.spyOn(testLunrSearchEngine, 'translator');
// Given: Set a translator spy on the search engine.
const translatorSpy = jest.fn().mockReturnValue({
lunrQueryString: '',
documentTypes: [],
});
testLunrSearchEngine.setTranslator(translatorSpy);
// Translate query and ensure the translator was invoked.
await testLunrSearchEngine.translator({
// When: querying the search engine
testLunrSearchEngine.query({
term: 'testTerm',
filters: {},
pageCursor: '',
});
expect(translatorSpy).toHaveBeenCalled();
// Then: the translator is invoked with expected args.
expect(translatorSpy).toHaveBeenCalledWith({
term: 'testTerm',
filters: {},
@@ -45,39 +59,54 @@ describe('LunrSearchEngine', () => {
});
it('should return translated query', async () => {
const mockedTranslatedQuery = await testLunrSearchEngine.translator({
const inspectableSearchEngine = new LunrSearchEngineForTranslatorTests({
logger: getVoidLogger(),
});
const translatorUnderTest = inspectableSearchEngine.getTranslator();
const actualTranslatedQuery = translatorUnderTest({
term: 'testTerm',
filters: {},
pageCursor: '',
});
expect(mockedTranslatedQuery).toMatchObject({
expect(actualTranslatedQuery).toMatchObject({
documentTypes: ['*'],
lunrQueryString: '+testTerm',
});
});
it('should return translated query with 1 filter', async () => {
const mockedTranslatedQuery = await testLunrSearchEngine.translator({
const inspectableSearchEngine = new LunrSearchEngineForTranslatorTests({
logger: getVoidLogger(),
});
const translatorUnderTest = inspectableSearchEngine.getTranslator();
const actualTranslatedQuery = translatorUnderTest({
term: 'testTerm',
filters: { kind: 'testKind' },
pageCursor: '',
});
expect(mockedTranslatedQuery).toMatchObject({
expect(actualTranslatedQuery).toMatchObject({
documentTypes: ['*'],
lunrQueryString: '+testTerm +kind:testKind',
});
});
it('should return translated query with multiple filters', async () => {
const mockedTranslatedQuery = await testLunrSearchEngine.translator({
const inspectableSearchEngine = new LunrSearchEngineForTranslatorTests({
logger: getVoidLogger(),
});
const translatorUnderTest = inspectableSearchEngine.getTranslator();
const actualTranslatedQuery = translatorUnderTest({
term: 'testTerm',
filters: { kind: 'testKind', namespace: 'testNameSpace' },
pageCursor: '',
});
expect(mockedTranslatedQuery).toMatchObject({
expect(actualTranslatedQuery).toMatchObject({
documentTypes: ['*'],
lunrQueryString: '+testTerm +kind:testKind +namespace:testNameSpace',
});
@@ -33,6 +33,8 @@ type LunrResultEnvelope = {
type: string;
};
type LunrQueryTranslator = (query: SearchQuery) => ConcreteLunrQuery;
export class LunrSearchEngine implements SearchEngine {
protected lunrIndices: Record<string, lunr.Index> = {};
protected docStore: Record<string, IndexableDocument>;
@@ -43,7 +45,7 @@ export class LunrSearchEngine implements SearchEngine {
this.docStore = {};
}
translator: QueryTranslator = ({
protected translator: QueryTranslator = ({
term,
filters,
types,
@@ -82,6 +84,10 @@ export class LunrSearchEngine implements SearchEngine {
};
};
setTranslator(translator: LunrQueryTranslator) {
this.translator = translator;
}
index(type: string, documents: IndexableDocument[]): void {
const lunrBuilder = new lunr.Builder();
// Make this lunr index aware of all relevant fields.
+12 -1
View File
@@ -59,7 +59,18 @@ export type QueryTranslator = (query: SearchQuery) => unknown;
* concrete, search engine-specific queries.
*/
export interface SearchEngine {
translator: QueryTranslator;
/**
* Override the default translator provided by the SearchEngine.
*/
setTranslator(translator: QueryTranslator): void;
/**
* Add the given documents to the SearchEngine index of the given type.
*/
index(type: string, documents: IndexableDocument[]): void;
/**
* Perform a search query against the SearchEngine.
*/
query(query: SearchQuery): Promise<SearchResultSet>;
}