先前把reader和book拆為2個aggregate,但一個交易會同時影響2個aggregate。這邊試著用另一個function處理(domain service?):
準備command:
pub enum ReaderBookCommand {
BorrowBook {
book_id: String,
reader_id: String,
borrow_date: DateTime<Utc>,
due_date: DateTime<Utc>,
},
ReturnBook {
book_id: String,
reader_id: String,
return_date: DateTime<Utc>,
},
}
handler,同時輸入兩個store:
pub async fn handle_reader_book_command(
reader_store: &impl EventStore<Reader>,
book_store: &impl EventStore<Book>,
reader_service: &ReaderService,
book_service: &BookService,
command: ReaderBookCommand,
) -> Result<(), ReaderBookError> {
match command {
ReaderBookCommand::BorrowBook { book_id, reader_id, borrow_date, due_date } => {
todo!()
}
ReaderBookCommand::ReturnBook { book_id, reader_id, return_date } => {
todo!()
}
}
Ok(())
借書command處理,先取書再給reader,兩個aggregate皆handle成功才會commit:
ReaderBookCommand::BorrowBook {
book_id, reader_id, borrow_date, due_date
} => {
let book_context = book_store.load_aggregate(&book_id).await?;
let book = book_context.aggregate();
let reader_context = reader_store.load_aggregate(&reader_id).await?;
let reader = reader_context.aggregate();
let book_events = book.handle(
BookCommand::LendBook(LendingRecord {
reader_id,
lent_date: borrow_date,
due_date,
}),
book_service).await?; // 檢核錯誤會回傳error
let reader_events = reader.handle(
ReaderCommand::BorrowBook {
book_id,
due_date,
borrowed_date: borrow_date,
},
reader_service).await?; // 檢核錯誤會回傳 error
book_store.commit(book_events, book_context, Default::default()).await?;
reader_store.commit(reader_events, reader_context, Default::default()).await?;
}
還書command處理:
ReaderBookCommand::ReturnBook { book_id, reader_id, return_date } => {
let book_context = book_store.load_aggregate(&book_id).await?;
let book = book_context.aggregate();
let reader_context = reader_store.load_aggregate(&reader_id).await?;
let reader = reader_context.aggregate();
let reader_events = reader.handle(
ReaderCommand::ReturnBook {
book_id,
return_date: return_date.clone(),
},
reader_service).await?;
let lent_record = book.lending_records.iter()
.find(|lent_record| lent_record.reader_id == reader_id).unwrap();
let book_events = book.handle(
BookCommand::ReturnBook(LentRecord {
reader_id: lent_record.reader_id.clone(),
lent_date: lent_record.lent_date,
due_date: lent_record.due_date,
returned_date: Some(return_date),
}),
book_service).await?;
reader_store.commit(reader_events, reader_context, Default::default()).await?;
book_store.commit(book_events, book_context, Default::default()).await?;
}