From 2b70b130f2e82bfe839678e891a90392c4c93be5 Mon Sep 17 00:00:00 2001 From: fluo10 Date: Sat, 28 Jun 2025 08:04:32 +0900 Subject: [PATCH] Implement SyncableModel derive --- .../src/data/entity/record_deletion.rs | 4 ++- lazy-supplements-core/src/data/syncable.rs | 22 ++++++------- lazy-supplements-macros/src/lib.rs | 31 +++++++++++-------- .../tests/derive_syncable.rs | 24 ++++++++------ 4 files changed, 47 insertions(+), 34 deletions(-) diff --git a/lazy-supplements-core/src/data/entity/record_deletion.rs b/lazy-supplements-core/src/data/entity/record_deletion.rs index cc06d28..edddd63 100644 --- a/lazy-supplements-core/src/data/entity/record_deletion.rs +++ b/lazy-supplements-core/src/data/entity/record_deletion.rs @@ -12,11 +12,13 @@ use crate::data::syncable::*; #[sea_orm(table_name = "record_deletion")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] - #[cfg_attr(feature="macros", syncable(uuid))] + #[cfg_attr(feature="macros", syncable(id))] pub id: Uuid, #[sea_orm(indexed)] #[cfg_attr(feature="macros", syncable(timestamp))] pub created_at: DateTimeUtc, + #[cfg_attr(feature="macros", syncable(author_id))] + pub created_by: Uuid, pub table_name: String, pub record_id: Uuid, } diff --git a/lazy-supplements-core/src/data/syncable.rs b/lazy-supplements-core/src/data/syncable.rs index 9c6e885..ec641ed 100644 --- a/lazy-supplements-core/src/data/syncable.rs +++ b/lazy-supplements-core/src/data/syncable.rs @@ -17,17 +17,17 @@ pub trait SyncableEntity: EntityTrait< type SyncableActiveModel: SyncableActiveModel; type SyncableColumn: SyncableColumn; - async fn get_updated(from: DateTimeUtc,until: DateTimeUtc, db: &DatabaseConnection) -> Result::Model>, SyncableError> { + async fn get_updated(from: DateTimeUtc, db: &DatabaseConnection) -> Result::Model>, SyncableError> { let result: Vec = ::find() - .filter(Self::SyncableColumn::timestamp_between(from, until)) + .filter(Self::SyncableColumn::timestamp_after(from)) .all(db) .await.unwrap(); Ok(result) } - async fn get_updated_by_author(from: DateTimeUtc, author: Uuid, db: &DatabaseConnection) -> Result::Model>, SyncableError> { + async fn get_updated_by(author: Uuid, from: DateTimeUtc, db: &DatabaseConnection) -> Result::Model>, SyncableError> { let result: Vec = ::find() - .filter(Self::SyncableColumn::timestamp_between(from, until)) - .filter(Self::SyncableColumn::author_eq(author)) + .filter(Self::SyncableColumn::timestamp_after(from)) + .filter(Self::SyncableColumn::author_id_eq(author)) .all(db) .await.unwrap(); Ok(result) @@ -42,14 +42,14 @@ pub trait SyncableActiveModel: ActiveModelTrait { type SyncableEntity: SyncableEntity; fn get_id(&self) -> Option; fn get_timestamp(&self) -> Option; - fn get_author_id(&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() { + if self.get_id().ok_or(SyncableError::MissingField("uuid"))? != other.get_id() { 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(){ + if column.should_synced(){ self.take(column).set_if_not_equals(other.get(column)); } } @@ -62,9 +62,9 @@ pub trait SyncableActiveModel: ActiveModelTrait { 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 should_synced(&self) -> bool; + fn timestamp_after(from: DateTimeUtc) -> SimpleExpr; + fn author_id_eq(author_id: Uuid) -> SimpleExpr; fn is_author_id(&self) -> bool; } diff --git a/lazy-supplements-macros/src/lib.rs b/lazy-supplements-macros/src/lib.rs index aae46e4..cfc1afa 100644 --- a/lazy-supplements-macros/src/lib.rs +++ b/lazy-supplements-macros/src/lib.rs @@ -23,11 +23,11 @@ pub fn syncable_model(input: TokenStream) -> TokenStream { fn get_id(&self) -> Uuid { self.#id_snake } - fn get_timestamp() -> DateTimeUtc { + fn get_timestamp(&self) -> DateTimeUtc { self.#timestamp_snake } - fn get_author_id() -> Uuid { - self.#timestamp_snake + fn get_author_id(&self) -> Uuid { + self.#author_id_snake } } impl SyncableEntity for Entity { @@ -39,14 +39,15 @@ pub fn syncable_model(input: TokenStream) -> TokenStream { impl SyncableActiveModel for ActiveModel { type SyncableEntity = Entity; fn get_id(&self) -> Option { - self.#id_snake.into_value() + self.#id_snake.try_as_ref().cloned() } fn get_timestamp(&self) -> Option { - self.#timestamp_snake.into_value() + self.#timestamp_snake.try_as_ref().cloned() } - fn get_author_id(&self) -> Option { - self.#author_id_snake.into_value() - } } + fn get_author_id(&self) -> Option { + self.#author_id_snake.try_as_ref().cloned() + } + } impl SyncableColumn for Column { fn is_id(&self) -> bool { matches!(self, Column::#id_camel) @@ -57,12 +58,16 @@ pub fn syncable_model(input: TokenStream) -> TokenStream { fn is_author_id(&self) -> bool { matches!(self, Column::#author_id_camel) } - fn should_sync(&self) -> bool { + fn should_synced(&self) -> bool { todo!() } - fn timestamp_between(from: DateTimeUtc, until: DateTimeUtc) -> SimpleExpr { - todo!() + fn timestamp_after(timestamp: DateTimeUtc) -> sea_orm::sea_query::expr::SimpleExpr { + Column::#timestamp_camel.gte(timestamp) } + fn author_id_eq(author_id: Uuid) -> sea_orm::sea_query::expr::SimpleExpr { + Column::#author_id_camel.eq(author_id) + } + } }; output.into() @@ -70,9 +75,9 @@ pub fn syncable_model(input: TokenStream) -> TokenStream { fn extract_unique_field_ident<'a>(fields: &'a FieldsNamed, attribute_arg: &'static str) -> &'a Ident { let mut fields = extract_field_idents(fields, attribute_arg); if fields.len() == 1 { - fields.pop().unwrap() + return fields.pop().unwrap() } else { - panic!("Model must need one {} field attribute", attribute_arg) + panic!("Model must need one {} field attribute", attribute_arg); } } diff --git a/lazy-supplements-macros/tests/derive_syncable.rs b/lazy-supplements-macros/tests/derive_syncable.rs index 813fe39..b5e1bfa 100644 --- a/lazy-supplements-macros/tests/derive_syncable.rs +++ b/lazy-supplements-macros/tests/derive_syncable.rs @@ -1,13 +1,15 @@ use chrono::Local; -use sea_orm::entity::{ - *, - prelude::* +use sea_orm::{ + prelude::*, + entity::{ + *, + prelude::* + } }; use lazy_supplements_core::data::syncable::*; use lazy_supplements_macros::SyncableModel; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize, SyncableModel)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, SyncableModel)] #[sea_orm(table_name = "syncable")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] @@ -16,14 +18,18 @@ pub struct Model { #[sea_orm(indexed)] #[syncable(timestamp)] pub created_at: DateTimeUtc, - pub table_name: String, - #[syncable(author_id)] - pub updated_by: Uuid, - pub record_id: Uuid, + pub created_by: Uuid, } #[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)] pub enum Relation{} impl ActiveModelBehavior for ActiveModel {} + +#[test] +fn test_columns() { + assert!(Column::Id.is_id()); + assert!(Column::CreatedAt.is_timestamp()); + assert!(Column::CreatedBy.is_author_id()); +} \ No newline at end of file