Skip to content

Commit

Permalink
Added 'reset' and 'erase' methods.
Browse files Browse the repository at this point in the history
  • Loading branch information
twoixter committed Mar 26, 2011
1 parent eb714ae commit 55c1990
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 23 deletions.
49 changes: 45 additions & 4 deletions lib/trackoid/tracker.rb
Expand Up @@ -76,8 +76,7 @@ def set(how_much, date = Date.today)
raise Errors::ModelNotSaved, "Can't update a new record" if @owner.new_record?
update_data(how_much, date)
@owner.collection.update(
@owner._selector,
{ "$set" => update_hash(how_much, date) },
@owner._selector, { "$set" => update_hash(how_much, date) },
:upsert => true
)
return unless @owner.aggregated?
Expand All @@ -87,13 +86,55 @@ def set(how_much, date = Date.today)
fk = @owner.class.name.to_s.foreign_key.to_sym
selector = { fk => @owner.id, :ns => k, :key => token.to_s }
@owner.aggregate_klass.collection.update(
selector,
{ "$set" => update_hash(how_much, date) },
selector, { "$set" => update_hash(how_much, date) },
:upsert => true
)
end
end

def reset(how_much, date = Date.today)
return erase(date) if how_much.nil?

# First, we use the default "set" for the tracking field
# This will also update one aggregate but... oh well...
set(how_much, date)

# Need to iterate over all aggregates and send an update or delete
# operations over all mongo records for this aggregate field
@owner.aggregate_fields.each do |(k,v)|
fk = @owner.class.name.to_s.foreign_key.to_sym
selector = { fk => @owner.id, :ns => k }
@owner.aggregate_klass.collection.update(
selector, { "$set" => update_hash(how_much, date) },
:upsert => true, :multi => true
)
end
end

def erase(date = Date.today)
raise Errors::ModelNotSaved, "Can't update a new record" if @owner.new_record?

# For the in memory data, we just need to set it to nil
update_data(nil, date)
@owner.collection.update(
@owner._selector,
{ "$unset" => update_hash(1, date) },
:upsert => true
)
return unless @owner.aggregated?

# Need to iterate over all aggregates and send an update or delete
# operations over all mongo records
@owner.aggregate_fields.each do |(k,v)|
fk = @owner.class.name.to_s.foreign_key.to_sym
selector = { fk => @owner.id, :ns => k }
@owner.aggregate_klass.collection.update(
selector, { "$unset" => update_hash(1, date) },
:upsert => true, :multi => true
)
end
end

private
def data_for(date)
return nil if date.nil?
Expand Down
137 changes: 118 additions & 19 deletions spec/aggregates_spec.rb
Expand Up @@ -158,7 +158,7 @@ class MockTest3
@object_id = SecondTestModel.first.id
@mock = SecondTestModel.find(@object_id)
end

it "should correctly save all aggregation keys as strings (inc)" do
@mock.something("test").inc
@mock.something.aggregate_one.first.key.is_a?(String).should be_true
Expand All @@ -174,7 +174,6 @@ class MockTest3
@mock.something.aggregate_three.first.key.is_a?(String).should be_true
@mock.something.aggregate_four.first.key.is_a?(String).should be_true
end

end

describe "when tracking a model with aggregation data" do
Expand Down Expand Up @@ -233,8 +232,8 @@ class MockTest3

it "should work adding 1 visit with different aggregation data" do
@mock.visits("Google Chrome").inc
@mock.visits.browsers.today.should == [["mozilla", 1], ["google", 1]]
@mock.visits.referers.today.should == [["firefox", 1], ["chrome", 1]]
@mock.visits.browsers.today.should =~ [["mozilla", 1], ["google", 1]]
@mock.visits.referers.today.should =~ [["firefox", 1], ["chrome", 1]]

# Just for testing array manipulations
@mock.visits.browsers.today.inject(0) {|total, c| total + c.last }.should == 2
Expand All @@ -246,29 +245,130 @@ class MockTest3

it "should work also with set" do
@mock.visits("Google Chrome").set(5)
@mock.visits.browsers.today.should == [["mozilla", 1], ["google", 5]]
@mock.visits.referers.today.should == [["firefox", 1], ["chrome", 5]]
@mock.visits.browsers.today.should =~ [["mozilla", 1], ["google", 5]]
@mock.visits.referers.today.should =~ [["firefox", 1], ["chrome", 5]]
@mock.visits.today.should == 5
end

it "let's check what happens when sorting the best browser..." do
@mock.visits("Google Chrome").inc
@mock.visits.browsers.today.should == [["mozilla", 1], ["google", 6]]
@mock.visits.browsers.today.should =~ [["mozilla", 1], ["google", 6]]
@mock.visits.browsers.today.max {|a,b| a.second <=> b.second }.should == ["google", 6]
end

it "should work without aggregation information" do
@mock.visits.inc
@mock.visits.browsers.today.should == [["mozilla", 1], ["google", 6]]
@mock.visits.referers.today.should == [["firefox", 1], ["chrome", 6]]
@mock.visits.browsers.today.should =~ [["mozilla", 1], ["google", 6]]
@mock.visits.referers.today.should =~ [["firefox", 1], ["chrome", 6]]

# A more throughout test would check totals...
visits_today = @mock.visits.today
visits_today_with_browser = @mock.visits.browsers.today.inject(0) {|total, c| total + c.last }
visits_today.should == visits_today_with_browser
end
end

describe "When using reset method for aggregates" do
before do
TestModel.all.map(&:destroy)
TestModel.create(:name => "test")

@object_id = TestModel.first.id
@mock = TestModel.first

@mock.visits("Mozilla Firefox").set(1, "2010-07-11")
@mock.visits("Google Chrome").set(2, "2010-07-11")
@mock.visits("Internet Explorer").set(3, "2010-07-11")

@mock.visits("Mozilla Firefox").set(4, "2010-07-14")
@mock.visits("Google Chrome").set(5, "2010-07-14")
@mock.visits("Internet Explorer").set(6, "2010-07-14")

@mock.uniques("Mozilla Firefox").set(1, "2010-07-11")
@mock.uniques("Google Chrome").set(2, "2010-07-11")
@mock.uniques("Internet Explorer").set(3, "2010-07-11")

@mock.uniques("Mozilla Firefox").set(4, "2010-07-14")
@mock.uniques("Google Chrome").set(5, "2010-07-14")
@mock.uniques("Internet Explorer").set(6, "2010-07-14")
end

it "should have the correct values when using a value" do
@mock.visits.reset(99, "2010-07-14")

@mock.visits.on("2010-07-14").should == 99
@mock.visits.browsers.all_values.should =~ [
["mozilla", [1, 0, 0, 99]],
["google", [2, 0, 0, 99]],
["internet", [3, 0, 0, 99]]
]
@mock.visits.referers.all_values.should =~ [
["firefox", [1, 0, 0, 99]],
["chrome", [2, 0, 0, 99]],
["explorer", [3, 0, 0, 99]]
]
end

it "should delete the values when using nil" do
@mock.visits.reset(nil, "2010-07-14")

@mock.visits.on("2010-07-14").should == 0
@mock.visits.browsers.all_values.should =~ [
["mozilla", [1]],
["google", [2]],
["internet", [3]]
]
@mock.visits.referers.all_values.should =~ [
["firefox", [1]],
["chrome", [2]],
["explorer", [3]]
]
end

it "erase method sould also work" do
@mock.visits.erase("2010-07-14")

@mock.visits.on("2010-07-14").should == 0
@mock.visits.browsers.all_values.should =~ [
["mozilla", [1]],
["google", [2]],
["internet", [3]]
]
end

it "should reset the correct tracking fields" do
@mock.visits.reset(99, "2010-07-14")

@mock.uniques.on("2010-07-14").should == 6
@mock.uniques.browsers.all_values.should =~ [
["mozilla", [1, 0, 0, 4]],
["google", [2, 0, 0, 5]],
["internet", [3, 0, 0, 6]]
]
@mock.uniques.referers.all_values.should =~ [
["firefox", [1, 0, 0, 4]],
["chrome", [2, 0, 0, 5]],
["explorer", [3, 0, 0, 6]]
]
end

it "should erase the correct tracking fields" do
@mock.visits.erase("2010-07-14")

@mock.uniques.on("2010-07-14").should == 6
@mock.uniques.browsers.all_values.should =~ [
["mozilla", [1, 0, 0, 4]],
["google", [2, 0, 0, 5]],
["internet", [3, 0, 0, 6]]
]
@mock.uniques.referers.all_values.should =~ [
["firefox", [1, 0, 0, 4]],
["chrome", [2, 0, 0, 5]],
["explorer", [3, 0, 0, 6]]
]
end
end

describe "Testing all accessors" do
before do
TestModel.all.map(&:destroy)
Expand All @@ -280,7 +380,7 @@ class MockTest3
@mock.visits("Mozilla Firefox").set(1, "2010-07-11")
@mock.visits("Google Chrome").set(2, "2010-07-12")
@mock.visits("Internet Explorer").set(3, "2010-07-13")

# For 'last' values
@mock.visits("Mozilla Firefox").set(4, "2010-07-14")
@mock.visits("Google Chrome").set(5, "2010-07-15")
Expand All @@ -290,46 +390,45 @@ class MockTest3
it "should return the correct values for .all_values" do
@mock.visits.all_values.should == [1, 2, 3, 4, 5, 6]
end

it "should return the all values for every aggregate" do
@mock.visits.browsers.all_values.should == [
@mock.visits.browsers.all_values.should =~ [
["mozilla", [1, 0, 0, 4]],
["google", [2, 0, 0, 5]],
["internet", [3, 0, 0, 6]]
]
end

it "should return the correct first_date for every aggregate" do
@mock.visits.browsers.first_date.should == [
@mock.visits.browsers.first_date.should =~ [
["mozilla", Date.parse("2010-07-11")],
["google", Date.parse("2010-07-12")],
["internet", Date.parse("2010-07-13")]
]
end

it "should return the correct last_date for every aggregate" do
@mock.visits.browsers.last_date.should == [
@mock.visits.browsers.last_date.should =~ [
["mozilla", Date.parse("2010-07-14")],
["google", Date.parse("2010-07-15")],
["internet", Date.parse("2010-07-16")]
]
end

it "should return the first value for aggregates" do
@mock.visits.browsers.first_value.should == [
@mock.visits.browsers.first_value.should =~ [
["mozilla", 1],
["google", 2],
["internet", 3]
]
end

it "should return the last value for aggregates" do
@mock.visits.browsers.last_value.should == [
@mock.visits.browsers.last_value.should =~ [
["mozilla", 4],
["google", 5],
["internet", 6]
]
end

end
end

0 comments on commit 55c1990

Please sign in to comment.