use super::metadata::get_metadata;
use crate::api_description::ApiEndpointBodyContentType;
use crate::api_description::ApiEndpointParameterLocation;
use crate::error::HttpError;
use crate::server::ServerContext;
use crate::ExtractorMetadata;
use crate::RequestContext;
use crate::RequestInfo;
use crate::SharedExtractor;
use async_trait::async_trait;
use schemars::JsonSchema;
use serde::de::DeserializeOwned;
use std::fmt::Debug;
#[derive(Debug)]
pub struct Query<QueryType: DeserializeOwned + JsonSchema + Send + Sync> {
inner: QueryType,
}
impl<QueryType: DeserializeOwned + JsonSchema + Send + Sync> Query<QueryType> {
pub fn into_inner(self) -> QueryType {
self.inner
}
pub fn map<T, F>(self, f: F) -> Query<T>
where
T: DeserializeOwned + JsonSchema + Send + Sync,
F: FnOnce(QueryType) -> T,
{
Query { inner: f(self.inner) }
}
pub fn try_map<T, E, F>(self, f: F) -> Result<Query<T>, E>
where
T: DeserializeOwned + JsonSchema + Send + Sync,
F: FnOnce(QueryType) -> Result<T, E>,
{
Ok(Query { inner: f(self.inner)? })
}
}
impl<QueryType: DeserializeOwned + JsonSchema + Send + Sync> From<QueryType>
for Query<QueryType>
{
fn from(value: QueryType) -> Self {
Self { inner: value }
}
}
fn http_request_load_query<QueryType>(
request: &RequestInfo,
) -> Result<Query<QueryType>, HttpError>
where
QueryType: DeserializeOwned + JsonSchema + Send + Sync,
{
let raw_query_string = request.uri().query().unwrap_or("");
match serde_urlencoded::from_str(raw_query_string) {
Ok(q) => Ok(Query { inner: q }),
Err(e) => Err(HttpError::for_bad_request(
None,
format!("unable to parse query string: {}", e),
)),
}
}
#[async_trait]
impl<QueryType> SharedExtractor for Query<QueryType>
where
QueryType: JsonSchema + DeserializeOwned + Send + Sync + 'static,
{
async fn from_request<Context: ServerContext>(
rqctx: &RequestContext<Context>,
) -> Result<Query<QueryType>, HttpError> {
http_request_load_query(&rqctx.request)
}
fn metadata(
_body_content_type: ApiEndpointBodyContentType,
) -> ExtractorMetadata {
get_metadata::<QueryType>(&ApiEndpointParameterLocation::Query)
}
}