Skip to content

Commit

Permalink
Fixing logic a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
winton committed Jun 10, 2010
1 parent 3346c09 commit 4ae81e0
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 141 deletions.
6 changes: 3 additions & 3 deletions README.markdown
Expand Up @@ -13,11 +13,11 @@ sudo gem install periodic_template
Create columns
--------------

For every counter column (X), you should also have a <code>X\_computed\_at</code> datetime column.
Define period columns using this format: <code>X\_last\_1\_week</code> or <code>X\_last\_6\_hours</code>.

To define period columns, use this format: <code>X\_last\_1\_week</code> or <code>X\_last\_6\_hours</code>. The name should follow the format of [ActiveSupport's time extensions](http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Numeric/Time.html).
The name should follow the format of [ActiveSupport's time extensions](http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Numeric/Time.html).

If you are adding this to a counter that already has a count, you will also need a <code>X\_starting\_value</code> integer column.
Also add a <code>counter_data</code> varchar column with a length of 2048.

Create configuration
--------------------
Expand Down
36 changes: 18 additions & 18 deletions lib/periodic_counter.rb
Expand Up @@ -26,40 +26,40 @@ def initialize(environment, root)
if columns
columns.each do |column|
if counters.include?(column)
# Find period columns
period = columns.select do |col|
col =~ /^#{column}/ &&
col != column &&
!col.include?('computed_at') &&
!col.include?('starting_value')
!col.include?('_data')
end
select_columns = [ 'id', column, "#{column}_computed_at", "#{column}_starting_value" ] + period
select_columns &= columns
# Grab all records
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')
computed_at = ActiveRecord::ConnectionAdapters::Column.string_to_time(
record.delete("#{column}_computed_at")
)
data = YAML::load(record["#{column}_data"] || '') || {}
computed_at = data['computed_at'] || Time.now.utc
count = record.delete(column).to_i
time_since_compute = Time.now.utc - computed_at.utc
if record.keys.include?("#{column}_starting_value")
unless record["#{column}_starting_value"]
record["#{column}_starting_value"] = count
end
starting_value = record["#{column}_starting_value"].to_i
end
starting_value ||= 0
time_since_compute = Time.now.utc - computed_at
# Set period counters
period.each do |col|
period_count = record[col].to_i
duration = column_to_period_integer(col)
starting_value = data[col].to_i
if (time_since_compute - duration) >= 0
record[col] = count - period_count - starting_value
record[col] = count - starting_value
data[col] = count
else
data[col] ||= count
end
end
set = record.collect { |col, value| "#{col} = #{value}" }
# Update record
data['computed_at'] = Time.now.utc
record["#{column}_data"] = "'#{YAML::dump(data)}'"
set = record.collect { |col, value| "#{col} = #{value || 0}" }
ActiveRecord::Base.connection.update <<-SQL
UPDATE #{table}
SET #{set.join(', ')}
Expand Down
@@ -1,12 +1,10 @@
class CountersWithoutStartingValue < ActiveRecord::Migration
class Counters < ActiveRecord::Migration
def self.up
create_table :counters do |t|
t.integer :counter
t.datetime :counter_computed_at
t.integer :counter_last_day
t.integer :counter_last_2_days
t.integer :counter_last_week
t.integer :counter_last_2_weeks
t.string :counter_data, :limit => 2048
end
end

Expand Down
17 changes: 0 additions & 17 deletions spec/db/migrate/002_counters_with_starting_value.rb

This file was deleted.

150 changes: 59 additions & 91 deletions spec/periodic_counter_spec.rb
@@ -1,98 +1,66 @@
require 'spec_helper'

describe PeriodicCounter do
describe "without starting value" do

before(:each) do
$db.migrate(1)
$db.migrate(0)
$db.migrate(1)
create_counter
end

it "should add to counter_last_day" do
stub_time(Time.now + 1.day)
start
Counter.last.counter_last_day.should == 2
Counter.last.counter_last_2_days.should == 1
Counter.last.counter_last_week.should == 1
Counter.last.counter_last_2_weeks.should == 1
end

it "should add to counter_last_2_days" do
stub_time(Time.now + 2.days)
start
Counter.last.counter_last_day.should == 2
Counter.last.counter_last_2_days.should == 2
Counter.last.counter_last_week.should == 1
Counter.last.counter_last_2_weeks.should == 1
end

it "should add to counter_last_week" do
stub_time(Time.now + 1.week)
start
Counter.last.counter_last_day.should == 2
Counter.last.counter_last_2_days.should == 2
Counter.last.counter_last_week.should == 2
Counter.last.counter_last_2_weeks.should == 1
end

it "should add to counter_last_2_weeks" do
stub_time(Time.now + 2.weeks)
start
Counter.last.counter_last_day.should == 2
Counter.last.counter_last_2_days.should == 2
Counter.last.counter_last_week.should == 2
Counter.last.counter_last_2_weeks.should == 2
end

before(:all) do
$db.migrate(1)
$db.migrate(0)
$db.migrate(1)
create_counter
end

it "should not do anything but set up data" do
start
attributes = Counter.last.attributes
data = attributes.delete('counter_data')
data.delete('computed_at').to_s.should == Time.now.utc.to_s
data.should == {
"counter_last_day"=>1,
"counter_last_2_days"=>1
}
attributes.should == {
"id"=>1,
"counter"=>1,
"counter_last_day"=>0,
"counter_last_2_days"=>0
}
end

it "should add to counter_last_day" do
Counter.last.update_attribute :counter, 2
stub_time(Time.now + 1.day)
start
attributes = Counter.last.attributes
data = attributes.delete('counter_data')
data.delete('computed_at').to_s.should == Time.now.utc.to_s
data.should == {
"counter_last_day"=>2,
"counter_last_2_days"=>1
}
attributes.should == {
"id"=>1,
"counter"=>2,
"counter_last_day"=>1,
"counter_last_2_days"=>0
}
end

describe "with starting value" do

before(:each) do
$db.migrate(2)
$db.migrate(0)
$db.migrate(2)
Counter.reset_column_information
create_counter
start
Counter.last.update_attribute :counter, 6
end

it "should add to counter_last_day" do
stub_time(Time.now + 1.day)
start
Counter.last.counter_last_day.should == 2
Counter.last.counter_last_2_days.should == 1
Counter.last.counter_last_week.should == 1
Counter.last.counter_last_2_weeks.should == 1
end

it "should add to counter_last_2_days" do
stub_time(Time.now + 2.days)
start
Counter.last.counter_last_day.should == 2
Counter.last.counter_last_2_days.should == 2
Counter.last.counter_last_week.should == 1
Counter.last.counter_last_2_weeks.should == 1
end

it "should add to counter_last_week" do
stub_time(Time.now + 1.week)
start
Counter.last.counter_last_day.should == 2
Counter.last.counter_last_2_days.should == 2
Counter.last.counter_last_week.should == 2
Counter.last.counter_last_2_weeks.should == 1
end

it "should add to counter_last_2_weeks" do
stub_time(Time.now + 2.weeks)
start
Counter.last.counter_last_day.should == 2
Counter.last.counter_last_2_days.should == 2
Counter.last.counter_last_week.should == 2
Counter.last.counter_last_2_weeks.should == 2
end
it "should add to counter_last_2_days" do
Counter.last.update_attribute :counter, 3
stub_time(Time.now + 3.days)
start
attributes = Counter.last.attributes
data = attributes.delete('counter_data')
data.delete('computed_at').to_s.should == Time.now.utc.to_s
data.should == {
"counter_last_day"=>3,
"counter_last_2_days"=>3
}
attributes.should == {
"id"=>1,
"counter"=>3,
"counter_last_day"=>1,
"counter_last_2_days"=>2
}
end
end
10 changes: 2 additions & 8 deletions spec/spec_helper.rb
Expand Up @@ -11,14 +11,7 @@
$db.establish_connection

def create_counter
Counter.create(
:counter => 3,
:counter_computed_at => Time.now,
:counter_last_day => 1,
:counter_last_2_days => 1,
:counter_last_week => 1,
:counter_last_2_weeks => 1
)
Counter.create(:counter => 1)
end

def start
Expand All @@ -30,4 +23,5 @@ def stub_time(time)
end

class Counter < ActiveRecord::Base
serialize :counter_data
end

0 comments on commit 4ae81e0

Please sign in to comment.