use std::sync::Arc;
use anyhow::Result;
use async_stream::stream;
use axum::extract::{Json, Path, Query, State};
use axum::http::StatusCode;
use axum::response::IntoResponse;
use axum_streams::StreamBodyAs;
use dihardts_omicstools::proteomics::proteases::functions::get_by_name as get_protease_by_name;
use futures::TryStreamExt;
use scylla::value::CqlValue;
use serde_json::Value as JsonValue;
use tracing::error;
use crate::database::scylla::protein_table::ProteinTable;
use crate::web::web_error::WebError;
use super::app_state::AppState;
#[derive(serde::Deserialize)]
pub struct GetProteinRequestQuery {
#[serde(default)]
include_peptide_protein_accession: bool,
}
pub async fn get_protein(
State(app_state): State<Arc<AppState>>,
Path(accession): Path<String>,
Query(query): Query<GetProteinRequestQuery>,
) -> Result<Json<JsonValue>, WebError> {
let accession = accession.to_uppercase();
let protein_opt = ProteinTable::select(
app_state.get_db_client_as_ref(),
"WHERE accession = ?",
&[&CqlValue::Text(accession)],
)
.await?
.try_collect::<Vec<_>>()
.await?
.pop();
if let Some(protein) = protein_opt {
let protease = get_protease_by_name(
app_state.get_configuration_as_ref().get_protease_name(),
app_state
.get_configuration_as_ref()
.get_min_peptide_length(),
app_state
.get_configuration_as_ref()
.get_max_peptide_length(),
app_state
.get_configuration_as_ref()
.get_max_number_of_missed_cleavages(),
)?;
return Ok(Json(
protein
.to_json_with_peptides(
app_state.get_db_client().clone(),
app_state.get_configuration_as_ref().get_partition_limits(),
protease.as_ref(),
query.include_peptide_protein_accession,
)
.await?,
));
} else {
Err(WebError::new(
StatusCode::NOT_FOUND,
"Protein not found".to_string(),
))
}
}
pub async fn search_protein(
State(app_state): State<Arc<AppState>>,
Path(attribute): Path<String>,
) -> impl IntoResponse {
if attribute.len() < 3 {
return StreamBodyAs::text(WebError::new_string_stream(
StatusCode::UNPROCESSABLE_ENTITY,
"Attribute must be at least 3 characters long".to_string(),
));
}
let attribute = attribute.replace("%", "\\%);").replace("_", "\\_");
let protease = match get_protease_by_name(
app_state.get_configuration_as_ref().get_protease_name(),
app_state
.get_configuration_as_ref()
.get_min_peptide_length(),
app_state
.get_configuration_as_ref()
.get_max_peptide_length(),
app_state
.get_configuration_as_ref()
.get_max_number_of_missed_cleavages(),
) {
Ok(protease) => protease,
Err(err) => {
return StreamBodyAs::text(WebError::new_string_stream(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Error when creating protease: {}", err),
));
}
};
let proteins = match ProteinTable::search(app_state.get_db_client(), attribute.clone()).await {
Ok(proteins) => proteins,
Err(err) => {
return StreamBodyAs::text(WebError::new_string_stream(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Error when selecting proteins: {}", err),
));
}
};
StreamBodyAs::json_array(stream! {
for await protein in proteins {
match protein {
Ok(protein) => yield match protein.to_json_with_peptides(
app_state.get_db_client().clone(),
app_state.get_configuration_as_ref().get_partition_limits(),
protease.as_ref(),
true
).await {
Ok(json) => json,
Err(err) => {
error!("{:?}", err);
continue;
}
},
Err(err) => error!("{:?}", err)
}
}
})
}