1use std::fmt::Display;
2
3use derive_builder::Builder;
4
5use crate::OpenlibraryRequest;
6
7#[derive(Default, Clone, Debug)]
8pub enum BookType {
9 #[default]
10 Works,
11 Editions,
12 ISBN,
13}
14
15impl Display for BookType {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 write!(
18 f,
19 "{}",
20 match self {
21 Self::Works => "/works",
22 Self::Editions => "/books",
23 Self::ISBN => "/isbn",
24 }
25 )
26 }
27}
28
29#[derive(Builder, Default, Debug)]
33#[builder(setter(into), default)]
34pub struct Books {
35 book_type: BookType,
36 id: String,
37}
38
39impl OpenlibraryRequest for Books {
40 fn path(&self) -> String {
41 format!("{}/{}.json", self.book_type, self.id)
42 }
43
44 fn query(&self) -> Vec<(&'static str, String)> {
45 vec![]
46 }
47}
48
49#[derive(Builder, Default, Debug)]
53#[builder(setter(into), default)]
54pub struct BooksGeneric {
55 #[builder(default = "vec![]")]
56 bibkeys: Vec<String>,
57 #[builder(default = r#"String::from("viewapi")"#)]
58 jscmd: String,
59}
60
61impl OpenlibraryRequest for BooksGeneric {
62 fn path(&self) -> String {
63 String::from("/api/books")
64 }
65
66 fn query(&self) -> Vec<(&'static str, String)> {
67 vec![
68 ("format", String::from("json")),
69 ("bibkeys", self.bibkeys.join(",")),
70 ("jscmd", self.jscmd.clone()),
71 ]
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use mockito::{mock, Matcher};
78 use serde_json::json;
79
80 use crate::OpenlibraryRequest;
81
82 use super::{BooksBuilder, BooksGenericBuilder};
83
84 #[test]
85 fn test_books_execute() {
86 let books = BooksBuilder::default().id("1234").build().unwrap();
87
88 let json = json!({
89 "title": "test",
90 "description": "this is a test",
91 "key": "/works/1234"
92 });
93
94 let _m = mock("GET", Matcher::Regex(format!(r"{}\w*", books.url().path())))
95 .with_header("content-type", "application/json")
96 .with_body(json.to_string())
97 .create();
98
99 let books_result = books.execute();
100
101 assert_eq!(books_result["title"], "test");
102 assert_eq!(books_result["description"], "this is a test");
103 assert_eq!(books_result["key"], "/works/1234");
104 }
105
106 #[test]
107 fn test_books_generic_execute() {
108 let books_generic = BooksGenericBuilder::default()
109 .bibkeys(vec!["ISBN:0385472579".to_string()])
110 .build()
111 .unwrap();
112
113 let json = json!({
114 "ISBN:0385472579": {
115 "bib_key": "ISBN:0385472579",
116 "preview": "noview",
117 "thumbnail_url": "https://covers.openlibrary.org/b/id/240726-S.jpg",
118 "preview_url": "https://openlibrary.org/books/OL1397864M/Zen_speaks",
119 "info_url": "https://openlibrary.org/books/OL1397864M/Zen_speaks"
120 }
121 });
122
123 let _m = mock(
124 "GET",
125 Matcher::Regex(format!(r"{}\w*", books_generic.url().path())),
126 )
127 .with_header("content-type", "application/json")
128 .with_body(json.to_string())
129 .create();
130
131 let result = books_generic.execute();
132 let inner_result = &result["ISBN:0385472579"];
133
134 assert_eq!(inner_result["bib_key"], "ISBN:0385472579");
135 assert_eq!(inner_result["preview"], "noview");
136 assert_eq!(
137 inner_result["thumbnail_url"],
138 "https://covers.openlibrary.org/b/id/240726-S.jpg"
139 );
140 assert_eq!(
141 inner_result["preview_url"],
142 "https://openlibrary.org/books/OL1397864M/Zen_speaks"
143 );
144 assert_eq!(
145 inner_result["info_url"],
146 "https://openlibrary.org/books/OL1397864M/Zen_speaks"
147 );
148 }
149}