|
| 1 | +use crate::models::{ArchiveOrgApiResponse, ArchiveOrgCountRespone, Book}; |
| 2 | +use async_trait::async_trait; |
| 3 | +use gloo_net::http::Request; |
| 4 | +use leptos::logging; |
| 5 | +use leptos_struct_table::{ColumnSort, PaginatedTableDataProvider}; |
| 6 | +use std::collections::VecDeque; |
| 7 | + |
| 8 | +pub struct BookDataProvider { |
| 9 | + sorting: VecDeque<(usize, ColumnSort)>, |
| 10 | +} |
| 11 | + |
| 12 | +impl Default for BookDataProvider { |
| 13 | + fn default() -> Self { |
| 14 | + Self { |
| 15 | + sorting: VecDeque::new(), |
| 16 | + } |
| 17 | + } |
| 18 | +} |
| 19 | + |
| 20 | +impl BookDataProvider { |
| 21 | + fn url_sort_param_for_column(&self, column: usize) -> &'static str { |
| 22 | + match column { |
| 23 | + 0 => "identifierSorter", |
| 24 | + 1 => "titleSorter", |
| 25 | + 2 => "creatorSorter", |
| 26 | + 3 => "publicdate", |
| 27 | + _ => "", |
| 28 | + } |
| 29 | + } |
| 30 | + |
| 31 | + fn url_sort_param_for_sort_pair(&self, pair: &(usize, ColumnSort)) -> String { |
| 32 | + let col = self.url_sort_param_for_column(pair.0); |
| 33 | + |
| 34 | + let dir = match pair.1 { |
| 35 | + ColumnSort::Ascending => "asc", |
| 36 | + ColumnSort::Descending => "desc", |
| 37 | + ColumnSort::None => return "".to_string(), |
| 38 | + }; |
| 39 | + |
| 40 | + format!("&sort%5B%5D={}+{}", col, dir) |
| 41 | + } |
| 42 | + |
| 43 | + fn get_url(&self, page_index: usize) -> String { |
| 44 | + let mut sort = String::new(); |
| 45 | + for pair in &self.sorting { |
| 46 | + sort.push_str(&self.url_sort_param_for_sort_pair(pair)); |
| 47 | + } |
| 48 | + |
| 49 | + format!( |
| 50 | + "https://archive.org/advancedsearch.php?q=creator%3A%28Lewis%29&fl%5B%5D=creator&fl%5B%5D=identifier&fl%5B%5D=publicdate&fl%5B%5D=title{sort}&rows={}&page={}&output=json&callback=", |
| 51 | + Self::PAGE_ROW_COUNT, |
| 52 | + page_index + 1, |
| 53 | + ) |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +#[async_trait(?Send)] |
| 58 | +impl PaginatedTableDataProvider<Book> for BookDataProvider { |
| 59 | + const PAGE_ROW_COUNT: usize = 50; |
| 60 | + |
| 61 | + async fn get_page(&self, page_index: usize) -> Result<Vec<Book>, String> { |
| 62 | + if page_index >= 10000 / Self::PAGE_ROW_COUNT { |
| 63 | + return Ok(vec![]); |
| 64 | + } |
| 65 | + |
| 66 | + let url = self.get_url(page_index); |
| 67 | + |
| 68 | + let resp: ArchiveOrgApiResponse = Request::get(&url) |
| 69 | + .send() |
| 70 | + .await |
| 71 | + .map_err(|e| e.to_string())? |
| 72 | + .json() |
| 73 | + .await |
| 74 | + .map_err(|e| e.to_string())?; |
| 75 | + |
| 76 | + match resp { |
| 77 | + ArchiveOrgApiResponse::Err { error } => Err(error), |
| 78 | + ArchiveOrgApiResponse::Ok { response } => Ok(response.docs), |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + async fn row_count(&self) -> Option<usize> { |
| 83 | + let resp: Option<ArchiveOrgCountRespone> = Request::get("https://archive.org/advancedsearch.php?q=creator%3A(Lewis)&fl[]=creator&fl[]=identifier&fl[]=publicdate&rows=0&page=0&output=json&callback=") |
| 84 | + .send() |
| 85 | + .await |
| 86 | + .map_err(|err| logging::error!("Failed to load count: {:?}", err)) |
| 87 | + .ok()? |
| 88 | + .json() |
| 89 | + .await |
| 90 | + .map_err(|err| logging::error!("Failed to parse count response: {:?}", err)) |
| 91 | + .ok(); |
| 92 | + |
| 93 | + // This API only allows to display up to 10000 results |
| 94 | + resp.map(|r| r.response.num_found.min(10000)) |
| 95 | + } |
| 96 | + |
| 97 | + fn set_sorting(&mut self, sorting: &VecDeque<(usize, ColumnSort)>) { |
| 98 | + self.sorting = sorting.clone(); |
| 99 | + } |
| 100 | +} |
0 commit comments