1use serde_json::Value;
2
3pub trait ApiResource {
4 fn to_array(&self) -> Value;
5}
6
7pub struct JsonResource<'a, T: ApiResource> {
8 pub data: &'a T,
9}
10
11impl<'a, T: ApiResource> JsonResource<'a, T> {
12 pub fn new(data: &'a T) -> Self {
13 Self { data }
14 }
15
16 pub fn resolve(&self) -> Value {
17 self.data.to_array()
18 }
19}
20
21pub struct ResourceCollection<'a, T: ApiResource> {
22 pub data: &'a [T],
23}
24
25impl<'a, T: ApiResource> ResourceCollection<'a, T> {
26 pub fn new(data: &'a [T]) -> Self {
27 Self { data }
28 }
29
30 pub fn resolve(&self) -> Value {
31 let array: Vec<Value> = self.data.iter().map(|item| item.to_array()).collect();
32 serde_json::json!(array)
33 }
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39 use serde_json::json;
40
41 struct DummyResource {
42 value: i32,
43 }
44
45 impl ApiResource for DummyResource {
46 fn to_array(&self) -> Value {
47 json!({ "value": self.value })
48 }
49 }
50
51 #[test]
52 fn test_json_resource_new_stores_data() {
53 let r = DummyResource { value: 42 };
54 let jr = JsonResource::new(&r);
55 assert_eq!(jr.data.value, 42);
56 }
57
58 #[test]
59 fn test_json_resource_resolve() {
60 let r = DummyResource { value: 7 };
61 let jr = JsonResource::new(&r);
62 let v = jr.resolve();
63 assert_eq!(v["value"], 7);
64 }
65
66 struct ComplexResource {
67 id: u64,
68 name: String,
69 tags: Vec<String>,
70 metadata: Option<Value>,
71 }
72
73 impl ApiResource for ComplexResource {
74 fn to_array(&self) -> Value {
75 json!({
76 "id": self.id,
77 "name": self.name,
78 "tags": self.tags,
79 "metadata": self.metadata,
80 "is_active": true,
81 })
82 }
83 }
84
85 #[test]
86 fn test_json_resource_resolve_complex() {
87 let r = ComplexResource {
88 id: 101,
89 name: "Alice".to_string(),
90 tags: vec!["admin".to_string(), "user".to_string()],
91 metadata: Some(json!({ "login_count": 5 })),
92 };
93 let jr = JsonResource::new(&r);
94 let v = jr.resolve();
95 assert_eq!(v["id"], 101);
96 assert_eq!(v["name"], "Alice");
97 assert_eq!(v["tags"].as_array().unwrap().len(), 2);
98 assert_eq!(v["tags"][0], "admin");
99 assert_eq!(v["metadata"]["login_count"], 5);
100 assert_eq!(v["is_active"], true);
101
102 let r_null = ComplexResource {
103 id: 102,
104 name: "Bob".to_string(),
105 tags: vec![],
106 metadata: None,
107 };
108 let jr_null = JsonResource::new(&r_null);
109 let v_null = jr_null.resolve();
110 assert!(v_null["metadata"].is_null());
111 assert_eq!(v_null["tags"].as_array().unwrap().len(), 0);
112 }
113
114 #[test]
115 fn test_resource_collection_new_stores_slice() {
116 let items = vec![DummyResource { value: 1 }, DummyResource { value: 2 }];
117 let rc = ResourceCollection::new(&items);
118 assert_eq!(rc.data.len(), 2);
119 }
120
121 #[test]
122 fn test_resource_collection_resolve_returns_array() {
123 let items = vec![DummyResource { value: 10 }, DummyResource { value: 20 }];
124 let rc = ResourceCollection::new(&items);
125 let v = rc.resolve();
126 assert!(v.is_array());
127 let arr = v.as_array().unwrap();
128 assert_eq!(arr.len(), 2);
129 assert_eq!(arr[0]["value"], 10);
130 assert_eq!(arr[1]["value"], 20);
131 }
132
133 #[test]
134 fn test_resource_collection_empty() {
135 let items: Vec<DummyResource> = vec![];
136 let rc = ResourceCollection::new(&items);
137 let v = rc.resolve();
138 assert_eq!(v.as_array().unwrap().len(), 0);
139 }
140
141 #[test]
142 fn test_resource_collection_single_item() {
143 let items = vec![DummyResource { value: 99 }];
144 let rc = ResourceCollection::new(&items);
145 let v = rc.resolve();
146 assert!(v.is_array());
147 let arr = v.as_array().unwrap();
148 assert_eq!(arr.len(), 1);
149 assert_eq!(arr[0]["value"], 99);
150 }
151
152 #[test]
153 fn test_resource_collection_complex_items() {
154 let items = vec![
155 ComplexResource {
156 id: 1,
157 name: "Alpha".to_string(),
158 tags: vec!["a".to_string()],
159 metadata: None,
160 },
161 ComplexResource {
162 id: 2,
163 name: "Beta".to_string(),
164 tags: vec!["b".to_string(), "c".to_string()],
165 metadata: Some(json!({"role": "admin"})),
166 },
167 ];
168 let rc = ResourceCollection::new(&items);
169 let v = rc.resolve();
170 let arr = v.as_array().unwrap();
171 assert_eq!(arr.len(), 2);
172 assert_eq!(arr[0]["name"], "Alpha");
173 assert_eq!(arr[1]["metadata"]["role"], "admin");
174 assert_eq!(arr[1]["tags"].as_array().unwrap().len(), 2);
175 }
176
177 #[test]
178 fn test_resource_collection_resolve_large() {
179 let items: Vec<DummyResource> = (0..10_000).map(|i| DummyResource { value: i }).collect();
180 let rc = ResourceCollection::new(&items);
181 let v = rc.resolve();
182 assert!(v.is_array());
183 let arr = v.as_array().unwrap();
184 assert_eq!(arr.len(), 10_000);
185 assert_eq!(arr[9_999]["value"], 9_999);
186 }
187}