redisrank 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +27 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +20 -0
  7. data/README.md +297 -0
  8. data/Rakefile +69 -0
  9. data/lib/redisrank.rb +106 -0
  10. data/lib/redisrank/buffer.rb +110 -0
  11. data/lib/redisrank/collection.rb +20 -0
  12. data/lib/redisrank/connection.rb +89 -0
  13. data/lib/redisrank/core_ext.rb +5 -0
  14. data/lib/redisrank/core_ext/bignum.rb +8 -0
  15. data/lib/redisrank/core_ext/date.rb +8 -0
  16. data/lib/redisrank/core_ext/fixnum.rb +8 -0
  17. data/lib/redisrank/core_ext/hash.rb +20 -0
  18. data/lib/redisrank/core_ext/time.rb +3 -0
  19. data/lib/redisrank/date.rb +88 -0
  20. data/lib/redisrank/event.rb +98 -0
  21. data/lib/redisrank/finder.rb +245 -0
  22. data/lib/redisrank/finder/date_set.rb +99 -0
  23. data/lib/redisrank/key.rb +84 -0
  24. data/lib/redisrank/label.rb +69 -0
  25. data/lib/redisrank/mixins/database.rb +11 -0
  26. data/lib/redisrank/mixins/date_helper.rb +8 -0
  27. data/lib/redisrank/mixins/options.rb +41 -0
  28. data/lib/redisrank/mixins/synchronize.rb +52 -0
  29. data/lib/redisrank/model.rb +77 -0
  30. data/lib/redisrank/result.rb +18 -0
  31. data/lib/redisrank/scope.rb +18 -0
  32. data/lib/redisrank/summary.rb +90 -0
  33. data/lib/redisrank/version.rb +3 -0
  34. data/redisrank.gemspec +31 -0
  35. data/spec/Find Results +3349 -0
  36. data/spec/buffer_spec.rb +104 -0
  37. data/spec/collection_spec.rb +20 -0
  38. data/spec/connection_spec.rb +67 -0
  39. data/spec/core_ext/hash_spec.rb +26 -0
  40. data/spec/database_spec.rb +10 -0
  41. data/spec/date_spec.rb +95 -0
  42. data/spec/event_spec.rb +86 -0
  43. data/spec/finder/date_set_spec.rb +527 -0
  44. data/spec/finder_spec.rb +205 -0
  45. data/spec/key_spec.rb +129 -0
  46. data/spec/label_spec.rb +86 -0
  47. data/spec/model_helper.rb +31 -0
  48. data/spec/model_spec.rb +191 -0
  49. data/spec/options_spec.rb +36 -0
  50. data/spec/redis-test.conf +9 -0
  51. data/spec/result_spec.rb +23 -0
  52. data/spec/scope_spec.rb +27 -0
  53. data/spec/spec_helper.rb +18 -0
  54. data/spec/summary_spec.rb +177 -0
  55. data/spec/synchronize_spec.rb +125 -0
  56. data/spec/thread_safety_spec.rb +39 -0
  57. metadata +235 -0
@@ -0,0 +1,104 @@
1
+ require "spec_helper"
2
+
3
+ describe Redisrank::Buffer do
4
+
5
+ before(:each) do
6
+ @class = Redisrank::Buffer
7
+ @buffer = Redisrank::Buffer.instance
8
+ @key = double("Key", :to_s => "Scope/label:2011")
9
+ @stats = {:count => 1, :views => 3}
10
+ @depth_limit = :hour
11
+ @opts = {:enable_grouping => true}
12
+ end
13
+
14
+ # let's cleanup after ourselves for the other specs
15
+ after(:each) do
16
+ @class.instance_variable_set("@instance", nil)
17
+ @buffer.size = 0
18
+ end
19
+
20
+ it "should provide instance of itself" do
21
+ @buffer.should be_a(@class)
22
+ end
23
+
24
+ it "should only buffer if buffer size setting is greater than 1" do
25
+ @buffer.size.should == 0
26
+ expect(@buffer.send(:should_buffer?)).to be false
27
+ @buffer.size = 1
28
+ @buffer.size.should == 1
29
+ expect(@buffer.send(:should_buffer?)).to be false
30
+ @buffer.size = 2
31
+ @buffer.size.should == 2
32
+ expect(@buffer.send(:should_buffer?)).to be true
33
+ end
34
+
35
+ it "should only flush buffer if buffer size is greater than or equal to buffer size setting" do
36
+ @buffer.size.should == 0
37
+ @buffer.send(:queue).size.should == 0
38
+ expect(@buffer.send(:should_flush?)).to be false
39
+ @buffer.send(:queue)[:hello] = 'world'
40
+ @buffer.send(:incr_count)
41
+ expect(@buffer.send(:should_flush?)).to be true
42
+ @buffer.size = 5
43
+ expect(@buffer.send(:should_flush?)).to be false
44
+ 3.times { |i|
45
+ @buffer.send(:queue)[i] = i.to_s
46
+ @buffer.send(:incr_count)
47
+ }
48
+ expect(@buffer.send(:should_flush?)).to be false
49
+ @buffer.send(:queue)[4] = '4'
50
+ @buffer.send(:incr_count)
51
+ expect(@buffer.send(:should_flush?)).to be true
52
+ end
53
+
54
+ it "should force flush queue irregardless of result of #should_flush? when #reset_queue is called with true" do
55
+ @buffer.send(:queue)[:hello] = 'world'
56
+ @buffer.send(:incr_count)
57
+ expect(@buffer.send(:should_flush?)).to be true
58
+ @buffer.size = 2
59
+ expect(@buffer.send(:should_flush?)).to be false
60
+ @buffer.send(:reset_queue).should == {}
61
+ @buffer.instance_variable_get("@count").should == 1
62
+ @buffer.send(:reset_queue, true).should == {:hello => 'world'}
63
+ @buffer.instance_variable_get("@count").should == 0
64
+ end
65
+
66
+ it "should #flush_data into Summary.update properly" do
67
+ # the root level key value doesn't actually matter, but it's something like this...
68
+ data = {'ScopeName/label/goes/here:2011::true:true' => {
69
+ :key => @key,
70
+ :stats => @stats,
71
+ :depth_limit => @depth_limit,
72
+ :opts => @opts
73
+ }}
74
+ item = data.first[1]
75
+ Redisrank::Summary.should_receive(:update).with(@key, @stats, @depth_limit, @opts)
76
+ @buffer.send(:flush_data, data)
77
+ end
78
+
79
+ it "should build #buffer_key correctly" do
80
+ opts = {:enable_grouping => true, :label_indexing => false, :connection_ref => nil}
81
+ @buffer.send(:buffer_key, @key, opts).should ==
82
+ "#{@key.to_s}:connection_ref::enable_grouping:true:label_indexing:false"
83
+ opts = {:enable_grouping => false, :label_indexing => true, :connection_ref => :omg}
84
+ @buffer.send(:buffer_key, @key, opts).should ==
85
+ "#{@key.to_s}:connection_ref:omg:enable_grouping:false:label_indexing:true"
86
+ end
87
+
88
+ describe "Buffering" do
89
+ it "should store items on buffer queue" do
90
+ expect(@buffer.store(@key, @stats, @depth_limit, @opts)).to be false
91
+ @buffer.size = 5
92
+ expect(@buffer.store(@key, @stats, @depth_limit, @opts)).to be true
93
+ expect(@buffer.send(:queue).count).to eq(1)
94
+ @buffer.send(:queue)[@buffer.send(:queue).keys.first][:stats][:count].should == 1
95
+ @buffer.send(:queue)[@buffer.send(:queue).keys.first][:stats][:views].should == 3
96
+ expect(@buffer.store(@key, @stats, @depth_limit, @opts)).to be true
97
+ expect(@buffer.send(:queue).count).to eq(1)
98
+ @buffer.send(:queue)[@buffer.send(:queue).keys.first][:stats][:count].should == 1
99
+ @buffer.send(:queue)[@buffer.send(:queue).keys.first][:stats][:views].should == 3
100
+ end
101
+
102
+ end
103
+
104
+ end
@@ -0,0 +1,20 @@
1
+ require "spec_helper"
2
+
3
+ describe Redisrank::Collection do
4
+
5
+ it "should initialize properly" do
6
+ options = {:from => "from", :till => "till", :depth => "depth"}
7
+ result = Redisrank::Collection.new(options)
8
+ result.from.should == options[:from]
9
+ result.till.should == options[:till]
10
+ result.depth.should == options[:depth]
11
+ end
12
+
13
+ it "should have a rank property" do
14
+ col = Redisrank::Collection.new()
15
+ col.rank.should == {}
16
+ col.rank = {:foo => "bar"}
17
+ col.rank.should == {:foo => "bar"}
18
+ end
19
+
20
+ end
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+ include Redisrank
3
+
4
+ describe Redisrank::Connection do
5
+
6
+ before(:each) do
7
+ @redis = Redisrank.redis
8
+ end
9
+
10
+ it "should have a valid Redis client instance" do
11
+ Redisrank.redis.should_not be_nil
12
+ end
13
+
14
+ it "should have initialized custom testing connection" do
15
+ @redis.client.host.should == '127.0.0.1'
16
+ @redis.client.port.should == 8379
17
+ @redis.client.db.should == 15
18
+ end
19
+
20
+ it "should be able to set and get data" do
21
+ @redis.set("hello", "world")
22
+ expect(@redis.get("hello")).to eq("world")
23
+ expect(@redis.del("hello")).to be 1
24
+ end
25
+
26
+ it "should be able to store hashes to Redis" do
27
+ @redis.hset("hash", "field", "1")
28
+ @redis.hget("hash", "field").should == "1"
29
+ @redis.hincrby("hash", "field", 1)
30
+ @redis.hget("hash", "field").should == "2"
31
+ @redis.hincrby("hash", "field", -1)
32
+ @redis.hget("hash", "field").should == "1"
33
+ @redis.del("hash")
34
+ end
35
+
36
+ it "should be accessible from Redisrank module" do
37
+ Redisrank.redis.should == Connection.get
38
+ Redisrank.redis.should == Redisrank.connection
39
+ end
40
+
41
+ it "should handle multiple connections with refs" do
42
+ Redisrank.redis.client.db.should == 15
43
+ Redisrank.connect(:port => 8379, :db => 14, :ref => "Custom")
44
+ Redisrank.redis.client.db.should == 15
45
+ Redisrank.redis("Custom").client.db.should == 14
46
+ end
47
+
48
+ it "should be able to overwrite default and custom refs" do
49
+ Redisrank.redis.client.db.should == 15
50
+ Redisrank.connect(:port => 8379, :db => 14)
51
+ Redisrank.redis.client.db.should == 14
52
+
53
+ Redisrank.redis("Custom").client.db.should == 14
54
+ Redisrank.connect(:port => 8379, :db => 15, :ref => "Custom")
55
+ Redisrank.redis("Custom").client.db.should == 15
56
+
57
+ # Reset the default connection to the testing server or all hell
58
+ # might brake loose from the rest of the specs
59
+ Redisrank.connect(:port => 8379, :db => 15)
60
+ end
61
+
62
+ # TODO: Test thread-safety
63
+ it "should be thread-safe" do
64
+ pending("need to figure out a way to test thread-safety")
65
+ end
66
+
67
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ describe Hash do
4
+
5
+ it "should #merge_to_max values" do
6
+ hash = {:count => 1}
7
+ expect(hash.merge_to_max(:sum, 3)).to be true
8
+ expect(hash).to eq({:count => 1, :sum => 3})
9
+ expect(hash.merge_to_max(:count, 4)).to be true
10
+ expect(hash).to eq({:count => 4, :sum => 3})
11
+ expect(hash.merge_to_max(:count, 3)).to be false
12
+ expect(hash.merge_to_max(:count, 'test')).to be false
13
+ expect(hash.merge_to_max(:view, 'test')).to be false
14
+ expect(hash).to eq({:count => 4, :sum => 3})
15
+ hash[:view] = 'test'
16
+ expect(hash.merge_to_max(:view, 3)).to be false
17
+ end
18
+
19
+ it "should #merge_to_max! hashes" do
20
+ hash = { :count => 1, :sum => 2}
21
+
22
+ expect(hash.clone.merge_to_max!({:mult => 3, :sum => 2, :count => 2})).to eq({:count => 2, :sum => 2, :mult => 3})
23
+ expect(hash.clone.merge_to_max!({:mult => 3, :sum => 3, :count => 2})).to eq({:count => 2, :sum => 3, :mult => 3})
24
+ end
25
+
26
+ end
@@ -0,0 +1,10 @@
1
+ require "spec_helper"
2
+
3
+ describe Redisrank::Database do
4
+ include Redisrank::Database
5
+
6
+ it "should make #db method available when included" do
7
+ db.should == Redisrank.redis
8
+ end
9
+
10
+ end
@@ -0,0 +1,95 @@
1
+ require "spec_helper"
2
+
3
+ describe Redisrank::Date do
4
+
5
+ it "should initialize from Time object" do
6
+ now = Time.now
7
+ [Redisrank::Date.new(now), now.to_rs].each do |rdate|
8
+ Redisrank::Date::DEPTHS.each { |k| rdate.send(k).should == now.send(k) }
9
+ end
10
+ end
11
+
12
+ it "should initialize from Date object" do
13
+ today = Date.today
14
+ [Redisrank::Date.new(today), today.to_rs].each do |rdate|
15
+ [:year, :month, :day].each { |k| rdate.send(k).should == today.send(k) }
16
+ [:hour, :min, :sec, :usec].each { |k| rdate.send(k).should == 0 }
17
+ end
18
+ end
19
+
20
+ it "should initialize from Fixnum object (UNIX Timestamp)" do
21
+ now = Time.now.to_i
22
+ time = Time.at(now)
23
+ [Redisrank::Date.new(now), now.to_rs].each do |rdate|
24
+ [:year, :month, :day, :hour, :min, :sec].each { |k| rdate.send(k).should == time.send(k) }
25
+ end
26
+ end
27
+
28
+ it "should initialize from String object" do
29
+ now = Time.now
30
+ rdate = Redisrank::Date.new(now.to_s)
31
+ [:year, :month, :day, :hour, :min, :sec].each { |k| rdate.send(k).should == now.send(k) }
32
+ end
33
+
34
+ it "should initialize from Redisrank date String" do
35
+ now = Time.now
36
+ rdate = Redisrank::Date.new(now.to_s)
37
+ [:year, :month, :day, :hour, :min, :sec].each { |k|
38
+ rdate.to_s(k).should == Redisrank::Date.new(rdate.to_s(k)).to_s(k)
39
+ }
40
+ end
41
+
42
+ it "should convert to Time object" do
43
+ now = Time.now
44
+ rdate = Redisrank::Date.new(now)
45
+ rdate.to_time.to_s.should == now.to_s
46
+ end
47
+
48
+ it "should convert to Date object" do
49
+ today = Date.today
50
+ rdate = Redisrank::Date.new(today)
51
+ rdate.to_date.to_s.should == today.to_s
52
+ end
53
+
54
+ it "should convert to Fixnum object (UNIX Timestamp)" do
55
+ now = Time.now
56
+ rdate = Redisrank::Date.new(now)
57
+ rdate.to_i.should == now.to_i
58
+ end
59
+
60
+ it "should convert to string with correct depths" do
61
+ today = Date.today
62
+ now = Time.now
63
+ [[now, Redisrank::Date.new(now)], [today, Redisrank::Date.new(today)]].each do |current, rdate|
64
+ props = [:year, :month, :day, :hour, :min, :sec, nil]
65
+ if rdate.usec > 0
66
+ rdate.to_s(:usec).should == props.map { |k| current.send(k).to_s.rjust(2, '0') if !k.nil? }.join + "." + current.usec.to_s.rjust(6, '0')
67
+ end
68
+ props.clone.each do
69
+ rdate.to_s(props.last).should == props.map { |k| current.send(k).to_s.rjust(2, '0') if !k.nil? }.join
70
+ props.pop
71
+ end
72
+ end
73
+ end
74
+
75
+ it "should add helper methods to Date, Time and Fixnum classes" do
76
+ Date.today.to_time.should == Time.parse(Date.today.to_s)
77
+ Time.now.to_i.to_time.should == Time.at(Time.now.to_i)
78
+ Date.today.to_rs.to_date.should == Date.today
79
+ end
80
+
81
+ it "should have a depth property" do
82
+ now = Time.now
83
+
84
+ date = Redisrank::Date.new(now)
85
+ date.depth.should be_nil
86
+ date.to_s.should == now.to_rs(:sec).to_s
87
+ date.to_s.should == now.to_rs.to_s(:sec)
88
+
89
+ date = Redisrank::Date.new(now, :hour)
90
+ date.depth.should == :hour
91
+ date.to_s.should == now.to_rs(:hour).to_s
92
+ date.to_s.should == now.to_rs.to_s(:hour)
93
+ end
94
+
95
+ end
@@ -0,0 +1,86 @@
1
+ require "spec_helper"
2
+
3
+ describe Redisrank::Event do
4
+ include Redisrank::Database
5
+
6
+ before(:each) do
7
+ db.flushdb
8
+ @scope = "PageViews"
9
+ @label = "about_us"
10
+ @label_hash = Digest::SHA1.hexdigest(@label)
11
+ @stats = {'views' => 1}
12
+ @meta = {'user_id' => 239}
13
+ @options = {:depth => :hour}
14
+ @date = Time.now
15
+ @event = Redisrank::Event.new(@scope, @label, @date, @stats, @options, @meta)
16
+ end
17
+
18
+ it "should initialize properly" do
19
+ @event.id.should be_nil
20
+ @event.scope.to_s.should == @scope
21
+ @event.label.to_s.should == @label
22
+ @event.label_hash.should == @label_hash
23
+ @event.date.to_time.to_s.should == @date.to_s
24
+ @event.stats.should == @stats
25
+ @event.meta.should == @meta
26
+ @event.options.should == @event.default_options.merge(@options)
27
+ end
28
+
29
+ it "should allow changing attributes" do
30
+ # date
31
+ @event.date.to_time.to_s.should == @date.to_s
32
+ @date = Time.now
33
+ @event.date = @date
34
+ @event.date.to_time.to_s.should == @date.to_s
35
+ # label
36
+ @event.label.to_s.should == @label
37
+ @event.label_hash.should == @label_hash
38
+ @label = "contact_us"
39
+ @label_hash = Digest::SHA1.hexdigest(@label)
40
+ @event.label = @label
41
+ @event.label.to_s.should == @label
42
+ @event.label_hash.should == @label_hash
43
+ end
44
+
45
+ it "should increment next_id" do
46
+ event = Redisrank::Event.new("VisitorCount", @label, @date, @stats, @options, @meta)
47
+ @event.next_id.should == 1
48
+ event.next_id.should == 1
49
+ @event.next_id.should == 2
50
+ event.next_id.should == 2
51
+ end
52
+
53
+ it "should store event properly" do
54
+ @event = Redisrank::Event.new(@scope, @label, @date, @stats, @options.merge({:store_event => true}), @meta)
55
+ expect(@event.new?).to be true
56
+ @event.save
57
+ expect(@event.new?).to be false
58
+ keys = db.keys "*"
59
+ keys.should include("#{@event.scope}#{Redisrank::KEY_EVENT}#{@event.id}")
60
+ keys.should include("#{@event.scope}#{Redisrank::KEY_EVENT_IDS}")
61
+ end
62
+
63
+ it "should find event by id" do
64
+ @event = Redisrank::Event.new(@scope, @label, @date, @stats, @options.merge({:store_event => true}), @meta).save
65
+ fetched = Redisrank::Event.find(@scope, @event.id)
66
+ @event.scope.to_s.should == fetched.scope.to_s
67
+ @event.label.to_s.should == fetched.label.to_s
68
+ @event.date.to_s.should == fetched.date.to_s
69
+ @event.stats.should == fetched.stats
70
+ @event.meta.should == fetched.meta
71
+ end
72
+
73
+ it "should store summarized statistics" do
74
+ 2.times do |i|
75
+ @event = Redisrank::Event.new(@scope, @label, @date, @stats, @options, @meta).save
76
+ Redisrank::Date::DEPTHS.each do |depth|
77
+ summary = db.zrevrange @event.key.to_s(depth), 0, -1, :with_scores => true
78
+ expect(summary.count).to be > 0
79
+ expect(summary.first.first).to eq("views")
80
+ expect(summary.first.last).to eq(1)
81
+ break if depth == :hour
82
+ end
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,527 @@
1
+ require "spec_helper"
2
+
3
+ describe Redisrank::Finder::DateSet do
4
+
5
+ before(:all) do
6
+ @finder = Redisrank::Finder::DateSet.new
7
+ end
8
+
9
+ it "should initialize properly" do
10
+ t_start = Time.utc(2010, 8, 28, 22, 54, 57)
11
+ t_end = Time.utc(2013, 12, 4, 22, 52, 3)
12
+ result = Redisrank::Finder::DateSet.new(t_start, t_end)
13
+ result.should == [
14
+ { :add => ["2010082822", "2010082823"], :rem => [] },
15
+ { :add => ["20131204"], :rem => ["2013120423"] },
16
+ { :add => ["20100829", "20100830", "20100831"], :rem => [] },
17
+ { :add => ["20131201", "20131202", "20131203"], :rem => [] },
18
+ { :add => ["201009", "201010", "201011", "201012"], :rem => [] },
19
+ { :add => ["2013"], :rem => ["201312"] },
20
+ { :add => ["2011", "2012"], :rem => [] }
21
+ ]
22
+ end
23
+
24
+ it "should find date sets by interval" do
25
+ t_start = Time.utc(2010, 8, 28, 18, 54, 57)
26
+
27
+ t_end = t_start + 4.hours
28
+ result = Redisrank::Finder::DateSet.new.find_date_sets(t_start, t_end, :hour, true)
29
+ result[0][:add].should == ["2010082818", "2010082819", "2010082820", "2010082821", "2010082822"]
30
+ result[0][:rem].should == []
31
+ result.should == Redisrank::Finder::DateSet.new(t_start, t_end, nil, :hour)
32
+
33
+ t_end = t_start + 4.days
34
+ result = Redisrank::Finder::DateSet.new.find_date_sets(t_start, t_end, :day, true)
35
+ result[0][:add].should == ["20100828", "20100829", "20100830", "20100831", "20100901"]
36
+ result[0][:rem].should == []
37
+ result.should == Redisrank::Finder::DateSet.new(t_start, t_end, nil, :day)
38
+ end
39
+
40
+ it "should find start keys properly" do
41
+
42
+ #
43
+ # Simple fetching
44
+ # Dates: 22:54, 26th August, 2010 --> 22:52, 14th December, 2010
45
+ #
46
+
47
+ t_start = Time.utc(2010, 8, 26, 22, 54, 57)
48
+ t_end = Time.utc(2013, 12, 14, 22, 52, 3)
49
+
50
+ result = @finder.send(:find_start_keys_for, :sec, t_start, t_end)
51
+ result[:add].should == ["20100826225458", "20100826225459"]
52
+ result[:rem].should == []
53
+
54
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end)
55
+ result[:add].should == ["201008262255", "201008262256", "201008262257", "201008262258", "201008262259"]
56
+ result[:rem].should == []
57
+
58
+ result = @finder.send(:find_start_keys_for, :hour, t_start, t_end)
59
+ result[:add].should == ["2010082623"]
60
+ result[:rem].should == []
61
+
62
+ result = @finder.send(:find_start_keys_for, :day, t_start, t_end)
63
+ result[:add].should == ["20100827", "20100828", "20100829", "20100830", "20100831"]
64
+ result[:rem].should == []
65
+
66
+ result = @finder.send(:find_start_keys_for, :month, t_start, t_end)
67
+ result[:add].should == ["201009", "201010", "201011", "201012"]
68
+ result[:rem].should == []
69
+
70
+ result = @finder.send(:find_start_keys_for, :year, t_start, t_end)
71
+ result[:add].should == ["2011", "2012"]
72
+ result[:rem].should == []
73
+
74
+ #
75
+ # Reverse / Inteligent fetching
76
+ # Dates: 5:06, 4th April, 2010 --> 22:52, 14th February, 2011
77
+ #
78
+
79
+ t_start = Time.utc(2010, 4, 4, 5, 6, 4)
80
+ t_end = Time.utc(2011, 2, 14, 22, 52, 3)
81
+
82
+ result = @finder.send(:find_start_keys_for, :sec, t_start, t_end)
83
+ result[:add].should == ["201004040506"]
84
+ result[:rem].should == ["20100404050600", "20100404050601", "20100404050602", "20100404050603", "20100404050604"]
85
+
86
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end)
87
+ result[:add].should == ["2010040405"]
88
+ result[:rem].should == ["201004040500", "201004040501", "201004040502", "201004040503", "201004040504", "201004040505", "201004040506"]
89
+
90
+ result = @finder.send(:find_start_keys_for, :hour, t_start, t_end)
91
+ result[:add].should == ["20100404"]
92
+ result[:rem].should == ["2010040400", "2010040401", "2010040402", "2010040403", "2010040404", "2010040405"]
93
+
94
+ result = @finder.send(:find_start_keys_for, :day, t_start, t_end)
95
+ result[:add].should == ["201004"]
96
+ result[:rem].should == ["20100401", "20100402", "20100403", "20100404"]
97
+
98
+ result = @finder.send(:find_start_keys_for, :month, t_start, t_end)
99
+ result[:add].should == ["2010"]
100
+ result[:rem].should == ["201001", "201002", "201003", "201004"]
101
+
102
+ result = @finder.send(:find_start_keys_for, :year, t_start, t_end)
103
+ result[:add].should == []
104
+ result[:rem].should == []
105
+
106
+ end
107
+
108
+ it "should find end keys properly" do
109
+
110
+ #
111
+ # Simple fetching
112
+ # Dates: 22:04, 26th December, 2007 --> 5:06, 7th May, 2010
113
+ #
114
+
115
+ t_start = Time.utc(2007, 12, 26, 22, 4, 4)
116
+ t_end = Time.utc(2010, 5, 7, 5, 6, 3)
117
+
118
+ result = @finder.send(:find_end_keys_for, :sec, t_start, t_end)
119
+ result[:add].should == ["20100507050600", "20100507050601", "20100507050602"]
120
+ result[:rem].should == []
121
+
122
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end)
123
+ result[:add].should == ["201005070500", "201005070501", "201005070502", "201005070503", "201005070504", "201005070505"]
124
+ result[:rem].should == []
125
+
126
+ result = @finder.send(:find_end_keys_for, :hour, t_start, t_end)
127
+ result[:add].should == ["2010050700", "2010050701", "2010050702", "2010050703", "2010050704"]
128
+ result[:rem].should == []
129
+
130
+ result = @finder.send(:find_end_keys_for, :day, t_start, t_end)
131
+ result[:add].should == ["20100501", "20100502", "20100503", "20100504", "20100505", "20100506"]
132
+ result[:rem].should == []
133
+
134
+ result = @finder.send(:find_end_keys_for, :month, t_start, t_end)
135
+ result[:add].should == ["201001", "201002", "201003", "201004"]
136
+ result[:rem].should == []
137
+
138
+ result = @finder.send(:find_end_keys_for, :year, t_start, t_end)
139
+ result[:add].should == []
140
+ result[:rem].should == []
141
+
142
+ #
143
+ # Reverse / Inteligent fetching
144
+ # Dates: 22:04, 26th December, 2009 --> 22:56, 27th October, 2010
145
+ #
146
+
147
+ t_start = Time.utc(2009, 12, 26, 22, 4, 4)
148
+ t_end = Time.utc(2010, 10, 27, 22, 56, 57)
149
+
150
+ result = @finder.send(:find_end_keys_for, :sec, t_start, t_end)
151
+ result[:add].should == ["201010272256"]
152
+ result[:rem].should == ["20101027225657", "20101027225658", "20101027225659"]
153
+
154
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end)
155
+ result[:add].should == ["2010102722"]
156
+ result[:rem].should == ["201010272256", "201010272257", "201010272258", "201010272259"]
157
+
158
+ result = @finder.send(:find_end_keys_for, :hour, t_start, t_end)
159
+ result[:add].should == ["20101027"]
160
+ result[:rem].should == ["2010102722", "2010102723"]
161
+
162
+ result = @finder.send(:find_end_keys_for, :day, t_start, t_end)
163
+ result[:add].should == ["201010"]
164
+ result[:rem].should == ["20101027", "20101028", "20101029", "20101030", "20101031"]
165
+
166
+ result = @finder.send(:find_end_keys_for, :month, t_start, t_end)
167
+ result[:add].should == ["2010"]
168
+ result[:rem].should == ["201010", "201011", "201012"]
169
+
170
+ result = @finder.send(:find_end_keys_for, :year, t_start, t_end)
171
+ result[:add].should == []
172
+ result[:rem].should == []
173
+
174
+ end
175
+
176
+ it "should fetch start/end keys with limits" do
177
+
178
+ #
179
+ # Simple fetching with Limits
180
+ #
181
+
182
+ # seconds
183
+ t_start = Time.utc(2010, 8, 26, 20, 54, 45)
184
+ t_end = t_start + 4.seconds
185
+
186
+ result = @finder.send(:find_start_keys_for, :sec, t_start, t_end)
187
+ result[:add].should == ["20100826205446", "20100826205447", "20100826205448"]
188
+ result[:rem].should == []
189
+
190
+ result = @finder.send(:find_end_keys_for, :sec, t_start, t_end)
191
+ result[:add].should == []
192
+ result[:rem].should == []
193
+
194
+ t_start = Time.utc(2010, 8, 26, 20, 54, 4)
195
+ t_end = t_start + 4.seconds
196
+
197
+ result = @finder.send(:find_start_keys_for, :sec, t_start, t_end)
198
+ result[:add].should == ["20100826205405", "20100826205406", "20100826205407"]
199
+ result[:rem].should == []
200
+
201
+ result = @finder.send(:find_end_keys_for, :sec, t_start, t_end)
202
+ result[:add].should == []
203
+ result[:rem].should == []
204
+
205
+ # minutes
206
+ t_start = Time.utc(2010, 8, 26, 20, 54)
207
+ t_end = t_start + 4.minutes
208
+
209
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end)
210
+ result[:add].should == ["201008262055", "201008262056", "201008262057"]
211
+ result[:rem].should == []
212
+
213
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end)
214
+ result[:add].should == []
215
+ result[:rem].should == []
216
+
217
+ t_start = Time.utc(2010, 8, 26, 20, 4)
218
+ t_end = t_start + 4.minutes
219
+
220
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end)
221
+ result[:add].should == ["201008262005", "201008262006", "201008262007"]
222
+ result[:rem].should == []
223
+
224
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end)
225
+ result[:add].should == []
226
+ result[:rem].should == []
227
+
228
+ # hours
229
+ t_start = Time.utc(2010, 8, 26, 20, 54)
230
+ t_end = t_start + 2.hours
231
+
232
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end)
233
+ result[:add].should == ["201008262055", "201008262056", "201008262057", "201008262058", "201008262059"]
234
+ result[:rem].should == []
235
+
236
+ result = @finder.send(:find_start_keys_for, :hour, t_start, t_end)
237
+ result[:add].should == ["2010082621"]
238
+ result[:rem].should == []
239
+
240
+ result = @finder.send(:find_end_keys_for, :hour, t_start, t_end)
241
+ result[:add].should == []
242
+ result[:rem].should == []
243
+
244
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end)
245
+ result[:add].should == ["2010082622"]
246
+ result[:rem].should == ["201008262254", "201008262255", "201008262256", "201008262257", "201008262258", "201008262259"]
247
+
248
+ t_start = Time.utc(2010, 8, 26, 4, 54)
249
+ t_end = t_start + 5.hours
250
+
251
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end)
252
+ result[:add].should == ["201008260455", "201008260456", "201008260457", "201008260458", "201008260459"]
253
+ result[:rem].should == []
254
+
255
+ result = @finder.send(:find_start_keys_for, :hour, t_start, t_end)
256
+ result[:add].should == ["2010082605", "2010082606", "2010082607", "2010082608"]
257
+ result[:rem].should == []
258
+
259
+ result = @finder.send(:find_end_keys_for, :hour, t_start, t_end)
260
+ result[:add].should == []
261
+ result[:rem].should == []
262
+
263
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end)
264
+ result[:add].should == ["2010082609"]
265
+ result[:rem].should == ["201008260954", "201008260955", "201008260956", "201008260957", "201008260958", "201008260959"]
266
+
267
+ # days
268
+ t_start = Time.utc(2010, 8, 26, 20, 54)
269
+ t_end = t_start + 2.day
270
+
271
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end)
272
+ result[:add].should == ["201008262055", "201008262056", "201008262057", "201008262058", "201008262059"]
273
+ result[:rem].should == []
274
+
275
+ result = @finder.send(:find_start_keys_for, :hour, t_start, t_end)
276
+ result[:add].should == ["2010082621", "2010082622", "2010082623"]
277
+ result[:rem].should == []
278
+
279
+ result = @finder.send(:find_start_keys_for, :day, t_start, t_end)
280
+ result[:add].should == ["20100827"]
281
+ result[:rem].should == []
282
+
283
+ result = @finder.send(:find_end_keys_for, :day, t_start, t_end)
284
+ result[:add].should == []
285
+ result[:rem].should == []
286
+
287
+ result = @finder.send(:find_end_keys_for, :hour, t_start, t_end)
288
+ result[:add].should == ["20100828"]
289
+ result[:rem].should == ["2010082820", "2010082821", "2010082822", "2010082823"]
290
+
291
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end)
292
+ result[:add].should == ["2010082820"]
293
+ result[:rem].should == ["201008282054", "201008282055", "201008282056", "201008282057", "201008282058", "201008282059"]
294
+
295
+ t_start = Time.utc(2010, 8, 6, 20, 54)
296
+ t_end = t_start + 2.day
297
+
298
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end)
299
+ result[:add].should == ["201008062055", "201008062056", "201008062057", "201008062058", "201008062059"]
300
+ result[:rem].should == []
301
+
302
+ result = @finder.send(:find_start_keys_for, :hour, t_start, t_end)
303
+ result[:add].should == ["2010080621", "2010080622", "2010080623"]
304
+ result[:rem].should == []
305
+
306
+ result = @finder.send(:find_start_keys_for, :day, t_start, t_end)
307
+ result[:add].should == ["20100807"]
308
+ result[:rem].should == []
309
+
310
+ result = @finder.send(:find_end_keys_for, :day, t_start, t_end)
311
+ result[:add].should == []
312
+ result[:rem].should == []
313
+
314
+ result = @finder.send(:find_end_keys_for, :hour, t_start, t_end)
315
+ result[:add].should == ["20100808"]
316
+ result[:rem].should == ["2010080820", "2010080821", "2010080822", "2010080823"]
317
+
318
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end)
319
+ result[:add].should == ["2010080820"]
320
+ result[:rem].should == ["201008082054", "201008082055", "201008082056", "201008082057", "201008082058", "201008082059"]
321
+
322
+ # months
323
+ t_start = Time.utc(2010, 8, 26, 20, 54)
324
+ t_end = t_start + 3.months
325
+
326
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end)
327
+ result[:add].should == ["201008262055", "201008262056", "201008262057", "201008262058", "201008262059"]
328
+ result[:rem].should == []
329
+
330
+ result = @finder.send(:find_start_keys_for, :hour, t_start, t_end)
331
+ result[:add].should == ["2010082621", "2010082622", "2010082623"]
332
+ result[:rem].should == []
333
+
334
+ result = @finder.send(:find_start_keys_for, :day, t_start, t_end)
335
+ result[:add].should == ["20100827", "20100828", "20100829", "20100830", "20100831"]
336
+ result[:rem].should == []
337
+
338
+ result = @finder.send(:find_start_keys_for, :month, t_start, t_end)
339
+ result[:add].should == ["201009", "201010"]
340
+ result[:rem].should == []
341
+
342
+ result = @finder.send(:find_end_keys_for, :month, t_start, t_end)
343
+ result[:add].should == []
344
+ result[:rem].should == []
345
+
346
+ result = @finder.send(:find_end_keys_for, :day, t_start, t_end)
347
+ result[:add].should == ["201011"]
348
+ result[:rem].should == ["20101126", "20101127", "20101128", "20101129", "20101130"]
349
+
350
+ result = @finder.send(:find_end_keys_for, :hour, t_start, t_end)
351
+ result[:add].should == ["20101126"]
352
+ result[:rem].should == ["2010112620", "2010112621", "2010112622", "2010112623"]
353
+
354
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end)
355
+ result[:add].should == ["2010112620"]
356
+ result[:rem].should == ["201011262054", "201011262055", "201011262056", "201011262057", "201011262058", "201011262059"]
357
+
358
+ t_start = Time.utc(2010, 4, 26, 20, 54)
359
+ t_end = t_start + 3.months
360
+
361
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end)
362
+ result[:add].should == ["201004262055", "201004262056", "201004262057", "201004262058", "201004262059"]
363
+ result[:rem].should == []
364
+
365
+ result = @finder.send(:find_start_keys_for, :hour, t_start, t_end)
366
+ result[:add].should == ["2010042621", "2010042622", "2010042623"]
367
+ result[:rem].should == []
368
+
369
+ result = @finder.send(:find_start_keys_for, :day, t_start, t_end)
370
+ result[:add].should == ["20100427", "20100428", "20100429", "20100430"]
371
+ result[:rem].should == []
372
+
373
+ result = @finder.send(:find_start_keys_for, :month, t_start, t_end)
374
+ result[:add].should == ["201005", "201006"]
375
+ result[:rem].should == []
376
+
377
+ result = @finder.send(:find_end_keys_for, :month, t_start, t_end)
378
+ result[:add].should == []
379
+ result[:rem].should == []
380
+
381
+ result = @finder.send(:find_end_keys_for, :day, t_start, t_end)
382
+ result[:add].should == ["201007"]
383
+ result[:rem].should == ["20100726", "20100727", "20100728", "20100729", "20100730", "20100731"]
384
+
385
+ result = @finder.send(:find_end_keys_for, :hour, t_start, t_end)
386
+ result[:add].should == ["20100726"]
387
+ result[:rem].should == ["2010072620", "2010072621", "2010072622", "2010072623"]
388
+
389
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end)
390
+ result[:add].should == ["2010072620"]
391
+ result[:rem].should == ["201007262054", "201007262055", "201007262056", "201007262057", "201007262058", "201007262059"]
392
+
393
+ end
394
+
395
+ it "should find inclusive keys on lowest depth" do
396
+
397
+ #
398
+ # Simple start fetching
399
+ # Dates: 22:54, 26th August, 2010 --> 22:52, 14th December, 2010
400
+ #
401
+
402
+ t_start = Time.utc(2010, 8, 26, 22, 54, 57)
403
+ t_end = Time.utc(2013, 12, 14, 22, 52, 3)
404
+
405
+ result = @finder.send(:find_start_keys_for, :sec, t_start, t_end, true)
406
+ result[:add].should == ["20100826225457", "20100826225458", "20100826225459"]
407
+ result[:rem].should == []
408
+
409
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end, true)
410
+ result[:add].should == ["201008262254", "201008262255", "201008262256", "201008262257", "201008262258", "201008262259"]
411
+ result[:rem].should == []
412
+
413
+ result = @finder.send(:find_start_keys_for, :hour, t_start, t_end, true)
414
+ result[:add].should == ["2010082622", "2010082623"]
415
+ result[:rem].should == []
416
+
417
+ result = @finder.send(:find_start_keys_for, :day, t_start, t_end, true)
418
+ result[:add].should == ["20100826", "20100827", "20100828", "20100829", "20100830", "20100831"]
419
+ result[:rem].should == []
420
+
421
+ result = @finder.send(:find_start_keys_for, :month, t_start, t_end, true)
422
+ result[:add].should == ["201008", "201009", "201010", "201011", "201012"]
423
+ result[:rem].should == []
424
+
425
+ result = @finder.send(:find_start_keys_for, :year, t_start, t_end, true)
426
+ result[:add].should == ["2011", "2012", "2013"]
427
+ result[:rem].should == []
428
+
429
+ #
430
+ # Reverse / Inteligent start fetching
431
+ # Dates: 5:06, 4th April, 2010 --> 22:52, 14th February, 2011
432
+ #
433
+
434
+ t_start = Time.utc(2010, 4, 4, 5, 6, 4)
435
+ t_end = Time.utc(2013, 2, 14, 22, 52, 3)
436
+
437
+ result = @finder.send(:find_start_keys_for, :sec, t_start, t_end, true)
438
+ result[:add].should == ["201004040506"]
439
+ result[:rem].should == ["20100404050600", "20100404050601", "20100404050602", "20100404050603"]
440
+
441
+ result = @finder.send(:find_start_keys_for, :min, t_start, t_end, true)
442
+ result[:add].should == ["2010040405"]
443
+ result[:rem].should == ["201004040500", "201004040501", "201004040502", "201004040503", "201004040504", "201004040505"]
444
+
445
+ result = @finder.send(:find_start_keys_for, :hour, t_start, t_end, true)
446
+ result[:add].should == ["20100404"]
447
+ result[:rem].should == ["2010040400", "2010040401", "2010040402", "2010040403", "2010040404"]
448
+
449
+ result = @finder.send(:find_start_keys_for, :day, t_start, t_end, true)
450
+ result[:add].should == ["201004"]
451
+ result[:rem].should == ["20100401", "20100402", "20100403"]
452
+
453
+ result = @finder.send(:find_start_keys_for, :month, t_start, t_end, true)
454
+ result[:add].should == ["2010"]
455
+ result[:rem].should == ["201001", "201002", "201003"]
456
+
457
+ result = @finder.send(:find_start_keys_for, :year, t_start, t_end, true)
458
+ result[:add].should == ["2011", "2012", "2013"]
459
+ result[:rem].should == []
460
+
461
+ #
462
+ # Simple fetching
463
+ # Dates: 22:04, 26th December, 2007 --> 5:06, 7th May, 2010
464
+ #
465
+
466
+ t_start = Time.utc(2007, 12, 26, 22, 4, 4)
467
+ t_end = Time.utc(2010, 5, 7, 5, 6, 3)
468
+
469
+ result = @finder.send(:find_end_keys_for, :sec, t_start, t_end, true)
470
+ result[:add].should == ["20100507050600", "20100507050601", "20100507050602", "20100507050603"]
471
+ result[:rem].should == []
472
+
473
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end, true)
474
+ result[:add].should == ["201005070500", "201005070501", "201005070502", "201005070503", "201005070504", "201005070505", "201005070506"]
475
+ result[:rem].should == []
476
+
477
+ result = @finder.send(:find_end_keys_for, :hour, t_start, t_end, true)
478
+ result[:add].should == ["2010050700", "2010050701", "2010050702", "2010050703", "2010050704", "2010050705"]
479
+ result[:rem].should == []
480
+
481
+ result = @finder.send(:find_end_keys_for, :day, t_start, t_end, true)
482
+ result[:add].should == ["20100501", "20100502", "20100503", "20100504", "20100505", "20100506", "20100507"]
483
+ result[:rem].should == []
484
+
485
+ result = @finder.send(:find_end_keys_for, :month, t_start, t_end, true)
486
+ result[:add].should == ["201001", "201002", "201003", "201004", "201005"]
487
+ result[:rem].should == []
488
+
489
+ result = @finder.send(:find_end_keys_for, :year, t_start, t_end, true)
490
+ result[:add].should == ["2010"]
491
+ result[:rem].should == []
492
+
493
+ #
494
+ # Reverse / Inteligent fetching
495
+ # Dates: 22:04, 26th December, 2009 --> 22:56, 27th October, 2010
496
+ #
497
+
498
+ t_start = Time.utc(2009, 12, 26, 22, 4, 4)
499
+ t_end = Time.utc(2010, 10, 27, 22, 56, 57)
500
+
501
+ result = @finder.send(:find_end_keys_for, :sec, t_start, t_end, true)
502
+ result[:add].should == ["201010272256"]
503
+ result[:rem].should == ["20101027225658", "20101027225659"]
504
+
505
+ result = @finder.send(:find_end_keys_for, :min, t_start, t_end, true)
506
+ result[:add].should == ["2010102722"]
507
+ result[:rem].should == ["201010272257", "201010272258", "201010272259"]
508
+
509
+ result = @finder.send(:find_end_keys_for, :hour, t_start, t_end, true)
510
+ result[:add].should == ["20101027"]
511
+ result[:rem].should == ["2010102723"]
512
+
513
+ result = @finder.send(:find_end_keys_for, :day, t_start, t_end, true)
514
+ result[:add].should == ["201010"]
515
+ result[:rem].should == ["20101028", "20101029", "20101030", "20101031"]
516
+
517
+ result = @finder.send(:find_end_keys_for, :month, t_start, t_end, true)
518
+ result[:add].should == ["2010"]
519
+ result[:rem].should == ["201011", "201012"]
520
+
521
+ result = @finder.send(:find_end_keys_for, :year, t_start, t_end, true)
522
+ result[:add].should == ["2010"]
523
+ result[:rem].should == []
524
+
525
+ end
526
+
527
+ end