借助reduce函数,它可以做魔术:能在事件溯源EventSourcing中聚合流(事件流)构建当前的聚合状态。
首先定义事件类型和聚合数据。我使用电影票预订作为示例用例:
interface SeatReserved { |
订票时可以保留座位并进行更改。重要的是两个事件都具有带有硬编码事件类型名称的eventType属性。我们稍后再使用。
在事件溯源中,事件在逻辑上被分组为流。流是实体的表达。在实体上进行的每个业务操作都应作为持久事件结束。
实体状态是通过读取所有事件并按出现顺序逐一应用它们来检索的。我们正在将事件集转换为单个实体。这是reduce函数的主要作用。它在每个数组元素上执行reducer函数(可以提供),从而产生单个输出值。
有3件事情要注意:
- TypeScript中的reduce是一种通用方法。它允许提供结果类型作为参数。它不必与数组元素的类型相同。
- 您还可以使用可选参数来提供默认值以进行累加。
- 使用Partial <Type>作为通用的reduce参数。它构造一个将类型的所有属性设置为可选optional的类型。它将返回一个代表指定类型的所有子集的类型。这是非常重要的,因为TypeScript会强制您定义所有必需的属性。我们将聚合状态的不同状态合并为一个最终状态。只有第一个事件(SeatReserved)需要提供所有必填属性字段。其他事件将仅进行属性字段的部分更新(SeatChanged仅更改seatId)。
让我们看看它在实践中是如何工作的:
var events: ReservationEvents[] = [ |
归功于强类型(ReservationEvents),我们可以确定事件数组的内容。我们知道这两个事件都将具有eventType属性。有了这一点,我们可以使用switch并为每个事件定义一个自定义状态变化逻辑。
剩下的唯一事情就是确保我们的最终结果具有正确的状态,并可用作Reservation 类型。请记住,reduce的结果将是Partial所有必填字段均设为可选。我们可以使用类型保护来验证是否部分也是有效的。
const reservationIsValid = |
另外,让我为您展示EventStoreDB NodeJS gRPC客户端的完整工作示例:
import { EventStoreDBClient, JSONEventType, jsonEvent } from "@eventstore/db-client"; |