use crate::{
domain::{
entities::{Tenant, TenantQuotas, TenantUsage},
value_objects::TenantId,
},
error::Result,
};
use async_trait::async_trait;
use chrono::{DateTime, Utc};
#[async_trait]
pub trait TenantRepository: Send + Sync {
async fn create(&self, id: TenantId, name: String, quotas: TenantQuotas) -> Result<Tenant>;
async fn save(&self, tenant: &Tenant) -> Result<()>;
async fn find_by_id(&self, id: &TenantId) -> Result<Option<Tenant>>;
async fn find_by_name(&self, name: &str) -> Result<Option<Tenant>>;
async fn find_all(&self, limit: usize, offset: usize) -> Result<Vec<Tenant>>;
async fn find_active(&self, limit: usize, offset: usize) -> Result<Vec<Tenant>>;
async fn count(&self) -> Result<usize>;
async fn count_active(&self) -> Result<usize>;
async fn delete(&self, id: &TenantId) -> Result<bool>;
async fn update_quotas(&self, id: &TenantId, quotas: TenantQuotas) -> Result<bool>;
async fn update_usage(&self, id: &TenantId, usage: TenantUsage) -> Result<bool>;
async fn activate(&self, id: &TenantId) -> Result<bool>;
async fn deactivate(&self, id: &TenantId) -> Result<bool>;
async fn exists(&self, id: &TenantId) -> Result<bool> {
Ok(self.find_by_id(id).await?.is_some())
}
async fn is_active(&self, id: &TenantId) -> Result<bool> {
match self.find_by_id(id).await? {
Some(tenant) => Ok(tenant.is_active()),
None => Ok(false),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct TenantQuery {
pub active_only: bool,
pub name_contains: Option<String>,
pub created_after: Option<DateTime<Utc>>,
pub created_before: Option<DateTime<Utc>>,
pub limit: Option<usize>,
pub offset: Option<usize>,
}
impl TenantQuery {
pub fn new() -> Self {
Self::default()
}
pub fn active_only(mut self) -> Self {
self.active_only = true;
self
}
pub fn with_name_filter(mut self, name: String) -> Self {
self.name_contains = Some(name);
self
}
pub fn created_after(mut self, date: DateTime<Utc>) -> Self {
self.created_after = Some(date);
self
}
pub fn created_before(mut self, date: DateTime<Utc>) -> Self {
self.created_before = Some(date);
self
}
pub fn with_pagination(mut self, limit: usize, offset: usize) -> Self {
self.limit = Some(limit);
self.offset = Some(offset);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tenant_query_builder() {
let query = TenantQuery::new()
.active_only()
.with_name_filter("acme".to_string())
.with_pagination(10, 0);
assert!(query.active_only);
assert_eq!(query.name_contains, Some("acme".to_string()));
assert_eq!(query.limit, Some(10));
assert_eq!(query.offset, Some(0));
}
#[test]
fn test_tenant_query_with_dates() {
let now = Utc::now();
let yesterday = now - chrono::Duration::days(1);
let query = TenantQuery::new()
.created_after(yesterday)
.created_before(now);
assert!(query.created_after.is_some());
assert!(query.created_before.is_some());
}
}