Skip to content

Commit

Permalink
feat: Use Seqvar and LinearStrucvar whenever possible (#366) (#378)
Browse files Browse the repository at this point in the history
  • Loading branch information
gromdimon authored Jan 10, 2024
1 parent a587af1 commit c35ae0f
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 102 deletions.
16 changes: 8 additions & 8 deletions frontend/src/api/__tests__/acmgSeqvar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe.concurrent('AcmgSeqVar Client', () => {
fetchMocker.mockResponse(JSON.stringify(mockAcmgRating))

const client = new AcmgSeqVarClient()
const result = await client.fetchAcmgRating(seqVar.toName())
const result = await client.fetchAcmgRating(seqVar)

expect(result).toEqual(mockAcmgRating)
})
Expand All @@ -66,7 +66,7 @@ describe.concurrent('AcmgSeqVar Client', () => {
})

const client = new AcmgSeqVarClient()
const result = await client.fetchAcmgRating(seqVar.toName())
const result = await client.fetchAcmgRating(seqVar)

expect(result).toEqual({ status: 500 })
})
Expand All @@ -75,7 +75,7 @@ describe.concurrent('AcmgSeqVar Client', () => {
fetchMocker.mockResponse(JSON.stringify(mockAcmgRating))

const client = new AcmgSeqVarClient()
const result = await client.saveAcmgRating(seqVar.toName(), mockAcmgRating)
const result = await client.saveAcmgRating(seqVar, mockAcmgRating)

expect(result).toEqual(mockAcmgRating)
})
Expand All @@ -89,7 +89,7 @@ describe.concurrent('AcmgSeqVar Client', () => {
})

const client = new AcmgSeqVarClient()
const result = await client.saveAcmgRating(seqVar.toName(), mockAcmgRating)
const result = await client.saveAcmgRating(seqVar, mockAcmgRating)

expect(result).toEqual({ status: 500 })
})
Expand All @@ -98,7 +98,7 @@ describe.concurrent('AcmgSeqVar Client', () => {
fetchMocker.mockResponse(JSON.stringify(mockAcmgRating))

const client = new AcmgSeqVarClient()
const result = await client.updateAcmgRating(seqVar.toName(), mockAcmgRating)
const result = await client.updateAcmgRating(seqVar, mockAcmgRating)

expect(result).toEqual(mockAcmgRating)
})
Expand All @@ -112,7 +112,7 @@ describe.concurrent('AcmgSeqVar Client', () => {
})

const client = new AcmgSeqVarClient()
const result = await client.updateAcmgRating(seqVar.toName(), mockAcmgRating)
const result = await client.updateAcmgRating(seqVar, mockAcmgRating)

expect(result).toEqual({ status: 500 })
})
Expand All @@ -121,7 +121,7 @@ describe.concurrent('AcmgSeqVar Client', () => {
fetchMocker.mockResponse(JSON.stringify({}))

const client = new AcmgSeqVarClient()
const result = await client.deleteAcmgRating(seqVar.toName())
const result = await client.deleteAcmgRating(seqVar)

expect(result).toEqual({})
})
Expand All @@ -135,7 +135,7 @@ describe.concurrent('AcmgSeqVar Client', () => {
})

const client = new AcmgSeqVarClient()
const result = await client.deleteAcmgRating(seqVar.toName())
const result = await client.deleteAcmgRating(seqVar)

expect(result).toEqual({ status: 500 })
})
Expand Down
10 changes: 7 additions & 3 deletions frontend/src/api/__tests__/annonars.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import { AnnonarsClient } from '@/api/annonars'
import * as BRCA1geneInfo from '@/assets/__tests__/BRCA1GeneInfo.json'
import * as BRCA1VariantInfo from '@/assets/__tests__/BRCA1VariantInfo.json'
import * as EMPSearchInfo from '@/assets/__tests__/EMPSearchInfo.json'
import { SeqvarImpl } from '@/lib/genomicVars'

const fetchMocker = createFetchMock(vi)

const seqVar = new SeqvarImpl('grch37', '1', 123, 'A', 'G')

describe.concurrent('Annonars Client', () => {
beforeEach(() => {
fetchMocker.enableMocks()
Expand Down Expand Up @@ -39,7 +42,7 @@ describe.concurrent('Annonars Client', () => {
fetchMocker.mockResponseOnce(JSON.stringify(BRCA1VariantInfo))

const client = new AnnonarsClient()
const result = await client.fetchVariantInfo('grch37', 'chr17', 43044295, 'A', 'G')
const result = await client.fetchVariantInfo(seqVar)
expect(JSON.stringify(result)).toEqual(JSON.stringify(BRCA1VariantInfo))
})

Expand All @@ -52,11 +55,12 @@ describe.concurrent('Annonars Client', () => {
})

const client = new AnnonarsClient()
const result = await client.fetchVariantInfo('grch38', 'chr17', 43044295, 'A', 'G')
const result = await client.fetchVariantInfo(seqVar)
expect(JSON.stringify(result)).toEqual(JSON.stringify(BRCA1VariantInfo))
})

it('fails to fetch variant info with wrong variant', async () => {
const seqVarInvalid = new SeqvarImpl('grch37', '1', 123, 'A', 'T')
fetchMocker.mockResponse((req) => {
if (req.url.includes('alternative=G')) {
return Promise.resolve(JSON.stringify(BRCA1VariantInfo))
Expand All @@ -65,7 +69,7 @@ describe.concurrent('Annonars Client', () => {
})

const client = new AnnonarsClient()
const result = await client.fetchVariantInfo('grch37', 'chr17', 43044295, 'A', 'T')
const result = await client.fetchVariantInfo(seqVarInvalid)
expect(JSON.stringify(result)).toEqual(JSON.stringify({ status: 400 }))
})

Expand Down
26 changes: 13 additions & 13 deletions frontend/src/api/__tests__/mehari.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ import createFetchMock from 'vitest-fetch-mock'
import { MehariClient } from '@/api/mehari'
import * as BRCA1TxInfo from '@/assets/__tests__/BRCA1TxInfo.json'
import * as SVInfo from '@/assets/__tests__/ExampleSVTxInfo.json'
import { SeqvarImpl } from '@/lib/genomicVars'
import { LinearStrucvarImpl } from '@/lib/genomicVars'

const fetchMocker = createFetchMock(vi)

const seqVar = new SeqvarImpl('grch37', '1', 123, 'A', 'G')
const strucVar = new LinearStrucvarImpl('DEL', 'grch37', 'chr17', 43044295, 43044297)

describe.concurrent('Mehari Client', () => {
beforeEach(() => {
fetchMocker.enableMocks()
Expand All @@ -17,26 +22,20 @@ describe.concurrent('Mehari Client', () => {
fetchMocker.mockResponseOnce(JSON.stringify(BRCA1TxInfo))

const client = new MehariClient()
const result = await client.retrieveSeqvarsCsq(
'grch37',
'chr17',
43044295,
'A',
'G',
'HGNC:1100'
)
const result = await client.retrieveSeqvarsCsq(seqVar, 'HGNC:1100')
expect(JSON.stringify(result)).toEqual(JSON.stringify(BRCA1TxInfo))
})

it('fetches TxCsq info correctly without HGNC id', async () => {
fetchMocker.mockResponseOnce(JSON.stringify(BRCA1TxInfo))

const client = new MehariClient()
const result = await client.retrieveSeqvarsCsq('grch37', 'chr17', 43044295, 'A', 'G')
const result = await client.retrieveSeqvarsCsq(seqVar)
expect(JSON.stringify(result)).toEqual(JSON.stringify(BRCA1TxInfo))
})

it('fails to fetch variant info with wrong variant', async () => {
const seqVarInvalid = new SeqvarImpl('grch37', '1', 123, 'A', 'T')
fetchMocker.mockResponse((req) => {
if (req.url.includes('alternative=G')) {
return Promise.resolve(JSON.stringify(BRCA1TxInfo))
Expand All @@ -45,28 +44,29 @@ describe.concurrent('Mehari Client', () => {
})

const client = new MehariClient()
const result = await client.retrieveSeqvarsCsq('grch37', 'chr17', 43044295, 'A', 'T')
const result = await client.retrieveSeqvarsCsq(seqVarInvalid)
expect(JSON.stringify(result)).toEqual(JSON.stringify({ status: 400 }))
})

it('fetches Structur Variant info correctly', async () => {
fetchMocker.mockResponseOnce(JSON.stringify(SVInfo))

const client = new MehariClient()
const result = await client.retrieveStrucvarsCsq('grch37', 'chr17', 43044295, 43044297, 'DEL')
const result = await client.retrieveStrucvarsCsq(strucVar)
expect(JSON.stringify(result)).toEqual(JSON.stringify(SVInfo))
})

it('fails to fetch variant info with wrong variant', async () => {
const strucVarInvalid = new LinearStrucvarImpl('DUP', 'grch37', 'chr17', 43044295, 43044297)
fetchMocker.mockResponse((req) => {
if (req.url.includes('alternative=G')) {
if (req.url.includes('DEL')) {
return Promise.resolve(JSON.stringify(SVInfo))
}
return Promise.resolve(JSON.stringify({ status: 400 }))
})

const client = new MehariClient()
const result = await client.retrieveStrucvarsCsq('grch37', 'chr17', 43044295, 43044297, 'INS')
const result = await client.retrieveStrucvarsCsq(strucVarInvalid)
expect(JSON.stringify(result)).toEqual(JSON.stringify({ status: 400 }))
})
})
19 changes: 10 additions & 9 deletions frontend/src/api/acmgSeqvar.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { API_V1_BASE_PREFIX } from '@/api/common'
import type { SeqvarImpl } from '@/lib/genomicVars'
import { type AcmgRatingBackend } from '@/stores/seqvarAcmgRating'

/**
Expand Down Expand Up @@ -33,11 +34,11 @@ export class AcmgSeqVarClient {
/**
* Obtains the ACMG rating for a variant.
*
* @param variantName The variant to retrieve the ACMG rating for.
* @param seqvar The variant to retrieve the ACMG rating for.
* @returns The ACMG rating for the variant.
*/
async fetchAcmgRating(variantName: string): Promise<any> {
const url = `${this.apiBaseUrl}acmgSeqvar/get?seqvar=${variantName}`
async fetchAcmgRating(seqvar: SeqvarImpl): Promise<any> {
const url = `${this.apiBaseUrl}acmgSeqvar/get?seqvar=${seqvar.toName()}`
const response = await fetch(url, {
method: 'GET',
mode: 'cors',
Expand All @@ -50,11 +51,11 @@ export class AcmgSeqVarClient {
* Save the ACMG rating for a variant.
*/
async saveAcmgRating(
variantName: string,
seqVar: SeqvarImpl,
acmgRating: AcmgRatingBackend
): Promise<AcmgRatingBackend> {
const postData = `{
"seqvar_name": "${variantName}",
"seqvar_name": "${seqVar.toName()}",
"acmg_rank": ${JSON.stringify(acmgRating)}
}`
const response = await fetch(`${this.apiBaseUrl}acmgSeqvar/create`, {
Expand All @@ -74,11 +75,11 @@ export class AcmgSeqVarClient {
* Update the ACMG rating for a variant.
*/
async updateAcmgRating(
variantName: string,
seqVar: SeqvarImpl,
acmgRating: AcmgRatingBackend
): Promise<AcmgRatingBackend> {
const postData = `{
"seqvar_name": "${variantName}",
"seqvar_name": "${seqVar.toName()}",
"acmg_rank": ${JSON.stringify(acmgRating)}
}`
const response = await fetch(`${this.apiBaseUrl}acmgSeqvar/update`, {
Expand All @@ -97,8 +98,8 @@ export class AcmgSeqVarClient {
/**
* Delete the ACMG rating for a variant.
*/
async deleteAcmgRating(variantName: string): Promise<AcmgRatingBackend> {
const response = await fetch(`${this.apiBaseUrl}acmgSeqvar/delete?seqvar=${variantName}`, {
async deleteAcmgRating(seqVar: SeqvarImpl): Promise<AcmgRatingBackend> {
const response = await fetch(`${this.apiBaseUrl}acmgSeqvar/delete?seqvar=${seqVar.toName()}`, {
method: 'DELETE',
mode: 'cors',
credentials: 'include'
Expand Down
38 changes: 14 additions & 24 deletions frontend/src/api/annonars.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { chunks } from '@reactgular/chunks'

import { API_INTERNAL_BASE_PREFIX_ANNONARS } from '@/api/common'
import type { LinearStrucvar, Seqvar } from '@/lib/genomicVars'

const API_BASE_URL = `${API_INTERNAL_BASE_PREFIX_ANNONARS}/`

Expand Down Expand Up @@ -28,28 +29,19 @@ export class AnnonarsClient {
/**
* Fetch variant information via annonars and mehari REST APIs.
*
* @param genomeRelease GRCh37 or GRCh38.
* @param chromosome Chromosome, e.g., `"chr1"`.
* @param pos Position of the variant.
* @param reference Reference nucleotide, e.g., `"A"`.
* @param alternative Alternative nucleotide, e.g., `"G"`.
* @param seqvar The variant to retrieve the information for.
*/
async fetchVariantInfo(
genomeRelease: string,
chromosome: string,
pos: number,
reference: string,
alternative: string
): Promise<any> {
let chrom = chromosome.replace('chr', '')
if (genomeRelease !== 'grch37') {
chrom = `chr${chrom}`
async fetchVariantInfo(seqvar: Seqvar): Promise<any> {
const { genomeBuild, chrom, pos, del, ins } = seqvar
let chromosome = chrom.replace('chr', '')
if (genomeBuild !== 'grch37') {
chromosome = `chr${chrom}`
}

const url =
`${this.apiBaseUrl}annos/variant?genome_release=${genomeRelease}&` +
`chromosome=${chrom}&pos=${pos}&reference=${reference}&` +
`alternative=${alternative}`
`${this.apiBaseUrl}annos/variant?genome_release=${genomeBuild}&` +
`chromosome=${chromosome}&pos=${pos}&reference=${del}&` +
`alternative=${ins}`

const response = await fetch(url, {
method: 'GET'
Expand Down Expand Up @@ -105,16 +97,14 @@ export class AnnonarsClient {
* Fetch overlapping ClinVar strucvars via annonars REST API.
*/
async fetchClinvarStrucvars(
genomeRelease: string,
chromosome: string,
start: number,
end: number,
strucvar: LinearStrucvar,
pageSize: number = 1000,
minOverlap: number = 0.1
): Promise<any> {
const { genomeBuild, chrom, start, stop } = strucvar
const url =
`${this.apiBaseUrl}clinvar-sv/query?genomeRelease=${genomeRelease}&` +
`chromosome=${chromosome}&start=${start}&stop=${end}&pageSize=${pageSize}&` +
`${this.apiBaseUrl}clinvar-sv/query?genomeRelease=${genomeBuild}&` +
`chromosome=${chrom}&start=${start}&stop=${stop}&pageSize=${pageSize}&` +
`minOverlap=${minOverlap}`

const response = await fetch(url, {
Expand Down
30 changes: 10 additions & 20 deletions frontend/src/api/mehari.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { API_INTERNAL_BASE_PREFIX_MEHARI } from '@/api/common'
import type { LinearStrucvar, Seqvar } from '@/lib/genomicVars'

const API_BASE_URL = `${API_INTERNAL_BASE_PREFIX_MEHARI}/`

Expand All @@ -11,36 +12,25 @@ export class MehariClient {
this.csrfToken = csrfToken ?? null
}

async retrieveSeqvarsCsq(
genomeRelease: string,
chromosome: string,
pos: number,
reference: string,
alternative: string,
hgnc_id?: string
): Promise<any> {
async retrieveSeqvarsCsq(seqvar: Seqvar, hgnc_id?: string): Promise<any> {
const { genomeBuild, chrom, pos, del, ins } = seqvar
const hgncSuffix = hgnc_id ? `&hgnc_id=${hgnc_id}` : ''
const url =
`${this.apiBaseUrl}seqvars/csq?genome_release=${genomeRelease}&` +
`chromosome=${chromosome}&position=${pos}&reference=${reference}&` +
`alternative=${alternative}${hgncSuffix}`
`${this.apiBaseUrl}seqvars/csq?genome_release=${genomeBuild}&` +
`chromosome=${chrom}&position=${pos}&reference=${del}&` +
`alternative=${ins}${hgncSuffix}`

const response = await fetch(url, {
method: 'GET'
})
return await response.json()
}

async retrieveStrucvarsCsq(
genomeRelease: string,
chromosome: string,
start: number,
stop: number,
sv_type: string
): Promise<any> {
async retrieveStrucvarsCsq(strucvar: LinearStrucvar): Promise<any> {
const { genomeBuild, chrom, start, stop, svType } = strucvar
const url =
`${this.apiBaseUrl}strucvars/csq?genome_release=${genomeRelease}&` +
`chromosome=${chromosome}&start=${start}&stop=${stop}&sv_type=${sv_type}`
`${this.apiBaseUrl}strucvars/csq?genome_release=${genomeBuild}&` +
`chromosome=${chrom}&start=${start}&stop=${stop}&sv_type=${svType}`
const response = await fetch(url, {
method: 'GET'
})
Expand Down
Loading

0 comments on commit c35ae0f

Please sign in to comment.