Created
November 1, 2015 16:26
-
-
Save jgaskins/0011c518359642833bb0 to your computer and use it in GitHub Desktop.
GrandCentral deep nesting w/ cache invalidation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'clearwater/component' | |
require 'clearwater/cached_render' | |
module Dispatcher | |
class Driver | |
include Clearwater::Component | |
include Clearwater::CachedRender | |
attr_reader :driver, :orders | |
# I'm passing in the driver and orders as "props", but they could easily be retrieved | |
# from the global store. | |
def initialize(driver, orders) | |
@driver = driver | |
@order = orders | |
end | |
# Example constructor for pulling from global state | |
def initialize(market, driver_id, store=Store) | |
@driver = store.state[:drivers][market.id][driver_id] | |
@orders = store.state[:orders][market][:by_driver_id][driver_id] | |
end | |
def render | |
# ... | |
end | |
def should_render? previous | |
!( | |
drivers.equal?(previous.drivers) && | |
orders.equal?(previous.orders) | |
) | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
markets = [ | |
Market.new( | |
id: 1, | |
name: 'My Example Market', | |
) | |
] | |
drivers = `gon.drivers`.map { |d| Driver.new(Hash.new(d)) } | |
orders = `gon.orders`.map { |o| Order.new(Hash.new(o)) } | |
index_drivers_by_market_id_and_driver_id = proc do |drivers| | |
drivers.group_by(&:market_id).reduce({}) do |hash, (market_id, drivers)| | |
hash.merge!( | |
market_id => drivers.reduce({}) { |driver_hash, driver| | |
driver_hash.merge! driver.id => driver | |
} | |
) | |
end | |
end | |
index_orders_by_market_id_etc = proc do |orders| | |
orders.reduce({}) { |hash, order| | |
market = markets.find { |m| m.id == order.market_id } | |
hash[market] ||= { | |
{ | |
by_id: {}, | |
by_driver_id: {}, | |
} | |
} | |
hash[market].merge!( | |
by_id: hash[market][:by_id].merge(order.id => order), | |
by_driver_id: hash[market][:by_driver_id] + [order] | |
) | |
} | |
end | |
initial_state = { | |
drivers: index_drivers_by_market_id_and_driver_id(drivers), | |
orders: index_orders_by_market_id_etc(orders), | |
} | |
Store = GrandCentral::Store.new(initial_state) do |state, action| | |
case action | |
# UpdateOrder is dispatched when we receive an update via WebSocket. We receive a whole new version | |
# of the order instead of a delta between the two in case we missed previous updates because of | |
# network disruption), so we can simply replace the old order with the new one. | |
# | |
# action.order = A new version of the order constructed from the data from the WebSocket | |
when Actions::UpdateOrder | |
order = action.order | |
market = markets.find { |m| m.id == order.market_id } | |
# Only update if this action is for a market we're tracking | |
if market | |
orders = state[:orders].fetch(market) { | |
{ | |
by_id: {}, | |
by_driver_id: {}, | |
} | |
} | |
state.merge( | |
orders: state[:orders].merge( | |
# Orders compartmentalized by market | |
market => { | |
# Index orders by id for O(1) selection | |
by_id: orders[:by_id].merge(order.id => order), | |
# Another index by driver_id, but drivers can have many orders, so we | |
# iterate over the array of them, replacing the old with the new. | |
by_driver_id: orders[:by_driver_id].fetch(order.driver_id) { [] }.map { |o| | |
if o.id == order.id | |
order | |
else | |
o | |
end | |
} | |
} | |
), | |
) | |
else | |
state | |
end | |
# Return the original state if we didn't handle the action. | |
else | |
state | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment