Implement SyncableModel derive
This commit is contained in:
parent
72c9710283
commit
2b70b130f2
4 changed files with 47 additions and 34 deletions
|
@ -12,11 +12,13 @@ use crate::data::syncable::*;
|
||||||
#[sea_orm(table_name = "record_deletion")]
|
#[sea_orm(table_name = "record_deletion")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key, auto_increment = false)]
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
#[cfg_attr(feature="macros", syncable(uuid))]
|
#[cfg_attr(feature="macros", syncable(id))]
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
#[sea_orm(indexed)]
|
#[sea_orm(indexed)]
|
||||||
#[cfg_attr(feature="macros", syncable(timestamp))]
|
#[cfg_attr(feature="macros", syncable(timestamp))]
|
||||||
pub created_at: DateTimeUtc,
|
pub created_at: DateTimeUtc,
|
||||||
|
#[cfg_attr(feature="macros", syncable(author_id))]
|
||||||
|
pub created_by: Uuid,
|
||||||
pub table_name: String,
|
pub table_name: String,
|
||||||
pub record_id: Uuid,
|
pub record_id: Uuid,
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,17 +17,17 @@ pub trait SyncableEntity: EntityTrait<
|
||||||
type SyncableActiveModel: SyncableActiveModel<SyncableEntity= Self>;
|
type SyncableActiveModel: SyncableActiveModel<SyncableEntity= Self>;
|
||||||
type SyncableColumn: SyncableColumn;
|
type SyncableColumn: SyncableColumn;
|
||||||
|
|
||||||
async fn get_updated(from: DateTimeUtc,until: DateTimeUtc, db: &DatabaseConnection) -> Result<Vec<<Self as EntityTrait>::Model>, SyncableError> {
|
async fn get_updated(from: DateTimeUtc, db: &DatabaseConnection) -> Result<Vec<<Self as EntityTrait>::Model>, SyncableError> {
|
||||||
let result: Vec<Self::SyncableModel> = <Self as EntityTrait>::find()
|
let result: Vec<Self::SyncableModel> = <Self as EntityTrait>::find()
|
||||||
.filter(Self::SyncableColumn::timestamp_between(from, until))
|
.filter(Self::SyncableColumn::timestamp_after(from))
|
||||||
.all(db)
|
.all(db)
|
||||||
.await.unwrap();
|
.await.unwrap();
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
async fn get_updated_by_author(from: DateTimeUtc, author: Uuid, db: &DatabaseConnection) -> Result<Vec<<Self as EntityTrait>::Model>, SyncableError> {
|
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()
|
let result: Vec<Self::SyncableModel> = <Self as EntityTrait>::find()
|
||||||
.filter(Self::SyncableColumn::timestamp_between(from, until))
|
.filter(Self::SyncableColumn::timestamp_after(from))
|
||||||
.filter(Self::SyncableColumn::author_eq(author))
|
.filter(Self::SyncableColumn::author_id_eq(author))
|
||||||
.all(db)
|
.all(db)
|
||||||
.await.unwrap();
|
.await.unwrap();
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
@ -42,14 +42,14 @@ pub trait SyncableActiveModel: ActiveModelTrait<Entity = Self::SyncableEntity> {
|
||||||
type SyncableEntity: SyncableEntity<SyncableActiveModel = Self>;
|
type SyncableEntity: SyncableEntity<SyncableActiveModel = Self>;
|
||||||
fn get_id(&self) -> Option<Uuid>;
|
fn get_id(&self) -> Option<Uuid>;
|
||||||
fn get_timestamp(&self) -> Option<DateTimeUtc>;
|
fn get_timestamp(&self) -> Option<DateTimeUtc>;
|
||||||
fn get_author_id(&self) -> Option<DateTimeUtc>;
|
fn get_author_id(&self) -> Option<Uuid>;
|
||||||
fn try_merge(&mut self, other: <Self::SyncableEntity as SyncableEntity>::SyncableModel) -> Result<(), SyncableError> {
|
fn try_merge(&mut self, other: <Self::SyncableEntity as SyncableEntity>::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)
|
return Err(SyncableError::MismatchUuid)
|
||||||
}
|
}
|
||||||
if self.get_timestamp().ok_or(SyncableError::MissingField("updated_at"))? < other.get_timestamp() {
|
if self.get_timestamp().ok_or(SyncableError::MissingField("updated_at"))? < other.get_timestamp() {
|
||||||
for column in <<<Self as ActiveModelTrait>::Entity as EntityTrait>::Column as Iterable>::iter() {
|
for column in <<<Self as ActiveModelTrait>::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));
|
self.take(column).set_if_not_equals(other.get(column));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,9 +62,9 @@ pub trait SyncableActiveModel: ActiveModelTrait<Entity = Self::SyncableEntity> {
|
||||||
pub trait SyncableColumn: ColumnTrait {
|
pub trait SyncableColumn: ColumnTrait {
|
||||||
fn is_id(&self) -> bool;
|
fn is_id(&self) -> bool;
|
||||||
fn is_timestamp(&self) -> bool;
|
fn is_timestamp(&self) -> bool;
|
||||||
fn should_sync(&self) -> bool;
|
fn should_synced(&self) -> bool;
|
||||||
fn timestamp_between(from: DateTimeUtc, to: DateTimeUtc) -> SimpleExpr;
|
fn timestamp_after(from: DateTimeUtc) -> SimpleExpr;
|
||||||
fn author_eq(author_id: Uuid) -> SimpleExpr;
|
fn author_id_eq(author_id: Uuid) -> SimpleExpr;
|
||||||
fn is_author_id(&self) -> bool;
|
fn is_author_id(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,11 +23,11 @@ pub fn syncable_model(input: TokenStream) -> TokenStream {
|
||||||
fn get_id(&self) -> Uuid {
|
fn get_id(&self) -> Uuid {
|
||||||
self.#id_snake
|
self.#id_snake
|
||||||
}
|
}
|
||||||
fn get_timestamp() -> DateTimeUtc {
|
fn get_timestamp(&self) -> DateTimeUtc {
|
||||||
self.#timestamp_snake
|
self.#timestamp_snake
|
||||||
}
|
}
|
||||||
fn get_author_id() -> Uuid {
|
fn get_author_id(&self) -> Uuid {
|
||||||
self.#timestamp_snake
|
self.#author_id_snake
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl SyncableEntity for Entity {
|
impl SyncableEntity for Entity {
|
||||||
|
@ -39,14 +39,15 @@ pub fn syncable_model(input: TokenStream) -> TokenStream {
|
||||||
impl SyncableActiveModel for ActiveModel {
|
impl SyncableActiveModel for ActiveModel {
|
||||||
type SyncableEntity = Entity;
|
type SyncableEntity = Entity;
|
||||||
fn get_id(&self) -> Option<Uuid> {
|
fn get_id(&self) -> Option<Uuid> {
|
||||||
self.#id_snake.into_value()
|
self.#id_snake.try_as_ref().cloned()
|
||||||
}
|
}
|
||||||
fn get_timestamp(&self) -> Option<DateTimeUtc> {
|
fn get_timestamp(&self) -> Option<DateTimeUtc> {
|
||||||
self.#timestamp_snake.into_value()
|
self.#timestamp_snake.try_as_ref().cloned()
|
||||||
}
|
}
|
||||||
fn get_author_id(&self) -> Option<DateTimeUtc> {
|
fn get_author_id(&self) -> Option<Uuid> {
|
||||||
self.#author_id_snake.into_value()
|
self.#author_id_snake.try_as_ref().cloned()
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
impl SyncableColumn for Column {
|
impl SyncableColumn for Column {
|
||||||
fn is_id(&self) -> bool {
|
fn is_id(&self) -> bool {
|
||||||
matches!(self, Column::#id_camel)
|
matches!(self, Column::#id_camel)
|
||||||
|
@ -57,12 +58,16 @@ pub fn syncable_model(input: TokenStream) -> TokenStream {
|
||||||
fn is_author_id(&self) -> bool {
|
fn is_author_id(&self) -> bool {
|
||||||
matches!(self, Column::#author_id_camel)
|
matches!(self, Column::#author_id_camel)
|
||||||
}
|
}
|
||||||
fn should_sync(&self) -> bool {
|
fn should_synced(&self) -> bool {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
fn timestamp_between(from: DateTimeUtc, until: DateTimeUtc) -> SimpleExpr {
|
fn timestamp_after(timestamp: DateTimeUtc) -> sea_orm::sea_query::expr::SimpleExpr {
|
||||||
todo!()
|
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()
|
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 {
|
fn extract_unique_field_ident<'a>(fields: &'a FieldsNamed, attribute_arg: &'static str) -> &'a Ident {
|
||||||
let mut fields = extract_field_idents(fields, attribute_arg);
|
let mut fields = extract_field_idents(fields, attribute_arg);
|
||||||
if fields.len() == 1 {
|
if fields.len() == 1 {
|
||||||
fields.pop().unwrap()
|
return fields.pop().unwrap()
|
||||||
} else {
|
} else {
|
||||||
panic!("Model must need one {} field attribute", attribute_arg)
|
panic!("Model must need one {} field attribute", attribute_arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use sea_orm::entity::{
|
use sea_orm::{
|
||||||
*,
|
prelude::*,
|
||||||
prelude::*
|
entity::{
|
||||||
|
*,
|
||||||
|
prelude::*
|
||||||
|
}
|
||||||
};
|
};
|
||||||
use lazy_supplements_core::data::syncable::*;
|
use lazy_supplements_core::data::syncable::*;
|
||||||
use lazy_supplements_macros::SyncableModel;
|
use lazy_supplements_macros::SyncableModel;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, SyncableModel)]
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize, SyncableModel)]
|
|
||||||
#[sea_orm(table_name = "syncable")]
|
#[sea_orm(table_name = "syncable")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key, auto_increment = false)]
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
@ -16,14 +18,18 @@ pub struct Model {
|
||||||
#[sea_orm(indexed)]
|
#[sea_orm(indexed)]
|
||||||
#[syncable(timestamp)]
|
#[syncable(timestamp)]
|
||||||
pub created_at: DateTimeUtc,
|
pub created_at: DateTimeUtc,
|
||||||
pub table_name: String,
|
|
||||||
|
|
||||||
#[syncable(author_id)]
|
#[syncable(author_id)]
|
||||||
pub updated_by: Uuid,
|
pub created_by: Uuid,
|
||||||
pub record_id: Uuid,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
||||||
pub enum Relation{}
|
pub enum Relation{}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_columns() {
|
||||||
|
assert!(Column::Id.is_id());
|
||||||
|
assert!(Column::CreatedAt.is_timestamp());
|
||||||
|
assert!(Column::CreatedBy.is_author_id());
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue