use pavex_macros::methods;
use crate::request::RequestHead;
use super::errors::{ExtractQueryParamsError, QueryDeserializationError};
#[doc(alias = "Query")]
#[doc(alias = "QueryParameters")]
pub struct QueryParams<T>(
pub T,
);
#[methods]
impl<T> QueryParams<T> {
#[request_scoped(pavex = crate, id = "QUERY_PARAMS_EXTRACT")]
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)
}
}
fn parse<'a, T>(s: &'a str) -> Result<T, ExtractQueryParamsError>
where
T: serde::Deserialize<'a>,
{
let deserializer = serde_html_form::Deserializer::new(form_urlencoded::parse(s.as_bytes()));
serde_path_to_error::deserialize(deserializer)
.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);
}
}