-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: adding GeneLiteratureCard (#30)
- Loading branch information
Showing
14 changed files
with
11,828 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { SearchResult } from './types' | ||
|
||
export * from './types' | ||
|
||
/** API base URL to use. */ | ||
const API_BASE_URL = '/internal/proxy/pubtator3-api' | ||
|
||
/** | ||
* Client for PubTator V3 API queries. | ||
*/ | ||
export class PubtatorClient { | ||
/** API base URL to use in this client instance. */ | ||
private apiBaseUrl: string | ||
|
||
/** | ||
* Create a new PubTator client. | ||
* | ||
* @param apiBaseUrl The API base URL to use, defaults to `API_BASE_URL`. | ||
*/ | ||
constructor(apiBaseUrl?: string) { | ||
this.apiBaseUrl = apiBaseUrl ?? API_BASE_URL | ||
} | ||
|
||
/** | ||
* Perform search for the given HGNC symbol. | ||
* | ||
* @param hgncSymbol HGNC symbol to search for. | ||
* @returns Promise for the search results. | ||
* @throws Error if the search fails. | ||
*/ | ||
async performSearch(hgncSymbol: string): Promise<{ [key: string]: SearchResult }> { | ||
const url = `${this.apiBaseUrl}/search/?text=@GENE_${hgncSymbol}` | ||
const searchRes = await fetch(url, { | ||
method: 'GET' | ||
}) | ||
if (!searchRes.ok) { | ||
throw new Error(`Error running PubTator 3 search: ${searchRes.statusText}`) | ||
} | ||
const searchData = await searchRes.json() | ||
|
||
// Then, extract PMID list and retrieve biocjson for the PMIDs | ||
const pmids: string[] = searchData!.results!.map((doc: any) => doc.pmid) | ||
const exportRes = await fetch( | ||
`${this.apiBaseUrl}}/publications/export/biocjson` + `?pmids=${pmids.join(',')}` | ||
) | ||
if (!exportRes.ok) { | ||
throw new Error(`Error running PubTator 3 export: ${exportRes.statusText}`) | ||
} | ||
const exportDataText = await exportRes.text() | ||
const exportDataLines = exportDataText.split(/\n/) | ||
|
||
// Zip search results and exports into searchResults | ||
const searchResults: { [key: string]: SearchResult } = {} | ||
for (const searchDataRecord of searchData.results) { | ||
searchResults[searchDataRecord.pmid] = { | ||
searchResult: searchDataRecord, | ||
abstract: undefined | ||
} | ||
} | ||
for (const exportDataLine of exportDataLines) { | ||
if (exportDataLine) { | ||
const exportDataRecord = JSON.parse(exportDataLine) | ||
searchResults[exportDataRecord.pmid].abstract = exportDataRecord | ||
} | ||
} | ||
|
||
return searchResults | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/** Interface for search result entry plus PubMed abstract. */ | ||
export interface SearchResult { | ||
/** The search result record. */ | ||
searchResult: any | ||
/** The PubMed abstract. */ | ||
abstract: any | ||
} |
62 changes: 62 additions & 0 deletions
62
src/components/GeneLiteratureCard/GeneLiteratureCard.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import fs from 'fs' | ||
import path from 'path' | ||
import { describe, expect, test } from 'vitest' | ||
|
||
import { setupMountedComponents } from '../../lib/testUtils' | ||
import { Record as GeneInfoRecord } from '../../pbs/annonars/genes/base' | ||
import { SearchResults } from '../../store/pubtator' | ||
import { StoreState } from '../../store/types' | ||
import GeneLiteratureCard from './GeneLiteratureCard.vue' | ||
|
||
// Load fixture data for gene TGDS (little data) and BRCA1 (lots of data). | ||
const geneInfoTgds = GeneInfoRecord.fromJsonString( | ||
fs.readFileSync( | ||
path.resolve(__dirname, '../GenePathogenicityCard/fixture.geneInfo.TGDS.json'), | ||
'utf8' | ||
) | ||
) | ||
const geneInfoBrca1 = GeneInfoRecord.fromJsonString( | ||
fs.readFileSync( | ||
path.resolve(__dirname, '../GenePathogenicityCard/fixture.geneInfo.BRCA1.json'), | ||
'utf8' | ||
) | ||
) | ||
const searchResultsTgds = JSON.parse( | ||
fs.readFileSync(path.resolve(__dirname, './fixture.pubtatorResults.TGDS.json'), 'utf8') | ||
) as SearchResults | ||
const searchResultsBrca1 = JSON.parse( | ||
fs.readFileSync(path.resolve(__dirname, './fixture.pubtatorResults.BRCA1.json'), 'utf8') | ||
) as SearchResults | ||
|
||
describe.concurrent('GeneLiteratureCard.vue', async () => { | ||
test.each([ | ||
['BRCA1', geneInfoBrca1, searchResultsBrca1], | ||
['TGDS', geneInfoTgds, searchResultsTgds] | ||
])( | ||
'renders for gene %s', | ||
async (hgncSymbol: string, geneInfo: GeneInfoRecord, searchResults: SearchResults) => { | ||
// arrange: | ||
const { wrapper } = await setupMountedComponents( | ||
{ component: GeneLiteratureCard }, | ||
{ | ||
props: { | ||
geneInfo | ||
}, | ||
initialStoreState: { | ||
pubtatorStore: { | ||
storeState: StoreState.Active, | ||
hgncSymbol, | ||
searchResults | ||
} | ||
} | ||
} | ||
) | ||
|
||
// act: nothing, only test rendering | ||
|
||
// assert: | ||
const vCards = wrapper.findAllComponents({ name: 'VCard' }) | ||
expect(vCards.length).toBe(1) | ||
} | ||
) | ||
}) |
65 changes: 65 additions & 0 deletions
65
src/components/GeneLiteratureCard/GeneLiteratureCard.stories.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { JsonValue } from '@protobuf-ts/runtime' | ||
import type { Meta, StoryObj } from '@storybook/vue3' | ||
|
||
import { Record as GeneInfoRecord } from '../../pbs/annonars/genes/base' | ||
import { StoreState } from '../../store' | ||
import { usePubtatorStore } from '../../store/pubtator' | ||
import geneInfoBrca1Json from '../GenePathogenicityCard/fixture.geneInfo.BRCA1.json' | ||
import geneInfoTgdsJson from '../GenePathogenicityCard/fixture.geneInfo.TGDS.json' | ||
import GeneLiteratureCard from './GeneLiteratureCard.vue' | ||
import searchResultsBrca1Json from './fixture.pubtatorResults.BRCA1.json' | ||
import searchResultsTgdsJson from './fixture.pubtatorResults.TGDS.json' | ||
|
||
// Here, fixture data is loaded via `import` from JSON file. Reading the file | ||
// as in the tests fails with "process is not defined" error in the browser. | ||
|
||
// @ts-ignore | ||
const geneInfoTgds = GeneInfoRecord.fromJson(geneInfoTgdsJson as JsonValue) | ||
// @ts-ignore | ||
const geneInfoBrca1 = GeneInfoRecord.fromJson(geneInfoBrca1Json as JsonValue) | ||
|
||
const meta = { | ||
title: 'Gene/GeneLiteratureCard', | ||
component: GeneLiteratureCard, | ||
tags: ['autodocs'], | ||
argTypes: { | ||
geneInfo: { control: { type: 'object' } } | ||
}, | ||
args: { | ||
geneInfo: geneInfoTgds, | ||
skipLoadViaStore: true | ||
} | ||
} satisfies Meta<typeof GeneLiteratureCard> | ||
|
||
export default meta | ||
|
||
type Story = StoryObj<typeof meta> | ||
|
||
export const TGDS: Story = { | ||
args: { | ||
geneInfo: geneInfoTgds | ||
}, | ||
play: async () => { | ||
// Setup the store contents after story selection. | ||
const pubtatorStore = usePubtatorStore() | ||
pubtatorStore.storeState = StoreState.Loading | ||
pubtatorStore.hgncSymbol = 'TGDS' | ||
pubtatorStore.searchResults = searchResultsTgdsJson | ||
pubtatorStore.storeState = StoreState.Active | ||
} | ||
} | ||
|
||
export const BRCA1: Story = { | ||
args: { | ||
geneInfo: geneInfoBrca1 | ||
}, | ||
play: async () => { | ||
console.log('play...') | ||
// Setup the store contents after story selection. | ||
const pubtatorStore = usePubtatorStore() | ||
pubtatorStore.storeState = StoreState.Loading | ||
pubtatorStore.hgncSymbol = 'BRCA1' | ||
pubtatorStore.searchResults = searchResultsBrca1Json | ||
pubtatorStore.storeState = StoreState.Active | ||
} | ||
} |
Oops, something went wrong.