use crate::blueprint::constructor::{Constructor, RegisteredConstructor};
use crate::blueprint::Blueprint;
use crate::f;
use crate::request::RequestHead;
use super::errors::{ExtractQueryParamsError, QueryDeserializationError};
#[doc(alias = "Query")]
#[doc(alias = "QueryParameters")]
pub struct QueryParams<T>(
pub T,
);
impl<T> QueryParams<T> {
pub fn extract<'request>(
request_head: &'request RequestHead,
) -> Result<Self, ExtractQueryParamsError>
where
T: serde::Deserialize<'request>,
{
let query = request_head.target.query().unwrap_or_default();
parse(query).map(QueryParams)
}
}
impl QueryParams<()> {
pub fn register(bp: &mut Blueprint) -> RegisteredConstructor {
Self::default_constructor().register(bp)
}
pub fn default_constructor() -> Constructor {
Constructor::request_scoped(f!(super::QueryParams::extract))
.error_handler(f!(super::errors::ExtractQueryParamsError::into_response))
}
}
fn parse<'a, T>(s: &'a str) -> Result<T, ExtractQueryParamsError>
where
T: serde::Deserialize<'a>,
{
serde_html_form::from_str(s)
.map_err(QueryDeserializationError::new)
.map_err(ExtractQueryParamsError::QueryDeserializationError)
}
#[cfg(test)]
mod tests {
use std::borrow::Cow;
use super::*;
#[test]
fn test_parse() {
#[derive(serde::Deserialize, Debug, PartialEq)]
struct Home<'a> {
home_id: u32,
home_price: f64,
home_name: Cow<'a, str>,
}
let query = "home_id=1&home_price=0.1&home_name=Hi%20there";
let expected = Home {
home_id: 1,
home_price: 0.1,
home_name: Cow::Borrowed("Hi there"),
};
let actual: Home = parse(query).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn test_sequence() {
#[derive(serde::Deserialize, Debug, PartialEq)]
struct Home {
room_ids: Vec<u32>,
}
let query = "room_ids=1&room_ids=2";
let expected = Home {
room_ids: vec![1, 2],
};
let actual: Home = parse(query).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn test_sequence_with_brackets() {
#[derive(serde::Deserialize, Debug, PartialEq)]
struct Home {
#[serde(rename = "room_ids[]")]
room_ids: Vec<u32>,
}
let query = "room_ids[]=1&room_ids[]=2";
let expected = Home {
room_ids: vec![1, 2],
};
let actual: Home = parse(query).unwrap();
assert_eq!(expected, actual);
}
}