1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::fmt::Display;
use derive_builder::Builder;
use reqwest::Url;
use crate::OpenlibraryRequest;
#[derive(Default, Clone, Debug)]
pub enum SearchType {
#[default]
Books,
Authors,
Subjects,
Lists,
}
impl Display for SearchType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Books => "",
Self::Authors => "/authors",
Self::Subjects => "/subjects",
Self::Lists => "/lists",
}
)
}
}
#[derive(Builder, Default, Debug)]
#[builder(setter(into), default)]
pub struct Search {
#[builder(setter(strip_option))]
query: Option<String>,
search_type: SearchType,
#[builder(default = "1")]
page: u32,
#[builder(default = "10")]
limit: u32,
#[builder(default = "vec![]")]
fields: Vec<String>,
}
impl OpenlibraryRequest for Search {
fn url(&self) -> Url {
let mut params = Vec::new();
params.push(("page", self.page.to_string()));
params.push(("limit", self.limit.to_string()));
params.push(("q", self.query.as_deref().unwrap_or_default().to_string()));
params.push(("fields", self.fields.join(",")));
Url::parse_with_params(
format!("{}/search{}.json", Self::host(), self.search_type,).as_str(),
params,
)
.unwrap()
}
}
#[cfg(test)]
mod tests {
use mockito::mock;
use serde_json::json;
use crate::OpenlibraryRequest;
use super::SearchBuilder;
#[test]
fn test_search_execute_valid_response() {
let search = SearchBuilder::default()
.query("test")
.fields(
["key", "title"]
.into_iter()
.map(String::from)
.collect::<Vec<String>>(),
)
.build()
.unwrap();
let json = json!({
"numFound": 1,
"start": 0,
"numFoundExact": true,
"docs": [
{
"key": "/works/43242",
"title": "test",
}
]
});
let _m = mock(
"GET",
format!("{}?{}", search.url().path(), search.url().query().unwrap()).as_str(),
)
.with_header("content-type", "application/json")
.with_body(json.to_string())
.create();
let search_result = search.execute();
assert_eq!(search_result["numFound"], 1);
assert_eq!(search_result["start"], 0);
assert_eq!(search_result["numFoundExact"], true);
assert_eq!(search_result["docs"].as_array().unwrap().len(), 1);
let doc = &search_result["docs"][0];
assert_eq!(doc.get("key").unwrap().as_str().unwrap(), "/works/43242");
assert_eq!(doc.get("title").unwrap().as_str().unwrap(), "test");
}
}