1use anyhow::Result;
4
5use crate::client::RommClient;
6use crate::endpoints::roms::GetRoms;
7use crate::types::RomList;
8
9pub const ROM_PAGE_CEILING: u64 = 20000;
11
12pub fn rom_list_fetch_complete(list: &RomList) -> bool {
15 let loaded = list.items.len() as u64;
16 loaded >= list.total || loaded >= ROM_PAGE_CEILING
17}
18
19pub async fn fetch_roms_paginated(client: &RommClient, req: &GetRoms) -> Result<RomList> {
21 let mut roms = client.call(req).await?;
22 while !rom_list_fetch_complete(&roms) {
23 let mut next_req = req.clone();
24 next_req.offset = Some(roms.items.len() as u32);
25 let next_batch = client.call(&next_req).await?;
26 if next_batch.items.is_empty() {
27 break;
28 }
29 roms.items.extend(next_batch.items);
30 }
31 Ok(roms)
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use crate::types::Rom;
38
39 fn minimal_rom(id: u64) -> Rom {
40 Rom {
41 id,
42 platform_id: 10,
43 platform_slug: None,
44 platform_fs_slug: None,
45 platform_custom_name: None,
46 platform_display_name: None,
47 fs_name: format!("game{id}.zip"),
48 fs_name_no_tags: format!("game{id}"),
49 fs_name_no_ext: format!("game{id}"),
50 fs_extension: "zip".to_string(),
51 fs_path: format!("/roms/game{id}.zip"),
52 fs_size_bytes: 1,
53 name: format!("Game {id}"),
54 slug: None,
55 summary: None,
56 path_cover_small: None,
57 path_cover_large: None,
58 url_cover: None,
59 has_manual: false,
60 path_manual: None,
61 url_manual: None,
62 is_unidentified: false,
63 is_identified: true,
64 files: Vec::new(),
65 ra_id: None,
66 merged_ra_metadata: None,
67 }
68 }
69
70 fn list(items: usize, total: u64) -> RomList {
71 RomList {
72 items: (0..items).map(|i| minimal_rom(i as u64)).collect(),
73 total,
74 limit: 50,
75 offset: 0,
76 }
77 }
78
79 #[test]
80 fn complete_when_items_cover_total() {
81 assert!(rom_list_fetch_complete(&list(3, 3)));
82 }
83
84 #[test]
85 fn incomplete_when_short_of_total() {
86 assert!(!rom_list_fetch_complete(&list(1, 100)));
87 }
88}