signer-crdt 0.4.1

Signer CRDT (Conflict-free Replicated Data Type) package.
Documentation
use sea_orm::{
    ActiveModelTrait as _, ActiveValue::Set, ColumnTrait, DatabaseTransaction, EntityTrait,
    ModelTrait, QueryFilter,
};

use crate::{SignerMeta, crdt::errors::CrdtError, delta::chat_do::ChatDO, entity::chat};

use super::{CrdtType, crdt::CrdtDelta};

impl CrdtType for ChatDO {
    // ( chat_key, chat_variant )
    type PrimaryKey = (String, String);

    async fn put(
        &self,
        core: &SignerMeta,
        tx: &DatabaseTransaction,
    ) -> Result<CrdtDelta<Self>, CrdtError> {
        let r = chat::Entity::find()
            .filter(
                chat::Column::ChatKey
                    .eq(&self.chat_key)
                    .and(chat::Column::ChatVariant.eq(&self.chat_variant)),
            )
            .one(tx)
            .await?;
        if let Some(val) = &r {
            let vo = serde_json::from_str(&val.view_object)?;
            if !self.has_changed(&vo) {
                return Ok(CrdtDelta::Skip);
            }
        }

        let m = chat::ActiveModel {
            chat_key: Set(self.chat_key.clone()),
            chat_variant: Set(self.chat_variant.clone()),
            view_object: Set(serde_json::to_string(&self.view_object.unwrap_ref())?),
        };

        match r {
            Some(val) => {
                let e = m.update(tx).await?;
                let from = serde_json::from_str(&e.view_object)?;
                let to = serde_json::from_str(&val.view_object)?;
                let chat_do = ChatDO::new(core, &from, &to).await?;
                Ok(CrdtDelta::Put(chat_do))
            }
            None => {
                let e = m.insert(tx).await?;
                Ok(CrdtDelta::Del((e.chat_variant, e.chat_key)))
            }
        }
    }

    async fn del(
        _core: &SignerMeta,
        key: &Self::PrimaryKey,
        tx: &DatabaseTransaction,
    ) -> Result<CrdtDelta<Self>, CrdtError> {
        let r = chat::Entity::find()
            .filter(
                chat::Column::ChatKey
                    .eq(&key.1)
                    .and(chat::Column::ChatVariant.eq(&key.0)),
            )
            .one(tx)
            .await?;

        match r {
            Some(val) => {
                let vo = serde_json::from_str(&val.view_object)?;
                let chat_do = ChatDO::from(vo);

                val.delete(tx).await?;

                Ok(CrdtDelta::Put(chat_do))
            }
            None => Ok(CrdtDelta::Skip),
        }
    }
}