1use crate::multi_tenancy::types::{MultiTenancyError, MultiTenancyResult};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::sync::{Arc, RwLock};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10pub enum IsolationLevel {
11 Namespace,
13
14 SeparateIndex,
16
17 Dedicated,
19}
20
21impl IsolationLevel {
22 pub fn strength(&self) -> u8 {
24 match self {
25 Self::Namespace => 3,
26 Self::SeparateIndex => 7,
27 Self::Dedicated => 10,
28 }
29 }
30
31 pub fn efficiency(&self) -> u8 {
33 match self {
34 Self::Namespace => 10,
35 Self::SeparateIndex => 6,
36 Self::Dedicated => 3,
37 }
38 }
39
40 pub fn for_tier(tier: &str) -> Self {
42 match tier {
43 "free" | "trial" => Self::Namespace,
44 "pro" | "business" => Self::SeparateIndex,
45 "enterprise" | "dedicated" => Self::Dedicated,
46 _ => Self::Namespace,
47 }
48 }
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct IsolationStrategy {
54 pub level: IsolationLevel,
56
57 pub encryption_at_rest: bool,
59
60 pub encryption_in_transit: bool,
62
63 pub namespace_separator: String,
65
66 pub max_namespace_depth: usize,
68}
69
70impl IsolationStrategy {
71 pub fn new(level: IsolationLevel) -> Self {
73 Self {
74 level,
75 encryption_at_rest: false,
76 encryption_in_transit: true,
77 namespace_separator: ":".to_string(),
78 max_namespace_depth: 5,
79 }
80 }
81
82 pub fn free_tier() -> Self {
84 Self::new(IsolationLevel::Namespace)
85 }
86
87 pub fn pro_tier() -> Self {
89 let mut strategy = Self::new(IsolationLevel::SeparateIndex);
90 strategy.encryption_at_rest = true;
91 strategy
92 }
93
94 pub fn enterprise_tier() -> Self {
96 let mut strategy = Self::new(IsolationLevel::Dedicated);
97 strategy.encryption_at_rest = true;
98 strategy
99 }
100
101 pub fn with_encryption(mut self, at_rest: bool, in_transit: bool) -> Self {
103 self.encryption_at_rest = at_rest;
104 self.encryption_in_transit = in_transit;
105 self
106 }
107
108 pub fn with_separator(mut self, separator: impl Into<String>) -> Self {
110 self.namespace_separator = separator.into();
111 self
112 }
113}
114
115pub struct NamespaceManager {
117 namespaces: Arc<RwLock<HashMap<String, Namespace>>>,
119
120 strategy: IsolationStrategy,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct Namespace {
127 pub tenant_id: String,
129
130 pub prefix: String,
132
133 pub sub_namespaces: Vec<String>,
135
136 pub metadata: HashMap<String, String>,
138}
139
140impl Namespace {
141 pub fn new(tenant_id: impl Into<String>, prefix: impl Into<String>) -> Self {
143 Self {
144 tenant_id: tenant_id.into(),
145 prefix: prefix.into(),
146 sub_namespaces: Vec::new(),
147 metadata: HashMap::new(),
148 }
149 }
150
151 pub fn create_sub_namespace(&mut self, name: impl Into<String>, separator: &str) -> String {
153 let sub = format!("{}{}{}", self.prefix, separator, name.into());
154 self.sub_namespaces.push(sub.clone());
155 sub
156 }
157
158 pub fn qualify_key(&self, key: &str, separator: &str) -> String {
160 format!("{}{}{}", self.prefix, separator, key)
161 }
162
163 pub fn owns_key(&self, key: &str) -> bool {
165 key.starts_with(&self.prefix)
166 }
167}
168
169impl NamespaceManager {
170 pub fn new(strategy: IsolationStrategy) -> Self {
172 Self {
173 namespaces: Arc::new(RwLock::new(HashMap::new())),
174 strategy,
175 }
176 }
177
178 pub fn register_tenant(&self, tenant_id: impl Into<String>) -> MultiTenancyResult<String> {
180 let tenant_id = tenant_id.into();
181 let prefix = self.generate_namespace_prefix(&tenant_id);
182
183 let namespace = Namespace::new(tenant_id.clone(), prefix.clone());
184
185 let mut namespaces =
186 self.namespaces
187 .write()
188 .map_err(|e| MultiTenancyError::InternalError {
189 message: format!("Lock error: {}", e),
190 })?;
191
192 if namespaces.contains_key(&tenant_id) {
193 return Err(MultiTenancyError::TenantAlreadyExists {
194 tenant_id: tenant_id.clone(),
195 });
196 }
197
198 namespaces.insert(tenant_id, namespace);
199
200 Ok(prefix)
201 }
202
203 pub fn unregister_tenant(&self, tenant_id: &str) -> MultiTenancyResult<()> {
205 let mut namespaces =
206 self.namespaces
207 .write()
208 .map_err(|e| MultiTenancyError::InternalError {
209 message: format!("Lock error: {}", e),
210 })?;
211
212 namespaces
213 .remove(tenant_id)
214 .ok_or_else(|| MultiTenancyError::TenantNotFound {
215 tenant_id: tenant_id.to_string(),
216 })?;
217
218 Ok(())
219 }
220
221 pub fn get_prefix(&self, tenant_id: &str) -> MultiTenancyResult<String> {
223 let namespaces = self
224 .namespaces
225 .read()
226 .map_err(|e| MultiTenancyError::InternalError {
227 message: format!("Lock error: {}", e),
228 })?;
229
230 namespaces
231 .get(tenant_id)
232 .map(|ns| ns.prefix.clone())
233 .ok_or_else(|| MultiTenancyError::TenantNotFound {
234 tenant_id: tenant_id.to_string(),
235 })
236 }
237
238 pub fn qualify_key(&self, tenant_id: &str, key: &str) -> MultiTenancyResult<String> {
240 let namespaces = self
241 .namespaces
242 .read()
243 .map_err(|e| MultiTenancyError::InternalError {
244 message: format!("Lock error: {}", e),
245 })?;
246
247 let namespace =
248 namespaces
249 .get(tenant_id)
250 .ok_or_else(|| MultiTenancyError::TenantNotFound {
251 tenant_id: tenant_id.to_string(),
252 })?;
253
254 Ok(namespace.qualify_key(key, &self.strategy.namespace_separator))
255 }
256
257 pub fn extract_tenant_id(&self, namespaced_key: &str) -> MultiTenancyResult<String> {
259 let namespaces = self
260 .namespaces
261 .read()
262 .map_err(|e| MultiTenancyError::InternalError {
263 message: format!("Lock error: {}", e),
264 })?;
265
266 for (tenant_id, namespace) in namespaces.iter() {
267 if namespace.owns_key(namespaced_key) {
268 return Ok(tenant_id.clone());
269 }
270 }
271
272 Err(MultiTenancyError::IsolationViolation {
273 message: format!("No tenant owns key: {}", namespaced_key),
274 })
275 }
276
277 pub fn validate_access(&self, tenant_id: &str, key: &str) -> MultiTenancyResult<bool> {
279 let namespaces = self
280 .namespaces
281 .read()
282 .map_err(|e| MultiTenancyError::InternalError {
283 message: format!("Lock error: {}", e),
284 })?;
285
286 let namespace =
287 namespaces
288 .get(tenant_id)
289 .ok_or_else(|| MultiTenancyError::TenantNotFound {
290 tenant_id: tenant_id.to_string(),
291 })?;
292
293 Ok(namespace.owns_key(key))
294 }
295
296 pub fn create_sub_namespace(
298 &self,
299 tenant_id: &str,
300 name: impl Into<String>,
301 ) -> MultiTenancyResult<String> {
302 let mut namespaces =
303 self.namespaces
304 .write()
305 .map_err(|e| MultiTenancyError::InternalError {
306 message: format!("Lock error: {}", e),
307 })?;
308
309 let namespace =
310 namespaces
311 .get_mut(tenant_id)
312 .ok_or_else(|| MultiTenancyError::TenantNotFound {
313 tenant_id: tenant_id.to_string(),
314 })?;
315
316 if namespace.sub_namespaces.len() >= self.strategy.max_namespace_depth {
317 return Err(MultiTenancyError::InvalidConfiguration {
318 message: "Maximum namespace depth exceeded".to_string(),
319 });
320 }
321
322 Ok(namespace.create_sub_namespace(name, &self.strategy.namespace_separator))
323 }
324
325 pub fn list_namespaces(&self) -> MultiTenancyResult<Vec<String>> {
327 let namespaces = self
328 .namespaces
329 .read()
330 .map_err(|e| MultiTenancyError::InternalError {
331 message: format!("Lock error: {}", e),
332 })?;
333
334 Ok(namespaces.keys().cloned().collect())
335 }
336
337 fn generate_namespace_prefix(&self, tenant_id: &str) -> String {
339 let sanitized: String = tenant_id
341 .chars()
342 .map(|c| match c {
343 '-' | '.' | '/' => '_',
344 c => c,
345 })
346 .collect();
347
348 format!("tenant_{}", sanitized)
349 }
350
351 pub fn strategy(&self) -> &IsolationStrategy {
353 &self.strategy
354 }
355}
356
357#[cfg(test)]
358mod tests {
359 use super::*;
360
361 #[test]
362 fn test_isolation_levels() {
363 assert_eq!(IsolationLevel::Namespace.strength(), 3);
364 assert_eq!(IsolationLevel::SeparateIndex.strength(), 7);
365 assert_eq!(IsolationLevel::Dedicated.strength(), 10);
366
367 assert_eq!(IsolationLevel::Namespace.efficiency(), 10);
368 assert_eq!(IsolationLevel::Dedicated.efficiency(), 3);
369 }
370
371 #[test]
372 fn test_isolation_level_for_tier() {
373 assert_eq!(IsolationLevel::for_tier("free"), IsolationLevel::Namespace);
374 assert_eq!(
375 IsolationLevel::for_tier("pro"),
376 IsolationLevel::SeparateIndex
377 );
378 assert_eq!(
379 IsolationLevel::for_tier("enterprise"),
380 IsolationLevel::Dedicated
381 );
382 }
383
384 #[test]
385 fn test_isolation_strategy() {
386 let strategy = IsolationStrategy::free_tier();
387 assert_eq!(strategy.level, IsolationLevel::Namespace);
388 assert!(!strategy.encryption_at_rest);
389
390 let strategy = IsolationStrategy::pro_tier();
391 assert_eq!(strategy.level, IsolationLevel::SeparateIndex);
392 assert!(strategy.encryption_at_rest);
393
394 let strategy = IsolationStrategy::enterprise_tier();
395 assert_eq!(strategy.level, IsolationLevel::Dedicated);
396 assert!(strategy.encryption_at_rest);
397 }
398
399 #[test]
400 fn test_namespace_creation() {
401 let ns = Namespace::new("tenant1", "tenant_tenant1");
402 assert_eq!(ns.tenant_id, "tenant1");
403 assert_eq!(ns.prefix, "tenant_tenant1");
404 assert!(ns.sub_namespaces.is_empty());
405 }
406
407 #[test]
408 fn test_namespace_qualification() {
409 let ns = Namespace::new("tenant1", "tenant_tenant1");
410 let qualified = ns.qualify_key("vector123", ":");
411 assert_eq!(qualified, "tenant_tenant1:vector123");
412 assert!(ns.owns_key(&qualified));
413 assert!(!ns.owns_key("other_tenant:vector123"));
414 }
415
416 #[test]
417 fn test_namespace_manager() {
418 let strategy = IsolationStrategy::new(IsolationLevel::Namespace);
419 let manager = NamespaceManager::new(strategy);
420
421 let prefix = manager.register_tenant("tenant1").unwrap();
423 assert!(prefix.contains("tenant_tenant1"));
424
425 let retrieved_prefix = manager.get_prefix("tenant1").unwrap();
427 assert_eq!(prefix, retrieved_prefix);
428
429 let qualified = manager.qualify_key("tenant1", "vector123").unwrap();
431 assert!(qualified.starts_with(&prefix));
432 assert!(qualified.contains("vector123"));
433
434 assert!(manager.validate_access("tenant1", &qualified).unwrap());
436 assert!(!manager
437 .validate_access("tenant1", "other_tenant:key")
438 .unwrap());
439
440 let extracted = manager.extract_tenant_id(&qualified).unwrap();
442 assert_eq!(extracted, "tenant1");
443
444 manager.unregister_tenant("tenant1").unwrap();
446 assert!(manager.get_prefix("tenant1").is_err());
447 }
448
449 #[test]
450 fn test_sub_namespaces() {
451 let strategy = IsolationStrategy::new(IsolationLevel::Namespace);
452 let manager = NamespaceManager::new(strategy);
453
454 manager.register_tenant("tenant1").unwrap();
455
456 let sub = manager.create_sub_namespace("tenant1", "vectors").unwrap();
458 assert!(sub.contains("tenant_tenant1"));
459 assert!(sub.contains("vectors"));
460
461 let sub2 = manager
463 .create_sub_namespace("tenant1", "embeddings")
464 .unwrap();
465 assert!(sub2.contains("embeddings"));
466 assert_ne!(sub, sub2);
467 }
468
469 #[test]
470 fn test_namespace_manager_errors() {
471 let strategy = IsolationStrategy::new(IsolationLevel::Namespace);
472 let manager = NamespaceManager::new(strategy);
473
474 assert!(manager.get_prefix("nonexistent").is_err());
476
477 assert!(manager.qualify_key("nonexistent", "key").is_err());
479
480 manager.register_tenant("tenant1").unwrap();
482 assert!(manager.register_tenant("tenant1").is_err());
483
484 assert!(manager.unregister_tenant("nonexistent").is_err());
486 }
487
488 #[test]
489 fn test_list_namespaces() {
490 let strategy = IsolationStrategy::new(IsolationLevel::Namespace);
491 let manager = NamespaceManager::new(strategy);
492
493 assert_eq!(manager.list_namespaces().unwrap().len(), 0);
494
495 manager.register_tenant("tenant1").unwrap();
496 manager.register_tenant("tenant2").unwrap();
497
498 let namespaces = manager.list_namespaces().unwrap();
499 assert_eq!(namespaces.len(), 2);
500 assert!(namespaces.contains(&"tenant1".to_string()));
501 assert!(namespaces.contains(&"tenant2".to_string()));
502 }
503}