Skip to content

Instantly share code, notes, and snippets.

@eterps
Created March 22, 2016 11:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eterps/9cf1245d347a8eba46ea to your computer and use it in GitHub Desktop.
Save eterps/9cf1245d347a8eba46ea to your computer and use it in GitHub Desktop.
Playing around with event sourcing principles
require 'yaml'
class Storage # Normally should be Redis or Kafka?
def self.events
@events ||= []
end
end
# Aggregates (models)
class Order
attr_reader :items
def initialize(order_id)
@order_id = order_id
@items = []
end
def order_total
@items.inject(0) do |sum, item|
sum + item.price
end
end
# Commands
def add_item(item_uid, price)
apply_event ItemAddedEvent.new(item_uid, price)
end
def remove_item(item_uid)
apply_event ItemRemovedEvent.new(item_uid)
end
# Applying events
def apply_event(event)
Storage.events << YAML.dump(event) # store event (should be Redis/Kafka)
# apply it
if event.is_a? ItemAddedEvent
@items << Item.new(event.item_uid, event.price)
# INSERT INTO # (immediate consistency)
elsif event.is_a? ItemRemovedEvent
@items.delete_if{|item| item.uid == event.item_uid}
# DELETE # (immediate consistency)
end
end
# Rebuilding
def rebuild
events = Storage.events.map{|event| YAML.load(event)}
events.each{|event| apply_event event}
end
end
class Item
attr_reader :uid, :price
def initialize(uid, price)
@uid = uid
@price = price
end
end
# Events
class ItemAddedEvent
attr_reader :item_uid, :price
def initialize(item_uid, price)
@item_uid = item_uid
@price = price
@time_added = Time.now
end
end
class ItemRemovedEvent
attr_reader :item_uid
def initialize(item_uid)
@item_uid = item_uid
end
end
# In Action
order = Order.new('0001')
order.add_item 'item_uid-1', 1.0 # should be +1.0 ? With de-duplication?
order.add_item 'item_uid-2', 2.0
order.add_item 'item_uid-3', 3.0
puts "Order total with 3 items: #{order.order_total}"
order.remove_item 'item_uid-2'
puts "Order total with 2 items: #{order.order_total}"
order = Order.new('0001')
order.rebuild
puts "Order total after rebuild: #{order.items.count} items, $#{order.order_total}"
# The write side and read side won't use the same data store, but can reside in the same database (but different tables)
# http://karmajunkie.com/event-sourcing-talk/#1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment