Skip to main content

rs_plugin_common_interfaces/domain/
book.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::domain::{other_ids::OtherIds, person::Person, rs_ids::RsIds};
5
6#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
7#[serde(rename_all = "camelCase")]
8pub struct Book {
9    #[serde(default)]
10    pub id: String,
11    pub name: String,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    #[serde(rename = "type")]
14    pub kind: Option<String>,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub serie_ref: Option<String>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub volume: Option<f64>,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub chapter: Option<f64>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub year: Option<u16>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub airdate: Option<i64>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub overview: Option<String>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub pages: Option<u32>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub params: Option<Value>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub lang: Option<String>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub original: Option<String>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub isbn13: Option<String>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub openlibrary_edition_id: Option<String>,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub openlibrary_work_id: Option<String>,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub google_books_volume_id: Option<String>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub asin: Option<String>,
45    pub otherids: Option<OtherIds>,
46    #[serde(default)]
47    pub modified: u64,
48    #[serde(default)]
49    pub added: u64,
50}
51
52impl From<Book> for RsIds {
53    fn from(value: Book) -> Self {
54        RsIds {
55            redseat: Some(value.id),
56            isbn13: value.isbn13,
57            openlibrary_edition_id: value.openlibrary_edition_id,
58            openlibrary_work_id: value.openlibrary_work_id,
59            google_books_volume_id: value.google_books_volume_id,
60            asin: value.asin,
61            other_ids: value.otherids,
62            volume: value.volume,
63            chapter: value.chapter,
64            ..Default::default()
65        }
66    }
67}
68
69#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
70#[serde(rename_all = "camelCase")]
71pub struct BookForUpdate {
72    pub name: Option<String>,
73    #[serde(rename = "type")]
74    pub kind: Option<String>,
75    pub serie_ref: Option<String>,
76    pub volume: Option<f64>,
77    pub chapter: Option<f64>,
78    pub year: Option<u16>,
79    pub airdate: Option<i64>,
80    pub overview: Option<String>,
81    pub pages: Option<u32>,
82    pub params: Option<Value>,
83    pub lang: Option<String>,
84    pub original: Option<String>,
85    pub isbn13: Option<String>,
86    pub openlibrary_edition_id: Option<String>,
87    pub openlibrary_work_id: Option<String>,
88    pub google_books_volume_id: Option<String>,
89    pub asin: Option<String>,
90    pub otherids: Option<OtherIds>,
91
92    pub people: Option<Vec<Person>>,
93}
94
95impl BookForUpdate {
96    pub fn has_update(&self) -> bool {
97        self != &BookForUpdate::default()
98    }
99}
100
101
102#[cfg(test)]
103mod tests {
104    use super::Book;
105    use crate::domain::other_ids::OtherIds;
106    use serde_json::json;
107
108    #[test]
109    fn book_otherids_serializes_as_array_and_rejects_string() {
110        let book = Book {
111            id: "book-1".to_string(),
112            name: "Book 1".to_string(),
113            otherids: Some(OtherIds(vec!["goodreads:321".to_string()])),
114            ..Default::default()
115        };
116        let value = serde_json::to_value(&book).unwrap();
117        assert_eq!(value.get("otherids"), Some(&json!(["goodreads:321"])));
118
119        let parsed: Book = serde_json::from_value(json!({
120            "id": "book-1",
121            "name": "Book 1",
122            "otherids": ["custom:1"]
123        }))
124        .unwrap();
125        assert_eq!(
126            parsed.otherids,
127            Some(OtherIds(vec!["custom:1".to_string()]))
128        );
129
130        let invalid = serde_json::from_value::<Book>(json!({
131            "id": "book-1",
132            "name": "Book 1",
133            "otherids": "custom:1"
134        }));
135        assert!(invalid.is_err());
136    }
137}