iT邦幫忙

2023 iThome 鐵人賽

DAY 17
0
Software Development

當rust 遇上 cqrs & es系列 第 17

D17 Command of Book in Surreal

  • 分享至 

  • xImage
  •  

先修一下昨天遇到,存入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。


上一篇
D16 Book ES in Surreal
下一篇
D18 Query of Book in Surreal
系列文
當rust 遇上 cqrs & es30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言