romm_cli/endpoints/
collections.rs1use crate::types::{Collection, VirtualCollectionRow};
2
3use super::Endpoint;
4
5#[derive(Debug, serde::Deserialize)]
7#[serde(untagged)]
8pub enum CollectionsList {
9 List(Vec<Collection>),
10 Paged { items: Vec<Collection> },
11}
12
13impl CollectionsList {
14 pub fn into_vec(self) -> Vec<Collection> {
15 match self {
16 CollectionsList::List(v) => v,
17 CollectionsList::Paged { items } => items,
18 }
19 }
20}
21
22pub fn merge_all_collection_sources(
24 mut manual: Vec<Collection>,
25 mut smart: Vec<Collection>,
26 virtual_rows: Vec<VirtualCollectionRow>,
27) -> Vec<Collection> {
28 for c in &mut manual {
29 c.is_smart = false;
30 c.is_virtual = false;
31 c.virtual_id = None;
32 }
33 for c in &mut smart {
34 c.is_smart = true;
35 c.is_virtual = false;
36 c.virtual_id = None;
37 }
38 let mut virtual_collections: Vec<Collection> =
39 virtual_rows.into_iter().map(Collection::from).collect();
40 manual.append(&mut smart);
41 manual.append(&mut virtual_collections);
42 manual
43}
44
45pub fn merge_manual_and_smart(manual: Vec<Collection>, smart: Vec<Collection>) -> Vec<Collection> {
47 merge_all_collection_sources(manual, smart, Vec::new())
48}
49
50#[derive(Debug, Default, Clone)]
52pub struct ListCollections;
53
54impl Endpoint for ListCollections {
55 type Output = CollectionsList;
56
57 fn method(&self) -> &'static str {
58 "GET"
59 }
60
61 fn path(&self) -> String {
62 "/api/collections".into()
63 }
64}
65
66#[derive(Debug, Default, Clone)]
68pub struct ListSmartCollections;
69
70impl Endpoint for ListSmartCollections {
71 type Output = CollectionsList;
72
73 fn method(&self) -> &'static str {
74 "GET"
75 }
76
77 fn path(&self) -> String {
78 "/api/collections/smart".into()
79 }
80}
81
82#[derive(Debug, Default, Clone)]
84pub struct ListVirtualCollections;
85
86impl Endpoint for ListVirtualCollections {
87 type Output = Vec<VirtualCollectionRow>;
88
89 fn method(&self) -> &'static str {
90 "GET"
91 }
92
93 fn path(&self) -> String {
94 "/api/collections/virtual".into()
95 }
96
97 fn query(&self) -> Vec<(String, String)> {
98 vec![("type".into(), "all".into())]
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::types::{Collection, VirtualCollectionRow};
106
107 #[test]
108 fn decode_bare_array() {
109 let v = serde_json::json!([
110 {"id": 1, "name": "A", "rom_count": 2}
111 ]);
112 let list: CollectionsList = serde_json::from_value(v).unwrap();
113 let list = list.into_vec();
114 assert_eq!(list.len(), 1);
115 assert_eq!(list[0].id, 1);
116 assert_eq!(list[0].name, "A");
117 }
118
119 #[test]
120 fn decode_paged_object() {
121 let v = serde_json::json!({
122 "items": [{"id": 2, "name": "B", "rom_count": 0}],
123 "total": 1
124 });
125 let list: CollectionsList = serde_json::from_value(v).unwrap();
126 let list = list.into_vec();
127 assert_eq!(list.len(), 1);
128 assert_eq!(list[0].id, 2);
129 }
130
131 #[test]
132 fn merge_manual_and_smart_marks_flags() {
133 let manual = vec![Collection {
134 id: 1,
135 name: "m".into(),
136 collection_type: None,
137 rom_count: Some(1),
138 is_smart: true,
139 is_virtual: false,
140 virtual_id: None,
141 }];
142 let smart = vec![Collection {
143 id: 2,
144 name: "s".into(),
145 collection_type: None,
146 rom_count: Some(2),
147 is_smart: false,
148 is_virtual: false,
149 virtual_id: None,
150 }];
151 let merged = super::merge_manual_and_smart(manual, smart);
152 assert_eq!(merged.len(), 2);
153 assert!(!merged[0].is_smart);
154 assert!(merged[1].is_smart);
155 }
156
157 #[test]
158 fn merge_all_includes_virtual() {
159 let manual = vec![Collection {
160 id: 1,
161 name: "m".into(),
162 collection_type: None,
163 rom_count: Some(1),
164 is_smart: false,
165 is_virtual: false,
166 virtual_id: None,
167 }];
168 let virtual_rows = vec![VirtualCollectionRow {
169 id: "recent".into(),
170 name: "Recent".into(),
171 collection_type: "recent".into(),
172 rom_count: 3,
173 is_virtual: true,
174 }];
175 let merged = super::merge_all_collection_sources(manual, Vec::new(), virtual_rows);
176 assert_eq!(merged.len(), 2);
177 assert!(merged[1].is_virtual);
178 assert_eq!(merged[1].virtual_id.as_deref(), Some("recent"));
179 }
180}