eurydice 1.2.3-java → 1.2.4-java

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.
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm --create use jruby-1.6.5@eurydice
1
+ rvm --create use jruby-1.7.2@eurydice
data/.travis.yml ADDED
@@ -0,0 +1,18 @@
1
+ language: ruby
2
+ script: 'rspec spec'
3
+ rvm:
4
+ # - jruby-19mode
5
+ - jruby-head
6
+ jdk:
7
+ - openjdk7
8
+ # - oraclejdk7
9
+ # - openjdk6
10
+ services:
11
+ - cassandra
12
+ before_script:
13
+ - 'cat /etc/cassandra/cassandra.yaml'
14
+ - 'cat /etc/init.d/cassandra'
15
+ - 'cat /usr/local/cassandra/conf/log4j-server.properties'
16
+ - 'cat /var/log/cassandra/system.log'
17
+ - '/etc/init.d/cassandra status'
18
+ - 'CASSANDRA_CONF=/etc/cassandra /usr/local/cassandra/bin/nodetool status'
data/Gemfile CHANGED
@@ -5,5 +5,5 @@ gemspec
5
5
  group :development do
6
6
  gem 'jruby-openssl'
7
7
  gem 'rake'
8
- gem 'rspec', '2.7.0' # 2.8.0 doesn't work with JRuby because of JRUBY-6324
8
+ gem 'rspec'
9
9
  end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- eurydice (1.2.3-java)
4
+ eurydice (1.2.4-java)
5
5
  pelops-jars (>= 1.3.0)
6
6
 
7
7
  GEM
@@ -15,14 +15,14 @@ GEM
15
15
  pelops-jars (1.3.0-java)
16
16
  cassandra-jars (~> 1.0.0)
17
17
  rake (0.9.2)
18
- rspec (2.7.0)
19
- rspec-core (~> 2.7.0)
20
- rspec-expectations (~> 2.7.0)
21
- rspec-mocks (~> 2.7.0)
22
- rspec-core (2.7.1)
23
- rspec-expectations (2.7.0)
24
- diff-lcs (~> 1.1.2)
25
- rspec-mocks (2.7.0)
18
+ rspec (2.12.0)
19
+ rspec-core (~> 2.12.0)
20
+ rspec-expectations (~> 2.12.0)
21
+ rspec-mocks (~> 2.12.0)
22
+ rspec-core (2.12.2)
23
+ rspec-expectations (2.12.1)
24
+ diff-lcs (~> 1.1.3)
25
+ rspec-mocks (2.12.1)
26
26
 
27
27
  PLATFORMS
28
28
  java
@@ -31,4 +31,4 @@ DEPENDENCIES
31
31
  eurydice!
32
32
  jruby-openssl
33
33
  rake
34
- rspec (= 2.7.0)
34
+ rspec
data/README.mdown CHANGED
@@ -6,10 +6,10 @@ See the `examples` directory and the specs for usage.
6
6
 
7
7
  ## Installation & requirements
8
8
 
9
- Tested with JRuby 1.6.2 in 1.9 mode and Cassandra 0.8.1.
9
+ Tested with the latest 1.6.x and 1.7.x versions of JRuby, against the current Datastax Community Edition (1.2.x) [on Travis](https://travis-ci.org/iconara/eurydice).
10
10
 
11
11
  gem install eurydice
12
-
12
+
13
13
  This will also install two dependencies: `pelops-jars` and `cassandra-jars` which contain the Pelops and Cassandra JAR files.
14
14
 
15
15
  ## Contributors
data/Rakefile CHANGED
@@ -1,6 +1,11 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'bundler'
4
+ require 'rspec/core/rake_task'
4
5
 
5
6
 
6
7
  Bundler::GemHelper.install_tasks
8
+
9
+ RSpec::Core::RakeTask.new(:spec)
10
+
11
+ task :default => :spec
data/lib/cassandra.rb CHANGED
@@ -28,14 +28,26 @@ module Cassandra
28
28
  }.freeze
29
29
 
30
30
  MARSHAL_TYPES = {
31
- :bytes => 'org.apache.cassandra.db.marshal.BytesType'.freeze,
32
- :ascii => 'org.apache.cassandra.db.marshal.AsciiType'.freeze,
33
- :utf8 => 'org.apache.cassandra.db.marshal.UTF8Type'.freeze,
34
- :long => 'org.apache.cassandra.db.marshal.LongType'.freeze,
35
- :lexical_uuid => 'org.apache.cassandra.db.marshal.LexicalUUIDType'.freeze,
36
- :time_uuid => 'org.apache.cassandra.db.marshal.TimeUUIDType'.freeze,
37
- :counter => 'org.apache.cassandra.db.marshal.CounterColumnType'.freeze,
38
- :counter_column => 'org.apache.cassandra.db.marshal.CounterColumnType'.freeze
31
+ :ascii => 'org.apache.cassandra.db.marshal.AsciiType'.freeze,
32
+ :boolean => 'org.apache.cassandra.db.marshal.BooleanType'.freeze,
33
+ :bytes => 'org.apache.cassandra.db.marshal.BytesType'.freeze,
34
+ :composite => 'org.apache.cassandra.db.marshal.CompositeType'.freeze,
35
+ :counter => 'org.apache.cassandra.db.marshal.CounterColumnType'.freeze,
36
+ :counter_column => 'org.apache.cassandra.db.marshal.CounterColumnType'.freeze,
37
+ :date => 'org.apache.cassandra.db.marshal.DateType'.freeze,
38
+ :decimal => 'org.apache.cassandra.db.marshal.DecimalType'.freeze,
39
+ :double => 'org.apache.cassandra.db.marshal.DoubleType'.freeze,
40
+ :dynamic_composite => 'org.apache.cassandra.db.marshal.DynamicCompositeType'.freeze,
41
+ :float => 'org.apache.cassandra.db.marshal.FloatType'.freeze,
42
+ :int32 => 'org.apache.cassandra.db.marshal.Int32Type'.freeze,
43
+ :int => 'org.apache.cassandra.db.marshal.IntegerType'.freeze,
44
+ :integer => 'org.apache.cassandra.db.marshal.IntegerType'.freeze,
45
+ :lexical_uuid => 'org.apache.cassandra.db.marshal.LexicalUUIDType'.freeze,
46
+ :long => 'org.apache.cassandra.db.marshal.LongType'.freeze,
47
+ :reversed => 'org.apache.cassandra.db.marshal.ReversedType'.freeze,
48
+ :time_uuid => 'org.apache.cassandra.db.marshal.TimeUUIDType'.freeze,
49
+ :utf8 => 'org.apache.cassandra.db.marshal.UTF8Type'.freeze,
50
+ :uuid => 'org.apache.cassandra.db.marshal.UUIDType'.freeze
39
51
  }.freeze
40
52
 
41
53
  INDEX_OPERATORS = {
data/lib/eurydice.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'java'
3
+ require 'eurydice/column_enumerator'
4
+ require 'eurydice/column_page'
4
5
  require 'eurydice/pelops'
5
6
 
6
7
  module Eurydice
7
8
  class EurydiceError < StandardError; end
9
+ class ConnectionError < EurydiceError; end
8
10
  class InvalidRequestError < EurydiceError; end
9
11
  class KeyspaceExistsError < InvalidRequestError; end
10
12
  class NotFoundError < EurydiceError; end
@@ -0,0 +1,110 @@
1
+ # encoding: utf-8
2
+
3
+ module Eurydice
4
+ class ColumnEnumeratorBase
5
+ include Enumerable
6
+
7
+ def initialize(column_family, row_key, options={})
8
+ @column_family, @row_key, @options = column_family, row_key, DEFAULT_OPTIONS.merge(options)
9
+ @max_retries = @options.delete(:max_retries)
10
+ end
11
+
12
+ def each
13
+ loop do
14
+ yield self.next
15
+ end
16
+ end
17
+
18
+ def rewind
19
+ end
20
+
21
+ private
22
+
23
+ FIRST_KEY = "\0".freeze
24
+ LAST_KEY = ''.freeze
25
+ DEFAULT_OPTIONS = {:max_column_count => 10_000, :max_retries => 3}.freeze
26
+ end
27
+
28
+ class ColumnEnumerator < ColumnEnumeratorBase
29
+ def initialize(*args)
30
+ super
31
+ rewind
32
+ end
33
+
34
+ def next
35
+ if @buffer.empty? && @exhausted
36
+ raise StopIteration
37
+ elsif @buffer.empty?
38
+ result = @column_family.get(@row_key, @options.merge(from_column: @offset))
39
+ keys = result.keys if result
40
+ if result.nil? || result.empty? || keys.last == @offset
41
+ @exhausted = true
42
+ raise StopIteration
43
+ end
44
+ result.shift if keys.first == @offset
45
+ result.each do |pair|
46
+ @buffer << pair
47
+ end
48
+ @offset = keys.last
49
+ end
50
+ @buffer.shift
51
+ end
52
+
53
+ def rewind
54
+ @offset = @options[:from_column] || (@options[:reversed] ? LAST_KEY : FIRST_KEY)
55
+ @reversed = @options[:reversed]
56
+ @buffer = []
57
+ @exhausted = false
58
+ end
59
+ end
60
+
61
+ class ConcurrentColumnEnumerator < ColumnEnumeratorBase
62
+ java_import 'java.util.concurrent.Executors'
63
+ java_import 'java.util.concurrent.ArrayBlockingQueue'
64
+ java_import 'java.util.concurrent.atomic.AtomicBoolean'
65
+ java_import 'org.jruby.threading.DaemonThreadFactory'
66
+
67
+ def initialize(*args)
68
+ super
69
+ @standard_enumerator = ColumnEnumerator.new(*args)
70
+ @queue = ArrayBlockingQueue.new(@options[:max_column_count] * 2)
71
+ @fetch_pool = Executors.new_single_thread_executor(DaemonThreadFactory.new(self.class.name))
72
+ @exhausted = true
73
+ rewind
74
+ end
75
+
76
+ def next
77
+ unless @running.get_and_set(true)
78
+ @fetch_pool.execute do
79
+ begin
80
+ while @running.get
81
+ pair = @standard_enumerator.next
82
+ @queue.put(pair)
83
+ end
84
+ rescue StopIteration
85
+ end
86
+ @queue.put(:stop_iteration)
87
+ end
88
+ end
89
+
90
+ raise StopIteration if @exhausted
91
+
92
+ value = @queue.take
93
+ if value == :stop_iteration
94
+ @exhausted = true
95
+ raise StopIteration
96
+ end
97
+
98
+ value
99
+ end
100
+
101
+ def rewind
102
+ @running = AtomicBoolean.new(false)
103
+ unless @exhausted
104
+ until @queue.take == :stop_iteration; end
105
+ end
106
+ @standard_enumerator.rewind
107
+ @exhausted = false
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,109 @@
1
+ # encoding: utf-8
2
+
3
+ module Eurydice
4
+ class ColumnPage
5
+ include Enumerable
6
+
7
+ attr_reader :page_size
8
+
9
+ def initialize(column_family, row_key, page_size, offset=FIRST_OFFSET)
10
+ @column_family = column_family
11
+ @row_key = row_key
12
+ @offset = offset
13
+ @page_size = page_size
14
+ end
15
+
16
+ def offset
17
+ if @offset == FIRST_OFFSET
18
+ slice.keys.first
19
+ else
20
+ @offset
21
+ end
22
+ end
23
+
24
+ def next_page
25
+ return nil if last?
26
+ ForwardColumnPage.new(@column_family, @row_key, @page_size, next_page_offset)
27
+ end
28
+
29
+ def prev_page
30
+ return nil if first?
31
+ ReverseColumnPage.new(@column_family, @row_key, @page_size, prev_page_offset)
32
+ end
33
+
34
+ def first?
35
+ @offset == FIRST_OFFSET
36
+ end
37
+
38
+ def last?
39
+ slice.size <= @page_size
40
+ end
41
+
42
+ def reverse?
43
+ false
44
+ end
45
+
46
+ def each_column(&block)
47
+ return self unless block_given?
48
+ slice.each.with_index do |item,i|
49
+ yield item if i < @page_size
50
+ end
51
+ end
52
+ alias_method :each, :each_column
53
+
54
+ private
55
+
56
+ def next_page_offset
57
+ slice.keys[-2]
58
+ end
59
+
60
+ def prev_page_offset
61
+ @offset
62
+ end
63
+
64
+ FIRST_OFFSET = "\0".freeze
65
+
66
+ def slice
67
+ @slice ||= @column_family.get(@row_key, from_column: @offset, max_column_count: @page_size + 2, reversed: reverse?)
68
+ end
69
+ end
70
+
71
+ class ForwardColumnPage < ColumnPage
72
+ def first?
73
+ false
74
+ end
75
+ end
76
+
77
+ class ReverseColumnPage < ColumnPage
78
+ def last?
79
+ false
80
+ end
81
+
82
+ def first?
83
+ slice.size <= @page_size + 1
84
+ end
85
+
86
+ def reverse?
87
+ true
88
+ end
89
+
90
+ def each_column(&block)
91
+ return self unless block_given?
92
+ first = slice.size == @page_size + 2 ? 1 : 0
93
+ last = slice.size - 2
94
+ slice.reverse_each.with_index do |item,i|
95
+ yield item if first <= i && i <= last
96
+ end
97
+ end
98
+
99
+ private
100
+
101
+ def next_page_offset
102
+ @offset
103
+ end
104
+
105
+ def prev_page_offset
106
+ slice.keys[-2]
107
+ end
108
+ end
109
+ end
@@ -108,8 +108,14 @@ module Eurydice
108
108
  raise EurydiceError, e.cause.message, e.backtrace
109
109
  when Thrift::TTransportException, ::Pelops::TimedOutException
110
110
  raise TimeoutError, e.cause.message, e.backtrace
111
+ when java.net.ConnectException
112
+ raise ConnectionError, e.cause.message, e.backtrace
111
113
  end
112
114
  end
115
+ case e
116
+ when ::Pelops::NotFoundException
117
+ raise NotFoundError, e.message, e.backtrace
118
+ end
113
119
  raise e
114
120
  end
115
121
 
@@ -113,25 +113,15 @@ module Eurydice
113
113
  nil
114
114
  end
115
115
 
116
- def each_column(row_key, options={})
117
- thrift_exception_handler do
118
- reversed = options.fetch(:reversed, false)
119
- batch_size = options.fetch(:batch_size, 100)
120
- start_beyond = options.fetch(:start_beyond, nil)
121
- start_beyond = to_pelops_bytes(start_beyond) if start_beyond
122
- selector = @keyspace.create_selector
123
- iterator = selector.iterate_columns_from_row(@name, to_pelops_bytes(row_key), start_beyond, reversed, batch_size, get_cl(options))
124
- if block_given?
125
- iterator.each do |column|
126
- yield column_to_kv(column, options)
127
- end
128
- else
129
- Enumerator.new do |y|
130
- iterator.each do |column|
131
- y << column_to_kv(column, options)
132
- end
133
- end
134
- end
116
+ def each_column(row_key, options={}, &block)
117
+ new_options = options.dup
118
+ new_options[:from_column] = options.delete(:start_beyond) if options.key?(:start_beyond)
119
+ new_options[:max_column_count] = options.delete(:batch_size) if options.key?(:batch_size)
120
+ enum = ColumnEnumerator.new(self, row_key, new_options)
121
+ if block_given?
122
+ enum.each(&block)
123
+ else
124
+ enum
135
125
  end
136
126
  end
137
127
 
@@ -13,7 +13,7 @@ module Eurydice
13
13
  @cluster = cluster
14
14
  @pool_name = pool_name
15
15
  @driver = driver
16
- @batch_key = "#{@name}-batch"
16
+ @batch_key = "#{@name}-batch-#{object_id}"
17
17
  end
18
18
 
19
19
  def definition(reload=false)
@@ -2,5 +2,5 @@
2
2
 
3
3
 
4
4
  module Eurydice
5
- VERSION = '1.2.3'
5
+ VERSION = '1.2.4'
6
6
  end
@@ -0,0 +1,197 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../spec_helper'
4
+
5
+
6
+ module Eurydice
7
+ class FakeColumnFamily
8
+ def initialize
9
+ end
10
+
11
+ def get(row_key, options)
12
+ if row_key == 'the_row'
13
+ if options[:max_column_count] == 3
14
+ if options[:reversed]
15
+ case options[:from_column]
16
+ when '' then {'g' => 7, 'f' => 6, 'e' => 5}
17
+ when 'e' then {'e' => 5, 'd' => 4, 'c' => 3, 'b' => 2}
18
+ when 'b' then {'b' => 2, 'a' => 1}
19
+ when 'a' then {'a' => 1}
20
+ end
21
+ else
22
+ case options[:from_column]
23
+ when "\0" then {'a' => 1, 'b' => 2, 'c' => 3}
24
+ when 'c' then {'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6}
25
+ when 'f' then {'f' => 6, 'g' => 7}
26
+ when 'g' then {'g' => 7}
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ shared_examples_for 'a column enumerator' do
35
+ let :column_family do
36
+ double(:column_family)
37
+ end
38
+
39
+ context 'as an Enumerator' do
40
+ describe '#next' do
41
+ context 'in the basic case' do
42
+ let :enumerator do
43
+ described_class.new(FakeColumnFamily.new, 'the_row', max_column_count: 3)
44
+ end
45
+
46
+ it 'returns the first column of the row' do
47
+ k, v = enumerator.next
48
+ k.should == 'a'
49
+ v.should == 1
50
+ end
51
+
52
+ it 'returns the second column of the row' do
53
+ enumerator.next
54
+ k, v = enumerator.next
55
+ k.should == 'b'
56
+ v.should == 2
57
+ end
58
+
59
+ it 'returns each column of the row in order' do
60
+ columns = []
61
+ 7.times do
62
+ columns << enumerator.next
63
+ end
64
+ columns = [['a', 1], ['b', 2], ['c', 3], ['d', 4], ['e', 5], ['f', 6], ['g', 7]]
65
+ end
66
+
67
+ it 'raises StopIteration when all columns have been returned' do
68
+ 7.times { enumerator.next }
69
+ expect { enumerator.next }.to raise_error(StopIteration)
70
+ expect { enumerator.next }.to raise_error(StopIteration)
71
+ end
72
+ end
73
+
74
+ context 'when enumerating in reverse' do
75
+ let :enumerator do
76
+ described_class.new(FakeColumnFamily.new, 'the_row', max_column_count: 3, reversed: true)
77
+ end
78
+
79
+ it 'returns the last column of the row' do
80
+ enumerator.next.should == ['g', 7]
81
+ end
82
+
83
+ it 'returns the next to last column of the row' do
84
+ enumerator.next
85
+ enumerator.next.should == ['f', 6]
86
+ end
87
+
88
+ it 'returns each column of the row in reverse order' do
89
+ columns = []
90
+ 7.times do
91
+ columns << enumerator.next
92
+ end
93
+ columns = [['g', 7], ['f', 6], ['e', 5], ['d', 4], ['c', 3], ['b', 2], ['a', 1]]
94
+ end
95
+
96
+ it 'raises StopIteration when all column have been returned' do
97
+ 7.times { enumerator.next }
98
+ expect { enumerator.next }.to raise_error(StopIteration)
99
+ expect { enumerator.next }.to raise_error(StopIteration)
100
+ end
101
+ end
102
+
103
+ context 'with special cases' do
104
+ let :enumerator do
105
+ described_class.new(column_family, 'the_row', max_column_count: 3)
106
+ end
107
+
108
+ let :slices do
109
+ [
110
+ {'a' => 1, 'b' => 2, 'c' => 3},
111
+ {'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6},
112
+ {'f' => 6, 'g' => 7},
113
+ {'g' => 7},
114
+ ]
115
+ end
116
+
117
+ it 'raises StopIteration immediately if the row does not exist' do
118
+ column_family.stub(:get).and_return(nil)
119
+ enumerator = described_class.new(column_family, 'another_row')
120
+ expect { enumerator.next }.to raise_error(StopIteration)
121
+ end
122
+
123
+ it 'raises StopIteration immediately if the row is empty' do
124
+ column_family.stub(:get).and_return({})
125
+ enumerator = described_class.new(column_family, 'another_row')
126
+ expect { enumerator.next }.to raise_error(StopIteration)
127
+ end
128
+
129
+ it 'correctly handles rows with columns that are exactly the page size' do
130
+ column_family.stub(:get).with('another_row', max_column_count: 3, from_column: "\0").and_return(slices[0].dup)
131
+ column_family.stub(:get).with('another_row', max_column_count: 3, from_column: 'c').and_return({'c' => 3})
132
+ enumerator = described_class.new(column_family, 'another_row', max_column_count: 3)
133
+ 3.times { enumerator.next }
134
+ expect { enumerator.next }.to raise_error(StopIteration)
135
+ end
136
+
137
+ it 'correctly handles rows with columns that are less then one page' do
138
+ column_family.stub(:get).with('another_row', max_column_count: 3, from_column: "\0").and_return({'a' => 1, 'b' => 2})
139
+ column_family.stub(:get).with('another_row', max_column_count: 3, from_column: 'b').and_return({'b' => 2})
140
+ enumerator = described_class.new(column_family, 'another_row', max_column_count: 3)
141
+ 2.times { enumerator.next }
142
+ expect { enumerator.next }.to raise_error(StopIteration)
143
+ end
144
+ end
145
+
146
+ context 'with a transformer'
147
+ context 'with query options'
148
+ context 'when transport errors occur'
149
+ end
150
+
151
+ describe '#rewind' do
152
+ let :enumerator do
153
+ described_class.new(FakeColumnFamily.new, 'the_row', max_column_count: 3)
154
+ end
155
+
156
+ it 'resets the enumerator so that it can be used again' do
157
+ first_results = 7.times.map { enumerator.next }
158
+ enumerator.rewind
159
+ second_results = 7.times.map { enumerator.next }
160
+ first_results.should == second_results
161
+ end
162
+ end
163
+ end
164
+
165
+ context 'as an Enumerable' do
166
+ let :enumerable do
167
+ described_class.new(FakeColumnFamily.new, 'the_row', max_column_count: 3)
168
+ end
169
+
170
+ describe '#each' do
171
+ it 'returns each column of the row in order' do
172
+ columns = []
173
+ enumerable.each do |k, v|
174
+ columns << [k, v]
175
+ end
176
+ columns = [['a', 1], ['b', 2], ['c', 3], ['d', 4], ['e', 5], ['f', 6], ['g', 7]]
177
+ end
178
+ end
179
+
180
+ describe '#map' do
181
+ it 'returns each column of the row in order' do
182
+ columns = []
183
+ columns = enumerable.map { |k, v| v }
184
+ columns = [1, 2, 3, 4, 5, 6, 7]
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ describe ColumnEnumerator do
191
+ it_behaves_like 'a column enumerator'
192
+ end
193
+
194
+ describe ConcurrentColumnEnumerator do
195
+ it_behaves_like 'a column enumerator'
196
+ end
197
+ end
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../spec_helper'
4
+
5
+
6
+ module Eurydice
7
+ describe ColumnPage do
8
+ before :all do
9
+ @keyspace_name = "eurydice_test_space_#{rand(1000)}"
10
+ @cf_name = "column_family_#{rand(1000)}"
11
+ @cluster = Eurydice.connect(host: ENV['CASSANDRA_HOST'])
12
+ @keyspace = @cluster.keyspace(@keyspace_name, :create => false)
13
+ @keyspace.drop! rescue nil
14
+ @keyspace.create!
15
+ end
16
+
17
+ let :column_family do
18
+ cf = @keyspace.column_family(@cf_name)
19
+ cf.insert('xyz', {'a' => '1', 'b' => '2', 'c' => '3', 'd' => '4', 'e' => '5', 'f' => '6', 'g' => '7', 'h' => '8'})
20
+ cf
21
+ end
22
+
23
+ describe '#next_page' do
24
+ it 'returns a new page with the correct offset' do
25
+ page = described_class.new(column_family, 'xyz', 3)
26
+ page.next_page.offset.should == 'd'
27
+ end
28
+
29
+ it 'returns a new page with the same page size' do
30
+ page = described_class.new(column_family, 'xyz', 3)
31
+ page.next_page.page_size.should == 3
32
+ end
33
+
34
+ it 'returns nil if there is no next page' do
35
+ page = described_class.new(column_family, 'xyz', 6)
36
+ page.next_page.next_page.should be_nil
37
+ end
38
+
39
+ it 'picks the right offsets when paging through the row' do
40
+ page = described_class.new(column_family, 'xyz', 3)
41
+ offsets = []
42
+ loop do
43
+ offsets << page.offset
44
+ page = page.next_page
45
+ break unless page
46
+ end
47
+ offsets.should == ['a','d','g']
48
+ end
49
+ end
50
+
51
+ describe '#prev_page' do
52
+ it 'returns a reverse page' do
53
+ page = described_class.new(column_family, 'xyz', 3).next_page
54
+ page.prev_page.should be_reverse
55
+ end
56
+
57
+ it 'returns a new page with the correct offset' do
58
+ page = described_class.new(column_family, 'xyz', 3).next_page
59
+ page.prev_page.offset.should == 'd'
60
+ end
61
+
62
+ it 'returns a new page with the same page size' do
63
+ page = described_class.new(column_family, 'xyz', 3).next_page
64
+ page.prev_page.page_size.should == 3
65
+ end
66
+
67
+ it 'returns nil if there is no previous page' do
68
+ page = described_class.new(column_family, 'xyz', 3)
69
+ page.prev_page.should be_nil
70
+ end
71
+
72
+ it 'picks the right offsets when paging through the row' do
73
+ page = described_class.new(column_family, 'xyz', 3)
74
+ page = page.next_page until page.last?
75
+ offsets = []
76
+ loop do
77
+ offsets << page.offset
78
+ page = page.prev_page
79
+ break unless page
80
+ end
81
+ offsets.should == ['g','g','d']
82
+ end
83
+ end
84
+
85
+ context 'navigating back and forth' do
86
+ it 'next + prev + next == next' do
87
+ page = described_class.new(column_family, 'xyz', 3)
88
+ page.next_page.prev_page.next_page.offset.should == 'd'
89
+ end
90
+ end
91
+
92
+ context 'with edge cases' do
93
+ it 'handles the case when row size is divisible by page size' do
94
+ [2,4,8].each do |page_size|
95
+ expected_page_count = 8/page_size
96
+ page = described_class.new(column_family, 'xyz', page_size)
97
+ page_count = 1
98
+ until page.last?
99
+ page = page.next_page
100
+ page_count += 1
101
+ page_count.should_not > expected_page_count
102
+ end
103
+ page_count.should == expected_page_count
104
+
105
+ page_count = 1
106
+ until page.first?
107
+ page = page.prev_page
108
+ page_count += 1
109
+ page_count.should_not > expected_page_count
110
+ end
111
+ page_count.should == expected_page_count
112
+ end
113
+ end
114
+
115
+ it 'handles the case when previous page is short' do
116
+ items = []
117
+ described_class.new(column_family, 'xyz', 3, 'b').prev_page.each_column do |key,value|
118
+ items << [key,value]
119
+ end
120
+ items.should == [%w[a 1]]
121
+ end
122
+ end
123
+
124
+ describe '#each_column' do
125
+ it 'yields every item in page' do
126
+ items = []
127
+ described_class.new(column_family, 'xyz', 3).each_column do |key,value|
128
+ items << [key,value]
129
+ end
130
+ items.should == [%w[a 1], %w[b 2], %w[c 3]]
131
+ end
132
+
133
+ it 'returns an enumerable unless block is given' do
134
+ enum = described_class.new(column_family, 'xyz', 3).each_column
135
+ enum.map { |k,v| v }.should == %w[1 2 3]
136
+ end
137
+ end
138
+ end
139
+ end
@@ -5,7 +5,7 @@ module Eurydice
5
5
  module Pelops
6
6
  describe Cluster do
7
7
  before :all do
8
- @cluster = Eurydice.connect
8
+ @cluster = Eurydice.connect(host: ENV['CASSANDRA_HOST'])
9
9
  end
10
10
 
11
11
  it_behaves_like 'Cluster', @cluster
@@ -7,7 +7,7 @@ module Eurydice
7
7
  before :all do
8
8
  @keyspace_name = "eurydice_test_space_#{rand(1000)}"
9
9
  @cf_name = "column_family_#{rand(1000)}"
10
- @cluster = Eurydice.connect
10
+ @cluster = Eurydice.connect(host: ENV['CASSANDRA_HOST'])
11
11
  @keyspace = @cluster.keyspace(@keyspace_name, :create => false)
12
12
  @keyspace.drop! rescue nil
13
13
  @keyspace.create!
@@ -6,7 +6,7 @@ module Eurydice
6
6
  describe Keyspace do
7
7
  before :all do
8
8
  @keyspace_name = "eurydice_test_space_#{rand(1000)}"
9
- @cluster = Eurydice.connect
9
+ @cluster = Eurydice.connect(host: ENV['CASSANDRA_HOST'])
10
10
  if @cluster.keyspaces.include?(@keyspace_name)
11
11
  @cluster.keyspace(@keyspace_name).drop!
12
12
  end
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,8 @@ $: << File.expand_path('../../lib', __FILE__)
3
3
  require 'bundler/setup'
4
4
  require 'eurydice/pelops'
5
5
 
6
+ ENV['CASSANDRA_HOST'] ||= 'localhost'
7
+
6
8
  require_relative 'eurydice/support/cluster'
7
9
  require_relative 'eurydice/support/column_family'
8
10
  require_relative 'eurydice/support/keyspace'
metadata CHANGED
@@ -1,94 +1,104 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: eurydice
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 1.2.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.4
5
+ prerelease:
6
6
  platform: java
7
- authors:
8
- - Theo Hultberg
9
- autorequire:
7
+ authors:
8
+ - Theo Hultberg
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2012-12-31 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: pelops-jars
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
19
- none: false
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 1.3.0
24
- type: :runtime
25
- version_requirements: *id001
26
- description: ""
27
- email:
28
- - theo@burtcorp.com
12
+ date: 2013-05-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: pelops-jars
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 1.3.0
21
+ none: false
22
+ requirement: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.3.0
27
+ none: false
28
+ prerelease: false
29
+ type: :runtime
30
+ description: ''
31
+ email:
32
+ - theo@burtcorp.com
29
33
  executables: []
30
-
31
34
  extensions: []
32
-
33
35
  extra_rdoc_files: []
34
-
35
- files:
36
- - .gitignore
37
- - .rspec
38
- - .rvmrc
39
- - Gemfile
40
- - Gemfile.lock
41
- - README.mdown
42
- - Rakefile
43
- - eurydice.gemspec
44
- - examples/01_connect.rb
45
- - examples/02_create_keyspace.rb
46
- - examples/03_create_column_family.rb
47
- - examples/04_storing_data.rb
48
- - examples/05_loading_data.rb
49
- - examples/06_cluster_info.rb
50
- - examples/common.rb
51
- - lib/cassandra.rb
52
- - lib/eurydice.rb
53
- - lib/eurydice/pelops.rb
54
- - lib/eurydice/pelops/cluster.rb
55
- - lib/eurydice/pelops/column_family.rb
56
- - lib/eurydice/pelops/keyspace.rb
57
- - lib/eurydice/pelops/mutator.rb
58
- - lib/eurydice/version.rb
59
- - spec/eurydice/pelops/cluster_spec.rb
60
- - spec/eurydice/pelops/column_family_spec.rb
61
- - spec/eurydice/pelops/keyspace_spec.rb
62
- - spec/eurydice/support/cluster.rb
63
- - spec/eurydice/support/column_family.rb
64
- - spec/eurydice/support/keyspace.rb
65
- - spec/spec_helper.rb
36
+ files:
37
+ - ".gitignore"
38
+ - ".rspec"
39
+ - ".rvmrc"
40
+ - ".travis.yml"
41
+ - Gemfile
42
+ - Gemfile.lock
43
+ - README.mdown
44
+ - Rakefile
45
+ - eurydice.gemspec
46
+ - examples/01_connect.rb
47
+ - examples/02_create_keyspace.rb
48
+ - examples/03_create_column_family.rb
49
+ - examples/04_storing_data.rb
50
+ - examples/05_loading_data.rb
51
+ - examples/06_cluster_info.rb
52
+ - examples/common.rb
53
+ - lib/cassandra.rb
54
+ - lib/eurydice.rb
55
+ - lib/eurydice/column_enumerator.rb
56
+ - lib/eurydice/column_page.rb
57
+ - lib/eurydice/pelops.rb
58
+ - lib/eurydice/pelops/cluster.rb
59
+ - lib/eurydice/pelops/column_family.rb
60
+ - lib/eurydice/pelops/keyspace.rb
61
+ - lib/eurydice/pelops/mutator.rb
62
+ - lib/eurydice/version.rb
63
+ - spec/eurydice/column_enumerator_spec.rb
64
+ - spec/eurydice/column_page_spec.rb
65
+ - spec/eurydice/pelops/cluster_spec.rb
66
+ - spec/eurydice/pelops/column_family_spec.rb
67
+ - spec/eurydice/pelops/keyspace_spec.rb
68
+ - spec/eurydice/support/cluster.rb
69
+ - spec/eurydice/support/column_family.rb
70
+ - spec/eurydice/support/keyspace.rb
71
+ - spec/spec_helper.rb
66
72
  homepage: http://github.com/iconara/eurydice
67
73
  licenses: []
68
-
69
- post_install_message:
74
+ post_install_message:
70
75
  rdoc_options: []
71
-
72
- require_paths:
73
- - lib
74
- required_ruby_version: !ruby/object:Gem::Requirement
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ version: !binary |-
85
+ MA==
86
+ hash: 2
75
87
  none: false
76
- requirements:
77
- - - ">="
78
- - !ruby/object:Gem::Version
79
- version: "0"
80
- required_rubygems_version: !ruby/object:Gem::Requirement
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ segments:
93
+ - 0
94
+ version: !binary |-
95
+ MA==
96
+ hash: 2
81
97
  none: false
82
- requirements:
83
- - - ">="
84
- - !ruby/object:Gem::Version
85
- version: "0"
86
98
  requirements: []
87
-
88
99
  rubyforge_project: eurydice
89
- rubygems_version: 1.8.9
90
- signing_key:
100
+ rubygems_version: 1.8.24
101
+ signing_key:
91
102
  specification_version: 3
92
103
  summary: Ruby wrapper for the Pelops library
93
104
  test_files: []
94
-