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}