json_api/query/
mod.rs

1//! An API for working with well-known query parameters.
2
3mod builder;
4mod page;
5mod sort;
6
7use std::fmt::{self, Formatter};
8
9use percent_encoding::percent_decode;
10use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
11use serde::ser::{Serialize, SerializeStruct, Serializer};
12use serde_qs;
13
14use error::Error;
15use value::{Key, Map, Path, Set, Stringify, Value};
16
17pub use self::builder::Builder;
18pub use self::page::Page;
19pub use self::sort::{Direction, Sort};
20
21/// Represents well-known query parameters.
22#[derive(Clone, Debug, Default, PartialEq)]
23pub struct Query {
24    /// A map where each key is a type name and the value is set of field names
25    /// that the client wishes to receive for the given type. If this is not present
26    /// when decoding a query string, an empty map is used (no allocation is required).
27    ///
28    /// It is recommeneded that consumers of this crate interpret a `None` value as the
29    /// client specifying that they want all of the available fields for a given type.
30    /// This behavior is already implemented when rendering a type that implements the
31    /// [`Resource`] trait via the [`resource!`] macro.
32    ///
33    /// For more information, check out the *[sparse fieldsets]* section of the JSON API
34    /// specification.
35    ///
36    /// [`Resource`]: ../trait.Resource.html
37    /// [`resource!`]: ../macro.resource.html
38    /// [sparse fieldsets]: http://jsonapi.org/format/#fetching-sparse-fieldsets
39    pub fields: Map<Key, Set>,
40
41    /// A map where each key is a field path and the value is the value the client
42    /// would like each item in the return document to have for the given field.
43    ///
44    /// For more information, check out the *[filter]* section of the JSON API
45    /// specification.
46    ///
47    /// [filtering]: http://jsonapi.org/format/#fetching-filtering
48    pub filter: Map<Path, Value>,
49
50    /// A set of relationship paths that specify included resources a client wishes to
51    /// receive in addition to a document's primary data.
52    ///
53    /// For more information, check out the *[inclusion of related resources]* section
54    /// of the JSON API specification.
55    ///
56    /// [inclusion of related resources]: http://jsonapi.org/format/#fetching-includes
57    pub include: Set<Path>,
58
59    /// Optional pagination parameters. To make life easier when this value is `None`,
60    /// the `Page` struct implements a sensible default.
61    ///
62    /// For more information, check out the *[pagination]* section of the JSON API
63    /// specification.
64    ///
65    /// [pagination]: http://jsonapi.org/format/#fetching-pagination
66    pub page: Option<Page>,
67
68    /// A set of sort instructions. Each element in the set contains the field name, and
69    /// the sort direction (ascending or descending).
70    ///
71    /// When a client specifies a field to sort by, if it is prefixed with `'-'` (i.e
72    /// `sort=-created-at`) the instruction is interpreted to mean "sort by the field
73    /// 'created-at' in descending order".
74    ///
75    /// For more information, check out the *[sorting]* section of the JSON API
76    /// specification.
77    ///
78    /// [sorting]: http://jsonapi.org/format/#fetching-sorting
79    pub sort: Set<Sort>,
80
81    /// Private field for backwards compatibility.
82    _ext: (),
83}
84
85impl Query {
86    /// Returns the decoded equivalent of an empty query string. Does not
87    /// require any allocations.
88    pub fn new() -> Self {
89        Default::default()
90    }
91
92    /// Returns a query builder that can be used to create a new query.
93    pub fn builder() -> Builder {
94        Default::default()
95    }
96}
97
98impl<'de> Deserialize<'de> for Query {
99    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
100    where
101        D: Deserializer<'de>,
102    {
103        const FIELDS: &[&str] = &["fields", "filter", "include", "page", "sort"];
104
105        #[derive(Debug, Deserialize)]
106        #[serde(field_identifier, rename_all = "lowercase")]
107        enum Field {
108            Fields,
109            Filter,
110            Include,
111            Page,
112            Sort,
113        }
114
115        struct QueryVisitor;
116
117        impl<'de> Visitor<'de> for QueryVisitor {
118            type Value = Query;
119
120            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
121                write!(f, "an object containing query parameters")
122            }
123
124            fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
125            where
126                A: MapAccess<'de>,
127            {
128                use serde::de::Error;
129
130                let mut fields = None;
131                let mut filter = None;
132                let mut include = None;
133                let mut page = None;
134                let mut sort = None;
135
136                while let Some(key) = access.next_key()? {
137                    match key {
138                        Field::Fields => {
139                            let data = access.next_value::<Map<_, String>>()?;
140                            let mut map = Map::with_capacity(data.len());
141
142                            for (field, value) in data {
143                                let value = value.parse().map_err(Error::custom)?;
144                                map.insert(field, value);
145                            }
146
147                            fields = Some(map);
148                        }
149                        Field::Filter => {
150                            filter = Some(access.next_value()?);
151                        }
152                        Field::Include => {
153                            let data = access.next_value::<String>()?;
154                            include = Some(data.parse().map_err(Error::custom)?);
155                        }
156                        Field::Page => {
157                            page = Some(access.next_value()?);
158                        }
159                        Field::Sort => {
160                            let data = access.next_value::<String>()?;
161                            sort = Some(data.parse().map_err(Error::custom)?);
162                        }
163                    }
164                }
165
166                Ok(Query {
167                    page,
168                    fields: fields.unwrap_or_default(),
169                    filter: filter.unwrap_or_default(),
170                    include: include.unwrap_or_default(),
171                    sort: sort.unwrap_or_default(),
172                    _ext: (),
173                })
174            }
175        }
176
177        deserializer.deserialize_struct("Query", FIELDS, QueryVisitor)
178    }
179}
180
181impl Serialize for Query {
182    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
183    where
184        S: Serializer,
185    {
186        let mut state = serializer.serialize_struct("Query", 5)?;
187
188        if !self.fields.is_empty() {
189            let mut fields = Map::with_capacity(self.fields.len());
190
191            for (key, value) in &self.fields {
192                fields.insert(key, value.stringify());
193            }
194
195            state.serialize_field("fields", &fields)?;
196        }
197
198        if !self.filter.is_empty() {
199            state.serialize_field("filter", &self.filter)?;
200        }
201
202        if !self.include.is_empty() {
203            state.serialize_field("include", &self.include.stringify())?;
204        }
205
206        if let Some(ref page) = self.page {
207            state.serialize_field("page", page)?;
208        }
209
210        if !self.sort.is_empty() {
211            state.serialize_field("sort", &self.sort.stringify())?;
212        }
213
214        state.end()
215    }
216}
217
218/// Deserialize a `Query` from the bytes of a percent encoded query string.
219pub fn from_slice(data: &[u8]) -> Result<Query, Error> {
220    let value = percent_decode(data).decode_utf8()?;
221    Ok(serde_qs::from_bytes(value.as_bytes())?)
222}
223
224/// Deserialize a `Query` from a percent encoded query string.
225pub fn from_str(data: &str) -> Result<Query, Error> {
226    from_slice(data.as_bytes())
227}
228
229/// Serialize the given `Query` as a percent encoded query string.
230pub fn to_string(query: &Query) -> Result<String, Error> {
231    use percent_encoding::{percent_encode, QUERY_ENCODE_SET};
232
233    let value = serde_qs::to_string(query)?;
234    let data = value.as_bytes();
235
236    Ok(percent_encode(data, QUERY_ENCODE_SET).collect())
237}
238
239/// Serialize the given `Query` as a representing percent encoded query string
240/// vector of bytes.
241pub fn to_vec(query: &Query) -> Result<Vec<u8>, Error> {
242    to_string(query).map(Vec::from)
243}