1use chrono::naive::NaiveDate;
2use serde::{Deserialize, Serialize};
3use std::fmt;
4use std::str::FromStr;
5use uuid::Uuid;
6
7use crate::errors::ThothError;
8#[cfg(feature = "backend")]
9use crate::schema::work;
10
11#[cfg_attr(feature = "backend", derive(DbEnum, juniper::GraphQLEnum))]
12#[cfg_attr(feature = "backend", DieselType = "Work_type")]
13#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
14#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
15pub enum WorkType {
16 #[cfg_attr(feature = "backend", db_rename = "book-chapter")]
17 BookChapter,
18 Monograph,
19 #[cfg_attr(feature = "backend", db_rename = "edited-book")]
20 EditedBook,
21 Textbook,
22 #[cfg_attr(feature = "backend", db_rename = "journal-issue")]
23 JournalIssue,
24 #[cfg_attr(feature = "backend", db_rename = "book-set")]
25 BookSet,
26}
27
28#[cfg_attr(feature = "backend", derive(DbEnum, juniper::GraphQLEnum))]
29#[cfg_attr(feature = "backend", DieselType = "Work_status")]
30#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
31#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
32pub enum WorkStatus {
33 Unspecified,
34 Cancelled,
35 Forthcoming,
36 #[cfg_attr(feature = "backend", db_rename = "postponed-indefinitely")]
37 PostponedIndefinitely,
38 Active,
39 #[cfg_attr(feature = "backend", db_rename = "no-longer-our-product")]
40 NoLongerOurProduct,
41 #[cfg_attr(feature = "backend", db_rename = "out-of-stock-indefinitely")]
42 OutOfStockIndefinitely,
43 #[cfg_attr(feature = "backend", db_rename = "out-of-print")]
44 OutOfPrint,
45 Inactive,
46 Unknown,
47 Remaindered,
48 #[cfg_attr(feature = "backend", db_rename = "withdrawn-from-sale")]
49 WithdrawnFromSale,
50 Recalled,
51}
52
53#[cfg_attr(feature = "backend", derive(Queryable))]
54pub struct Work {
55 pub work_id: Uuid,
56 pub work_type: WorkType,
57 pub work_status: WorkStatus,
58 pub full_title: String,
59 pub title: String,
60 pub subtitle: Option<String>,
61 pub reference: Option<String>,
62 pub edition: i32,
63 pub imprint_id: Uuid,
64 pub doi: Option<String>,
65 pub publication_date: Option<NaiveDate>,
66 pub place: Option<String>,
67 pub width: Option<i32>,
68 pub height: Option<i32>,
69 pub page_count: Option<i32>,
70 pub page_breakdown: Option<String>,
71 pub image_count: Option<i32>,
72 pub table_count: Option<i32>,
73 pub audio_count: Option<i32>,
74 pub video_count: Option<i32>,
75 pub license: Option<String>,
76 pub copyright_holder: String,
77 pub landing_page: Option<String>,
78 pub lccn: Option<i32>,
79 pub oclc: Option<i32>,
80 pub short_abstract: Option<String>,
81 pub long_abstract: Option<String>,
82 pub general_note: Option<String>,
83 pub toc: Option<String>,
84 pub cover_url: Option<String>,
85 pub cover_caption: Option<String>,
86}
87
88#[cfg_attr(
89 feature = "backend",
90 derive(juniper::GraphQLInputObject, Insertable),
91 table_name = "work"
92)]
93pub struct NewWork {
94 pub work_type: WorkType,
95 pub work_status: WorkStatus,
96 pub full_title: String,
97 pub title: String,
98 pub subtitle: Option<String>,
99 pub reference: Option<String>,
100 pub edition: i32,
101 pub imprint_id: Uuid,
102 pub doi: Option<String>,
103 pub publication_date: Option<NaiveDate>,
104 pub place: Option<String>,
105 pub width: Option<i32>,
106 pub height: Option<i32>,
107 pub page_count: Option<i32>,
108 pub page_breakdown: Option<String>,
109 pub image_count: Option<i32>,
110 pub table_count: Option<i32>,
111 pub audio_count: Option<i32>,
112 pub video_count: Option<i32>,
113 pub license: Option<String>,
114 pub copyright_holder: String,
115 pub landing_page: Option<String>,
116 pub lccn: Option<i32>,
117 pub oclc: Option<i32>,
118 pub short_abstract: Option<String>,
119 pub long_abstract: Option<String>,
120 pub general_note: Option<String>,
121 pub toc: Option<String>,
122 pub cover_url: Option<String>,
123 pub cover_caption: Option<String>,
124}
125
126#[cfg_attr(
127 feature = "backend",
128 derive(juniper::GraphQLInputObject, AsChangeset),
129 changeset_options(treat_none_as_null = "true"),
130 table_name = "work"
131)]
132pub struct PatchWork {
133 pub work_id: Uuid,
134 pub work_type: WorkType,
135 pub work_status: WorkStatus,
136 pub full_title: String,
137 pub title: String,
138 pub subtitle: Option<String>,
139 pub reference: Option<String>,
140 pub edition: i32,
141 pub imprint_id: Uuid,
142 pub doi: Option<String>,
143 pub publication_date: Option<NaiveDate>,
144 pub place: Option<String>,
145 pub width: Option<i32>,
146 pub height: Option<i32>,
147 pub page_count: Option<i32>,
148 pub page_breakdown: Option<String>,
149 pub image_count: Option<i32>,
150 pub table_count: Option<i32>,
151 pub audio_count: Option<i32>,
152 pub video_count: Option<i32>,
153 pub license: Option<String>,
154 pub copyright_holder: String,
155 pub landing_page: Option<String>,
156 pub lccn: Option<i32>,
157 pub oclc: Option<i32>,
158 pub short_abstract: Option<String>,
159 pub long_abstract: Option<String>,
160 pub general_note: Option<String>,
161 pub toc: Option<String>,
162 pub cover_url: Option<String>,
163 pub cover_caption: Option<String>,
164}
165
166impl Default for WorkType {
167 fn default() -> WorkType {
168 WorkType::Monograph
169 }
170}
171
172impl Default for WorkStatus {
173 fn default() -> WorkStatus {
174 WorkStatus::Inactive
175 }
176}
177
178impl fmt::Display for WorkType {
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 match self {
181 WorkType::BookChapter => write!(f, "Book Chapter"),
182 WorkType::Monograph => write!(f, "Monograph"),
183 WorkType::EditedBook => write!(f, "Edited Book"),
184 WorkType::Textbook => write!(f, "Textbook"),
185 WorkType::JournalIssue => write!(f, "Journal Issue"),
186 WorkType::BookSet => write!(f, "Book Set"),
187 }
188 }
189}
190
191impl FromStr for WorkType {
192 type Err = ThothError;
193
194 fn from_str(input: &str) -> Result<WorkType, ThothError> {
195 match input {
196 "Book Chapter" => Ok(WorkType::BookChapter),
197 "Monograph" => Ok(WorkType::Monograph),
198 "Edited Book" => Ok(WorkType::EditedBook),
199 "Textbook" => Ok(WorkType::Textbook),
200 "Journal Issue" => Ok(WorkType::JournalIssue),
201 "Book Set" => Ok(WorkType::BookSet),
202 _ => Err(ThothError::InvalidWorkType(input.to_string())),
203 }
204 }
205}
206
207impl fmt::Display for WorkStatus {
208 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209 match self {
210 WorkStatus::Unspecified => write!(f, "Unspecified"),
211 WorkStatus::Cancelled => write!(f, "Cancelled"),
212 WorkStatus::Forthcoming => write!(f, "Forthcoming"),
213 WorkStatus::PostponedIndefinitely => write!(f, "Postponed Indefinitely"),
214 WorkStatus::Active => write!(f, "Active"),
215 WorkStatus::NoLongerOurProduct => write!(f, "No Longer Our Product"),
216 WorkStatus::OutOfStockIndefinitely => write!(f, "Out Of Stock Indefinitely"),
217 WorkStatus::OutOfPrint => write!(f, "Out Of Print"),
218 WorkStatus::Inactive => write!(f, "Inactive"),
219 WorkStatus::Unknown => write!(f, "Unknown"),
220 WorkStatus::Remaindered => write!(f, "Remaindered"),
221 WorkStatus::WithdrawnFromSale => write!(f, "Withdrawn From Sale"),
222 WorkStatus::Recalled => write!(f, "Recalled"),
223 }
224 }
225}
226
227impl FromStr for WorkStatus {
228 type Err = ThothError;
229
230 fn from_str(input: &str) -> Result<WorkStatus, ThothError> {
231 match input {
232 "Unspecified" => Ok(WorkStatus::Unspecified),
233 "Cancelled" => Ok(WorkStatus::Cancelled),
234 "Forthcoming" => Ok(WorkStatus::Forthcoming),
235 "Postponed Indefinitely" => Ok(WorkStatus::PostponedIndefinitely),
236 "Active" => Ok(WorkStatus::Active),
237 "No Longer Our Product" => Ok(WorkStatus::NoLongerOurProduct),
238 "Out Of Stock Indefinitely" => Ok(WorkStatus::OutOfStockIndefinitely),
239 "Out Of Print" => Ok(WorkStatus::OutOfPrint),
240 "Inactive" => Ok(WorkStatus::Inactive),
241 "Unknown" => Ok(WorkStatus::Unknown),
242 "Remaindered" => Ok(WorkStatus::Remaindered),
243 "Withdrawn From Sale" => Ok(WorkStatus::WithdrawnFromSale),
244 "Recalled" => Ok(WorkStatus::Recalled),
245 _ => Err(ThothError::InvalidWorkStatus(input.to_string())),
246 }
247 }
248}
249
250#[test]
251fn test_worktype_default() {
252 let worktype: WorkType = Default::default();
253 assert_eq!(worktype, WorkType::Monograph);
254}
255
256#[test]
257fn test_workstatus_default() {
258 let workstatus: WorkStatus = Default::default();
259 assert_eq!(workstatus, WorkStatus::Inactive);
260}
261
262#[test]
263fn test_worktype_display() {
264 assert_eq!(format!("{}", WorkType::BookChapter), "Book Chapter");
265 assert_eq!(format!("{}", WorkType::Monograph), "Monograph");
266 assert_eq!(format!("{}", WorkType::EditedBook), "Edited Book");
267 assert_eq!(format!("{}", WorkType::Textbook), "Textbook");
268 assert_eq!(format!("{}", WorkType::JournalIssue), "Journal Issue");
269 assert_eq!(format!("{}", WorkType::BookSet), "Book Set");
270}
271
272#[test]
273fn test_workstatus_display() {
274 assert_eq!(format!("{}", WorkStatus::Cancelled), "Cancelled");
275 assert_eq!(format!("{}", WorkStatus::Forthcoming), "Forthcoming");
276 assert_eq!(
277 format!("{}", WorkStatus::PostponedIndefinitely),
278 "Postponed Indefinitely"
279 );
280 assert_eq!(format!("{}", WorkStatus::Active), "Active");
281 assert_eq!(
282 format!("{}", WorkStatus::NoLongerOurProduct),
283 "No Longer Our Product"
284 );
285 assert_eq!(
286 format!("{}", WorkStatus::OutOfStockIndefinitely),
287 "Out Of Stock Indefinitely"
288 );
289 assert_eq!(format!("{}", WorkStatus::OutOfPrint), "Out Of Print");
290 assert_eq!(format!("{}", WorkStatus::Inactive), "Inactive");
291 assert_eq!(format!("{}", WorkStatus::Unknown), "Unknown");
292 assert_eq!(format!("{}", WorkStatus::Remaindered), "Remaindered");
293 assert_eq!(
294 format!("{}", WorkStatus::WithdrawnFromSale),
295 "Withdrawn From Sale"
296 );
297 assert_eq!(format!("{}", WorkStatus::Recalled), "Recalled");
298}
299
300#[test]
301fn test_worktype_fromstr() {
302 assert_eq!(
303 WorkType::from_str("Book Chapter").unwrap(),
304 WorkType::BookChapter
305 );
306 assert_eq!(
307 WorkType::from_str("Monograph").unwrap(),
308 WorkType::Monograph
309 );
310 assert_eq!(
311 WorkType::from_str("Edited Book").unwrap(),
312 WorkType::EditedBook
313 );
314 assert_eq!(WorkType::from_str("Textbook").unwrap(), WorkType::Textbook);
315 assert_eq!(
316 WorkType::from_str("Journal Issue").unwrap(),
317 WorkType::JournalIssue
318 );
319 assert_eq!(WorkType::from_str("Book Set").unwrap(), WorkType::BookSet);
320
321 assert!(WorkType::from_str("Book Section").is_err());
322 assert!(WorkType::from_str("Manuscript").is_err());
323}
324
325#[test]
326fn test_workstatus_fromstr() {
327 assert_eq!(
328 WorkStatus::from_str("Unspecified").unwrap(),
329 WorkStatus::Unspecified
330 );
331 assert_eq!(
332 WorkStatus::from_str("Cancelled").unwrap(),
333 WorkStatus::Cancelled
334 );
335 assert_eq!(
336 WorkStatus::from_str("Forthcoming").unwrap(),
337 WorkStatus::Forthcoming
338 );
339 assert_eq!(
340 WorkStatus::from_str("Postponed Indefinitely").unwrap(),
341 WorkStatus::PostponedIndefinitely
342 );
343 assert_eq!(WorkStatus::from_str("Active").unwrap(), WorkStatus::Active);
344 assert_eq!(
345 WorkStatus::from_str("No Longer Our Product").unwrap(),
346 WorkStatus::NoLongerOurProduct
347 );
348 assert_eq!(
349 WorkStatus::from_str("Out Of Stock Indefinitely").unwrap(),
350 WorkStatus::OutOfStockIndefinitely
351 );
352 assert_eq!(
353 WorkStatus::from_str("Out Of Print").unwrap(),
354 WorkStatus::OutOfPrint
355 );
356 assert_eq!(
357 WorkStatus::from_str("Inactive").unwrap(),
358 WorkStatus::Inactive
359 );
360 assert_eq!(
361 WorkStatus::from_str("Unknown").unwrap(),
362 WorkStatus::Unknown
363 );
364 assert_eq!(
365 WorkStatus::from_str("Remaindered").unwrap(),
366 WorkStatus::Remaindered
367 );
368 assert_eq!(
369 WorkStatus::from_str("Withdrawn From Sale").unwrap(),
370 WorkStatus::WithdrawnFromSale
371 );
372 assert_eq!(
373 WorkStatus::from_str("Recalled").unwrap(),
374 WorkStatus::Recalled
375 );
376
377 assert!(WorkStatus::from_str("Published").is_err());
378 assert!(WorkStatus::from_str("Unpublished").is_err());
379}