1use crate::format::KeyedValue;
2use crate::models::identifiers::OpenLibraryIdentifier;
3use crate::models::works::Work;
4use crate::models::{Link, LinkName, OpenLibraryModel, OpenLibraryResource};
5use crate::OpenLibraryError;
6use chrono::NaiveDateTime;
7use serde::de::Error;
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9use std::borrow::Cow;
10use std::collections::HashMap;
11use std::convert::TryFrom;
12use std::fmt;
13use std::fmt::Display;
14use std::str::FromStr;
15use url::Url;
16
17#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
18pub struct Author {
19 pub key: String,
20 #[serde(default)]
21 #[serde(skip_serializing_if = "Vec::is_empty")]
22 pub text: Vec<String>,
23 #[serde(rename(deserialize = "type"))]
24 pub r#type: String,
25 pub name: String,
26 #[serde(default)]
27 #[serde(skip_serializing_if = "Vec::is_empty")]
28 pub alternate_names: Vec<String>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub birth_date: Option<String>,
31 pub top_work: String,
32 pub work_count: i32,
33 pub top_subjects: Vec<String>,
34 pub _version_: u64,
35}
36
37#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
38pub struct AuthorReference {
39 #[serde(rename = "type")]
40 #[serde(deserialize_with = "deserialize_author_type")]
41 pub author_type: KeyedValue<AuthorType>,
42 #[serde(rename = "author")]
43 pub identifier: KeyedValue<OpenLibraryResource>,
44}
45
46#[derive(Debug, Eq, PartialEq)]
47pub enum AuthorType {
48 AuthorRole,
49}
50
51impl Display for AuthorType {
52 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53 match self {
54 AuthorType::AuthorRole => write!(f, "/type/author_role"),
55 }
56 }
57}
58
59impl FromStr for AuthorType {
60 type Err = OpenLibraryError;
61
62 fn from_str(value: &str) -> Result<Self, Self::Err> {
63 match value {
64 "author_role" => Ok(Self::AuthorRole),
65 _ => Err(OpenLibraryError::ParsingError {
66 reason: format!("Unable to parse string ({}) into an Author Type", &value),
67 }),
68 }
69 }
70}
71
72impl<'de> Deserialize<'de> for AuthorType {
73 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
74 where
75 D: Deserializer<'de>,
76 {
77 let value: String = Deserialize::deserialize(deserializer).map_err(D::Error::custom)?;
78
79 let chunks = value
80 .split('/')
81 .filter(|str| !str.is_empty())
82 .collect::<Vec<&str>>();
83
84 match chunks.get(0) {
85 Some(&"type") => match chunks.get(1) {
86 Some(value) => Ok(AuthorType::from_str(*value).map_err(D::Error::custom)?),
87 None => Err(D::Error::custom("No Author Type was provided!")),
88 },
89 _ => Err(D::Error::custom(format!(
90 "Invalid format for Author Type: {}",
91 &value
92 ))),
93 }
94 }
95}
96
97impl Serialize for AuthorType {
98 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
99 where
100 S: Serializer,
101 {
102 serializer.serialize_str(self.to_string().as_str())
103 }
104}
105
106#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
107pub struct AuthorDetails {
108 #[serde(skip_serializing_if = "Option::is_none")]
109 pub title: Option<String>,
110 #[serde(default)]
111 #[serde(skip_serializing_if = "Vec::is_empty")]
112 pub source_records: Vec<String>, pub key: OpenLibraryResource,
114 #[serde(default)]
115 #[serde(with = "crate::format::value")]
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub bio: Option<String>,
118 pub photos: Vec<i32>,
119 pub birth_date: String,
121 pub personal_name: String,
122 pub remote_ids: HashMap<String, String>,
123 pub entity_type: Option<String>, pub links: Vec<Link>,
125 pub name: String,
126 pub alternate_names: Vec<String>,
127 pub wikipedia: Option<Url>,
128 pub latest_revision: u16,
129 pub revision: u16,
130 #[serde(with = "crate::format::value")]
131 pub created: Option<NaiveDateTime>,
132 #[serde(with = "crate::format::value")]
133 pub last_modified: Option<NaiveDateTime>,
134}
135
136impl OpenLibraryModel for AuthorDetails {}
137
138#[derive(Deserialize, Debug, Eq, PartialEq, Serialize)]
139pub struct AuthorWorksRequest {
140 pub identifier: OpenLibraryIdentifier,
141 pub limit: Option<u32>,
142 pub offset: Option<u32>,
143}
144
145impl TryFrom<OpenLibraryIdentifier> for AuthorWorksRequest {
146 type Error = OpenLibraryError;
147
148 fn try_from(identifier: OpenLibraryIdentifier) -> Result<Self, OpenLibraryError> {
149 Ok(Self {
150 identifier,
151 limit: None,
152 offset: None,
153 })
154 }
155}
156
157impl TryFrom<Url> for AuthorWorksRequest {
158 type Error = OpenLibraryError;
159
160 fn try_from(value: Url) -> Result<Self, Self::Error> {
161 let path_segments = value
162 .path_segments()
163 .ok_or(OpenLibraryError::ParsingError {
164 reason: "Invalid URL supplied, no path segments found".to_string(),
165 })?
166 .collect::<Vec<&str>>();
167
168 let path_index = path_segments.iter().position(|x| *x == "authors").ok_or(
169 OpenLibraryError::ParsingError {
170 reason: "Invalid URL supplied, unable to determine author identifier".to_string(),
171 },
172 )?;
173
174 let query_parameters = value
175 .query_pairs()
176 .collect::<HashMap<Cow<'_, str>, Cow<'_, str>>>();
177
178 let result = *path_segments
179 .get(path_index + 1)
180 .ok_or(OpenLibraryError::ParsingError {
181 reason: "Unable to find an author identifier within the URL path".to_string(),
182 })?;
183
184 let limit = match query_parameters.get("limit") {
185 Some(x) => Some(x.clone().into_owned().parse::<u32>().map_err(|e| {
186 OpenLibraryError::ParsingError {
187 reason: e.to_string(),
188 }
189 })?),
190 None => None,
191 };
192
193 let offset = match query_parameters.get("offset") {
194 Some(z) => Some(z.clone().into_owned().parse::<u32>().map_err(|e| {
195 OpenLibraryError::ParsingError {
196 reason: e.to_string(),
197 }
198 })?),
199 None => None,
200 };
201
202 Ok(Self {
203 identifier: OpenLibraryIdentifier::from_str(result)?,
204 limit: limit,
205 offset: offset,
206 })
207 }
208}
209
210#[derive(Deserialize, Debug, Eq, PartialEq, Serialize)]
211pub struct AuthorWorksResponse {
212 #[serde(default)]
213 #[serde(skip_serializing_if = "HashMap::is_empty")]
214 pub links: HashMap<LinkName, String>,
215 pub size: u32,
216 #[serde(default)]
217 #[serde(skip_serializing_if = "Vec::is_empty")]
218 pub entries: Vec<Work>,
219}
220
221impl OpenLibraryModel for AuthorWorksResponse {}
222
223#[derive(Debug, Deserialize, Serialize)]
224pub struct AuthorResponse {
225 #[serde(rename = "numFound")]
226 pub num_found: i32,
227 pub start: i32,
228 #[serde(rename = "numFoundExact")]
229 pub num_found_exact: bool,
230 pub docs: Vec<Author>,
231}
232
233impl OpenLibraryModel for AuthorResponse {}
234
235fn deserialize_author_type<'de, D>(deserializer: D) -> Result<KeyedValue<AuthorType>, D::Error>
236where
237 D: Deserializer<'de>,
238{
239 #[derive(Deserialize)]
240 #[serde(untagged)]
241 enum StringOrKeyedValue {
242 String(AuthorType),
243 KeyedValue(KeyedValue<AuthorType>),
244 }
245
246 Ok(match StringOrKeyedValue::deserialize(deserializer)? {
247 StringOrKeyedValue::String(v) => KeyedValue { key: v },
248 StringOrKeyedValue::KeyedValue(v) => v,
249 })
250}