Linking to stream
An event, once published, can live in more than one stream. Such quality comes useful in order to persistently group events of particular kinds.
Let's assume you've got an Order
aggregate of 68a5214d-3194-4cfd-8997-5033bcb7e68a
id and an OrderPlaced
event. By convention OrderPlaced
event will be published in Order$68a5214d-3194-4cfd-8997-5033bcb7e68a
stream:
OrderPlaced = Class.new(RailsEventStore::Event)
class Order
def initialize(id)
@id = id
end
def place
event_store.publish(OrderPlaced.new(data: { id: @id }), stream_name: stream_name)
end
private
def event_store
Rails.configuration.event_store
end
def stream_name
"Order$#{@id}"
end
end
order = Order.new("68a5214d-3194-4cfd-8997-5033bcb7e68a")
order.place
Now imagine you'd like to see in one place all facts about placed orders in Jan 2018. This can be done processing all events collected so far in the event store. Each time you want such report, it runs from beginning — filtering irrelevant events out.
For repeated use it would be much better process events only once and store them in some sort of a collection — the stream:
order_placed =
RailsEventStore::Projection
.from_all_streams
.init(-> { })
.when(
[OrderPlaced],
->(state, event) do
time = event.metadata[:timestamp]
if time.year == 2018 && time.month == 1
event_store.link(event.event_id, stream_name: "OrderPlaced$2018-01", expected_version: :any)
end
end,
)
order_placed.run(event_store)
Now going for OrderPlaced
events in January is as simple as reading:
event_store.read.stream("OrderPlaced$2018-01").to_a
Linking can be even managed as soon as event is published, via event handler:
class OrderPlacedReport
def call(event)
event_store.link(event.event_id, stream_name: stream_name(event.metadata[:timestamp]), expected_version: :any)
end
private
def stream_name(timestamp)
"OrderPlaced$%4d-%02d" % [timestamp.year, timestamp.month]
end
def event_store
Rails.configuration.event_store
end
end
subscriber = OrderPlacedReport.new
event_store.subscribe(subscriber, [OrderPlaced])
It is worth remembering that linking an event does not trigger event handlers and you cannot link same event more than once in a given stream.
Linking also follows the same rules regarding expected_version as publishing an event for the first time.