poem_openapi/param/
query.rs

1use std::ops::{Deref, DerefMut};
2
3use itertools::Either;
4use poem::{Request, RequestBody, Result};
5
6use crate::{
7    ApiExtractor, ApiExtractorType, ExtractParamOptions,
8    base::UrlQuery,
9    error::ParseParamError,
10    registry::{MetaParamIn, MetaSchemaRef, Registry},
11    types::ParseFromParameter,
12};
13
14/// Represents the parameters passed by the query string.
15pub struct Query<T>(pub T);
16
17impl<T> Deref for Query<T> {
18    type Target = T;
19
20    fn deref(&self) -> &Self::Target {
21        &self.0
22    }
23}
24
25impl<T> DerefMut for Query<T> {
26    fn deref_mut(&mut self) -> &mut Self::Target {
27        &mut self.0
28    }
29}
30
31impl<'a, T: ParseFromParameter> ApiExtractor<'a> for Query<T> {
32    const TYPES: &'static [ApiExtractorType] = &[ApiExtractorType::Parameter];
33    const PARAM_IS_REQUIRED: bool = T::IS_REQUIRED;
34
35    type ParamType = T;
36    type ParamRawType = T::RawValueType;
37
38    fn register(registry: &mut Registry) {
39        T::register(registry);
40    }
41
42    fn param_in() -> Option<MetaParamIn> {
43        Some(MetaParamIn::Query)
44    }
45
46    fn param_schema_ref() -> Option<MetaSchemaRef> {
47        Some(T::schema_ref())
48    }
49
50    fn param_raw_type(&self) -> Option<&Self::ParamRawType> {
51        self.0.as_raw_value()
52    }
53
54    async fn from_request(
55        request: &'a Request,
56        _body: &mut RequestBody,
57        param_opts: ExtractParamOptions<Self::ParamType>,
58    ) -> Result<Self> {
59        let url_query = request.extensions().get::<UrlQuery>().unwrap();
60        let mut values = if !param_opts.ignore_case {
61            Either::Left(url_query.get_all(param_opts.name))
62        } else {
63            Either::Right(url_query.get_all_by(|n| param_opts.name.eq_ignore_ascii_case(n)))
64        }
65        .peekable();
66
67        match &param_opts.default_value {
68            Some(default_value) if values.peek().is_none() => {
69                return Ok(Self(default_value()));
70            }
71            _ => {}
72        }
73
74        if param_opts.explode {
75            ParseFromParameter::parse_from_parameters(values)
76                .map(Self)
77                .map_err(|err| {
78                    ParseParamError {
79                        name: param_opts.name,
80                        reason: err.into_message(),
81                    }
82                    .into()
83                })
84        } else {
85            let values = values.next().unwrap().split(',').map(|v| v.trim());
86            ParseFromParameter::parse_from_parameters(values)
87                .map(Self)
88                .map_err(|err| {
89                    ParseParamError {
90                        name: param_opts.name,
91                        reason: err.into_message(),
92                    }
93                    .into()
94                })
95        }
96    }
97}