use serde::{Deserialize, Serialize};
use super::validation::{EntityId, Namespace, ValidationError};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Action {
id: EntityId,
#[serde(default)]
namespace: Namespace,
}
impl Action {
pub fn new(id: impl Into<String>) -> Self {
Self {
id: EntityId::new(id),
namespace: Namespace::default(),
}
}
pub fn try_new(id: impl Into<String>) -> Result<Self, ValidationError> {
let action = Self::new(id);
action.validate()?;
Ok(action)
}
pub fn with_namespace(mut self, namespace: Vec<String>) -> Self {
self.namespace = Namespace::new(namespace);
self
}
pub fn try_with_namespace(self, namespace: Vec<String>) -> Result<Self, ValidationError> {
let action = self.with_namespace(namespace);
action.validate()?;
Ok(action)
}
pub fn id(&self) -> &str {
self.id.as_str()
}
pub fn namespace(&self) -> &[String] {
self.namespace.as_slice()
}
pub fn validate(&self) -> Result<(), ValidationError> {
self.id.validate("action.id")?;
self.namespace.validate("action.namespace")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn action_serialization() {
let action = Action::new("create");
let json = serde_json::to_value(&action).unwrap();
assert_eq!(json["id"], "create");
assert_eq!(json["namespace"], serde_json::json!([]));
}
#[test]
fn action_with_namespace() {
let action = Action::new("delete").with_namespace(vec!["Admin".to_string()]);
let json = serde_json::to_value(&action).unwrap();
assert_eq!(json["namespace"], serde_json::json!(["Admin"]));
}
#[test]
fn action_roundtrip() {
let action =
Action::new("view").with_namespace(vec!["App".to_string(), "Core".to_string()]);
let json = serde_json::to_value(&action).unwrap();
let deserialized: Action = serde_json::from_value(json).unwrap();
assert_eq!(action, deserialized);
}
}