diff --git a/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.test.ts b/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.test.ts index 3557bbf513..a06c91f26d 100644 --- a/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.test.ts +++ b/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.test.ts @@ -6,50 +6,89 @@ import last from '../../test_data/names/f.json' import Adapter from './JBrowse1TextSearchAdapter' import configSchema from './configSchema' -test('adapter can fetch files from names index', async () => { - function mockFetch(url: string): Promise { - let response = {} - if (url.includes('names/meta.json')) { - response = meta - } - if (url.includes('names/0.json')) { - response = first - } - if (url.includes('names/f.json')) { - response = last - } - return Promise.resolve(new Response(JSON.stringify(response))) +function mockFetch(url: string) { + let response = {} + if (url.includes('names/meta.json')) { + response = meta } + if (url.includes('names/0.json')) { + response = first + } + if (url.includes('names/f.json')) { + response = last + } + return Promise.resolve(new Response(JSON.stringify(response))) +} - const rootTemplate = path - .join(__dirname, '..', '..', '..', '..', 'test_data', 'names') - .replace(/\\/g, '\\\\') +const rootTemplate = path + .join(__dirname, '..', '..', '..', '..', 'test_data', 'names') + .replace(/\\/g, '\\\\') +test('search upper case', async () => { const spy = jest.spyOn(global, 'fetch') // eslint-disable-next-line @typescript-eslint/no-explicit-any spy.mockImplementation(mockFetch as any) - const urlPath = decodeURI(new URL(`file://${rootTemplate}`).href) - const args = { - type: 'JBrowse1TextSearchAdapter', - textSearchAdapterId: 'JBrowse1GenerateNamesAdapterTest', - namesIndexLocation: { - uri: urlPath, - locationType: 'UriLocation', - }, - } - // create adapter - const adapter = new Adapter(configSchema.create(args)) - // prefix search + const adapter = new Adapter( + configSchema.create({ + type: 'JBrowse1TextSearchAdapter', + textSearchAdapterId: 'JBrowse1GenerateNamesAdapterTest', + namesIndexLocation: { + uri: decodeURI(new URL(`file://${rootTemplate}`).href), + locationType: 'UriLocation', + }, + }), + ) + const results = await adapter.searchIndex({ + searchType: 'prefix', + queryString: 'Apple', + }) + // check results are of type BaseResult for prefix search + expect(results.length).toBeGreaterThan(0) + expect(results[0] instanceof BaseResult).toBeTruthy() + expect(results[0].getLabel()).toEqual('Apple1') + expect(results[1].getLabel()).toEqual('Apple2') + expect(results[2].getLabel()).toEqual('Apple3') + + // exact search + const results2 = await adapter.searchIndex({ + searchType: 'exact', + queryString: 'Apple3', + }) + // check results are of type location for exact search + expect(results2.length).toEqual(5) + expect(results2.length).toBeGreaterThan(0) + expect(results2[0] instanceof BaseResult).toBeTruthy() + expect(results2[0].getLabel()).toEqual('Apple3') + expect(results2[0].getLocation()).toEqual('ctgA:17399-23000') +}) + +test('search lower case', async () => { + const spy = jest.spyOn(global, 'fetch') + // eslint-disable-next-line @typescript-eslint/no-explicit-any + spy.mockImplementation(mockFetch as any) + + const adapter = new Adapter( + configSchema.create({ + type: 'JBrowse1TextSearchAdapter', + textSearchAdapterId: 'JBrowse1GenerateNamesAdapterTest', + namesIndexLocation: { + uri: decodeURI(new URL(`file://${rootTemplate}`).href), + locationType: 'UriLocation', + }, + }), + ) const results = await adapter.searchIndex({ searchType: 'prefix', queryString: 'apple', }) // check results are of type BaseResult for prefix search + expect(results.length).toBeGreaterThan(0) expect(results[0] instanceof BaseResult).toBeTruthy() expect(results[0].getLabel()).toEqual('Apple1') expect(results[1].getLabel()).toEqual('Apple2') expect(results[2].getLabel()).toEqual('Apple3') + // exact search const results2 = await adapter.searchIndex({ searchType: 'exact', @@ -57,8 +96,8 @@ test('adapter can fetch files from names index', async () => { }) // check results are of type location for exact search expect(results2.length).toEqual(5) - const test2 = results2[0] - expect(test2 instanceof BaseResult).toBeTruthy() - expect(test2.getLabel()).toEqual('Apple3') - expect(test2.getLocation()).toEqual('ctgA:17399-23000') + expect(results2.length).toBeGreaterThan(0) + expect(results2[0] instanceof BaseResult).toBeTruthy() + expect(results2[0].getLabel()).toEqual('Apple3') + expect(results2[0].getLocation()).toEqual('ctgA:17399-23000') }) diff --git a/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.ts b/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.ts index 709f12dfe2..511af73240 100644 --- a/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.ts +++ b/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.ts @@ -4,9 +4,10 @@ import { BaseAdapter, } from '@jbrowse/core/data_adapters/BaseAdapter' import BaseResult from '@jbrowse/core/TextSearch/BaseResults' -import { Instance } from 'mobx-state-tree' -import { readConfObject } from '@jbrowse/core/configuration' -import MyConfigSchema from './configSchema' +import { + AnyConfigurationModel, + readConfObject, +} from '@jbrowse/core/configuration' import HttpMap from './HttpMap' import PluginManager from '@jbrowse/core/PluginManager' import { getSubAdapterType } from '@jbrowse/core/data_adapters/dataAdapterCache' @@ -23,7 +24,8 @@ interface SearchResults { export type NamesIndexRecord = string | Array -// Jbrowse1 text search adapter +type IndexFile = Record + // Uses index built by generate-names.pl export default class JBrowse1TextSearchAdapter extends BaseAdapter @@ -34,19 +36,15 @@ export default class JBrowse1TextSearchAdapter tracksNames?: string[] constructor( - config: Instance, + config: AnyConfigurationModel, getSubAdapter?: getSubAdapterType, pluginManager?: PluginManager, ) { super(config, getSubAdapter, pluginManager) - const namesIndexLocation = readConfObject(config, 'namesIndexLocation') - if (!namesIndexLocation) { - throw new Error('must provide namesIndexLocation') - } + const namesIndex = readConfObject(config, 'namesIndexLocation') + const { baseUri, uri } = namesIndex this.httpMap = new HttpMap({ - url: namesIndexLocation.baseUri - ? new URL(namesIndexLocation.uri, namesIndexLocation.baseUri).href - : namesIndexLocation.uri, + url: baseUri ? new URL(uri, baseUri).href : uri, }) } @@ -55,30 +53,31 @@ export default class JBrowse1TextSearchAdapter * else it returns empty * @param query - string query */ - async loadIndexFile(query: string): Promise> { + async loadIndexFile(query: string): Promise { return this.httpMap.getBucket(query) } async searchIndex(args: BaseArgs) { const { searchType, queryString } = args const tracks = this.tracksNames || (await this.httpMap.getTrackNames()) - const entries = await this.loadIndexFile(queryString.toLowerCase()) - if (entries[queryString]) { - return this.formatResults(entries[queryString], tracks, searchType) - } - return [] + const str = queryString.toLowerCase() + const entries = await this.loadIndexFile(str) + return entries[str] + ? this.formatResults(entries[str], tracks, searchType) + : [] } formatResults(results: SearchResults, tracks: string[], searchType?: string) { return [ ...(searchType === 'exact' ? [] - : results.prefix.map(result => { - return new BaseResult({ - label: typeof result === 'object' ? result.name : result, - matchedAttribute: 'name', - matchedObject: { result: result }, - }) - })), + : results.prefix.map( + result => + new BaseResult({ + label: typeof result === 'object' ? result.name : result, + matchedAttribute: 'name', + matchedObject: { result: result }, + }), + )), ...results.exact.map(result => { const name = result[0] const trackIndex = result[1]