bindizr-service 0.1.0-beta.4

Application services for bindizr zone, record, token, and notification workflows
Documentation
use bindizr_db::repository::ZoneFilter;

use super::{ZoneService, validation::normalize_zone_lookup_name};
use crate::{
    RepositoryTx,
    error::ServiceError,
    log_error,
    model::{zone::Zone, zone_change::ZoneChange},
    repository::RepositoryService,
    types::{GetZonesFilter, PaginatedResponse, Pagination},
};

impl ZoneService {
    pub async fn find(zone_name: &str) -> Result<Option<Zone>, ServiceError> {
        let lookup_name = normalize_zone_lookup_name(zone_name)?;
        RepositoryService::get_zone_by_name(&lookup_name).await
    }

    pub async fn find_tx(
        tx: &mut RepositoryTx<'_>,
        zone_name: &str,
    ) -> Result<Option<Zone>, ServiceError> {
        let lookup_name = normalize_zone_lookup_name(zone_name)?;
        RepositoryService::get_zone_by_name_tx(tx, &lookup_name).await
    }

    pub async fn find_by_id(zone_id: i32) -> Result<Option<Zone>, ServiceError> {
        RepositoryService::get_zone_by_id(zone_id).await
    }

    pub async fn get_changes_between_serials(
        zone_id: i32,
        from_serial: i32,
        to_serial: i32,
    ) -> Result<Vec<ZoneChange>, ServiceError> {
        RepositoryService::get_zone_changes_between_serials(zone_id, from_serial, to_serial).await
    }

    pub async fn list() -> Result<Vec<Zone>, ServiceError> {
        RepositoryService::get_all_zones().await.map_err(|e| {
            log_error!("Failed to fetch zones: {}", e);
            ServiceError::Internal("Failed to fetch zones".to_string())
        })
    }

    pub async fn list_by_filter(
        filter: GetZonesFilter,
    ) -> Result<PaginatedResponse<Zone>, ServiceError> {
        let limit = filter.limit;
        let offset = filter.offset;

        let zone_filter = ZoneFilter {
            name: filter.name,
            id: filter.id,
            primary_ns: filter.primary_ns,
            admin_email: filter.admin_email,
            ttl: filter.ttl,
            min_ttl: filter.min_ttl,
            max_ttl: filter.max_ttl,
            serial: filter.serial,
            search: filter.search,
            limit,
            offset,
        };

        let total = RepositoryService::count_zones_by_filter(zone_filter.clone()).await?;
        let zones = RepositoryService::get_zones_by_filter(zone_filter).await?;
        let offset = offset.unwrap_or(0);
        let limit = limit.unwrap_or_else(|| total.min(u64::from(u32::MAX)) as u32);

        Ok(PaginatedResponse {
            items: zones,
            pagination: Pagination {
                limit,
                offset,
                total,
            },
        })
    }

    pub async fn get_by_name(zone_name: &str) -> Result<Zone, ServiceError> {
        let lookup_name = normalize_zone_lookup_name(zone_name)?;

        match RepositoryService::get_zone_by_name(&lookup_name).await {
            Ok(Some(zone)) => Ok(zone),
            Ok(None) => Err(ServiceError::NotFound(format!(
                "Zone with name '{}' not found",
                zone_name
            ))),
            Err(e) => {
                log_error!("Failed to fetch zone: {}", e);
                Err(ServiceError::Internal("Failed to fetch zone".to_string()))
            }
        }
    }
}