#cqrs #event-sourcing #ddd #cqrs-es

mini_cqrs_es

最小化、有偏见的微框架,用于在Rust中实现CQRS/ES

2个不稳定版本

0.7.0 2023年10月26日
0.6.0 2023年10月25日

#9 in #ddd

MIT 协议

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();

请注意,除了 CqrsSnapshotAggregateManager 类型外,其余都是某些特质的实现。特别是,InMemory* 类型已被实现以模拟 存储。在实际使用场景中,您可能需要围绕某些数据库客户端或其他存储解决方案构建包装器。

文档

代码已进行文档编写,并在需要时进行改进。要查看完整的实现,您可以检查 示例

测试

考虑到这个库由特质组成,唯一检查它们是否工作的方式是运行示例。

贡献

如果您发现任何错误或有任何建议,请 提交一个问题

许可证

此项目是开源的,可在 MIT 许可证 下使用。

依赖关系

~5–12MB
~126K SLoC