arts_n_crafts/core/
command_handler.rs1use crate::core::base_payload::BasePayload;
2use crate::core::command::Command;
3use async_trait::async_trait;
4use serde::Serialize;
5
6#[async_trait]
7pub trait CommandHandler<TPayload, TResult, TError>
8where
9 TPayload: BasePayload + AsRef<str>,
10 TResult: Serialize + Send + Sync + Clone,
11{
12 async fn execute(&self, a_command: Command<TPayload>) -> Result<TResult, TError>;
13}
14
15#[cfg(test)]
16mod command_handler_tests {
17 use super::*;
18 use crate::domain::with_identifier::WithIdentifier;
19 use rstest::rstest;
20 use serde::{Deserialize, Serialize};
21 use strum_macros::AsRefStr;
22 use uuid::Uuid;
23
24 #[allow(dead_code)]
25 #[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
26 struct User {
27 pub id: String,
28 pub name: String,
29 pub likes: u8,
30 }
31
32 #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, AsRefStr)]
33 enum UserCommandPayload {
34 CreateUser { name: String },
35 LikeUser,
36 }
37
38 struct CreateUserCommandHandler;
39
40 #[async_trait]
41 impl CommandHandler<UserCommandPayload, WithIdentifier, ()> for CreateUserCommandHandler {
42 async fn execute(
43 &self,
44 a_command: Command<UserCommandPayload>,
45 ) -> Result<WithIdentifier, ()> {
46 Ok(WithIdentifier {
47 id: a_command.aggregate_id,
48 })
49 }
50 }
51
52 #[rstest]
53 #[tokio::test]
54 async fn it_should_return_the_id_of_the_created_user() {
55 let an_aggregate_id = Uuid::now_v7().to_string();
56 let a_payload = UserCommandPayload::CreateUser {
57 name: "John Doe".to_string(),
58 };
59 let a_command = Command::create(an_aggregate_id.clone(), a_payload);
60 let a_command_handler = CreateUserCommandHandler {};
61 let a_result = a_command_handler
62 .execute(a_command)
63 .await
64 .expect("failed to execute command");
65 assert_eq!(a_result.id, an_aggregate_id);
66 }
67}