From e1253b696982c198a29a316c9945d9ef145eb51e Mon Sep 17 00:00:00 2001 From: mpostma Date: Tue, 16 Feb 2021 15:54:07 +0100 Subject: [PATCH] enable search with get route --- src/data/mod.rs | 4 +- src/data/search.rs | 2 +- src/routes/key.rs | 2 +- src/routes/search.rs | 103 ++++++++++++++++++++++++++++++++++--------- 4 files changed, 86 insertions(+), 25 deletions(-) diff --git a/src/data/mod.rs b/src/data/mod.rs index 8c512895c..656d19880 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -1,7 +1,7 @@ mod search; mod updates; -pub use search::{SearchQuery, SearchResult}; +pub use search::{SearchQuery, SearchResult, DEFAULT_SEARCH_LIMIT}; use std::fs::create_dir_all; use std::ops::Deref; @@ -28,7 +28,7 @@ impl Deref for Data { #[derive(Clone)] pub struct DataInner { pub index_controller: Arc, - api_keys: ApiKeys, + pub api_keys: ApiKeys, options: Opt, } diff --git a/src/data/search.rs b/src/data/search.rs index b4be47c35..461cfb644 100644 --- a/src/data/search.rs +++ b/src/data/search.rs @@ -11,7 +11,7 @@ use serde_json::{Value, Map}; use crate::index_controller::IndexController; use super::Data; -const DEFAULT_SEARCH_LIMIT: usize = 20; +pub const DEFAULT_SEARCH_LIMIT: usize = 20; const fn default_search_limit() -> usize { DEFAULT_SEARCH_LIMIT } diff --git a/src/routes/key.rs b/src/routes/key.rs index 7fb6ae00a..a0cbaccc3 100644 --- a/src/routes/key.rs +++ b/src/routes/key.rs @@ -17,7 +17,7 @@ struct KeysResponse { } #[get("/keys", wrap = "Authentication::Admin")] -async fn list(_data: web::Data) -> HttpResponse { +async fn list(data: web::Data) -> HttpResponse { let api_keys = data.api_keys.clone(); HttpResponse::Ok().json(KeysResponse { private: api_keys.private, diff --git a/src/routes/search.rs b/src/routes/search.rs index 715d40426..a9e87d1a6 100644 --- a/src/routes/search.rs +++ b/src/routes/search.rs @@ -1,38 +1,99 @@ -use actix_web::{get, post, web, HttpResponse}; +use std::collections::HashSet; +use std::convert::{TryFrom, TryInto}; +use actix_web::{get, post, web, HttpResponse}; +use serde::Deserialize; + +use crate::data::{SearchQuery, DEFAULT_SEARCH_LIMIT}; use crate::error::ResponseError; use crate::helpers::Authentication; use crate::routes::IndexParam; use crate::Data; -use crate::data::SearchQuery; pub fn services(cfg: &mut web::ServiceConfig) { cfg.service(search_with_post).service(search_with_url_query); } -//#[derive(Serialize, Deserialize)] -//#[serde(rename_all = "camelCase", deny_unknown_fields)] -//pub struct SearchQuery { - //q: Option, - //offset: Option, - //limit: Option, - //attributes_to_retrieve: Option, - //attributes_to_crop: Option, - //crop_length: Option, - //attributes_to_highlight: Option, - //filters: Option, - //matches: Option, - //facet_filters: Option, - //facets_distribution: Option, -//} +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct SearchQueryGet { + q: Option, + offset: Option, + limit: Option, + attributes_to_retrieve: Option, + attributes_to_crop: Option, + crop_length: Option, + attributes_to_highlight: Option, + filters: Option, + matches: Option, + facet_filters: Option, + facets_distribution: Option, +} + +impl TryFrom for SearchQuery { + type Error = anyhow::Error; + + fn try_from(other: SearchQueryGet) -> anyhow::Result { + let attributes_to_retrieve = other + .attributes_to_retrieve + .map(|attrs| attrs.split(",").map(String::from).collect::>()); + + let attributes_to_crop = other + .attributes_to_crop + .map(|attrs| attrs.split(",").map(String::from).collect::>()); + + let attributes_to_highlight = other + .attributes_to_highlight + .map(|attrs| attrs.split(",").map(String::from).collect::>()); + + let facets_distribution = other + .facets_distribution + .map(|attrs| attrs.split(",").map(String::from).collect::>()); + + let facet_filters = match other.facet_filters { + Some(ref f) => Some(serde_json::from_str(f)?), + None => None, + }; + + Ok(Self { + q: other.q, + offset: other.offset, + limit: other.limit.unwrap_or(DEFAULT_SEARCH_LIMIT), + attributes_to_retrieve, + attributes_to_crop, + crop_length: other.crop_length, + attributes_to_highlight, + filters: other.filters, + matches: other.matches, + facet_filters, + facets_distribution, + facet_condition: None, + }) + } +} #[get("/indexes/{index_uid}/search", wrap = "Authentication::Public")] async fn search_with_url_query( - _data: web::Data, - _path: web::Path, - _params: web::Query, + data: web::Data, + path: web::Path, + params: web::Query, ) -> Result { - todo!() + let query: SearchQuery = match params.into_inner().try_into() { + Ok(q) => q, + Err(e) => { + return Ok(HttpResponse::BadRequest().body(serde_json::json!({ "error": e.to_string() }))) + } + }; + let search_result = data.search(&path.index_uid, query); + match search_result { + Ok(docs) => { + let docs = serde_json::to_string(&docs).unwrap(); + Ok(HttpResponse::Ok().body(docs)) + } + Err(e) => { + Ok(HttpResponse::BadRequest().body(serde_json::json!({ "error": e.to_string() }))) + } + } } #[post("/indexes/{index_uid}/search", wrap = "Authentication::Public")]