1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
def time_summary(klass,group_operator,field,from,to,step) data_with_missing_counts(klass.find( :all, :select => "#{group_operator}(#{field}) as result, round(UNIX_TIMESTAMP(created_at)/#{step}) as timestamp", :group => "round(UNIX_TIMESTAMP(created_at) / #{step})", :conditions => ["created_at BETWEEN ? AND ?", from, to] ).inject({}){|data,user| data.merge({ user.timestamp.to_i => user.result})},from.to_i/step.t_i,to.to_i/step.to_i) end def data_with_missing_counts(data, from, to) result = [] from.upto(to) do |idx| puts "idx=#{idx}, data[idx]=#{data[idx]}" result << (data[idx] || 0) end return result end @revenue_past_week_chart_data = time_summary(Order,'sum','amount',1.week.ago,Time.now,6.hours).map(&:to_f)
Refactorings
No refactoring yet !
Adam
September 3, 2008, September 03, 2008 16:21, permalink
This is completely untested since I don't have a good environment to play in, but this should hopefully give you a pretty good idea of where you can go with this. Use mixins if you are performing the same operation on more than one model.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
class Summary < Struct.new(:klass, :options) def range options[:range] || options[:from]..options[:to] end def step options[:step] end def calculate(method, *args) klass.between(range).by_timestamp(step).send(method, *args) end def method_missing(method, *args, &block) records = Hash[calculate(method, *args).map(&:reverse).flatten] range.map { |time| records[time.to_i].to_f } end end class Order < ActiveRecord::Base named_scope :between, lambda { |range| { :conditions => { :created_at => range } } } named_scope :by_timestamp, lambda { |step| { :group => "round(UNIX_TIMESTAMP(created_at)/#{step})" } } def self.summary(options) Summary.new(self, options) end end # Example usage: # # Order.summary(:from => Time.now, :to => 6.hours.from_now, :step => 10).sum(:amount) # Order.summary(:from => Time.now, :to => 6.hours.from_now, :step => 10).count(:amount)
Give a count or sum group operation, a time range, and a resolution, and a class, I want to get a list of timestamps and values. I want to use this to feed to google charts. Here is the code I have, which works, but is not very rubyish. Can you do better?