2个不稳定版本
0.7.0 | 2023年10月26日 |
---|---|
0.6.0 | 2023年10月25日 |
#9 in #ddd
30KB
355 行
MiniCQRS/ES - 简化Rust中的CQRS
简单、最小化、有偏见的微框架,用于在Rust中实现CQRS/ES。已经有大量的有偏见的库可以这样做,但实际上,我并不赞同它们的观点,并且看到了提高我的Rust知识和实践的机会。
这个轻量级库提供了必要的组件抽象和最小的粘合剂,以简化CQRS架构的实现,使得管理应用程序的数据流变得轻而易举。
特性
-
它是一个微框架,所以非常“微”,你主要只能得到“框架”,工作在你自己。
- 你编写自己的实现;
- 你选择库、存储引擎和其他外部工具;
- 你可以选择你需要的部分(聚合、命令、事件、查询等)。
-
几乎所有内容都使用Tokio运行时异步。
架构
-
聚合:将你的领域实体定义为聚合,处理状态变化,并使用简单的特质应用事件。
-
命令:通过最小的工作量实现自定义命令,以更改聚合的状态。
-
事件存储:高效存储和检索事件,以实现无缝的事件溯源。
-
快照存储:可选使用快照以加速聚合状态的恢复。
-
事件处理:轻松管理和消费聚合生成的事件,以执行操作和实时更新。
-
查询:实现自定义查询,从你的只读模型中检索数据。
状态
这个库对于实验一些实际用例来说是有点可用的,但我不建议在生产环境中使用它,API还不能被认为是稳定的,因此它仍在积极开发中,可能会引入意外的破坏性更改。
安装
在你的项目目录中运行以下Cargo命令
cargo add mini_cqrs_es
或者将以下行添加到你的Cargo.toml
[dependencies]
mini_cqrs_es = "0.7.0"
用法
一旦将库添加到项目的依赖项中,你可以通过导入库开始使用它
use mini_cqrs_es::*;
// or importing single components:
// use mini_cqrs_es::{Aggregate, etc...};
由于MiniCQRS/ES几乎完全由特质组成,因此它非常灵活,但当然也需要一些样板代码。因此,你可以查看示例目录以获取更多详细信息。
在实现了库中的各种特质之后,你最终可以构建你的CQRS架构。
以下是一个灵感来自游戏示例的片段
// An implementation of the EvenStore trait
let event_store = InMemoryEventStore::new();
// An implementation of the SnapshotStore trait
let snapshot_store = InMemorySnapshotStore::<GameAggregate>::new();
// An AggregateManager that supports the SnapshotStore is already implemented by MiniCQRS/ES
let aggregate_manager = SnapshotAggregateManager::new(snapshot_store);
// An implementation of the Repository trait to handle read models
let repo = Arc::new(Mutex::new(InMemoryRepository::new()));
// A set of event consumers
let event_consumers = GameEventConsumersGroup {
main: GameMainConsumer::new(repo.clone()),
print: PrintEventConsumer {},
};
// The Cqrs type is provided by MiniCQRS/ES and wraps the previous components
let mut cqrs = Cqrs::new(aggregate_manager, event_store, event_consumers);
// Build a Command along with some arguments
let player_1 = Player { id: "player_1".to_string(), points: 0, };
let player_2 = Player { id: "player_2".to_string(), points: 0, };
let aggregate_id = Uuid::new_v4();
// every Command implementation knows the type of the target Aggregate
let cmd = CmdStartGame { player_1: player_1, player_2: player_2, goal: 3, };
// Execute the Command
cqrs.execute(aggregate_id, &cmd).await?;
// Query the read model
// every Query implementation can have its own shape, initialization logic and read model type as output
let query = GetGameQuery::new(aggregate_id, repo.clone());
let result = cqrs.query(&query).await?.unwrap();
请注意,除了 Cqrs
和 SnapshotAggregateManager
类型外,其余都是某些特质的实现。特别是,InMemory*
类型已被实现以模拟 存储。在实际使用场景中,您可能需要围绕某些数据库客户端或其他存储解决方案构建包装器。
文档
代码已进行文档编写,并在需要时进行改进。要查看完整的实现,您可以检查 示例。
测试
考虑到这个库由特质组成,唯一检查它们是否工作的方式是运行示例。
贡献
如果您发现任何错误或有任何建议,请 提交一个问题。
许可证
此项目是开源的,可在 MIT 许可证 下使用。
依赖关系
~5–12MB
~126K SLoC