armature_cqrs/lib.rs
1//! CQRS (Command Query Responsibility Segregation) for Armature
2//!
3//! This crate provides CQRS pattern implementation with command/query separation.
4//!
5//! ## Features
6//!
7//! - **Command Bus** - Execute commands (writes)
8//! - **Query Bus** - Execute queries (reads)
9//! - **Projections** - Build read models from events
10//! - **Type-safe** - Strong typing with compile-time safety
11//! - **Async** - Full async/await support
12//!
13//! ## Quick Start
14//!
15//! ```rust,ignore
16//! use armature_cqrs::*;
17//! use async_trait::async_trait;
18//!
19//! // Define a command
20//! struct CreateUserCommand {
21//! email: String,
22//! }
23//!
24//! impl Command for CreateUserCommand {
25//! type Result = String; // User ID
26//! }
27//!
28//! // Define command handler
29//! struct CreateUserHandler;
30//!
31//! #[async_trait]
32//! impl CommandHandler<CreateUserCommand> for CreateUserHandler {
33//! async fn handle(&self, command: CreateUserCommand) -> Result<String, CommandError> {
34//! // Business logic here
35//! Ok(format!("user-{}", uuid::Uuid::new_v4()))
36//! }
37//! }
38//!
39//! // Define a query
40//! struct GetUserQuery {
41//! user_id: String,
42//! }
43//!
44//! impl Query for GetUserQuery {
45//! type Result = User;
46//! }
47//!
48//! // Define query handler
49//! struct GetUserHandler;
50//!
51//! #[async_trait]
52//! impl QueryHandler<GetUserQuery> for GetUserHandler {
53//! async fn handle(&self, query: GetUserQuery) -> Result<User, QueryError> {
54//! // Fetch from read model
55//! Ok(User {
56//! id: query.user_id,
57//! email: "alice@example.com".to_string(),
58//! })
59//! }
60//! }
61//!
62//! // Use the buses
63//! #[tokio::main]
64//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
65//! // Create buses
66//! let command_bus = CommandBus::new();
67//! let query_bus = QueryBus::new();
68//!
69//! // Register handlers
70//! command_bus.register::<CreateUserCommand, _>(CreateUserHandler);
71//! query_bus.register::<GetUserQuery, _>(GetUserHandler);
72//!
73//! // Execute command
74//! let user_id = command_bus.execute(CreateUserCommand {
75//! email: "alice@example.com".to_string(),
76//! }).await?;
77//!
78//! // Execute query
79//! let user = query_bus.execute(GetUserQuery { user_id }).await?;
80//! println!("User: {:?}", user);
81//!
82//! Ok(())
83//! }
84//! ```
85//!
86//! ## Projections
87//!
88//! ```rust,ignore
89//! use armature_events::Event;
90//! use async_trait::async_trait;
91//!
92//! struct UserListProjection {
93//! // Read model storage
94//! }
95//!
96//! #[async_trait]
97//! impl Projection for UserListProjection {
98//! async fn project(&self, event: &dyn Event) -> Result<(), ProjectionError> {
99//! match event.event_name() {
100//! "user_created" => {
101//! // Update read model
102//! }
103//! "user_deleted" => {
104//! // Update read model
105//! }
106//! _ => {}
107//! }
108//! Ok(())
109//! }
110//! }
111//! ```
112//!
113//! ## Integration with Event Sourcing
114//!
115//! ```rust,ignore
116//! use armature_eventsourcing::*;
117//! use armature_events::EventBus;
118//!
119//! // Command handler uses aggregate repository
120//! #[async_trait]
121//! impl CommandHandler<CreateUserCommand> for CreateUserHandler {
122//! async fn handle(&self, command: CreateUserCommand) -> Result<String, CommandError> {
123//! let mut user = UserAggregate::new_instance(uuid::Uuid::new_v4().to_string());
124//!
125//! // Add domain event
126//! user.create(command.email)?;
127//!
128//! // Save aggregate (persists events)
129//! self.repository.save(&mut user).await?;
130//!
131//! // Publish events to event bus for projections
132//! for event in user.uncommitted_events() {
133//! self.event_bus.publish(event.clone()).await?;
134//! }
135//!
136//! Ok(user.aggregate_id().to_string())
137//! }
138//! }
139//! ```
140
141pub mod command;
142pub mod projection;
143pub mod query;
144
145pub use command::{Command, CommandBus, CommandError, CommandHandler};
146pub use projection::{Projection, ProjectionError, ProjectionEventHandler, ProjectionManager};
147pub use query::{Query, QueryBus, QueryError, QueryHandler};
148
149#[cfg(test)]
150mod tests {
151 #[test]
152 fn test_module_exports() {
153 // Ensure module compiles
154 }
155}