use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::rest::{ResourceOperation, ResourcePath, RestResource};
use crate::HttpMethod;
pub use super::common::ThemeRole;
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct Theme {
#[serde(skip_serializing)]
pub id: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<ThemeRole>,
#[serde(skip_serializing)]
pub previewable: Option<bool>,
#[serde(skip_serializing)]
pub processing: Option<bool>,
#[serde(skip_serializing)]
pub created_at: Option<DateTime<Utc>>,
#[serde(skip_serializing)]
pub updated_at: Option<DateTime<Utc>>,
#[serde(skip_serializing)]
pub admin_graphql_api_id: Option<String>,
}
impl RestResource for Theme {
type Id = u64;
type FindParams = ThemeFindParams;
type AllParams = ThemeListParams;
type CountParams = ();
const NAME: &'static str = "Theme";
const PLURAL: &'static str = "themes";
const PATHS: &'static [ResourcePath] = &[
ResourcePath::new(
HttpMethod::Get,
ResourceOperation::Find,
&["id"],
"themes/{id}",
),
ResourcePath::new(HttpMethod::Get, ResourceOperation::All, &[], "themes"),
ResourcePath::new(HttpMethod::Post, ResourceOperation::Create, &[], "themes"),
ResourcePath::new(
HttpMethod::Put,
ResourceOperation::Update,
&["id"],
"themes/{id}",
),
ResourcePath::new(
HttpMethod::Delete,
ResourceOperation::Delete,
&["id"],
"themes/{id}",
),
];
fn get_id(&self) -> Option<Self::Id> {
self.id
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct ThemeFindParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub fields: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct ThemeListParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<ThemeRole>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub since_id: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_info: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fields: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::rest::{get_path, ResourceOperation};
#[test]
fn test_theme_struct_serialization() {
let theme = Theme {
id: Some(12345),
name: Some("My Custom Theme".to_string()),
role: Some(ThemeRole::Unpublished),
previewable: Some(true),
processing: Some(false),
created_at: Some(
DateTime::parse_from_rfc3339("2024-01-15T10:30:00Z")
.unwrap()
.with_timezone(&Utc),
),
updated_at: Some(
DateTime::parse_from_rfc3339("2024-06-20T15:45:00Z")
.unwrap()
.with_timezone(&Utc),
),
admin_graphql_api_id: Some("gid://shopify/Theme/12345".to_string()),
};
let json = serde_json::to_string(&theme).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(parsed["name"], "My Custom Theme");
assert_eq!(parsed["role"], "unpublished");
assert!(parsed.get("id").is_none());
assert!(parsed.get("previewable").is_none());
assert!(parsed.get("processing").is_none());
assert!(parsed.get("created_at").is_none());
assert!(parsed.get("updated_at").is_none());
assert!(parsed.get("admin_graphql_api_id").is_none());
}
#[test]
fn test_theme_deserialization_from_api_response() {
let json = r#"{
"id": 828155753,
"name": "Dawn",
"role": "main",
"previewable": true,
"processing": false,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-06-20T15:45:00Z",
"admin_graphql_api_id": "gid://shopify/Theme/828155753"
}"#;
let theme: Theme = serde_json::from_str(json).unwrap();
assert_eq!(theme.id, Some(828155753));
assert_eq!(theme.name, Some("Dawn".to_string()));
assert_eq!(theme.role, Some(ThemeRole::Main));
assert_eq!(theme.previewable, Some(true));
assert_eq!(theme.processing, Some(false));
assert!(theme.created_at.is_some());
assert!(theme.updated_at.is_some());
assert_eq!(
theme.admin_graphql_api_id,
Some("gid://shopify/Theme/828155753".to_string())
);
}
#[test]
fn test_theme_role_enum_variants() {
let main: ThemeRole = serde_json::from_str("\"main\"").unwrap();
assert_eq!(main, ThemeRole::Main);
let unpublished: ThemeRole = serde_json::from_str("\"unpublished\"").unwrap();
assert_eq!(unpublished, ThemeRole::Unpublished);
let demo: ThemeRole = serde_json::from_str("\"demo\"").unwrap();
assert_eq!(demo, ThemeRole::Demo);
let development: ThemeRole = serde_json::from_str("\"development\"").unwrap();
assert_eq!(development, ThemeRole::Development);
}
#[test]
fn test_theme_paths() {
let find_path = get_path(Theme::PATHS, ResourceOperation::Find, &["id"]);
assert!(find_path.is_some());
assert_eq!(find_path.unwrap().template, "themes/{id}");
let all_path = get_path(Theme::PATHS, ResourceOperation::All, &[]);
assert!(all_path.is_some());
assert_eq!(all_path.unwrap().template, "themes");
let create_path = get_path(Theme::PATHS, ResourceOperation::Create, &[]);
assert!(create_path.is_some());
assert_eq!(create_path.unwrap().template, "themes");
let update_path = get_path(Theme::PATHS, ResourceOperation::Update, &["id"]);
assert!(update_path.is_some());
assert_eq!(update_path.unwrap().template, "themes/{id}");
let delete_path = get_path(Theme::PATHS, ResourceOperation::Delete, &["id"]);
assert!(delete_path.is_some());
assert_eq!(delete_path.unwrap().template, "themes/{id}");
let count_path = get_path(Theme::PATHS, ResourceOperation::Count, &[]);
assert!(count_path.is_none());
}
#[test]
fn test_theme_list_params_serialization() {
let params = ThemeListParams {
role: Some(ThemeRole::Main),
limit: Some(50),
since_id: Some(12345),
page_info: None,
fields: Some("id,name,role".to_string()),
};
let json = serde_json::to_value(¶ms).unwrap();
assert_eq!(json["role"], "main");
assert_eq!(json["limit"], 50);
assert_eq!(json["since_id"], 12345);
assert_eq!(json["fields"], "id,name,role");
assert!(json.get("page_info").is_none());
let empty_params = ThemeListParams::default();
let empty_json = serde_json::to_value(&empty_params).unwrap();
assert_eq!(empty_json, serde_json::json!({}));
}
#[test]
fn test_theme_get_id_returns_correct_value() {
let theme_with_id = Theme {
id: Some(123456789),
name: Some("Test Theme".to_string()),
..Default::default()
};
assert_eq!(theme_with_id.get_id(), Some(123456789));
let theme_without_id = Theme {
id: None,
name: Some("New Theme".to_string()),
..Default::default()
};
assert_eq!(theme_without_id.get_id(), None);
}
#[test]
fn test_theme_constants() {
assert_eq!(Theme::NAME, "Theme");
assert_eq!(Theme::PLURAL, "themes");
}
#[test]
fn test_theme_status_fields() {
let json = r#"{
"id": 123,
"name": "Processing Theme",
"role": "unpublished",
"previewable": false,
"processing": true
}"#;
let theme: Theme = serde_json::from_str(json).unwrap();
assert_eq!(theme.previewable, Some(false));
assert_eq!(theme.processing, Some(true));
let serialized = serde_json::to_value(&theme).unwrap();
assert!(serialized.get("previewable").is_none());
assert!(serialized.get("processing").is_none());
}
}