Skip to content

Commit 59b1c7e

Browse files
authored
feat(eventually): add query::Handler trait, serde::Convert implements Copy (#296)
- feat(eventually): add derive(Copy) to serde::Convert - feat(eventually): add query module - fix(eventually): aggregate::test::Scenario implements Default trait correctly
1 parent 0ac7441 commit 59b1c7e

3 files changed

Lines changed: 72 additions & 2 deletions

File tree

eventually/src/aggregate/test.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::event;
1111

1212
/// A test scenario that can be used to test an [Aggregate] and [Aggregate Root][Root]
1313
/// using a [given-then-when canvas](https://www.agilealliance.org/glossary/gwt/) approach.
14-
#[derive(Default, Clone, Copy)]
14+
#[derive(Clone, Copy)]
1515
pub struct Scenario<T>(PhantomData<T>)
1616
where
1717
T: Aggregate,
@@ -26,6 +26,12 @@ where
2626
T::Event: Debug + PartialEq,
2727
T::Error: Debug,
2828
{
29+
/// Creates a new [Scenario] instance.
30+
#[must_use]
31+
pub fn new() -> Self {
32+
Self(PhantomData)
33+
}
34+
2935
/// Specifies the precondition for the test [Scenario].
3036
///
3137
/// In other words, it can be used to specify all the Domain [Event][event::Envelope]s
@@ -57,6 +63,18 @@ where
5763
}
5864
}
5965

66+
impl<T> Default for Scenario<T>
67+
where
68+
T: Aggregate,
69+
T::Id: Clone,
70+
T::Event: Debug + PartialEq,
71+
T::Error: Debug,
72+
{
73+
fn default() -> Self {
74+
Self::new()
75+
}
76+
}
77+
6078
#[doc(hidden)]
6179
pub struct ScenarioGiven<T>
6280
where

eventually/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub mod aggregate;
99
pub mod command;
1010
pub mod event;
1111
pub mod message;
12-
// pub mod query;
12+
pub mod query;
1313
pub mod serde;
1414
#[cfg(feature = "tracing")]
1515
pub mod tracing;

eventually/src/query.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//! Module `query` contains types and helpful abstractions to model Domain Queries
2+
//! and implement Domain Query Handlers.
3+
4+
use async_trait::async_trait;
5+
use futures::Future;
6+
7+
use crate::message;
8+
9+
/// A [Message][message::Message] carrying the Domain Query itself as payload
10+
/// and other relevant information as metadata.
11+
pub type Envelope<T> = message::Envelope<T>;
12+
13+
/// An Handler describes an implementation that is able to handle specific [Queries][Envelope].
14+
///
15+
/// The Handler evaluates the Domain Query and produces a **result**, here described
16+
/// through the [Output][Handler::Output] associated type.
17+
#[async_trait]
18+
pub trait Handler<T>: Send + Sync
19+
where
20+
T: message::Message + Send + Sync,
21+
{
22+
/// The result type the Handler produces when evaluating a Query.
23+
type Output: Send + Sync;
24+
/// The error type returned by the Handler when Query evaluation fails.
25+
type Error: Send + Sync;
26+
27+
/// Evaluates the [Query][Envelope] provided and returns a result type,
28+
/// described by the [Output][Handler::Output] parameter.
29+
///
30+
/// # Errors
31+
///
32+
/// As the Handler can fail to evaluate the Query, an [Error][Handler::Error]
33+
/// can be returned instead.
34+
async fn handle(&self, query: Envelope<T>) -> Result<Self::Output, Self::Error>;
35+
}
36+
37+
#[async_trait]
38+
impl<T, R, Err, F, Fut> Handler<T> for F
39+
where
40+
T: message::Message + Send + Sync + 'static,
41+
R: Send + Sync,
42+
Err: Send + Sync,
43+
F: Send + Sync + Fn(Envelope<T>) -> Fut,
44+
Fut: Send + Sync + Future<Output = Result<R, Err>>,
45+
{
46+
type Output = R;
47+
type Error = Err;
48+
49+
async fn handle(&self, command: Envelope<T>) -> Result<R, Self::Error> {
50+
self(command).await
51+
}
52+
}

0 commit comments

Comments
 (0)