caretta-sync/core/src/data/syncable.rs

79 lines
3 KiB
Rust
Raw Normal View History

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