use hexser::{Directive, DirectiveHandler, QueryHandler};
fn main() -> hexser::HexResult<()> {
println!("=== CQRS Pattern Example ===\n");
let write_repo = InMemoryUserRepository::new();
let query_repo = InMemoryUserQueryRepository::new();
let create_handler = CreateUserHandler {
repository: write_repo,
};
let create_directive = CreateUserDirective {
email: String::from("alice@example.com"),
name: String::from("Alice"),
};
println!("Creating user via directive...");
create_handler.handle(create_directive)?;
println!("✓ User created");
let query_handler = FindUserByEmailHandler {
repository: &query_repo,
};
let find_query = FindUserByEmailQuery {
email: String::from("alice@example.com"),
};
println!("\nQuerying user...");
if let Some(user_view) = query_handler.handle(find_query)? {
println!("✓ Found user: {} ({})", user_view.name, user_view.email);
}
println!("\n✅ CQRS example completed!");
Ok(())
}
#[derive(Clone)]
struct User {
id: String,
email: String,
name: String,
}
impl hexser::domain::HexEntity for User {
type Id = String;
}
struct CreateUserDirective {
email: String,
name: String,
}
impl hexser::application::Directive for CreateUserDirective {
fn validate(&self) -> hexser::HexResult<()> {
if !self.email.contains('@') {
return Err(hexser::Hexserror::validation("Invalid email format").with_field("email"));
}
if self.name.is_empty() {
return Err(hexser::Hexserror::validation("Name cannot be empty").with_field("name"));
}
Ok(())
}
}
struct CreateUserHandler {
repository: InMemoryUserRepository,
}
impl hexser::application::DirectiveHandler<CreateUserDirective> for CreateUserHandler {
fn handle(&self, directive: CreateUserDirective) -> hexser::HexResult<()> {
directive.validate()?;
let user = User {
id: String::from("1"),
email: directive.email,
name: directive.name,
};
println!("Would save user: {} <{}>", user.name, user.email);
Ok(())
}
}
struct FindUserByEmailQuery {
email: String,
}
#[derive(Clone)]
struct UserView {
id: String,
email: String,
name: String,
}
struct FindUserByEmailHandler<'a> {
repository: &'a InMemoryUserQueryRepository,
}
impl<'a> hexser::application::QueryHandler<FindUserByEmailQuery, Option<UserView>>
for FindUserByEmailHandler<'a>
{
fn handle(&self, query: FindUserByEmailQuery) -> hexser::HexResult<Option<UserView>> {
self.repository.find_by_email(&query.email)
}
}
struct InMemoryUserRepository {
users: Vec<User>,
}
impl InMemoryUserRepository {
fn new() -> Self {
Self { users: Vec::new() }
}
}
impl hexser::adapters::Adapter for InMemoryUserRepository {}
impl hexser::ports::Repository<User> for InMemoryUserRepository {
fn save(&mut self, user: User) -> hexser::HexResult<()> {
self.users.push(user);
Ok(())
}
}
struct InMemoryUserQueryRepository {
users: Vec<UserView>,
}
impl InMemoryUserQueryRepository {
fn new() -> Self {
Self {
users: vec![UserView {
id: String::from("1"),
email: String::from("alice@example.com"),
name: String::from("Alice"),
}],
}
}
fn find_by_email(&self, email: &str) -> hexser::HexResult<Option<UserView>> {
Ok(self.users.iter().find(|u| u.email == email).cloned())
}
}