use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
mod datetime_option {
use chrono::{DateTime, Utc};
use serde::{Deserialize, Deserializer, Serializer};
#[allow(clippy::ref_option)]
pub(super) fn serialize<S>(
date: &Option<DateTime<Utc>>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match date {
Some(dt) => serializer.serialize_some(&dt.to_rfc3339()),
None => serializer.serialize_none(),
}
}
pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<Option<DateTime<Utc>>, D::Error>
where
D: Deserializer<'de>,
{
let opt: Option<String> = Option::deserialize(deserializer)?;
match opt {
Some(s) => DateTime::parse_from_rfc3339(&s)
.map(|dt| Some(dt.with_timezone(&Utc)))
.map_err(serde::de::Error::custom),
None => Ok(None),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct PolicyStoreMetadata {
pub(crate) cedar_version: String,
pub(crate) policy_store: PolicyStoreInfo,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct PolicyStoreInfo {
#[serde(default)]
pub id: String,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default)]
pub version: String,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "datetime_option"
)]
pub created_date: Option<DateTime<Utc>>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "datetime_option"
)]
pub updated_date: Option<DateTime<Utc>>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_policy_store_metadata_serialization() {
let created = DateTime::parse_from_rfc3339("2024-01-01T00:00:00Z")
.unwrap()
.with_timezone(&Utc);
let updated = DateTime::parse_from_rfc3339("2024-01-02T00:00:00Z")
.unwrap()
.with_timezone(&Utc);
let metadata = PolicyStoreMetadata {
cedar_version: "4.4.0".to_string(),
policy_store: PolicyStoreInfo {
id: "abc123".to_string(),
name: "test_store".to_string(),
description: Some("A test policy store".to_string()),
version: "1.0.0".to_string(),
created_date: Some(created),
updated_date: Some(updated),
},
};
let json = serde_json::to_string(&metadata).unwrap();
assert!(json.contains("cedar_version"));
assert!(json.contains("4.4.0"));
let deserialized: PolicyStoreMetadata = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, metadata);
}
}