use crate::role::Role;
#[cfg(feature = "persistence")]
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
pub struct RoleHierarchyTree {
pub root: RoleNode,
pub total_roles: usize,
pub max_depth: usize,
pub metadata: HierarchyMetadata,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
pub struct RoleNode {
pub role: Role,
pub children: Vec<RoleNode>,
pub depth: usize,
pub descendant_count: usize,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
pub struct HierarchyMetadata {
#[cfg(feature = "persistence")]
pub generated_at: chrono::DateTime<chrono::Utc>,
pub schema_version: String,
pub total_permissions: usize,
pub generation_time_ms: u64,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
pub struct RoleRelationship {
pub child_role_id: String,
pub parent_role_id: String,
pub relationship_type: RelationshipType,
#[cfg(feature = "persistence")]
pub created_at: Option<chrono::DateTime<chrono::Utc>>,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
pub enum RelationshipType {
Direct,
Inherited,
}
#[derive(Debug, Clone)]
pub struct HierarchyConfig {
pub enable_hierarchy_access: bool,
pub max_hierarchy_depth: usize,
pub cache_hierarchy: bool,
pub max_traversal_size: usize,
pub include_permission_counts: bool,
}
impl Default for HierarchyConfig {
fn default() -> Self {
Self {
enable_hierarchy_access: false, max_hierarchy_depth: 10,
cache_hierarchy: true,
max_traversal_size: 1000,
include_permission_counts: true,
}
}
}
pub struct HierarchyConfigBuilder {
config: HierarchyConfig,
}
impl HierarchyConfigBuilder {
pub fn new() -> Self {
Self {
config: HierarchyConfig::default(),
}
}
pub fn enable_hierarchy_access(mut self, enable: bool) -> Self {
self.config.enable_hierarchy_access = enable;
self
}
pub fn max_depth(mut self, depth: usize) -> Self {
self.config.max_hierarchy_depth = depth;
self
}
pub fn enable_caching(mut self, enable: bool) -> Self {
self.config.cache_hierarchy = enable;
self
}
pub fn max_traversal_size(mut self, size: usize) -> Self {
self.config.max_traversal_size = size;
self
}
pub fn include_permission_counts(mut self, include: bool) -> Self {
self.config.include_permission_counts = include;
self
}
pub fn build(self) -> HierarchyConfig {
self.config
}
}
impl Default for HierarchyConfigBuilder {
fn default() -> Self {
Self::new()
}
}
impl RoleHierarchyTree {
pub fn new(root: RoleNode) -> Self {
let total_roles = root.descendant_count + 1;
let max_depth = Self::calculate_max_depth(&root);
Self {
root,
total_roles,
max_depth,
metadata: HierarchyMetadata {
#[cfg(feature = "persistence")]
generated_at: chrono::Utc::now(),
schema_version: "1.1.0".to_string(),
total_permissions: 0, generation_time_ms: 0,
},
}
}
fn calculate_max_depth(node: &RoleNode) -> usize {
if node.children.is_empty() {
node.depth
} else {
node.children
.iter()
.map(Self::calculate_max_depth)
.max()
.unwrap_or(node.depth)
}
}
pub fn flatten(&self) -> Vec<&Role> {
let mut roles = Vec::new();
Self::flatten_node(&self.root, &mut roles);
roles
}
fn flatten_node<'a>(node: &'a RoleNode, roles: &mut Vec<&'a Role>) {
roles.push(&node.role);
for child in &node.children {
Self::flatten_node(child, roles);
}
}
pub fn find_node(&self, role_id: &str) -> Option<&RoleNode> {
Self::find_node_recursive(&self.root, role_id)
}
fn find_node_recursive<'a>(node: &'a RoleNode, role_id: &str) -> Option<&'a RoleNode> {
if node.role.id() == role_id {
return Some(node);
}
for child in &node.children {
if let Some(found) = Self::find_node_recursive(child, role_id) {
return Some(found);
}
}
None
}
}
impl RoleNode {
pub fn new(role: Role, depth: usize) -> Self {
Self {
role,
children: Vec::new(),
depth,
descendant_count: 0,
}
}
pub fn add_child(&mut self, child: RoleNode) {
self.descendant_count += child.descendant_count + 1;
self.children.push(child);
}
pub fn get_descendant_ids(&self) -> Vec<String> {
let mut ids = Vec::new();
for child in &self.children {
ids.push(child.role.id().to_string());
ids.extend(child.get_descendant_ids());
}
ids
}
pub fn is_leaf(&self) -> bool {
self.children.is_empty()
}
pub fn is_root(&self) -> bool {
self.depth == 0
}
}
impl RoleRelationship {
pub fn new(
child_role_id: String,
parent_role_id: String,
relationship_type: RelationshipType,
) -> Self {
Self {
child_role_id,
parent_role_id,
relationship_type,
#[cfg(feature = "persistence")]
created_at: Some(chrono::Utc::now()),
metadata: HashMap::new(),
}
}
pub fn direct(child_role_id: String, parent_role_id: String) -> Self {
Self::new(child_role_id, parent_role_id, RelationshipType::Direct)
}
pub fn inherited(child_role_id: String, parent_role_id: String) -> Self {
Self::new(child_role_id, parent_role_id, RelationshipType::Inherited)
}
pub fn with_metadata(mut self, key: String, value: String) -> Self {
self.metadata.insert(key, value);
self
}
pub fn is_direct(&self) -> bool {
self.relationship_type == RelationshipType::Direct
}
pub fn is_inherited(&self) -> bool {
self.relationship_type == RelationshipType::Inherited
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::role::Role;
#[test]
fn test_hierarchy_config_builder() {
let config = HierarchyConfigBuilder::new()
.enable_hierarchy_access(true)
.max_depth(15)
.enable_caching(false)
.max_traversal_size(500)
.build();
assert!(config.enable_hierarchy_access);
assert_eq!(config.max_hierarchy_depth, 15);
assert!(!config.cache_hierarchy);
assert_eq!(config.max_traversal_size, 500);
}
#[test]
fn test_role_node_creation() {
let role = Role::new("test_role");
let node = RoleNode::new(role, 2);
assert_eq!(node.depth, 2);
assert_eq!(node.descendant_count, 0);
assert!(node.is_leaf());
assert!(!node.is_root());
}
#[test]
fn test_role_relationship_creation() {
let rel = RoleRelationship::direct("child".to_string(), "parent".to_string());
assert_eq!(rel.child_role_id, "child");
assert_eq!(rel.parent_role_id, "parent");
assert!(rel.is_direct());
assert!(!rel.is_inherited());
}
#[test]
fn test_hierarchy_tree_creation() {
let role = Role::new("root");
let root_node = RoleNode::new(role, 0);
let tree = RoleHierarchyTree::new(root_node);
assert_eq!(tree.total_roles, 1);
assert_eq!(tree.max_depth, 0);
assert_eq!(tree.metadata.schema_version, "1.1.0");
}
}