Attribute Macro ruva_macro::aggregate

source ·
#[aggregate]
Expand description

Define Aggregate root

§Example

#[aggregate]
pub struct TestAggregate {
    pub(crate) age: i64,
}

fn test_aggregate() {
let aggregate = TestAggregate::default().set_age(1);
assert_eq!(aggregate.version, 0);
assert!(!aggregate.is_existing);
assert_eq!(aggregate.events.len(), 0);
assert_eq!(aggregate.age, 1)
}
#[aggregate]
pub struct TestAggregate {
    pub(crate) age: i64,
    pub(crate) name: String,
}

Likewise, not specifying identifier will also error out

#[aggregate]
pub struct TestAggregate {
    pub(crate) age: i64,
    pub(crate) name: String,
}

{your aggregate name}Adapter will be generated automatically so you can use it to adapt it to database rust,no_run

#[aggregate] pub struct AggregateStruct { #[adapter_ignore] id: i32, #[serde(skip_serializing)] name: String, some_other_field: i32, } let aggregate = AggregateStruct::default(); let serialized = serde_json::to_string(&aggregate).unwrap(); assert_eq!(serialized, “{"id":0,"some_other_field":0,"version":0}”);

let adapter = AggregateStructAdapter::default(); let serialized = serde_json::to_string(&adapter).unwrap(); assert_eq!(serialized, “{"some_other_field":0}”);


# Automatic derive macro
`#[derive(Default, Debug, Serialize, Deserialize)]` will be automatically added to the struct.
```rust,no_run
#[aggregate]
pub struct AggregateStruct {
   #[adapter_ignore]
  id: i32,
 #[serde(skip_serializing)]
name: String,
some_other_field: i32,
}

Even if you add Default, Debug, Serialize, Deserialize there won’t be any conflict.

Conversion is automatically done as follows: rust,no_run let aggregate = AggregateStruct { name: “migo”.into(), some_other_field: 2, id: 1, ..Default::default() }; let converted_adapter = AggregateStructAdapter::from(aggregate); assert_eq!(converted_adapter.name, “migo”); assert_eq!(converted_adapter.some_other_field, 2); let converted_struct = AggregateStruct::from(converted_adapter); assert_eq!(converted_struct.name, “migo”); assert_eq!(converted_struct.some_other_field, 2);


Generic can also be used for aggregate:
```rust,no_run
#[derive(Default, Debug, Serialize, Deserialize)]
struct Unset;

#[aggregate]
#[derive(Default, Debug, Serialize, Clone)]
struct MyStruct<T = Unset>
where
    T: Send + Sync + Default + 'static,
{
    name: String,
    age: i32,

    #[adapter_ignore]
    sub_type: T,
}

impl MyStruct<String> {
    fn do_something_with_string(&self) -> String {
        self.sub_type.clone()
    }
}

impl MyStruct<i32> {
    fn do_something_with_i32(&self) -> i32 {
        self.sub_type
    }
}

let adapter = MyStructAdapter {
    name: "hello".to_string(),
    age: 10,
};

let _my_unset_struct = Into::<MyStruct>::into(adapter.clone()); // default type is set which has no method attached.

let my_string_struct = Into::<MyStruct<String>>::into(adapter.clone());
let my_int32_struct = Into::<MyStruct<i32>>::into(adapter.clone());

assert_eq!(my_string_struct.do_something_with_string(), String::default());
assert_eq!(my_int32_struct.do_something_with_i32(), i32::default());