Projections
You can create a projection abstract based on single stream.
stream_name = "Customer$1"
client.publish(MoneyDeposited.new(data: { amount: 10 }), stream_name: stream_name)
client.publish(custom_event = MoneyDeposited.new(data: { amount: 20 }), stream_name: stream_name)
client.publish(MoneyWithdrawn.new(data: { amount: 5 }), stream_name: stream_name)
account_balance = RailsEventStore::Projection.
from_stream(stream_name).
init(-> { { total: 0 } }).
when(MoneyDeposited, ->(state, event) { state[:total] += event.data[:amount] }).
when(MoneyWithdrawn, ->(state, event) { state[:total] -= event.data[:amount] })
account_balance.run(client) # => {total: 25}
In order to narrow the results, simply pass event_id
to run
method.
account_balance.run(client, start: custom_event.event_id) # => {total: -5}
You may also subscribe one handler to multiple events by passing an array to #when
method:
account_cashflow = RailsEventStore::Projection.
from_all_streams.
init( -> { { total: 0 } }).
when([MoneyDeposited, MoneyWithdrawn], ->(state, event) { state[:total] += event.data[:amount] })
account_cashflow.run(client) # => {total: 35}
Projection based on multiple streams
client.publish(MoneyDeposited.new(data: { amount: 15 }), stream_name: "Customer$1")
client.publish(MoneyDeposited.new(data: { amount: 25 }), stream_name: "Customer$2")
client.publish(custom_event = MoneyWithdrawn.new(data: { amount: 10 }), stream_name: "Customer$3")
client.publish(MoneyWithdrawn.new(data: { amount: 20 }), stream_name: "Customer$3")
account_balance = RailsEventStore::Projection.
from_stream("Customer$1", "Customer$3").
init( -> { { total: 0 } }).
when(MoneyDeposited, ->(state, event) { state[:total] += event.data[:amount] }).
when(MoneyWithdrawn, ->(state, event) { state[:total] -= event.data[:amount] })
account_balance.run(client) # => {total: -15}
In order to narrow the results, you have to pass array with event_id
for each stream or nil to start from beggining of the stream. So, in example below we start from beggining of stream for Customer$1
and custom_event.event_id
for Customer$3
.
account_balance.run(client, start: [nil, custom_event.event_id]) # => {total: -5}
Projection based on all streams
client.publish(MoneyDeposited.new(data: { amount: 10 }), stream_name: "Customer$1")
client.publish(MoneyDeposited.new(data: { amount: 10 }), stream_name: "Customer$2")
client.publish(custom_event = MoneyDeposited.new(data: { amount: 10 }), stream_name: "Customer$3")
client.publish(MoneyWithdrawn.new(data: { amount: 20 }), stream_name: "Customer$4")
account_balance = RailsEventStore::Projection.
from_all_streams.
init( -> { { total: 0 } }).
when(MoneyDeposited, ->(state, event) { state[:total] += event.data[:amount] }).
when(MoneyWithdrawn, ->(state, event) { state[:total] -= event.data[:amount] })
account_balance.run(client) # => {total: 10}
account_balance.run(client, start: custom_event.event_id) # => {total: -20}