1use super::mapper::SchemaMapper;
8use crate::error::ScimError;
9use crate::schema::Schema;
10use serde_json::Value;
11use std::collections::HashMap;
12use std::sync::Arc;
13
14#[derive(Clone)]
16pub enum AttributeHandler {
17 Getter(Arc<dyn Fn(&Value) -> Option<Value> + Send + Sync>),
18 Setter(Arc<dyn Fn(&mut Value, Value) -> Result<(), ScimError> + Send + Sync>),
19 Transformer(Arc<dyn Fn(&Value, &str) -> Option<Value> + Send + Sync>),
20}
21
22#[derive(Clone)]
24pub struct ResourceHandler {
25 pub schema: Schema,
26 pub handlers: HashMap<String, AttributeHandler>,
27 pub mappers: Vec<Arc<dyn SchemaMapper>>,
28 pub custom_methods:
29 HashMap<String, Arc<dyn Fn(&DynamicResource) -> Result<Value, ScimError> + Send + Sync>>,
30}
31
32impl std::fmt::Debug for ResourceHandler {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 f.debug_struct("ResourceHandler")
35 .field("schema", &self.schema)
36 .field("handlers", &format!("{} handlers", self.handlers.len()))
37 .field("mappers", &format!("{} mappers", self.mappers.len()))
38 .field(
39 "custom_methods",
40 &format!("{} custom methods", self.custom_methods.len()),
41 )
42 .finish()
43 }
44}
45
46pub struct SchemaResourceBuilder {
48 schema: Schema,
49 handlers: HashMap<String, AttributeHandler>,
50 mappers: Vec<Arc<dyn SchemaMapper>>,
51 custom_methods:
52 HashMap<String, Arc<dyn Fn(&DynamicResource) -> Result<Value, ScimError> + Send + Sync>>,
53}
54
55impl SchemaResourceBuilder {
56 pub fn new(schema: Schema) -> Self {
57 Self {
58 schema,
59 handlers: HashMap::new(),
60 mappers: Vec::new(),
61 custom_methods: HashMap::new(),
62 }
63 }
64
65 pub fn with_getter<F>(mut self, attribute: &str, getter: F) -> Self
66 where
67 F: Fn(&Value) -> Option<Value> + Send + Sync + 'static,
68 {
69 self.handlers.insert(
70 format!("get_{}", attribute),
71 AttributeHandler::Getter(Arc::new(getter)),
72 );
73 self
74 }
75
76 pub fn with_setter<F>(mut self, attribute: &str, setter: F) -> Self
77 where
78 F: Fn(&mut Value, Value) -> Result<(), ScimError> + Send + Sync + 'static,
79 {
80 self.handlers.insert(
81 format!("set_{}", attribute),
82 AttributeHandler::Setter(Arc::new(setter)),
83 );
84 self
85 }
86
87 pub fn with_transformer<F>(mut self, attribute: &str, transformer: F) -> Self
88 where
89 F: Fn(&Value, &str) -> Option<Value> + Send + Sync + 'static,
90 {
91 self.handlers.insert(
92 format!("transform_{}", attribute),
93 AttributeHandler::Transformer(Arc::new(transformer)),
94 );
95 self
96 }
97
98 pub fn with_custom_method<F>(mut self, method_name: &str, method: F) -> Self
99 where
100 F: Fn(&DynamicResource) -> Result<Value, ScimError> + Send + Sync + 'static,
101 {
102 self.custom_methods
103 .insert(method_name.to_string(), Arc::new(method));
104 self
105 }
106
107 pub fn with_mapper(mut self, mapper: Arc<dyn SchemaMapper>) -> Self {
108 self.mappers.push(mapper);
109 self
110 }
111
112 pub fn with_database_mapping(
113 self,
114 table_name: &str,
115 column_mappings: HashMap<String, String>,
116 ) -> Self {
117 self.with_mapper(Arc::new(super::mapper::DatabaseMapper::new(
118 table_name,
119 column_mappings,
120 )))
121 }
122
123 pub fn build(self) -> ResourceHandler {
124 ResourceHandler {
125 schema: self.schema,
126 handlers: self.handlers,
127 mappers: self.mappers,
128 custom_methods: self.custom_methods,
129 }
130 }
131}
132
133#[derive(Clone, Debug)]
135pub struct DynamicResource {
136 pub resource_type: String,
137 pub data: Value,
138 pub handler: Arc<ResourceHandler>,
139}
140
141impl DynamicResource {
142 pub fn new(resource_type: String, data: Value, handler: Arc<ResourceHandler>) -> Self {
143 Self {
144 resource_type,
145 data,
146 handler,
147 }
148 }
149
150 pub fn get_attribute_dynamic(&self, attribute: &str) -> Option<Value> {
151 let getter_key = format!("get_{}", attribute);
152 if let Some(AttributeHandler::Getter(getter)) = self.handler.handlers.get(&getter_key) {
153 getter(&self.data)
154 } else {
155 self.data.get(attribute).cloned()
157 }
158 }
159
160 pub fn set_attribute_dynamic(
161 &mut self,
162 attribute: &str,
163 value: Value,
164 ) -> Result<(), ScimError> {
165 let setter_key = format!("set_{}", attribute);
166 if let Some(AttributeHandler::Setter(setter)) = self.handler.handlers.get(&setter_key) {
167 setter(&mut self.data, value)
168 } else {
169 if let Some(obj) = self.data.as_object_mut() {
171 obj.insert(attribute.to_string(), value);
172 }
173 Ok(())
174 }
175 }
176
177 pub fn call_custom_method(&self, method_name: &str) -> Result<Value, ScimError> {
178 if let Some(method) = self.handler.custom_methods.get(method_name) {
179 method(self)
180 } else {
181 Err(ScimError::MethodNotFound(method_name.to_string()))
182 }
183 }
184
185 pub fn to_implementation_schema(&self, mapper_index: usize) -> Result<Value, ScimError> {
186 if let Some(mapper) = self.handler.mappers.get(mapper_index) {
187 mapper.to_implementation(&self.data)
188 } else {
189 Err(ScimError::MapperNotFound(mapper_index))
190 }
191 }
192
193 pub fn from_implementation_schema(
194 &mut self,
195 impl_data: &Value,
196 mapper_index: usize,
197 ) -> Result<(), ScimError> {
198 if let Some(mapper) = self.handler.mappers.get(mapper_index) {
199 self.data = mapper.from_implementation(impl_data)?;
200 Ok(())
201 } else {
202 Err(ScimError::MapperNotFound(mapper_index))
203 }
204 }
205}