use sea_orm::{prelude::*, query::*, sea_query::SimpleExpr, *}; #[cfg(feature="macros")] pub use lazy_supplements_macros::SyncableModel; pub trait SyncableModel: ModelTrait { type SyncableEntity: SyncableEntity; fn get_timestamp(&self) -> DateTimeUtc; fn get_id(&self) -> Uuid; fn get_author_id(&self) -> Uuid; } pub trait SyncableEntity: EntityTrait< Model = Self::SyncableModel, ActiveModel = Self::SyncableActiveModel, Column = Self::SyncableColumn, >{ type SyncableModel: SyncableModel + FromQueryResult; type SyncableActiveModel: SyncableActiveModel; type SyncableColumn: SyncableColumn; async fn get_updated(from: DateTimeUtc,until: DateTimeUtc, db: &DatabaseConnection) -> Result::Model>, SyncableError> { let result: Vec = ::find() .filter(Self::SyncableColumn::timestamp_between(from, until)) .all(db) .await.unwrap(); Ok(result) } async fn get_updated_by_author(from: DateTimeUtc, author: Uuid, db: &DatabaseConnection) -> Result::Model>, SyncableError> { let result: Vec = ::find() .filter(Self::SyncableColumn::timestamp_between(from, until)) .filter(Self::SyncableColumn::author_eq(author)) .all(db) .await.unwrap(); Ok(result) } fn apply_updated(models: Vec<::Model>, db: &DatabaseConnection) { todo!() } } pub trait SyncableActiveModel: ActiveModelTrait { type SyncableEntity: SyncableEntity; fn get_id(&self) -> Option; fn get_timestamp(&self) -> Option; fn get_author_id(&self) -> Option; fn try_merge(&mut self, other: ::SyncableModel) -> Result<(), SyncableError> { if self.get_uuid().ok_or(SyncableError::MissingField("uuid"))? != other.get_uuid() { return Err(SyncableError::MismatchUuid) } if self.get_timestamp().ok_or(SyncableError::MissingField("updated_at"))? < other.get_timestamp() { for column in <<::Entity as EntityTrait>::Column as Iterable>::iter() { if column.should_sync(){ self.take(column).set_if_not_equals(other.get(column)); } } } Ok(()) } } pub trait SyncableColumn: ColumnTrait { fn is_id(&self) -> bool; fn is_timestamp(&self) -> bool; fn should_sync(&self) -> bool; fn timestamp_between(from: DateTimeUtc, to: DateTimeUtc) -> SimpleExpr; fn author_eq(author_id: Uuid) -> SimpleExpr; fn is_author_id(&self) -> bool; } #[derive(Debug, thiserror::Error)] pub enum SyncableError { #[error("Invalid UUID")] MismatchUuid, #[error("mandatory field {0} is missing")] MissingField(&'static str), }