use std::{any::Any, collections::VecDeque, fmt::Debug};
use crate::outbox::OutBox;
use downcast_rs::{impl_downcast, Downcast};
use serde::Serialize;
use serde_json::Value;
pub trait Aggregate: Send + Sync + Default {
fn collect_events(&mut self) -> VecDeque<Box<dyn Message>> {
if !self.events().is_empty() {
self.take_events()
} else {
VecDeque::new()
}
}
fn events(&self) -> &std::collections::VecDeque<Box<dyn Message>>;
fn take_events(&mut self) -> std::collections::VecDeque<Box<dyn Message>>;
fn raise_event(
&mut self,
event: Box<dyn Message>,
);
}
#[macro_export]
macro_rules! count {
() => (0usize);
( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
}
#[macro_export]
macro_rules! Aggregate {
(
$( #[$attr:meta] )*
$pub:vis
struct $aggregate:ident {
$(#[$event_field_attr:meta])*
events: std::collections::VecDeque<std::boxed::Box<dyn Message>>,
$(
$(#[$field_attr:meta])*
$field_vis:vis $field_name:ident : $field_type:ty
),* $(,)?
}
) => {
$( #[$attr])*
impl Aggregate for $aggregate {
fn events(&self) -> &std::collections::VecDeque<Box<dyn Message>> {
&self.events
}
fn take_events(&mut self) -> std::collections::VecDeque<Box<dyn Message>> {
std::mem::take(&mut self.events)
}
fn raise_event(&mut self, event: Box<dyn Message>) {
self.events.push_back(event)
}
}
};
}
#[macro_export]
macro_rules! Entity {
(
$( #[$attr:meta] )*
$pub:vis
struct $classic:ident {
$(
$(#[$field_attr:meta])*
$field_vis:vis $field_name:ident : $field_type:ty
),* $(,)?
}
) => {
impl $classic {
$(
$crate::paste!{
pub fn [< set_ $field_name >] (mut self, $field_name:$field_type)-> Self{
self.$field_name = $field_name;
self
}
}
)*
}
};
}
pub trait Message: Sync + Send + Any + Downcast {
fn externally_notifiable(&self) -> bool {
false
}
fn internally_notifiable(&self) -> bool {
false
}
fn metadata(&self) -> MessageMetadata;
fn outbox(&self) -> Box<dyn OutBox>;
fn message_clone(&self) -> Box<dyn Message>;
fn state(&self) -> String;
fn to_message(self) -> Box<dyn Message + 'static>;
}
impl_downcast!(Message);
impl Debug for dyn Message {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
write!(f, "{}", self.metadata().topic)
}
}
pub struct MessageMetadata {
pub aggregate_id: String,
pub topic: String,
}
pub trait MailSendable: Message + Serialize + Send + Sync + 'static {
fn template_name(&self) -> String;
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap()
}
}
#[macro_export]
macro_rules! MailSendable {
(
$( #[$attr:meta] )*
$pub:vis
struct $mail_sendable:ident {
$(
$(#[$field_attr:meta])*
$field_vis:vis $field_name:ident : $field_type:ty
),* $(,)?
}
) => {
$( #[$attr])*
impl $crate::domain::MailSendable for $mail_sendable {
fn template_name(&self) -> String {
stringify!($mail_sendable).into()
}
}
};
}
#[macro_export]
macro_rules! message {
($event:ty $(, $v1:ident $(, $v2:ident)? )? ) => {
impl $crate::domain::Message for $event {
fn metadata(&self) -> $crate::domain::MessageMetadata {
$crate::domain::MessageMetadata {
aggregate_id: self.id.to_string(),
topic: stringify!($event).into(),
}
}
fn message_clone(&self) -> Box<dyn $crate::domain::Message> {
Box::new(self.clone())
}
fn state(&self) -> String {
serde_json::to_string(&self).expect("Failed to serialize")
}
fn to_message(self)-> Box<dyn $crate::domain::Message+'static>{
Box::new(self)
}
fn outbox(&self) -> Box<dyn $crate::outbox::OutBox>
{
let metadata = self.metadata();
Box::new(Outbox::new(metadata.aggregate_id, metadata.topic, self.state()))
}
$(fn $v1(&self) -> bool {
true
}
$(fn $v2(&self) -> bool {
true
})?
)?
}
};
}
pub trait Command: 'static + Send + Any + Sync {}
#[test]
fn test_aggregate_macro() {
use crate::domain::Message;
use crate::Aggregate;
use serde::{Deserialize, Serialize};
#[derive(Debug,Default,Serialize,Deserialize,Aggregate!)]
pub struct SampleAggregate {
#[serde(skip_deserializing, skip_serializing)]
events: std::collections::VecDeque<std::boxed::Box<dyn Message>>,
pub(crate) id: String,
pub(crate) entity: Vec<Entity>,
}
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct Entity {
pub(crate) id: i64,
pub(crate) sub_entity: Vec<SubEntity>,
}
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct SubEntity {
pub(crate) id: i64,
}
let mut aggregate = SampleAggregate::default();
let mut entity = Entity::default();
entity.sub_entity.push(SubEntity { id: 1 });
aggregate.entity.push(entity);
let res = serde_json::to_string(&aggregate).unwrap();
println!("{:?}", res)
}