iT邦幫忙

2023 iThome 鐵人賽

DAY 7
0
Software Development

當rust 遇上 cqrs & es系列 第 7

D7 ~~測試~~ 用 es 存放 book 事件

  • 分享至 

  • xImage
  •  

今天接續使用es,來試試多次book事件的commit是不是都可以正確的作用。

第一個指令:建立書籍檔案

let store = mem_store::MemStore::<Book>::default();

let book_id = String::from("test-book-id");
let mut aggregate = store
    .load_aggregate(&book_id)
    .await
    .unwrap();

let command = BookCommand::CreateBook {
    id: book_id.to_string(),
    title: "test-book-title".to_string(),
    isbn10: "1234567890".to_string(),
    description: "test-book-description".to_string(),
};
let events = aggregate.aggregate.handle(command).await.unwrap();
store.commit(events, aggregate, Default::default()).await.unwrap();
println!("\n=== create 後的 es ===\n{:#?}", store);

store內容

=== create 後的 es ===
MemStore {
    events: RwLock {
        data: {
            "test-book-id": [
                EventEnvelope {
                    aggregate_id: "test-book-id",
                    sequence: 1,
                    payload: BookCreated {
                        id: "test-book-id",
                        title: "test-book-title",
                        isbn10: "1234567890",
                        description: "test-book-description",
                    },
                    metadata: {},
                },
            ],
        },
        poisoned: false,
        ..
    },
}

book aggregate:

=== create 後的 aggregate ===
MemStoreAggregateContext {
    aggregate_id: "test-book-id",
    aggregate: Book {
        id: "test-book-id",
        title: "test-book-title",
        isbn10: "1234567890",
        description: "test-book-description",
        copies: 0,
        lending_records: [],
        lent_history: [],
    },
    current_sequence: 1,
}

書籍入庫指令:

let command = BookCommand::IngestBook {
    id: "test-book-id".to_string(),
    copies: 3,
};
let events = aggregate.aggregate.handle(command).await.unwrap();
store.commit(events, aggregate, Default::default()).await.unwrap();
println!("\n=== ingest 後的 es ===\n{:#?}", store);

入庫後的 es:

data: {
    "test-book-id": [
        EventEnvelope {
            aggregate_id: "test-book-id",
            sequence: 1,
            payload: BookCreated {
                id: "test-book-id",
                title: "test-book-title",
                isbn10: "1234567890",
                description: "test-book-description",
            },
            metadata: {},
        },
        EventEnvelope {
            aggregate_id: "test-book-id",
            sequence: 2,
            payload: BookIngested {
                id: "test-book-id",
                copies: 3,
            },
            metadata: {},
        },
    ],
},

入庫後的 aggregate

MemStoreAggregateContext {
    aggregate_id: "test-book-id",
    aggregate: Book {
        id: "test-book-id",
        title: "test-book-title",
        isbn10: "1234567890",
        description: "test-book-description",
        copies: 3,
        lending_records: [],
        lent_history: [],
    },
    current_sequence: 2,
}

借閱指令

let command = BookCommand::LendBook(
    LendingRecord {
        reader_id: "test-reader-id".to_string(),
        lent_date: Utc::now(),
        due_date: Utc::now().add(chrono::Duration::days(7)),
    });
let events = aggregate.aggregate.handle(command).await.unwrap();
store.commit(events, aggregate, Default::default()).await.unwrap();
println!("\n=== lend 後的 es ===\n{:#?}", store);

借閱後 es

data: {
    "test-book-id": [
        EventEnvelope {
            aggregate_id: "test-book-id",
            sequence: 1,
            payload: BookCreated {
                id: "test-book-id",
                title: "test-book-title",
                isbn10: "1234567890",
                description: "test-book-description",
            },
        },
        EventEnvelope {
            aggregate_id: "test-book-id",
            sequence: 2,
            payload: BookIngested {
                id: "test-book-id",
                copies: 3,
            },
        },
        EventEnvelope {
            aggregate_id: "test-book-id",
            sequence: 3,
            payload: BookLent(
                LendingRecord {
                    reader_id: "test-reader-id",
                    lent_date: 2023-09-22T13:13:26.980063588Z,
                    due_date: 2023-09-29T13:13:26.980065730Z,
                },
            ),
        },
    ],
},

借閱後aggregate

MemStoreAggregateContext {
    aggregate_id: "test-book-id",
    aggregate: Book {
        id: "test-book-id",
        title: "test-book-title",
        isbn10: "1234567890",
        description: "test-book-description",
        copies: 3,
        lending_records: [
            LendingRecord {
                reader_id: "test-reader-id",
                lent_date: 2023-09-22T13:13:26.980063588Z,
                due_date: 2023-09-29T13:13:26.980065730Z,
            },
        ],
        lent_history: [],
    },
    current_sequence: 3,
}

歸還指令

let command = BookCommand::ReturnBook(
    LentRecord {
        reader_id: "test-reader-id".to_string(),
        lent_date: Utc::now(),
        due_date: Utc::now().add(chrono::Duration::days(7)),
        returned_date: Some(Utc::now()),
    });

let events = aggregate.aggregate.handle(command).await.unwrap();
store.commit(events, aggregate, Default::default()).await.unwrap();
println!("\n=== return 後的 es ===\n{:#?}", store);

歸還後 store

data: {
    "test-book-id": [
        EventEnvelope {
            aggregate_id: "test-book-id",
            sequence: 1,
            payload: BookCreated {
                id: "test-book-id",
                title: "test-book-title",
                isbn10: "1234567890",
                description: "test-book-description",
            },
            metadata: {},
        },
        EventEnvelope {
            aggregate_id: "test-book-id",
            sequence: 2,
            payload: BookIngested {
                id: "test-book-id",
                copies: 3,
            },
            metadata: {},
        },
        EventEnvelope {
            aggregate_id: "test-book-id",
            sequence: 3,
            payload: BookLent(
                LendingRecord {
                    reader_id: "test-reader-id",
                    lent_date: 2023-09-22T13:30:51.377688412Z,
                    due_date: 2023-09-29T13:30:51.377691261Z,
                },
            ),
            metadata: {},
        },
        EventEnvelope {
            aggregate_id: "test-book-id",
            sequence: 4,
            payload: BookReturned(
                LentRecord {
                    reader_id: "test-reader-id",
                    lent_date: 2023-09-22T13:30:51.377878940Z,
                    due_date: 2023-09-29T13:30:51.377879745Z,
                    returned_date: Some(
                        2023-09-22T13:30:51.377880700Z,
                    ),
                },
            ),
            metadata: {},
        },
    ],
},

歸還後 aggregate

MemStoreAggregateContext {
    aggregate_id: "test-book-id",
    aggregate: Book {
        id: "test-book-id",
        title: "test-book-title",
        isbn10: "1234567890",
        description: "test-book-description",
        copies: 3,
        lending_records: [],
        lent_history: [
            LentRecord {
                reader_id: "test-reader-id",
                lent_date: 2023-09-22T13:30:51.377878940Z,
                due_date: 2023-09-29T13:30:51.377879745Z,
                returned_date: Some(
                    2023-09-22T13:30:51.377880700Z,
                ),
            },
        ],
    },
    current_sequence: 4,
}

可以看到存放event store裡用 event envelop存放事件本身資料,以及事件的meta資訊,而從store讀取aggregate時,會依每個事件套用,並顯示aggregate目前版次current_sequence


上一篇
D6 測試event apply & rollback
下一篇
D8 實現基本資料結構(3)
系列文
當rust 遇上 cqrs & es30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言