use crate::engine::{Operation, ProcessingStep, Transform, Analysis, Filter, Aggregation};
use ahash::AHashMap;
use serde::{Deserialize, Serialize};
use parking_lot::RwLock;
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Template {
pub id: String,
pub name: String,
pub description: String,
pub steps: Vec<ProcessingStep>,
pub metadata: TemplateMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateMetadata {
pub version: String,
pub author: String,
pub created_at: String,
pub updated_at: String,
pub tags: Vec<String>,
pub performance: PerformanceProfile,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceProfile {
pub avg_execution_time_ms: f64,
pub memory_usage_bytes: usize,
pub complexity: u8,
}
pub struct TemplateRegistry {
templates: Arc<RwLock<AHashMap<String, Template>>>,
}
impl TemplateRegistry {
pub fn new() -> Self {
let registry = Self {
templates: Arc::new(RwLock::new(AHashMap::new())),
};
registry.load_default_templates();
registry
}
pub fn register(&self, template: Template) {
self.templates.write().insert(template.id.clone(), template);
}
pub fn get(&self, id: &str) -> Option<Template> {
self.templates.read().get(id).cloned()
}
pub fn list(&self) -> Vec<String> {
self.templates.read().keys().cloned().collect()
}
pub fn remove(&self, id: &str) -> Option<Template> {
self.templates.write().remove(id)
}
fn load_default_templates(&self) {
self.register(Template {
id: "analysis-basic".to_string(),
name: "Basic Analysis".to_string(),
description: "Performs basic statistical and pattern analysis".to_string(),
steps: vec![
ProcessingStep {
name: "normalize".to_string(),
operation: Operation::Transform(Transform::Normalize),
},
ProcessingStep {
name: "analyze".to_string(),
operation: Operation::Analyze(Analysis::Statistical),
},
ProcessingStep {
name: "expand".to_string(),
operation: Operation::Transform(Transform::Expand),
},
],
metadata: TemplateMetadata {
version: "1.0.0".to_string(),
author: "FACT Team".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
tags: vec!["analysis".to_string(), "statistics".to_string()],
performance: PerformanceProfile {
avg_execution_time_ms: 50.0,
memory_usage_bytes: 1024 * 1024, complexity: 3,
},
},
});
self.register(Template {
id: "pattern-detection".to_string(),
name: "Pattern Detection".to_string(),
description: "Detects patterns in structured data".to_string(),
steps: vec![
ProcessingStep {
name: "normalize".to_string(),
operation: Operation::Transform(Transform::Normalize),
},
ProcessingStep {
name: "pattern-analysis".to_string(),
operation: Operation::Analyze(Analysis::Pattern),
},
ProcessingStep {
name: "semantic-enrichment".to_string(),
operation: Operation::Analyze(Analysis::Semantic),
},
],
metadata: TemplateMetadata {
version: "1.0.0".to_string(),
author: "FACT Team".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
tags: vec!["pattern".to_string(), "detection".to_string(), "ai".to_string()],
performance: PerformanceProfile {
avg_execution_time_ms: 75.0,
memory_usage_bytes: 2 * 1024 * 1024, complexity: 5,
},
},
});
self.register(Template {
id: "data-aggregation".to_string(),
name: "Data Aggregation".to_string(),
description: "Aggregates numerical data with various operations".to_string(),
steps: vec![
ProcessingStep {
name: "filter-numbers".to_string(),
operation: Operation::Filter(Filter::Range { min: 0.0, max: 1000000.0 }),
},
ProcessingStep {
name: "sum".to_string(),
operation: Operation::Aggregate(Aggregation::Sum),
},
ProcessingStep {
name: "average".to_string(),
operation: Operation::Aggregate(Aggregation::Average),
},
ProcessingStep {
name: "count".to_string(),
operation: Operation::Aggregate(Aggregation::Count),
},
],
metadata: TemplateMetadata {
version: "1.0.0".to_string(),
author: "FACT Team".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
tags: vec!["aggregation".to_string(), "numerical".to_string(), "statistics".to_string()],
performance: PerformanceProfile {
avg_execution_time_ms: 25.0,
memory_usage_bytes: 512 * 1024, complexity: 2,
},
},
});
self.register(Template {
id: "quick-transform".to_string(),
name: "Quick Transform".to_string(),
description: "Fast data transformation for caching".to_string(),
steps: vec![
ProcessingStep {
name: "compress".to_string(),
operation: Operation::Transform(Transform::Compress),
},
ProcessingStep {
name: "normalize".to_string(),
operation: Operation::Transform(Transform::Normalize),
},
],
metadata: TemplateMetadata {
version: "1.0.0".to_string(),
author: "FACT Team".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
tags: vec!["transform".to_string(), "fast".to_string(), "cache".to_string()],
performance: PerformanceProfile {
avg_execution_time_ms: 10.0,
memory_usage_bytes: 256 * 1024, complexity: 1,
},
},
});
}
pub fn search_by_tags(&self, tags: &[String]) -> Vec<Template> {
self.templates
.read()
.values()
.filter(|template| {
tags.iter().any(|tag| template.metadata.tags.contains(tag))
})
.cloned()
.collect()
}
pub fn get_by_performance(&self, max_complexity: u8) -> Vec<Template> {
let mut templates: Vec<_> = self.templates
.read()
.values()
.filter(|t| t.metadata.performance.complexity <= max_complexity)
.cloned()
.collect();
templates.sort_by(|a, b| {
a.metadata.performance.avg_execution_time_ms
.partial_cmp(&b.metadata.performance.avg_execution_time_ms)
.unwrap()
});
templates
}
}
impl Default for TemplateRegistry {
fn default() -> Self {
Self::new()
}
}
pub struct TemplateBuilder {
id: String,
name: String,
description: String,
steps: Vec<ProcessingStep>,
tags: Vec<String>,
}
impl TemplateBuilder {
pub fn new(id: impl Into<String>) -> Self {
Self {
id: id.into(),
name: String::new(),
description: String::new(),
steps: Vec::new(),
tags: Vec::new(),
}
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = description.into();
self
}
pub fn add_step(mut self, step: ProcessingStep) -> Self {
self.steps.push(step);
self
}
pub fn add_tag(mut self, tag: impl Into<String>) -> Self {
self.tags.push(tag.into());
self
}
pub fn build(self) -> Template {
Template {
id: self.id,
name: self.name,
description: self.description,
steps: self.steps,
metadata: TemplateMetadata {
version: "1.0.0".to_string(),
author: "Custom".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
tags: self.tags,
performance: PerformanceProfile {
avg_execution_time_ms: 0.0,
memory_usage_bytes: 0,
complexity: 5,
},
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_template_registry() {
let registry = TemplateRegistry::new();
assert!(registry.get("analysis-basic").is_some());
assert!(registry.get("pattern-detection").is_some());
assert!(registry.get("data-aggregation").is_some());
assert!(registry.get("quick-transform").is_some());
let templates = registry.list();
assert!(templates.len() >= 4);
}
#[test]
fn test_template_builder() {
let template = TemplateBuilder::new("custom-template")
.name("Custom Template")
.description("A custom template for testing")
.add_tag("custom")
.add_tag("test")
.add_step(ProcessingStep {
name: "normalize".to_string(),
operation: Operation::Transform(Transform::Normalize),
})
.build();
assert_eq!(template.id, "custom-template");
assert_eq!(template.name, "Custom Template");
assert_eq!(template.steps.len(), 1);
assert_eq!(template.metadata.tags.len(), 2);
}
#[test]
fn test_search_by_tags() {
let registry = TemplateRegistry::new();
let analysis_templates = registry.search_by_tags(&[String::from("analysis")]);
assert!(!analysis_templates.is_empty());
let pattern_templates = registry.search_by_tags(&[String::from("pattern")]);
assert!(!pattern_templates.is_empty());
}
}