# this is a mock-up. No persistence, no parallelism, no optimizations, # merely intended to demonstrate views. class View def initialize(value) @map_output = {} @reduce_input = {} instance_eval(value) @data = {} end def get(key) @data[key] end def update(id, value) old_map = @map_output[id.to_s] new_map = self.map(id, value) schedule = [] # out with the old (old_map.to_a - new_map.to_a).each do |key, value| @reduce_input[key].delete_at(@reduce_input[key].index(value)) @reduce_input.delete(key) if @reduce_input[key].empty? schedule << key end # in with the new (new_map.to_a - old_map.to_a).each do |key, value| @reduce_input[key] ||= [] @reduce_input[key] << value schedule << key unless schedule.index(key) end # update intermediate tables @map_output[id] = new_map schedule.each do |key| if @reduce_input[key] @data[key] = reduce(key, @reduce_input[key]) else @data.delete(key) end end end end class CouchDB def initialize(name) @data = {} @views = {} end def get(id) segments = id.split('/') if segments.length == 1 @data[id] else @views[segments.first].get(segments.last) end end def post(id, value) id.chop! if id[-1] == ?/ @views[id.to_s] = View.new(value) # on a real database, this would be done in parallel @data.each_pair {|name,value| @views[id.to_s].update(name, value)} end def put(id, value) @data[id.to_s] = value @views.each_value {|view| view.update(id, value)} end def delete(id) @data.delete(id) end end