redisrank 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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