shopify_sdk/rest/resources/v2025_10/
theme.rs1use chrono::{DateTime, Utc};
33use serde::{Deserialize, Serialize};
34
35use crate::rest::{ResourceOperation, ResourcePath, RestResource};
36use crate::HttpMethod;
37
38pub use super::common::ThemeRole;
40
41#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
63pub struct Theme {
64 #[serde(skip_serializing)]
67 pub id: Option<u64>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub name: Option<String>,
72
73 #[serde(skip_serializing_if = "Option::is_none")]
76 pub role: Option<ThemeRole>,
77
78 #[serde(skip_serializing)]
81 pub previewable: Option<bool>,
82
83 #[serde(skip_serializing)]
86 pub processing: Option<bool>,
87
88 #[serde(skip_serializing)]
91 pub created_at: Option<DateTime<Utc>>,
92
93 #[serde(skip_serializing)]
96 pub updated_at: Option<DateTime<Utc>>,
97
98 #[serde(skip_serializing)]
101 pub admin_graphql_api_id: Option<String>,
102}
103
104impl RestResource for Theme {
105 type Id = u64;
106 type FindParams = ThemeFindParams;
107 type AllParams = ThemeListParams;
108 type CountParams = ();
109
110 const NAME: &'static str = "Theme";
111 const PLURAL: &'static str = "themes";
112
113 const PATHS: &'static [ResourcePath] = &[
118 ResourcePath::new(
119 HttpMethod::Get,
120 ResourceOperation::Find,
121 &["id"],
122 "themes/{id}",
123 ),
124 ResourcePath::new(HttpMethod::Get, ResourceOperation::All, &[], "themes"),
125 ResourcePath::new(HttpMethod::Post, ResourceOperation::Create, &[], "themes"),
126 ResourcePath::new(
127 HttpMethod::Put,
128 ResourceOperation::Update,
129 &["id"],
130 "themes/{id}",
131 ),
132 ResourcePath::new(
133 HttpMethod::Delete,
134 ResourceOperation::Delete,
135 &["id"],
136 "themes/{id}",
137 ),
138 ];
139
140 fn get_id(&self) -> Option<Self::Id> {
141 self.id
142 }
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
147pub struct ThemeFindParams {
148 #[serde(skip_serializing_if = "Option::is_none")]
150 pub fields: Option<String>,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
155pub struct ThemeListParams {
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub role: Option<ThemeRole>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub limit: Option<u32>,
163
164 #[serde(skip_serializing_if = "Option::is_none")]
166 pub since_id: Option<u64>,
167
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub page_info: Option<String>,
171
172 #[serde(skip_serializing_if = "Option::is_none")]
174 pub fields: Option<String>,
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use crate::rest::{get_path, ResourceOperation};
181
182 #[test]
183 fn test_theme_struct_serialization() {
184 let theme = Theme {
185 id: Some(12345),
186 name: Some("My Custom Theme".to_string()),
187 role: Some(ThemeRole::Unpublished),
188 previewable: Some(true),
189 processing: Some(false),
190 created_at: Some(
191 DateTime::parse_from_rfc3339("2024-01-15T10:30:00Z")
192 .unwrap()
193 .with_timezone(&Utc),
194 ),
195 updated_at: Some(
196 DateTime::parse_from_rfc3339("2024-06-20T15:45:00Z")
197 .unwrap()
198 .with_timezone(&Utc),
199 ),
200 admin_graphql_api_id: Some("gid://shopify/Theme/12345".to_string()),
201 };
202
203 let json = serde_json::to_string(&theme).unwrap();
204 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
205
206 assert_eq!(parsed["name"], "My Custom Theme");
208 assert_eq!(parsed["role"], "unpublished");
209
210 assert!(parsed.get("id").is_none());
212 assert!(parsed.get("previewable").is_none());
213 assert!(parsed.get("processing").is_none());
214 assert!(parsed.get("created_at").is_none());
215 assert!(parsed.get("updated_at").is_none());
216 assert!(parsed.get("admin_graphql_api_id").is_none());
217 }
218
219 #[test]
220 fn test_theme_deserialization_from_api_response() {
221 let json = r#"{
222 "id": 828155753,
223 "name": "Dawn",
224 "role": "main",
225 "previewable": true,
226 "processing": false,
227 "created_at": "2024-01-15T10:30:00Z",
228 "updated_at": "2024-06-20T15:45:00Z",
229 "admin_graphql_api_id": "gid://shopify/Theme/828155753"
230 }"#;
231
232 let theme: Theme = serde_json::from_str(json).unwrap();
233
234 assert_eq!(theme.id, Some(828155753));
235 assert_eq!(theme.name, Some("Dawn".to_string()));
236 assert_eq!(theme.role, Some(ThemeRole::Main));
237 assert_eq!(theme.previewable, Some(true));
238 assert_eq!(theme.processing, Some(false));
239 assert!(theme.created_at.is_some());
240 assert!(theme.updated_at.is_some());
241 assert_eq!(
242 theme.admin_graphql_api_id,
243 Some("gid://shopify/Theme/828155753".to_string())
244 );
245 }
246
247 #[test]
248 fn test_theme_role_enum_variants() {
249 let main: ThemeRole = serde_json::from_str("\"main\"").unwrap();
251 assert_eq!(main, ThemeRole::Main);
252
253 let unpublished: ThemeRole = serde_json::from_str("\"unpublished\"").unwrap();
254 assert_eq!(unpublished, ThemeRole::Unpublished);
255
256 let demo: ThemeRole = serde_json::from_str("\"demo\"").unwrap();
257 assert_eq!(demo, ThemeRole::Demo);
258
259 let development: ThemeRole = serde_json::from_str("\"development\"").unwrap();
260 assert_eq!(development, ThemeRole::Development);
261 }
262
263 #[test]
264 fn test_theme_paths() {
265 let find_path = get_path(Theme::PATHS, ResourceOperation::Find, &["id"]);
267 assert!(find_path.is_some());
268 assert_eq!(find_path.unwrap().template, "themes/{id}");
269
270 let all_path = get_path(Theme::PATHS, ResourceOperation::All, &[]);
272 assert!(all_path.is_some());
273 assert_eq!(all_path.unwrap().template, "themes");
274
275 let create_path = get_path(Theme::PATHS, ResourceOperation::Create, &[]);
277 assert!(create_path.is_some());
278 assert_eq!(create_path.unwrap().template, "themes");
279
280 let update_path = get_path(Theme::PATHS, ResourceOperation::Update, &["id"]);
282 assert!(update_path.is_some());
283 assert_eq!(update_path.unwrap().template, "themes/{id}");
284
285 let delete_path = get_path(Theme::PATHS, ResourceOperation::Delete, &["id"]);
287 assert!(delete_path.is_some());
288 assert_eq!(delete_path.unwrap().template, "themes/{id}");
289
290 let count_path = get_path(Theme::PATHS, ResourceOperation::Count, &[]);
292 assert!(count_path.is_none());
293 }
294
295 #[test]
296 fn test_theme_list_params_serialization() {
297 let params = ThemeListParams {
298 role: Some(ThemeRole::Main),
299 limit: Some(50),
300 since_id: Some(12345),
301 page_info: None,
302 fields: Some("id,name,role".to_string()),
303 };
304
305 let json = serde_json::to_value(¶ms).unwrap();
306
307 assert_eq!(json["role"], "main");
308 assert_eq!(json["limit"], 50);
309 assert_eq!(json["since_id"], 12345);
310 assert_eq!(json["fields"], "id,name,role");
311 assert!(json.get("page_info").is_none());
312
313 let empty_params = ThemeListParams::default();
315 let empty_json = serde_json::to_value(&empty_params).unwrap();
316 assert_eq!(empty_json, serde_json::json!({}));
317 }
318
319 #[test]
320 fn test_theme_get_id_returns_correct_value() {
321 let theme_with_id = Theme {
323 id: Some(123456789),
324 name: Some("Test Theme".to_string()),
325 ..Default::default()
326 };
327 assert_eq!(theme_with_id.get_id(), Some(123456789));
328
329 let theme_without_id = Theme {
331 id: None,
332 name: Some("New Theme".to_string()),
333 ..Default::default()
334 };
335 assert_eq!(theme_without_id.get_id(), None);
336 }
337
338 #[test]
339 fn test_theme_constants() {
340 assert_eq!(Theme::NAME, "Theme");
341 assert_eq!(Theme::PLURAL, "themes");
342 }
343
344 #[test]
345 fn test_theme_status_fields() {
346 let json = r#"{
347 "id": 123,
348 "name": "Processing Theme",
349 "role": "unpublished",
350 "previewable": false,
351 "processing": true
352 }"#;
353
354 let theme: Theme = serde_json::from_str(json).unwrap();
355
356 assert_eq!(theme.previewable, Some(false));
357 assert_eq!(theme.processing, Some(true));
358
359 let serialized = serde_json::to_value(&theme).unwrap();
361 assert!(serialized.get("previewable").is_none());
362 assert!(serialized.get("processing").is_none());
363 }
364}