1#[doc(inline)]
4pub use query_params_macro::QueryParams;
5
6#[doc(hidden)]
7pub use urlencoding;
8
9extern crate self as to_query_params;
10
11pub trait ToQueryParams {
16 fn to_query_params(&self) -> Vec<(String, String)>;
18
19 fn to_encoded_params(&self) -> Vec<(String, String)> {
21 self.to_query_params()
22 .iter()
23 .map(|(k, v)| {
24 (
25 urlencoding::encode(k).to_string(),
26 urlencoding::encode(v).to_string(),
27 )
28 })
29 .collect()
30 }
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36
37 #[derive(QueryParams, Debug, PartialEq)]
38 struct TestItem {
39 #[query(required)]
40 a: i32,
41 #[query(required)]
42 b: i32,
43 }
44
45 #[derive(QueryParams, Debug, PartialEq)]
46 struct TestExcludeItem {
47 #[query(required)]
48 a: i32,
49 #[query(exclude)]
50 b: i32,
51 #[query(exclude)]
52 c: Option<i32>,
53 #[query(required)]
54 d: i32,
55 }
56
57 #[derive(QueryParams, Debug, PartialEq)]
58 struct TestStringItem {
59 #[query(required)]
60 a: String,
61 #[query(required, rename = "please encode")]
62 b: String,
63 }
64
65 #[derive(QueryParams, Debug, PartialEq)]
66 struct TestItemRequiredRename {
67 #[query(required, rename = "alpha")]
68 a: i32,
69 #[query(required)]
70 b: i32,
71 }
72
73 #[derive(QueryParams, Debug, PartialEq)]
74 struct TestItemOptionals {
75 a: Option<String>,
76 b: Option<bool>,
77 }
78
79 #[derive(QueryParams, Debug, PartialEq)]
80 struct TestItemRename {
81 #[query(rename = "alpha")]
82 a: Option<String>,
83 #[query(rename = "beta")]
84 b: Option<bool>,
85 }
86
87 #[derive(QueryParams, Debug, PartialEq)]
88 struct TestItemMixedRequiredOptionals {
89 a: Option<String>,
90 b: Option<bool>,
91 #[query(required)]
92 c: i32,
93 }
94
95 #[derive(QueryParams, Debug, PartialEq)]
96 struct TestItemMixedRequiredOptionalsAndRename {
97 #[query(rename = "alpha")]
98 a: Option<String>,
99 b: Option<bool>,
100 #[query(rename = "gamma")]
101 #[query(required)]
102 c: i32,
103 }
104
105 #[test]
106 fn test_developer_experience() {
107 let t = trybuild::TestCases::new();
108 t.compile_fail("tests/ui/*.rs");
109 }
110
111 #[test]
112 fn test_query_params_required_case() {
113 let test_item = TestItem { a: 0, b: 1 };
114
115 let expected = vec![
116 ("a".to_string(), "0".to_string()),
117 ("b".to_string(), "1".to_string()),
118 ];
119
120 assert_eq!(test_item.to_query_params(), expected);
121 }
122
123 #[test]
124 fn test_exclude_attribute() {
125 let test_item = TestExcludeItem {
126 a: 0,
127 b: 1,
128 c: Some(2),
129 d: 3,
130 };
131
132 let expected = vec![
133 ("a".to_string(), "0".to_string()),
134 ("d".to_string(), "3".to_string()),
135 ];
136
137 assert_eq!(test_item.to_query_params(), expected);
138 }
139
140 #[test]
141 fn test_query_params_encoding() {
142 let test_item = TestStringItem {
143 a: "please encode me".into(),
144 b: "this works?".into(),
145 };
146
147 let expected = vec![
148 ("a".to_string(), "please%20encode%20me".to_string()),
149 ("please%20encode".to_string(), "this%20works%3F".to_string()),
150 ];
151
152 assert_eq!(test_item.to_encoded_params(), expected);
153 }
154
155 #[test]
156 fn test_required_rename_case() {
157 let test_item = TestItemRequiredRename { a: 0, b: 1 };
158
159 let expected = vec![
160 ("alpha".to_string(), "0".to_string()),
161 ("b".to_string(), "1".to_string()),
162 ];
163
164 assert_eq!(test_item.to_query_params(), expected);
165 }
166
167 #[test]
168 fn test_query_params_optional_case() {
169 let test_item = TestItemOptionals {
170 a: Some("a".to_string()),
171 b: None,
172 };
173
174 let expected = vec![("a".to_string(), "a".to_string())];
175
176 assert_eq!(test_item.to_query_params(), expected);
177 }
178
179 #[test]
180 fn test_query_params_optional_rename_case() {
181 let test_item = TestItemRename {
182 a: Some("a".to_string()),
183 b: Some(true),
184 };
185
186 let expected = vec![
187 ("alpha".to_string(), "a".to_string()),
188 ("beta".to_string(), "true".to_string()),
189 ];
190
191 assert_eq!(test_item.to_query_params(), expected);
192 }
193
194 #[test]
195 fn test_query_params_mixed_case() {
196 let test_item = TestItemMixedRequiredOptionals {
197 a: Some("a".to_string()),
198 b: None,
199 c: 42,
200 };
201
202 let expected = vec![
203 ("a".to_string(), "a".to_string()),
204 ("c".to_string(), "42".to_string()),
205 ];
206
207 let mut actual = test_item.to_query_params();
208
209 actual.sort();
211
212 assert_eq!(actual, expected);
213 }
214
215 #[test]
216 fn test_query_params_mixed_case_with_rename() {
217 let test_item = TestItemMixedRequiredOptionalsAndRename {
218 a: Some("a".to_string()),
219 b: None,
220 c: 42,
221 };
222
223 let expected = vec![
224 ("alpha".to_string(), "a".to_string()),
225 ("gamma".to_string(), "42".to_string()),
226 ];
227
228 let mut actual = test_item.to_query_params();
229
230 actual.sort();
232
233 assert_eq!(actual, expected);
234 }
235}