diff --git a/Cargo.lock b/Cargo.lock index 3630733..b25ad9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -280,7 +280,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cheminee" -version = "0.1.9" +version = "0.1.10" dependencies = [ "bitvec", "clap", diff --git a/Cargo.toml b/Cargo.toml index 0e6f8cf..b568772 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cheminee" -version = "0.1.9" +version = "0.1.10" edition = "2021" description = "Molecule indexing and search" license = "MIT" diff --git a/src/rest_api/api/search/mod.rs b/src/rest_api/api/search/mod.rs index 97dc383..d70cc0b 100644 --- a/src/rest_api/api/search/mod.rs +++ b/src/rest_api/api/search/mod.rs @@ -1,7 +1,8 @@ +mod search; mod substructure_search; - use poem_openapi::payload::Json; use poem_openapi_derive::{ApiResponse, Object}; +pub use search::*; pub use substructure_search::*; use tantivy::{DocAddress, Searcher}; diff --git a/src/rest_api/api/search/search.rs b/src/rest_api/api/search/search.rs new file mode 100644 index 0000000..bf19ff0 --- /dev/null +++ b/src/rest_api/api/search/search.rs @@ -0,0 +1,68 @@ +use poem_openapi::payload::Json; +use poem_openapi_derive::{ApiResponse, Object}; + +use crate::{ + indexing::index_manager::IndexManager, + rest_api::{ + api::{aggregate_search_hits, GetStructureSearchResponse, StructureResponseError}, + models::GenericResponseError, + }, + search::{ + compound_processing::{get_cpd_properties, get_tautomers}, + prepare_query_structure, + substructure_search::substructure_search, + }, +}; + +#[derive(ApiResponse)] +pub enum GetIndexesSearchResponse { + #[oai(status = "200")] + Ok(Json>), + #[oai(status = "404")] + IndexDoesNotExist, + #[oai(status = "500")] + Err(Json), +} + +#[derive(Object, Debug)] +pub struct SearchHit { + pub error: String, +} + +pub fn v1_index_search( + index_manager: &IndexManager, + index: String, + query: Option, + limit: Option, + offset: Option, +) -> GetIndexesSearchResponse { + if !index_manager.exists(&index) { + return GetIndexesSearchResponse::IndexDoesNotExist; + } + + let index = index_manager.open(&index); + + let index = match index { + Ok(i) => i, + Err(e) => return GetIndexesSearchResponse::Err(Json(e.into())), + }; + + let query_parser = tantivy::query::QueryParser::for_index(&index, vec![]); + let schema = index.schema(); + + let reader = match index.reader() { + Ok(r) => r, + Err(e) => return GetIndexesSearchResponse::Err(e.into()), + }; + + let searcher = reader.searcher(); + + let query = query_parser.parse_query(query.as_deref().unwrap()); + let query = match query { + Ok(q) => q, + Err(e) => return GetIndexesSearchResponse::Err(e.into()), + }; + + let collector = tantivy::collector::TopDocs::with_limit(1000) + searcher.search(&query) +} diff --git a/src/rest_api/models/error.rs b/src/rest_api/models/error.rs new file mode 100644 index 0000000..0a28c67 --- /dev/null +++ b/src/rest_api/models/error.rs @@ -0,0 +1,19 @@ +use std::error::Error; + +use poem_openapi_derive::Object; + +#[derive(Object, Debug)] +pub struct GenericResponseError { + pub error: String, +} + +impl From for GenericResponseError +where + T: Error, +{ + fn from(err: T) -> Self { + Self { + error: err.to_string(), + } + } +} diff --git a/src/rest_api/models/mod.rs b/src/rest_api/models/mod.rs index a03bf95..c05d6a2 100644 --- a/src/rest_api/models/mod.rs +++ b/src/rest_api/models/mod.rs @@ -1,2 +1,5 @@ +mod error; +pub use error::*; + mod smile; pub use smile::*; diff --git a/src/rest_api/openapi_server.rs b/src/rest_api/openapi_server.rs index b4fcbbe..51fff56 100644 --- a/src/rest_api/openapi_server.rs +++ b/src/rest_api/openapi_server.rs @@ -12,10 +12,11 @@ use crate::{ indexing::index_manager::IndexManager, rest_api::{ api::{ - v1_get_index, v1_index_search_substructure, v1_list_indexes, v1_list_schemas, - v1_post_index, v1_post_index_bulk, v1_standardize, BulkRequest, GetIndexesResponse, - GetStructureSearchResponse, ListIndexesResponse, ListSchemasResponse, - PostIndexResponse, PostIndexesBulkIndexResponse, StandardizeResponse, + v1_get_index, v1_index_search, v1_index_search_substructure, v1_list_indexes, + v1_list_schemas, v1_post_index, v1_post_index_bulk, v1_standardize, BulkRequest, + GetIndexesResponse, GetIndexesSearchResponse, GetStructureSearchResponse, + ListIndexesResponse, ListSchemasResponse, PostIndexResponse, + PostIndexesBulkIndexResponse, StandardizeResponse, }, models::Smile, }, @@ -136,6 +137,18 @@ impl Api { v1_post_index_bulk(&self.index_manager, index.to_string(), bulk_request.0).await } + #[oai(path = "/v1/indexes/:index/search", method = "get")] + /// The no-smarts search, just applies a tantivy query to the index and serializes the response + pub async fn v1_index_search( + &self, + index: Path, + q: Query>, + limit: Query>, + offset: Query>, + ) -> GetIndexesSearchResponse { + v1_index_search(&self.index_manager, index.to_string, q.0, offset.0) + } + #[oai(path = "/v1/indexes/:index/search/substructure", method = "get")] /// Perform substructure search against index pub async fn v1_index_search_substructure(