raisfast 0.2.23

The last backend you'll ever need. Rust-powered headless CMS with built-in blog, ecommerce, wallet, payment and 4 plugin engines.
use crate::types::snowflake_id::SnowflakeId;
use serde::Serialize;
use serde_json::Value;

use crate::db::Pool;
use crate::errors::app_error::{AppError, AppResult};
use crate::models::content_revision::{self, ContentRevision, RevisionSummary};

#[derive(Debug, Serialize)]
pub struct DiffResult {
    pub revision_a: ContentRevision,
    pub revision_b: ContentRevision,
    pub diff: Value,
}

pub async fn list_revisions(
    pool: &Pool,
    content_type: &str,
    content_id: SnowflakeId,
    _page: i64,
    _page_size: i64,
) -> AppResult<(Vec<RevisionSummary>, i64)> {
    let items = content_revision::list_revisions(pool, content_type, content_id).await?;
    let total = items.len() as i64;
    let summaries = items
        .into_iter()
        .map(|r| RevisionSummary {
            id: r.id,
            revision_number: r.revision_number,
            created_by: r.created_by,
            created_at: r.created_at,
        })
        .collect();
    Ok((summaries, total))
}

pub async fn get_revision(
    pool: &Pool,
    content_type: &str,
    content_id: SnowflakeId,
    revision_id: SnowflakeId,
) -> AppResult<ContentRevision> {
    content_revision::get_revision(pool, content_type, content_id, revision_id)
        .await?
        .ok_or_else(|| AppError::not_found("revision"))
}

pub async fn restore_revision(
    pool: &Pool,
    content_type: &str,
    content_id: SnowflakeId,
    revision_id: SnowflakeId,
) -> AppResult<Value> {
    let revision = get_revision(pool, content_type, content_id, revision_id).await?;
    let mut snapshot: Value =
        serde_json::from_str(&revision.snapshot).map_err(|e| AppError::Internal(e.into()))?;
    if let Some(obj) = snapshot.as_object_mut() {
        obj.remove(crate::constants::COL_ID);
        obj.remove("created_at");
        obj.remove("updated_at");
    }
    Ok(snapshot)
}

pub async fn diff_revisions(
    pool: &Pool,
    content_type: &str,
    content_id: SnowflakeId,
    rev_id_a: i64,
    rev_id_b: i64,
) -> AppResult<DiffResult> {
    let a = get_revision(pool, content_type, content_id, SnowflakeId(rev_id_a)).await?;
    let b = get_revision(pool, content_type, content_id, SnowflakeId(rev_id_b)).await?;
    let snap_a: Value =
        serde_json::from_str(&a.snapshot).map_err(|e| AppError::Internal(e.into()))?;
    let snap_b: Value =
        serde_json::from_str(&b.snapshot).map_err(|e| AppError::Internal(e.into()))?;
    let diff = content_revision::compute_diff(&snap_a, &snap_b);
    Ok(DiffResult {
        revision_a: a,
        revision_b: b,
        diff,
    })
}