Skip to content

Commit

Permalink
feat: adding breakpoint SV type support to library (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
holtgrewe authored Feb 23, 2024
1 parent c6267b2 commit eb519cc
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 12 deletions.
11 changes: 8 additions & 3 deletions src/api/annonars/client.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { chunks } from '@reactgular/chunks'

import type { LinearStrucvar, Seqvar } from '../../lib/genomicVars'
import type { Seqvar, Strucvar } from '../../lib/genomicVars'
import { urlConfig } from '../../lib/urlConfig'
import { ClinvarPerGeneRecord } from '../../pbs/annonars/clinvar/per_gene'
import { Record as GeneInfoRecord } from '../../pbs/annonars/genes/base'
Expand Down Expand Up @@ -150,11 +150,16 @@ export class AnnonarsClient {
* Fetch overlapping ClinVar strucvars via annonars REST API.
*/
async fetchClinvarStrucvars(
strucvar: LinearStrucvar,
strucvar: Strucvar,
pageSize: number = 1000,
minOverlap: number = 0.1
): Promise<ClinvarSvQueryResponse> {
const { genomeBuild, chrom, start, stop } = strucvar
const { svType, genomeBuild, chrom, start, stop } = strucvar
if (svType === 'BND') {
// We don't properly support ClinVar BNDs (and there will be few..)
return { records: [] }
}

const url =
`${this.apiBaseUrl}/clinvar-sv/query?genomeRelease=${genomeBuild}&` +
`chromosome=${chrom}&start=${start}&stop=${stop}&pageSize=${pageSize}&` +
Expand Down
4 changes: 2 additions & 2 deletions src/api/mehari/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { LinearStrucvar, Seqvar } from '../../lib/genomicVars'
import type { Seqvar, Strucvar } from '../../lib/genomicVars'
import { urlConfig } from '../../lib/urlConfig'
import { GeneTranscriptsResponse } from '../../pbs/mehari/server'
import { GenomeBuild } from '../../pbs/mehari/txs'
Expand Down Expand Up @@ -58,7 +58,7 @@ export class MehariClient {
* @returns The response from the API.
* @throws Error if the API request fails.
*/
async retrieveStrucvarsCsq(strucvar: LinearStrucvar): Promise<StrucvarResult> {
async retrieveStrucvarsCsq(strucvar: Strucvar): Promise<StrucvarResult> {
const { genomeBuild, chrom, start, stop, svType } = strucvar
const url =
`${this.apiBaseUrl}/strucvars/csq?genome_release=${genomeBuild}&` +
Expand Down
119 changes: 112 additions & 7 deletions src/lib/genomicVars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,11 @@ export const REGEX_CNV_COLON =
export const REGEX_CNV_HYPHEN =
/^(?<svType>DEL|DUP)-(?:(?:(?:(?<genomeBuild>(?:\w+))-)?(?<chrom>(?:chr)?(?:[1-9]|1[0-9]|2[0-2]|X|Y|M|MT)))|(?<sequence>NC_(?:\d\d\d\d\d\d\.\d+)))-(?<start>\d+)-(?<stop>\d+)$/i

/** CNV types. */
export type CnvType = 'DEL' | 'DUP'

/** Currently supported SV types. */
export type SvType = 'DEL' | 'DUP'
export type SvType = CnvType | 'INV' | 'BND'

/** Interface for regex groups when parsing with `REGEX_CNV_COLON` or `REGEX_CNV_HYPHEN`. */
export interface RegexCnvGroups {
Expand Down Expand Up @@ -319,13 +322,13 @@ export function parseCanonicalSpdiSeqvar(value: string): Seqvar {
}

/**
* Interface that describes a canonical DEL or DUP strucvar.
* Interface that describes a canonical DEL, DUP, or INV strucvar.
*
* This will later be extended to inversions as well.
*/
export interface LinearStrucvar {
/** The type of the SV. */
svType: 'DEL' | 'DUP'
svType: 'DEL' | 'DUP' | 'INV'
/** The genome build. */
genomeBuild: GenomeBuild
/**
Expand All @@ -347,7 +350,7 @@ export interface LinearStrucvar {
* Implementation of the `LinearStrucvar` interface.
*/
export class LinearStrucvarImpl implements LinearStrucvar {
svType: 'DEL' | 'DUP'
svType: 'DEL' | 'DUP' | 'INV'
genomeBuild: GenomeBuild
chrom: string
start: number
Expand All @@ -356,7 +359,7 @@ export class LinearStrucvarImpl implements LinearStrucvar {
userRepr: string

constructor(
svType: 'DEL' | 'DUP',
svType: 'DEL' | 'DUP' | 'INV',
genomeBuild: GenomeBuild,
chrom: string,
start: number,
Expand Down Expand Up @@ -395,8 +398,110 @@ export function linearStrucvarImplFromLinearStrucvar(variant: LinearStrucvar): L
)
}

/**
* The strand orientation of a breakend.
*/
export enum StrandOrientation {
/** 3' to 3' */
THREE_TO_THREE = '3to3',
/** 5' to 3' */
FIVE_TO_THREE = '5to3',
/** 3' to 5' */
THREE_TO_FIVE = '3to5',
/** 5' to 5' */
FIVE_TO_FIVE = '5to5',
/** not applicable or unknown */
NOT_APPLICABLE = 'NtoN'
}

/**
* Interface that describes a breakend.
*/
export interface BreakendStrucvar {
/** The type of the SV. */
svType: 'BND'
/** The genome build. */
genomeBuild: GenomeBuild
/**
* Canonical chromomsome name "1", .., "22", "X", "Y", "MT" **without**
* `chr` prefix.
*/
chrom: string
/** Canonical chromosome of the second end. */
chrom2: string
/** The 1-based start position. */
start: number
/** The 1-based stop position (on second end). */
stop: number
/** Strand orientation */
strandOrientation: StrandOrientation
/** The user-facing representation. */
userRepr: string
}

/**
* Implementation of the `BreakendStrucvar` interface.
*/
export class BreakendStrucvarImpl implements BreakendStrucvar {
svType: 'BND'
genomeBuild: GenomeBuild
chrom: string
chrom2: string
start: number
stop: number
strandOrientation: StrandOrientation
userRepr: string

constructor(
genomeBuild: GenomeBuild,
chrom: string,
chrom2: string,
start: number,
stop: number,
strandOrientation?: StrandOrientation,
userRepr?: string
) {
this.svType = 'BND'
this.genomeBuild = genomeBuild
this.chrom = chrom
this.chrom2 = chrom2
this.start = start
this.stop = stop
this.strandOrientation = strandOrientation ?? StrandOrientation.NOT_APPLICABLE
this.userRepr =
userRepr ??
`${this.svType}-${this.genomeBuild}-${this.chrom}-${this.start}-${this.chrom2}-` +
`${this.stop}-${this.strandOrientation}`
}

/** Return the "object name" to be used in the API to the backend etc. */
toName(): string {
return (
`${this.svType}-${this.genomeBuild}-${this.chrom}-${this.start}-${this.chrom2}-` +
`${this.stop}-${this.strandOrientation}`
)
}
}

/**
* Construct a `BreakendStrucvarImpl` from a `BreakendStrucvar`.
*/
export function breakendStrucvarImplFromBreakendStrucvar(
bnd: BreakendStrucvar
): BreakendStrucvarImpl {
return new BreakendStrucvarImpl(
bnd.genomeBuild,
bnd.chrom,
bnd.chrom2,
bnd.start,
bnd.stop,
bnd.strandOrientation,
bnd.userRepr
)
}

/** All supported structural variant types. */
export type Strucvar = LinearStrucvar // | ...
export type Strucvar = LinearStrucvar | BreakendStrucvar

/**
* Attempt parsing of a colon/hyphen-separated structural variant.
Expand All @@ -411,7 +516,7 @@ export type Strucvar = LinearStrucvar // | ...
export function parseSeparatedStrucvar(
value: string,
defaultGenomeBuild: GenomeBuild = 'grch37'
): LinearStrucvar {
): Strucvar {
const match = value.match(REGEX_CNV_COLON) ?? value.match(REGEX_CNV_HYPHEN)
if (!match || !match.groups) {
throw new ParseError(`Unable to parse colon/hyphen separated strucvar: ${value}`)
Expand Down

0 comments on commit eb519cc

Please sign in to comment.