先修一下昨天遇到,存入DB的event sequence沒有照順序的問題,看了很久是先前在event repository裡沒下ORDER 排序的關係,修改一下:
#[async_trait]
impl PersistedEventRepository for SurrealEventRepository {
async fn get_events<A: Aggregate>(&self, aggregate_id: &str) -> Result<Vec<SerializedEvent>, PersistenceError> {
let result = self.db
.query("SELECT * FROM events WHERE aggregate_id = $id ORDER by sequence")
.bind(("id", aggregate_id))
.await?
.take(0)?;
Ok(result)
}
async fn get_last_events<A: Aggregate>(&self, aggregate_id: &str, last_sequence: usize) -> Result<Vec<SerializedEvent>, PersistenceError> {
println!("get_last_events: aggregate_id: {}, last_sequence: {}", aggregate_id, last_sequence);
let result = self.db
.query("SELECT * FROM events WHERE aggregate_id = $id AND sequence > $last_sequence ORDER by sequence")
.bind(("id", aggregate_id))
.bind(("last_sequence", last_sequence))
.await?
.take(0)?;
Ok(result)
}
}
接續昨天的book案例,在兩本庫存都借出的情況下,再下第三位讀書借閱的指令:
let reader3_borrow = book_cqrs.execute("test-book-1", BookCommand::LendBook (
LendingRecord{
reader_id: "test-reader-3".to_string(),
lent_date: Utc::now(),
due_date: Utc::now().add(chrono::Duration::days(7)),
}
)).await;
println!("=== reader3_borrow ===\n{:#?}", reader3_borrow);
出現錯誤,並且未儲存相關event:
=== reader3_borrow ===
Err(
UserError(
BookError(
"書籍已無庫存",
),
),
)
最後加一個還書事件,看整個有沒有串接完整:
let _ = book_cqrs.execute("test-book-1", BookCommand::ReturnBook(
LentRecord {
reader_id: "test-reader-1".to_string(),
lent_date: Utc::now(),
due_date: Utc::now().add(chrono::Duration::days(7)),
returned_date: Some(Utc::now().add(chrono::Duration::days(2))),
})).await;
最終 aggregate長相,正確把借閱紀錄轉為歷史紀錄:
======== Book ========
Book {
id: "test-book-1",
title: "Rust 語言開發實戰",
isbn10: "1234567890",
description: "使用rust,併同cqrs框架,實現event sourcing",
copies: 2,
lending_records: [
LendingRecord {
reader_id: "test-reader-2",
lent_date: 2023-10-02T12:57:14.125393166Z,
due_date: 2023-10-09T12:57:14.125394486Z,
},
],
lent_history: [
LentRecord {
reader_id: "test-reader-1",
lent_date: 2023-10-02T12:57:14.129073955Z,
due_date: 2023-10-09T12:57:14.129075141Z,
returned_date: Some(
2023-10-04T12:57:14.129077210Z,
),
},
],
}
看一下Event Sorucing的順序是否都正確:
======== Events ========
[
SerializedEvent {
aggregate_id: "test-book-1",
sequence: 1,
aggregate_type: "Book",
event_type: "BookEvent",
event_version: "0.1.0",
payload: Object {
"BookCreated": Object {
"description": String("使用rust,併同cqrs框架,實現event sourcing"),
"id": String("test-book-1"),
"isbn10": String("1234567890"),
"title": String("Rust 語言開發實戰"),
},
},
metadata: Object {},
},
SerializedEvent {
aggregate_id: "test-book-1",
sequence: 2,
aggregate_type: "Book",
event_type: "BookEvent",
event_version: "0.1.0",
payload: Object {
"BookIngested": Object {
"copies": Number(2),
"id": String("test-book-1"),
},
},
metadata: Object {},
},
SerializedEvent {
aggregate_id: "test-book-1",
sequence: 3,
aggregate_type: "Book",
event_type: "BookEvent",
event_version: "0.1.0",
payload: Object {
"BookLent": Object {
"due_date": String("2023-10-09T13:01:03.172972038Z"),
"lent_date": String("2023-10-02T13:01:03.172969258Z"),
"reader_id": String("test-reader-1"),
},
},
metadata: Object {},
},
SerializedEvent {
aggregate_id: "test-book-1",
sequence: 4,
aggregate_type: "Book",
event_type: "BookEvent",
event_version: "0.1.0",
payload: Object {
"BookLent": Object {
"due_date": String("2023-10-09T13:01:03.174666023Z"),
"lent_date": String("2023-10-02T13:01:03.174664835Z"),
"reader_id": String("test-reader-2"),
},
},
metadata: Object {},
},
SerializedEvent {
aggregate_id: "test-book-1",
sequence: 5,
aggregate_type: "Book",
event_type: "BookEvent",
event_version: "0.1.0",
payload: Object {
"BookReturned": Object {
"due_date": String("2023-10-09T13:01:03.177930558Z"),
"lent_date": String("2023-10-02T13:01:03.177929591Z"),
"reader_id": String("test-reader-1"),
"returned_date": String("2023-10-04T13:01:03.177932178Z"),
},
},
metadata: Object {},
},
]
這次序號都對了,操作也都對,我們算是完成了Command的部分,接下來還有Query的部分,明天再來試試加ViewModel。