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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
# File 'lib/periodic_counter.rb', line 8
def initialize(environment, root)
@db, @log, @mail = ActiveWrapper.setup(
:base => root,
:env => environment
)
@db.establish_connection
@tables = ActiveRecord::Base.connection.tables.inject({}) do |hash, table|
hash[table] = ActiveRecord::Base.connection.columns(table).collect(&:name)
hash
end
if File.exists?(counters_yml = "#{root}/config/counters.yml")
@counters = YAML::load(File.open(counters_yml))
else
raise "#{counters_yml} not found"
end
@counters.each do |table, counters|
columns = @tables[table]
if columns
columns.each do |column|
if counters.include?(column)
period = columns.select do |col|
col =~ /^#{column}/ &&
(col =~ /_last_/ || col =~ /_ago$/)
end
select_columns = [ 'id', column, "#{column}_data" ]
select_columns += period
records = ActiveRecord::Base.connection.select_all <<-SQL
SELECT #{select_columns.join(', ')}
FROM #{table}
SQL
records.each do |record|
id = record.delete('id')
data = YAML::load(record["#{column}_data"] || '') || {}
count = record.delete(column).to_i
period.each do |col|
if WEEKDAYS.include?(weekday = col.split('_last_')[1])
data["#{col}_before_today"] ||= 0
if self.class.weekday(weekday)
record[col] = count - data["#{col}_before_today"]
else
data["#{col}_before_today"] = count
end
else
computed_at = data["#{col}_at"]
last_time =
if col.include?('minute')
self.class.this_minute
elsif col.include?('hour')
self.class.this_hour
elsif col.include?('day')
self.class.today
elsif col.include?('week')
self.class.last_monday
elsif col.include?('month')
self.class.first_of_the_month
end
if col =~ /_ago$/
duration = column_to_period_integer(col, -3, -2)
if !computed_at || last_time == computed_at
data[col] = count
data["#{col}_at"] = last_time
end
if computed_at && (Time.now.utc - computed_at - duration) >= 0
record[col] = data[col]
data[col] = count
data["#{col}_at"] = last_time
end
else
duration = column_to_period_integer(col, -2, -1)
if !computed_at || (Time.now.utc - computed_at - duration) >= 0
data[col] = count
data["#{col}_at"] = last_time
else
data[col] ||= count
data["#{col}_at"] ||= last_time
end
record[col] = count - data[col].to_i
end
end
end
record["#{column}_data"] = "'#{YAML::dump(data)}'"
set = record.collect { |col, value| "#{col} = #{value || 0}" }
ActiveRecord::Base.connection.update <<-SQL
UPDATE #{table}
SET #{set.join(', ')}
WHERE id = #{id}
SQL
end
end
end
end
end
end
|