corteq 0.1.0

Enterprise-grade multi-tenant SaaS framework for Rust with security-first design
Documentation
//! Tenant repository for database operations

use crate::{Result, Tenant};
use sqlx::PgPool;
use uuid::Uuid;

/// Repository for tenant database operations
#[derive(Debug, Clone)]
pub struct TenantRepository {
    pool: PgPool,
}

impl TenantRepository {
    /// Create a new tenant repository
    pub fn new(pool: PgPool) -> Self {
        Self { pool }
    }

    /// Find a tenant by ID
    ///
    /// Returns None if tenant doesn't exist or is soft-deleted
    pub async fn find_by_id(&self, id: &Uuid) -> Result<Option<Tenant>> {
        let tenant = sqlx::query_as::<_, Tenant>(
            "SELECT id, name, slug, encryption_key_id, created_at, updated_at, deleted_at
             FROM tenants
             WHERE id = $1 AND deleted_at IS NULL",
        )
        .bind(id)
        .fetch_optional(&self.pool)
        .await?;

        Ok(tenant)
    }

    /// Find a tenant by slug
    ///
    /// Returns None if tenant doesn't exist or is soft-deleted
    pub async fn find_by_slug(&self, slug: &str) -> Result<Option<Tenant>> {
        let tenant = sqlx::query_as::<_, Tenant>(
            "SELECT id, name, slug, encryption_key_id, created_at, updated_at, deleted_at
             FROM tenants
             WHERE slug = $1 AND deleted_at IS NULL",
        )
        .bind(slug)
        .fetch_optional(&self.pool)
        .await?;

        Ok(tenant)
    }

    /// List all active tenants
    pub async fn list_all(&self) -> Result<Vec<Tenant>> {
        let tenants = sqlx::query_as::<_, Tenant>(
            "SELECT id, name, slug, encryption_key_id, created_at, updated_at, deleted_at
             FROM tenants
             WHERE deleted_at IS NULL
             ORDER BY created_at DESC",
        )
        .fetch_all(&self.pool)
        .await?;

        Ok(tenants)
    }

    /// Create a new tenant
    pub async fn create(&self, name: &str, slug: &str, encryption_key_id: &str) -> Result<Tenant> {
        let tenant = sqlx::query_as::<_, Tenant>(
            "INSERT INTO tenants (name, slug, encryption_key_id)
             VALUES ($1, $2, $3)
             RETURNING id, name, slug, encryption_key_id, created_at, updated_at, deleted_at",
        )
        .bind(name)
        .bind(slug)
        .bind(encryption_key_id)
        .fetch_one(&self.pool)
        .await?;

        Ok(tenant)
    }

    /// Soft delete a tenant
    pub async fn soft_delete(&self, id: &Uuid) -> Result<()> {
        sqlx::query("UPDATE tenants SET deleted_at = NOW() WHERE id = $1")
            .bind(id)
            .execute(&self.pool)
            .await?;

        Ok(())
    }
}

// Integration tests are in tests/ directory