Skip to content

Commit

Permalink
feat: adding /genes/lookup endpoint (#193)
Browse files Browse the repository at this point in the history
  • Loading branch information
holtgrewe authored Aug 31, 2023
1 parent bc39d84 commit eeb5753
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 8 deletions.
69 changes: 69 additions & 0 deletions src/server/actix_server/genes_lookup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//! Implementation of `/genes/lookup` that allows to lookup genes by symbol or identifier.
//!
//! In contrast to gene search, more than one query may be given but this must match exactly
//! the symbol or HGNC/NCBI/ENSEMBL identifier.
use actix_web::{
get,
web::{self, Data, Json, Path},
Responder,
};

use crate::server::GeneNames;

use super::error::CustomError;
use serde_with::{formats::CommaSeparator, StringWithSeparator};

/// Parameters for `handle`.
#[serde_with::skip_serializing_none]
#[serde_with::serde_as]
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
struct Request {
/// The strings to search for.
#[serde_as(as = "StringWithSeparator::<CommaSeparator, String>")]
pub q: Vec<String>,
}

/// Result for `handle`.
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde_with::skip_serializing_none]
struct Container {
// TODO: add data version
/// The resulting gene information.
pub genes: indexmap::IndexMap<String, Option<GeneNames>>,
}

/// Query for annotations for one variant.
#[allow(clippy::option_map_unit_fn)]
#[get("/genes/lookup")]
async fn handle(
data: Data<crate::server::WebServerData>,
_path: Path<()>,
query: web::Query<Request>,
) -> actix_web::Result<impl Responder, CustomError> {
if query.q.len() < 2 {
return Ok(Json(Container {
// server_version: VERSION.to_string(),
// builder_version,
genes: Default::default(),
}));
}

let genes_db = data.genes.as_ref().ok_or(CustomError::new(anyhow::anyhow!(
"genes database not available"
)))?;

let genes = indexmap::IndexMap::from_iter(query.q.iter().map(|q| {
let v = genes_db
.name_to_hgnc_idx
.get(q)
.map(|idx| genes_db.gene_names[*idx].clone());
(q.clone(), v)
}));

Ok(Json(Container {
// server_version: VERSION.to_string(),
// builder_version,
genes,
}))
}
5 changes: 4 additions & 1 deletion src/server/actix_server/genes_search.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
//! Implementation of `/genes/search` that allows to search for genes by symbol etc.
//!
//! Gene identifiers (HGNC, NCBI, ENSEMBL) must match. As for symbols and names, the
//! search string may also be a substring.
use actix_web::{
get,
web::{self, Data, Json, Path},
Expand Down Expand Up @@ -105,7 +108,7 @@ async fn handle(
let fields_contains = |field: &Fields| -> bool { fields.is_empty() || fields.contains(field) };

let mut genes = genes_db
.gene_strings
.gene_names
.iter()
.map(|gn| -> Scored<GeneNames> {
let score = if (fields_contains(&Fields::HgncId) && &gn.hgnc_id == q)
Expand Down
4 changes: 3 additions & 1 deletion src/server/actix_server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod annos_variant;
pub mod error;
pub mod fetch;
pub mod genes_info;
pub mod genes_lookup;
pub mod genes_search;

use actix_web::{middleware::Logger, web::Data, App, HttpServer};
Expand All @@ -26,7 +27,8 @@ pub async fn main(args: &Args, dbs: Data<WebServerData>) -> std::io::Result<()>
.service(annos_range::handle)
.service(annos_db_info::handle)
.service(genes_info::handle)
.service(genes_search::handle);
.service(genes_search::handle)
.service(genes_lookup::handle);
app.wrap(Logger::default())
})
.bind((args.listen_host.as_str(), args.listen_port))?
Expand Down
34 changes: 28 additions & 6 deletions src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pub mod actix_server;

use std::time::Instant;
use std::{collections::HashMap, time::Instant};

use clap::Parser;
use indicatif::ParallelProgressIterator;
Expand Down Expand Up @@ -121,7 +121,9 @@ pub struct GeneInfoDb {
/// The database.
pub db: rocksdb::DBWithThreadMode<rocksdb::MultiThreaded>,
/// Gene information to keep in memory (for `/genes/search`).
pub gene_strings: Vec<GeneNames>,
pub gene_names: Vec<GeneNames>,
/// Mapping from allowed gene name string to index in `gene_names`.
pub name_to_hgnc_idx: HashMap<String, usize>,
}

/// Genome-release specific annotation for each database.
Expand Down Expand Up @@ -316,18 +318,33 @@ pub fn run(args_common: &common::cli::Args, args: &Args) -> Result<(), anyhow::E
if let Some(path_genes) = args.path_genes.as_ref() {
tracing::info!("Opening genes database {}...", path_genes);
let before_open = Instant::now();
let genes = open_db(path_genes, "genes")?;
let db = open_db(path_genes, "genes")?;
tracing::info!(
"...done opening genes database in {:?}",
before_open.elapsed()
);
tracing::info!("Building gene names...");
let before_open = Instant::now();
let gene_names = extract_gene_names(&genes)?;
let gene_names = extract_gene_names(&db)?;
let name_to_hgnc_idx = {
let mut result = HashMap::new();
for (idx, gene_name) in gene_names.iter().enumerate() {
result.insert(gene_name.hgnc_id.clone(), idx);
if let Some(ensembl_gene_id) = gene_name.ensembl_gene_id.as_ref() {
result.insert(ensembl_gene_id.clone(), idx);
}
if let Some(ncbi_gene_id) = gene_name.ncbi_gene_id.as_ref() {
result.insert(ncbi_gene_id.clone(), idx);
}
result.insert(gene_name.symbol.clone(), idx);
}
result
};
tracing::info!("...done building genes names {:?}", before_open.elapsed());
data.genes = Some(GeneInfoDb {
db: genes,
gene_strings: gene_names,
db,
gene_names,
name_to_hgnc_idx,
});
}
// Argument lists from the command line with the corresponding database enum value.
Expand Down Expand Up @@ -394,6 +411,11 @@ pub fn run(args_common: &common::cli::Args, args: &Args) -> Result<(), anyhow::E
args.listen_host.as_str(),
args.listen_port
);
tracing::info!(
" try: http://{}:{}/genes/lookup?q=BRCA,BRCA1,HGNC:1100",
args.listen_host.as_str(),
args.listen_port
);
tracing::info!(
" try: http://{}:{}/genes/info?hgnc_id=HGNC:12403",
args.listen_host.as_str(),
Expand Down

0 comments on commit eeb5753

Please sign in to comment.