pubmed_client/pubmed/query/advanced.rs
1//! Advanced search methods for MeSH terms, authors, and specialized filtering
2
3use super::SearchQuery;
4
5impl SearchQuery {
6 /// Filter by MeSH major topic
7 ///
8 /// # Arguments
9 ///
10 /// * `mesh_term` - MeSH term to filter by as a major topic
11 ///
12 /// # Example
13 ///
14 /// ```
15 /// use pubmed_client::pubmed::SearchQuery;
16 ///
17 /// let query = SearchQuery::new()
18 /// .mesh_major_topic("Diabetes Mellitus, Type 2");
19 /// ```
20 pub fn mesh_major_topic<S: Into<String>>(mut self, mesh_term: S) -> Self {
21 self.filters.push(format!("{}[majr]", mesh_term.into()));
22 self
23 }
24
25 /// Filter by MeSH term
26 ///
27 /// # Arguments
28 ///
29 /// * `mesh_term` - MeSH term to filter by
30 ///
31 /// # Example
32 ///
33 /// ```
34 /// use pubmed_client::pubmed::SearchQuery;
35 ///
36 /// let query = SearchQuery::new()
37 /// .mesh_term("Neoplasms");
38 /// ```
39 pub fn mesh_term<S: Into<String>>(mut self, mesh_term: S) -> Self {
40 self.filters.push(format!("{}[mh]", mesh_term.into()));
41 self
42 }
43
44 /// Filter by multiple MeSH terms
45 ///
46 /// # Arguments
47 ///
48 /// * `mesh_terms` - MeSH terms to filter by
49 ///
50 /// # Example
51 ///
52 /// ```
53 /// use pubmed_client::pubmed::SearchQuery;
54 ///
55 /// let query = SearchQuery::new()
56 /// .mesh_terms(&["Neoplasms", "Antineoplastic Agents"]);
57 /// ```
58 pub fn mesh_terms<S: AsRef<str>>(mut self, mesh_terms: &[S]) -> Self {
59 for term in mesh_terms {
60 self = self.mesh_term(term.as_ref());
61 }
62 self
63 }
64
65 /// Filter by MeSH subheading
66 ///
67 /// # Arguments
68 ///
69 /// * `subheading` - MeSH subheading to filter by
70 ///
71 /// # Example
72 ///
73 /// ```
74 /// use pubmed_client::pubmed::SearchQuery;
75 ///
76 /// let query = SearchQuery::new()
77 /// .mesh_term("Diabetes Mellitus")
78 /// .mesh_subheading("drug therapy");
79 /// ```
80 pub fn mesh_subheading<S: Into<String>>(mut self, subheading: S) -> Self {
81 self.filters.push(format!("{}[sh]", subheading.into()));
82 self
83 }
84
85 /// Filter by first author
86 ///
87 /// # Arguments
88 ///
89 /// * `author` - First author name to search for
90 ///
91 /// # Example
92 ///
93 /// ```
94 /// use pubmed_client::pubmed::SearchQuery;
95 ///
96 /// let query = SearchQuery::new()
97 /// .query("cancer treatment")
98 /// .first_author("Smith J");
99 /// ```
100 pub fn first_author<S: Into<String>>(mut self, author: S) -> Self {
101 self.filters.push(format!("{}[1au]", author.into()));
102 self
103 }
104
105 /// Filter by last author
106 ///
107 /// # Arguments
108 ///
109 /// * `author` - Last author name to search for
110 ///
111 /// # Example
112 ///
113 /// ```
114 /// use pubmed_client::pubmed::SearchQuery;
115 ///
116 /// let query = SearchQuery::new()
117 /// .query("genomics")
118 /// .last_author("Johnson M");
119 /// ```
120 pub fn last_author<S: Into<String>>(mut self, author: S) -> Self {
121 self.filters.push(format!("{}[lastau]", author.into()));
122 self
123 }
124
125 /// Filter by any author
126 ///
127 /// # Arguments
128 ///
129 /// * `author` - Author name to search for
130 ///
131 /// # Example
132 ///
133 /// ```
134 /// use pubmed_client::pubmed::SearchQuery;
135 ///
136 /// let query = SearchQuery::new()
137 /// .query("machine learning")
138 /// .author("Williams K");
139 /// ```
140 pub fn author<S: Into<String>>(mut self, author: S) -> Self {
141 self.filters.push(format!("{}[au]", author.into()));
142 self
143 }
144
145 /// Filter by institution/affiliation
146 ///
147 /// # Arguments
148 ///
149 /// * `institution` - Institution name to search for
150 ///
151 /// # Example
152 ///
153 /// ```
154 /// use pubmed_client::pubmed::SearchQuery;
155 ///
156 /// let query = SearchQuery::new()
157 /// .query("cardiology research")
158 /// .affiliation("Harvard Medical School");
159 /// ```
160 pub fn affiliation<S: Into<String>>(mut self, institution: S) -> Self {
161 self.filters.push(format!("{}[ad]", institution.into()));
162 self
163 }
164
165 /// Filter by ORCID identifier
166 ///
167 /// # Arguments
168 ///
169 /// * `orcid_id` - ORCID identifier to search for
170 ///
171 /// # Example
172 ///
173 /// ```
174 /// use pubmed_client::pubmed::SearchQuery;
175 ///
176 /// let query = SearchQuery::new()
177 /// .query("computational biology")
178 /// .orcid("0000-0001-2345-6789");
179 /// ```
180 pub fn orcid<S: Into<String>>(mut self, orcid_id: S) -> Self {
181 self.filters.push(format!("{}[auid]", orcid_id.into()));
182 self
183 }
184
185 /// Filter by organism using MeSH terms (scientific or common name)
186 ///
187 /// # Arguments
188 ///
189 /// * `organism` - Organism name (scientific or common name)
190 ///
191 /// # Examples
192 ///
193 /// ```
194 /// use pubmed_client::pubmed::SearchQuery;
195 ///
196 /// // Using scientific name
197 /// let query = SearchQuery::new()
198 /// .query("gene expression")
199 /// .organism_mesh("Mus musculus");
200 ///
201 /// // Using common name
202 /// let query = SearchQuery::new()
203 /// .query("metabolism")
204 /// .organism_mesh("Mice");
205 ///
206 /// // Using bacteria
207 /// let query = SearchQuery::new()
208 /// .query("antibiotic resistance")
209 /// .organism_mesh("Escherichia coli");
210 /// ```
211 pub fn organism_mesh<S: Into<String>>(mut self, organism: S) -> Self {
212 self.filters.push(format!("{}[mh]", organism.into()));
213 self
214 }
215
216 /// Filter to human studies only
217 ///
218 /// # Example
219 ///
220 /// ```
221 /// use pubmed_client::pubmed::SearchQuery;
222 ///
223 /// let query = SearchQuery::new()
224 /// .query("drug treatment")
225 /// .human_studies_only();
226 /// ```
227 pub fn human_studies_only(mut self) -> Self {
228 self.filters.push("humans[mh]".to_string());
229 self
230 }
231
232 /// Filter to animal studies only
233 ///
234 /// # Example
235 ///
236 /// ```
237 /// use pubmed_client::pubmed::SearchQuery;
238 ///
239 /// let query = SearchQuery::new()
240 /// .query("preclinical research")
241 /// .animal_studies_only();
242 /// ```
243 pub fn animal_studies_only(mut self) -> Self {
244 self.filters.push("animals[mh]".to_string());
245 self
246 }
247
248 /// Filter by age group
249 ///
250 /// # Arguments
251 ///
252 /// * `age_group` - Age group to filter by (e.g., "Child", "Adult", "Aged")
253 ///
254 /// # Example
255 ///
256 /// ```
257 /// use pubmed_client::pubmed::SearchQuery;
258 ///
259 /// let query = SearchQuery::new()
260 /// .query("pediatric medicine")
261 /// .age_group("Child");
262 /// ```
263 pub fn age_group<S: Into<String>>(mut self, age_group: S) -> Self {
264 self.filters.push(format!("{}[mh]", age_group.into()));
265 self
266 }
267
268 /// Add a custom filter
269 ///
270 /// # Arguments
271 ///
272 /// * `filter` - Custom filter string in PubMed syntax
273 ///
274 /// # Example
275 ///
276 /// ```
277 /// use pubmed_client::pubmed::SearchQuery;
278 ///
279 /// let query = SearchQuery::new()
280 /// .query("research")
281 /// .custom_filter("humans[mh]");
282 /// ```
283 pub fn custom_filter<S: Into<String>>(mut self, filter: S) -> Self {
284 self.filters.push(filter.into());
285 self
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292
293 #[test]
294 fn test_mesh_term() {
295 let query = SearchQuery::new().mesh_term("Neoplasms");
296 assert_eq!(query.build(), "Neoplasms[mh]");
297 }
298
299 #[test]
300 fn test_mesh_major_topic() {
301 let query = SearchQuery::new().mesh_major_topic("Diabetes Mellitus, Type 2");
302 assert_eq!(query.build(), "Diabetes Mellitus, Type 2[majr]");
303 }
304
305 #[test]
306 fn test_multiple_mesh_terms() {
307 let mesh_terms = ["Neoplasms", "Antineoplastic Agents"];
308 let query = SearchQuery::new().mesh_terms(&mesh_terms);
309 assert_eq!(query.build(), "Neoplasms[mh] AND Antineoplastic Agents[mh]");
310 }
311
312 #[test]
313 fn test_mesh_subheading() {
314 let query = SearchQuery::new()
315 .mesh_term("Diabetes Mellitus")
316 .mesh_subheading("drug therapy");
317 assert_eq!(query.build(), "Diabetes Mellitus[mh] AND drug therapy[sh]");
318 }
319
320 #[test]
321 fn test_first_author() {
322 let query = SearchQuery::new().first_author("Smith J");
323 assert_eq!(query.build(), "Smith J[1au]");
324 }
325
326 #[test]
327 fn test_last_author() {
328 let query = SearchQuery::new().last_author("Johnson M");
329 assert_eq!(query.build(), "Johnson M[lastau]");
330 }
331
332 #[test]
333 fn test_any_author() {
334 let query = SearchQuery::new().author("Williams K");
335 assert_eq!(query.build(), "Williams K[au]");
336 }
337
338 #[test]
339 fn test_affiliation() {
340 let query = SearchQuery::new().affiliation("Harvard Medical School");
341 assert_eq!(query.build(), "Harvard Medical School[ad]");
342 }
343
344 #[test]
345 fn test_orcid() {
346 let query = SearchQuery::new().orcid("0000-0001-2345-6789");
347 assert_eq!(query.build(), "0000-0001-2345-6789[auid]");
348 }
349
350 #[test]
351 fn test_organism_mesh() {
352 let query = SearchQuery::new().organism_mesh("Mus musculus");
353 assert_eq!(query.build(), "Mus musculus[mh]");
354 }
355
356 #[test]
357 fn test_organism_mesh_with_common_name() {
358 let query = SearchQuery::new().organism_mesh("Mice");
359 assert_eq!(query.build(), "Mice[mh]");
360 }
361
362 #[test]
363 fn test_human_studies_only() {
364 let query = SearchQuery::new().human_studies_only();
365 assert_eq!(query.build(), "humans[mh]");
366 }
367
368 #[test]
369 fn test_animal_studies_only() {
370 let query = SearchQuery::new().animal_studies_only();
371 assert_eq!(query.build(), "animals[mh]");
372 }
373
374 #[test]
375 fn test_age_group() {
376 let query = SearchQuery::new().age_group("Child");
377 assert_eq!(query.build(), "Child[mh]");
378 }
379
380 #[test]
381 fn test_custom_filter() {
382 let query = SearchQuery::new().custom_filter("custom[field]");
383 assert_eq!(query.build(), "custom[field]");
384 }
385
386 #[test]
387 fn test_combined_advanced_filters() {
388 let query = SearchQuery::new()
389 .query("cancer treatment")
390 .mesh_term("Neoplasms")
391 .author("Smith J")
392 .human_studies_only()
393 .affiliation("Harvard");
394
395 let expected =
396 "cancer treatment AND Neoplasms[mh] AND Smith J[au] AND humans[mh] AND Harvard[ad]";
397 assert_eq!(query.build(), expected);
398 }
399
400 #[test]
401 fn test_empty_mesh_terms_array() {
402 let mesh_terms: &[&str] = &[];
403 let query = SearchQuery::new().mesh_terms(mesh_terms);
404 assert_eq!(query.build(), "");
405 }
406
407 #[test]
408 fn test_single_mesh_term_via_array() {
409 let mesh_terms = ["Neoplasms"];
410 let query = SearchQuery::new().mesh_terms(&mesh_terms);
411 assert_eq!(query.build(), "Neoplasms[mh]");
412 }
413
414 #[test]
415 fn test_mesh_term_with_spaces() {
416 let query = SearchQuery::new().mesh_term("Diabetes Mellitus, Type 2");
417 assert_eq!(query.build(), "Diabetes Mellitus, Type 2[mh]");
418 }
419
420 #[test]
421 fn test_author_with_special_characters() {
422 let query = SearchQuery::new().author("O'Connor J");
423 assert_eq!(query.build(), "O'Connor J[au]");
424 }
425
426 #[test]
427 fn test_affiliation_with_special_characters() {
428 let query = SearchQuery::new().affiliation("Johns Hopkins & MIT");
429 assert_eq!(query.build(), "Johns Hopkins & MIT[ad]");
430 }
431
432 #[test]
433 fn test_custom_filter_preservation() {
434 let query = SearchQuery::new()
435 .custom_filter("first[custom]")
436 .custom_filter("second[custom]");
437 assert_eq!(query.build(), "first[custom] AND second[custom]");
438 }
439}