干净地验证 RailsEventStore 中的事件模式
Cleanly validating event schemas in RailsEventStore
我正在使用 Rails 和 RailsEventStore 构建一个 CQRS 和事件源应用程序。在 RailsEventStore 中,您似乎应该继承代表来自 RailsEventStore::Event.
的事件的 classes
class UserRegistered < RailsEventStore::Event
…
end
这个基础 class 公开了一个 event_id、一个数据散列和一个可选的元数据散列。据我所知,这看起来更像是 Greg Young 曾经称之为事件信封的东西,我的域模型应该只关心存储在信封数据哈希中的实际事件。
现在我想对我的事件强制执行一个模式。但似乎 RailsEventStore 希望我为由我的域模型区分的每个事件类型建模 RailsEventStore::Event(信封)的子class。
在信封的子 class 中验证数据散列的内容感觉很老套和肮脏。我总是需要覆盖初始化方法并传递我真正不关心的东西。
class UserRegistered < RailsEventStore::Event
def initialize(event_id: SecureRandom.uuid, metadata: nil, data: {})
ensure_valid!(data)
super(event_id: event_id, metadata: metadata, data: data)
end
def ensure_valid!(data)
raise ArgumentError unless data[:user_id]
end
end
通过 event.data[:my_attribute]
访问所有事件属性也感觉不太好。为每个信封子添加很多委托方法class 似乎也是一种浪费。
我更愿意建模一个普通的 Ruby 对象或使用 Dry::Struct 之类的东西来对我的事件的内容属性强制执行模式。
class UserRegistered < Dry::Struct
attribute :user_id, Dry::Types::String
end
我是不是漏掉了什么?如何以干净的方式验证我的事件?
Dry::Struct 模式的示例可以在示例应用存储库中找到:
https://github.com/RailsEventStore/cqrs-es-sample-with-res/blob/e4983433bc5d71252da58a23da9374f17e1d5cb3/ordering/lib/ordering/order_submitted.rb +
https://github.com/RailsEventStore/cqrs-es-sample-with-res/blob/e4983433bc5d71252da58a23da9374f17e1d5cb3/ordering/lib/ordering/order_submitted.rb
虽然从 RailsEventStore::Event
继承是最简单的,但这不是必需的。 Protobuf 集成就是一个很好的例子:
https://railseventstore.org/docs/protobuf/#defining-events。它更像一个事件信封。
传递给 RES 的事件需要至少响应 event_id
、data
、metadata
和 type
:
https://github.com/RailsEventStore/rails_event_store/blob/cfc91c9cb367e514ba1c6de1a711a7610780b520/ruby_event_store/lib/ruby_event_store/mappers/transformation/domain_event.rb#L9-L12。您还可以在那里看到它是如何从商店加载时实例化的。
当您提供 own mapper 或仅替换负责该转换的 RubyEventStore::Mappers::Transformation::DomainEvent
时,可以更改此行为。
我正在使用 Rails 和 RailsEventStore 构建一个 CQRS 和事件源应用程序。在 RailsEventStore 中,您似乎应该继承代表来自 RailsEventStore::Event.
的事件的 classesclass UserRegistered < RailsEventStore::Event
…
end
这个基础 class 公开了一个 event_id、一个数据散列和一个可选的元数据散列。据我所知,这看起来更像是 Greg Young 曾经称之为事件信封的东西,我的域模型应该只关心存储在信封数据哈希中的实际事件。
现在我想对我的事件强制执行一个模式。但似乎 RailsEventStore 希望我为由我的域模型区分的每个事件类型建模 RailsEventStore::Event(信封)的子class。
在信封的子 class 中验证数据散列的内容感觉很老套和肮脏。我总是需要覆盖初始化方法并传递我真正不关心的东西。
class UserRegistered < RailsEventStore::Event
def initialize(event_id: SecureRandom.uuid, metadata: nil, data: {})
ensure_valid!(data)
super(event_id: event_id, metadata: metadata, data: data)
end
def ensure_valid!(data)
raise ArgumentError unless data[:user_id]
end
end
通过 event.data[:my_attribute]
访问所有事件属性也感觉不太好。为每个信封子添加很多委托方法class 似乎也是一种浪费。
我更愿意建模一个普通的 Ruby 对象或使用 Dry::Struct 之类的东西来对我的事件的内容属性强制执行模式。
class UserRegistered < Dry::Struct
attribute :user_id, Dry::Types::String
end
我是不是漏掉了什么?如何以干净的方式验证我的事件?
Dry::Struct 模式的示例可以在示例应用存储库中找到:
https://github.com/RailsEventStore/cqrs-es-sample-with-res/blob/e4983433bc5d71252da58a23da9374f17e1d5cb3/ordering/lib/ordering/order_submitted.rb + https://github.com/RailsEventStore/cqrs-es-sample-with-res/blob/e4983433bc5d71252da58a23da9374f17e1d5cb3/ordering/lib/ordering/order_submitted.rb
虽然从 RailsEventStore::Event
继承是最简单的,但这不是必需的。 Protobuf 集成就是一个很好的例子:
https://railseventstore.org/docs/protobuf/#defining-events。它更像一个事件信封。
传递给 RES 的事件需要至少响应 event_id
、data
、metadata
和 type
:
https://github.com/RailsEventStore/rails_event_store/blob/cfc91c9cb367e514ba1c6de1a711a7610780b520/ruby_event_store/lib/ruby_event_store/mappers/transformation/domain_event.rb#L9-L12。您还可以在那里看到它是如何从商店加载时实例化的。
当您提供 own mapper 或仅替换负责该转换的 RubyEventStore::Mappers::Transformation::DomainEvent
时,可以更改此行为。