cassandra 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ v0.11.0
2
+ - Remove direct thrift dependency. Allow thrift_client to require it.
3
+ - Add functions for each and each_key to iterate through key ranges.
4
+ - Add function for get_range_keys which returns an array of keys in a given range.
5
+ - Changed the return value of get_range to an OrderedHash.
6
+ - Change get_range to accept both a range of keys and a range of columns.
7
+ - Add batched range support to get_range and add get_range_batch.
8
+
1
9
  v0.10.0 Major Update (rjackson)
2
10
  - Update Rakefile to install 0.6.13, 0.7.4, 0.8.0-beta1 to ~/cassandra/cassandra-VERSION
3
11
  - Add data:load task to Rakefile for creating the schema required for the tests
data/Rakefile CHANGED
@@ -42,10 +42,7 @@ def setup_cassandra_version(version = CASSANDRA_VERSION)
42
42
  end
43
43
  end
44
44
 
45
- desc "Start Cassandra"
46
- task :cassandra => :java do
47
- setup_cassandra_version
48
-
45
+ def setup_environment
49
46
  env = ""
50
47
  if !ENV["CASSANDRA_INCLUDE"]
51
48
  env << "CASSANDRA_INCLUDE=#{File.expand_path(Dir.pwd)}/conf/#{CASSANDRA_VERSION}/cassandra.in.sh "
@@ -57,13 +54,26 @@ task :cassandra => :java do
57
54
  env << "CASSANDRA_CONF=#{ENV['CASSANDRA_CONF']}"
58
55
  end
59
56
 
60
- puts env
57
+ env
58
+ end
59
+
60
+ desc "Start Cassandra"
61
+ task :cassandra => :java do
62
+ setup_cassandra_version
63
+
64
+ env = setup_environment
61
65
 
62
66
  Dir.chdir(File.join(CASSANDRA_HOME, "cassandra-#{CASSANDRA_VERSION}")) do
63
67
  sh("env #{env} bin/cassandra -f")
64
68
  end
65
69
  end
66
70
 
71
+ desc "Run the Cassandra CLI"
72
+ task :cli do
73
+ Dir.chdir(File.join(CASSANDRA_HOME, "cassandra-#{CASSANDRA_VERSION}")) do
74
+ sh("bin/cassandra-cli -host localhost -port 9160")
75
+ end
76
+ end
67
77
 
68
78
  desc "Check Java version"
69
79
  task :java do
@@ -85,15 +95,16 @@ namespace :data do
85
95
 
86
96
  desc "Load test data structures."
87
97
  task :load do
88
- return true if CASSANDRA_VERSION == '0.6'
89
-
90
- schema_path = "#{File.expand_path(Dir.pwd)}/conf/#{CASSANDRA_VERSION}/schema.txt"
91
- puts "Loading test data structures."
92
- Dir.chdir(File.join(CASSANDRA_HOME, "cassandra-#{CASSANDRA_VERSION}")) do
93
- begin
94
- sh("bin/cassandra-cli --host localhost --batch < #{schema_path}")
95
- rescue
96
- puts "Schema already loaded."
98
+ unless CASSANDRA_VERSION == '0.6'
99
+
100
+ schema_path = "#{File.expand_path(Dir.pwd)}/conf/#{CASSANDRA_VERSION}/schema.txt"
101
+ puts "Loading test data structures."
102
+ Dir.chdir(File.join(CASSANDRA_HOME, "cassandra-#{CASSANDRA_VERSION}")) do
103
+ begin
104
+ sh("bin/cassandra-cli --host localhost --batch < #{schema_path}")
105
+ rescue
106
+ puts "Schema already loaded."
107
+ end
97
108
  end
98
109
  end
99
110
  end
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{cassandra}
5
- s.version = "0.10.0"
5
+ s.version = "0.11.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0.8") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Evan Weaver, Ryan King"]
9
- s.date = %q{2011-04-28}
9
+ s.date = %q{2011-05-18}
10
10
  s.description = %q{A Ruby client for the Cassandra distributed database.}
11
11
  s.email = %q{}
12
12
  s.executables = ["cassandra_helper"]
@@ -1,6 +1,4 @@
1
1
  require 'rubygems'
2
- gem 'thrift', '~> 0.5.0'
3
- require 'thrift'
4
2
  gem 'thrift_client', '~> 0.6.0'
5
3
  require 'thrift_client'
6
4
  gem 'simple_uuid' , '~> 0.1.0'
@@ -71,22 +71,19 @@ class Cassandra
71
71
  end
72
72
  end
73
73
 
74
- def _get_range(column_family, start, finish, count, consistency)
74
+ def _get_range(column_family, start_key, finish_key, key_count, columns, start, finish, count, consistency)
75
75
  column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
76
- predicate = CassandraThrift::SlicePredicate.new(:slice_range => CassandraThrift::SliceRange.new(:start => '', :finish => ''))
77
- range = CassandraThrift::KeyRange.new(:start_key => start, :end_key => finish, :count => count)
78
- client.get_range_slices(@keyspace, column_parent, predicate, range, 1)
79
- end
80
-
81
- def _get_range_keys(column_family, start, finish, count, consistency)
82
- _get_range(column_family, start, finish, count, consistency).collect{|i| i.key }
83
- end
84
-
85
- def each_key(column_family)
86
- column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family.to_s)
87
- predicate = CassandraThrift::SlicePredicate.new(:column_names => [])
88
- range = CassandraThrift::KeyRange.new(:start_key => '', :end_key => '')
89
- client.get_range_slices(@keyspace, column_parent, predicate, range, 1).each{|i| yield i.key }
76
+ predicate = if columns
77
+ CassandraThrift::SlicePredicate.new(:column_names => columns)
78
+ else
79
+ CassandraThrift::SlicePredicate.new(:slice_range =>
80
+ CassandraThrift::SliceRange.new(
81
+ :start => start,
82
+ :finish => finish,
83
+ :count => count))
84
+ end
85
+ range = CassandraThrift::KeyRange.new(:start_key => start_key, :end_key => finish_key, :count => key_count)
86
+ client.get_range_slices(@keyspace, column_parent, predicate, range, consistency)
90
87
  end
91
88
  end
92
89
  end
@@ -83,15 +83,19 @@ class Cassandra
83
83
  end
84
84
  end
85
85
 
86
- def _get_range(column_family, start, finish, count, consistency)
86
+ def _get_range(column_family, start_key, finish_key, key_count, columns, start, finish, count, consistency)
87
87
  column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
88
- predicate = CassandraThrift::SlicePredicate.new(:slice_range => CassandraThrift::SliceRange.new(:start => '', :finish => ''))
89
- range = CassandraThrift::KeyRange.new(:start_key => start, :end_key => finish, :count => count)
90
- client.get_range_slices(column_parent, predicate, range, 1)
91
- end
92
-
93
- def _get_range_keys(column_family, start, finish, count, consistency)
94
- _get_range(column_family, start, finish, count, consistency).collect{|i| i.key }
88
+ predicate = if columns
89
+ CassandraThrift::SlicePredicate.new(:column_names => columns)
90
+ else
91
+ CassandraThrift::SlicePredicate.new(:slice_range =>
92
+ CassandraThrift::SliceRange.new(
93
+ :start => start,
94
+ :finish => finish,
95
+ :count => count))
96
+ end
97
+ range = CassandraThrift::KeyRange.new(:start_key => start_key, :end_key => finish_key, :count => key_count)
98
+ client.get_range_slices(column_parent, predicate, range, consistency)
95
99
  end
96
100
 
97
101
  # TODO: Supercolumn support
@@ -109,12 +113,5 @@ class Cassandra
109
113
  end
110
114
  client.get_indexed_slices(column_parent, idx_clause, predicate, consistency)
111
115
  end
112
-
113
- def each_key(column_family)
114
- column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family.to_s)
115
- predicate = CassandraThrift::SlicePredicate.new(:column_names => [])
116
- range = CassandraThrift::KeyRange.new(:start_key => '', :end_key => '')
117
- client.get_range_slices(column_parent, predicate, range, 1).each{|i| yield i.key }
118
- end
119
116
  end
120
117
  end
@@ -83,15 +83,19 @@ class Cassandra
83
83
  end
84
84
  end
85
85
 
86
- def _get_range(column_family, start, finish, count, consistency)
86
+ def _get_range(column_family, start_key, finish_key, key_count, columns, start, finish, count, consistency)
87
87
  column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
88
- predicate = CassandraThrift::SlicePredicate.new(:slice_range => CassandraThrift::SliceRange.new(:start => '', :finish => ''))
89
- range = CassandraThrift::KeyRange.new(:start_key => start, :end_key => finish, :count => count)
90
- client.get_range_slices(column_parent, predicate, range, 1)
91
- end
92
-
93
- def _get_range_keys(column_family, start, finish, count, consistency)
94
- _get_range(column_family, start, finish, count, consistency).collect{|i| i.key }
88
+ predicate = if columns
89
+ CassandraThrift::SlicePredicate.new(:column_names => columns)
90
+ else
91
+ CassandraThrift::SlicePredicate.new(:slice_range =>
92
+ CassandraThrift::SliceRange.new(
93
+ :start => start,
94
+ :finish => finish,
95
+ :count => count))
96
+ end
97
+ range = CassandraThrift::KeyRange.new(:start_key => start_key, :end_key => finish_key, :count => key_count)
98
+ client.get_range_slices(column_parent, predicate, range, consistency)
95
99
  end
96
100
 
97
101
  # TODO: Supercolumn support
@@ -109,12 +113,5 @@ class Cassandra
109
113
  end
110
114
  client.get_indexed_slices(column_parent, idx_clause, predicate, consistency)
111
115
  end
112
-
113
- def each_key(column_family)
114
- column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family.to_s)
115
- predicate = CassandraThrift::SlicePredicate.new(:column_names => [])
116
- range = CassandraThrift::KeyRange.new(:start_key => '', :end_key => '')
117
- client.get_range_slices(column_parent, predicate, range, 1).each{|i| yield i.key }
118
- end
119
116
  end
120
117
  end
@@ -30,7 +30,7 @@ For write methods, valid option parameters are:
30
30
 
31
31
  For the initial client instantiation, you may also pass in <tt>:thrift_client<tt> with a ThriftClient subclass attached. On connection, that class will be used instead of the default ThriftClient class, allowing you to add additional behavior to the connection (e.g. query logging).
32
32
 
33
- =end rdoc
33
+ =end
34
34
 
35
35
  class Cassandra
36
36
  include Columns
@@ -226,21 +226,120 @@ class Cassandra
226
226
  end
227
227
  end
228
228
 
229
- # Return a list of keys in the column_family you request. Only works well if
229
+ # Return an OrderedHash containing the columns specified for the given
230
+ # range of keys in the column_family you request. Only works well if
230
231
  # the table is partitioned with OrderPreservingPartitioner. Supports the
231
- # <tt>:count</tt>, <tt>:start</tt>, <tt>:finish</tt>, and <tt>:consistency</tt>
232
- # options.
232
+ # <tt>:key_count</tt>, <tt>:start_key</tt>, <tt>:finish_key</tt>,
233
+ # <tt>:columns</tt>, <tt>:start</tt>, <tt>:finish</tt>, <tt>:count</tt>,
234
+ # and <tt>:consistency</tt> options. Please note that Cassandra returns
235
+ # a row for each row that has existed in the system since gc_grace_seconds.
236
+ # This is because deleted row keys are marked as deleted, but left in the
237
+ # system until the cluster has had resonable time to replicate the deletion.
238
+ # This function attempts to suppress deleted rows (actually any row returned without
239
+ # columns is suppressed).
233
240
  def get_range(column_family, options = {})
241
+ if block_given? || options[:key_count] || options[:batch_size]
242
+ get_range_batch(column_family, options)
243
+ else
244
+ get_range_single(column_family, options)
245
+ end
246
+ end
247
+
248
+ def get_range_single(column_family, options = {})
249
+ return_empty_rows = options.delete(:return_empty_rows) || false
250
+
234
251
  column_family, _, _, options =
235
- extract_and_validate_params(column_family, "", [options], READ_DEFAULTS)
236
- _get_range(column_family, options[:start].to_s, options[:finish].to_s, options[:count], options[:consistency])
252
+ extract_and_validate_params(column_family, "", [options],
253
+ READ_DEFAULTS.merge(:start_key => '',
254
+ :end_key => '',
255
+ :key_count => 100,
256
+ :columns => nil
257
+ )
258
+ )
259
+
260
+ results = _get_range( column_family,
261
+ options[:start_key].to_s,
262
+ options[:finish_key].to_s,
263
+ options[:key_count],
264
+ options[:columns],
265
+ options[:start].to_s,
266
+ options[:finish].to_s,
267
+ options[:count],
268
+ options[:consistency] )
269
+
270
+ multi_key_slices_to_hash(column_family, results, return_empty_rows)
271
+ end
272
+
273
+ def get_range_batch(column_family, options = {})
274
+ batch_size = options.delete(:batch_size) || 100
275
+ count = options.delete(:key_count)
276
+ result = {}
277
+
278
+ options[:start_key] ||= ''
279
+ last_key = nil
280
+
281
+ while options[:start_key] != last_key && (count.nil? || count > result.length)
282
+ options[:start_key] = last_key
283
+ res = get_range_single(column_family, options.merge!(:start_key => last_key,
284
+ :key_count => batch_size,
285
+ :return_empty_rows => true
286
+ ))
287
+ res.each do |key, columns|
288
+ next if options[:start_key] == key
289
+ next if result.length == count
290
+
291
+ unless columns == {}
292
+ yield key, columns if block_given?
293
+ result[key] = columns
294
+ end
295
+ last_key = key
296
+ end
297
+ end
298
+
299
+ result
237
300
  end
238
301
 
239
- # Count all rows in the column_family you request. Requires the table
240
- # to be partitioned with OrderPreservingHash. Supports the <tt>:start</tt>,
241
- # <tt>:finish</tt>, and <tt>:consistency</tt> options.
302
+ # Count all rows in the column_family you request. Supports the <tt>:start_key</tt>,
303
+ # <tt>:finish_key</tt>, and <tt>:consistency</tt> options. Please note that
304
+ # <tt>:start_key</tt> and <tt>:finish_key</tt> only work properly when
305
+ # OrderPreservingPartitioner.
242
306
  def count_range(column_family, options = {})
243
- get_range(column_family, options).select{|r| r.columns.length > 0}.compact.length
307
+ get_range_keys(column_family, options).length
308
+ end
309
+
310
+ # Return an Array containing all of the keys within a given range. (Only works
311
+ # properly if the Cassandra cluster is using the OrderPreservingPartitioner.)
312
+ # Supports <tt>:start_key</tt>, <tt>:finish_key</tt>, <tt>:count</tt>, and
313
+ # <tt>:consistency</tt> options.
314
+ def get_range_keys(column_family, options = {})
315
+ get_range(column_family,options.merge!(:count => 1)).keys
316
+ end
317
+
318
+ # Iterate through each key within the given parameters. This function can be
319
+ # used to iterate over each key in the given column family. However, if you
320
+ # only want to walk through a range of keys you need to have your cluster
321
+ # setup with OrderPreservingPartitioner. Please note that this function walks
322
+ # the list of keys in batches using the passed in <tt>:count</tt> option.
323
+ # Supports <tt>:start_key</tt>, <tt>:finish_key</tt>, <tt>:count</tt>, and
324
+ # <tt>:consistency</tt> options.
325
+ def each_key(column_family, options = {})
326
+ get_range_batch(column_family, options) do |key, columns|
327
+ yield key
328
+ end
329
+ end
330
+
331
+ # Iterate through each row and yields each key and value within the given parameters.
332
+ # This function can be used to iterate over each key in the given column family.
333
+ # However, if you only want to walk through a range of keys you need to have your
334
+ # cluster setup with OrderPreservingPartitioner. Please note that this function walks
335
+ # the list of keys in batches using the passed in <tt>:count</tt> option.
336
+ # Supports the <tt>:key_count</tt>, <tt>:start_key</tt>, <tt>:finish_key</tt>,
337
+ # <tt>:columns</tt>, <tt>:start</tt>, <tt>:finish</tt>, <tt>:count</tt>,
338
+ # and <tt>:consistency</tt> options.
339
+ def each(column_family, options = {})
340
+ get_range_batch(column_family, options) do |key, columns|
341
+ yield key, columns
342
+ end
244
343
  end
245
344
 
246
345
  # Open a batch operation and yield self. Inserts and deletes will be queued
@@ -34,6 +34,15 @@ class Cassandra
34
34
  schema[column_family][key]
35
35
  end
36
36
 
37
+ def multi_key_slices_to_hash(column_family, array, return_empty_rows = false)
38
+ ret = {}
39
+ array.each do |value|
40
+ next if return_empty_rows == false && value.columns.length == 0
41
+ ret[value.key] = columns_to_hash(column_family, value.columns)
42
+ end
43
+ ret
44
+ end
45
+
37
46
  def multi_column_to_hash!(hash)
38
47
  hash.each do |key, column_or_supercolumn|
39
48
  hash[key] = (column_or_supercolumn.column.value if column_or_supercolumn.column)
@@ -181,19 +181,57 @@ class Cassandra
181
181
  end
182
182
 
183
183
  def get_range(column_family, options = {})
184
- column_family, _, _, options = extract_and_validate_params_for_real(column_family, "", [options], READ_DEFAULTS)
185
- _get_range(column_family, options[:start], options[:finish], options[:count]).keys
184
+ column_family, _, _, options = extract_and_validate_params_for_real(column_family, "", [options],
185
+ READ_DEFAULTS.merge(:start_key => '',
186
+ :end_key => '',
187
+ :key_count => 100,
188
+ :columns => nil
189
+ )
190
+ )
191
+ _get_range(column_family,
192
+ options[:start_key],
193
+ options[:finish_key],
194
+ options[:key_count],
195
+ options[:columns],
196
+ options[:start],
197
+ options[:finish],
198
+ options[:count],
199
+ options[:consistency])
200
+ end
201
+
202
+ def get_range_keys(column_family, options = {})
203
+ get_range(column_family,options.merge!(:columns => [])).keys
204
+ end
205
+
206
+ def count_range(column_family, options = {})
207
+ get_range(column_family, options).select{|k,v| v.length > 0}.keys.compact.length
208
+ end
209
+
210
+ def each_key(column_family, options = {})
211
+ each(column_family, options.merge!(:columns => [])) do |key, value|
212
+ yield key
213
+ end
186
214
  end
187
215
 
188
- def count_range(column_family, options={})
189
- count = 0
190
- l = []
191
- start_key = ''
192
- while (l = get_range(column_family, options.merge(:count => 1000, :start => start_key))).size > 0
193
- count += l.size
194
- start_key = l.last.succ
216
+ def each(column_family, options = {})
217
+ batch_size = options.delete(:batch_size) || 100
218
+ count = options.delete(:key_count)
219
+ yielded_count = 0
220
+
221
+ options[:start_key] ||= ''
222
+ last_key = nil
223
+
224
+ while options[:start_key] != last_key && (count.nil? || count > yielded_count)
225
+ options[:start_key] = last_key
226
+ res = get_range(column_family, options.merge!(:start_key => last_key, :key_count => batch_size))
227
+ res.each do |key, columns|
228
+ next if options[:start_key] == key
229
+ next if yielded_count == count
230
+ yield key, columns
231
+ yielded_count += 1
232
+ last_key = key
233
+ end
195
234
  end
196
- count
197
235
  end
198
236
 
199
237
  def create_index(ks_name, cf_name, c_name, v_class)
@@ -264,14 +302,18 @@ class Cassandra
264
302
  @schema
265
303
  end
266
304
 
267
- def _get_range(column_family, start, finish, count)
305
+ def _get_range(column_family, start_key, finish_key, key_count, columns, start, finish, count, consistency)
268
306
  ret = OrderedHash.new
269
307
  start = to_compare_with_type(start, column_family)
270
308
  finish = to_compare_with_type(finish, column_family)
271
309
  cf(column_family).keys.sort.each do |key|
272
- break if ret.keys.size >= count
273
- if (start.nil? || key >= start) && (finish.nil? || key <= finish)
274
- ret[key] = cf(column_family)[key]
310
+ break if ret.keys.size >= key_count
311
+ if (start_key.nil? || key >= start_key) && (finish_key.nil? || key <= finish_key)
312
+ if columns
313
+ ret[key] = columns.inject(OrderedHash.new){|hash, column_name| hash[column_name] = cf(column_family)[key][column_name]; hash;}
314
+ else
315
+ ret[key] = apply_range(cf(column_family)[key], column_family, start, finish, !is_super(column_family))
316
+ end
275
317
  end
276
318
  end
277
319
  ret
@@ -38,7 +38,7 @@ class CassandraMockTest < CassandraTest
38
38
  def test_sorting_row_keys
39
39
  @twitter.insert(:Statuses, 'b', {:text => 'foo'})
40
40
  @twitter.insert(:Statuses, 'a', {:text => 'foo'})
41
- assert_equal ['a'], @twitter.get_range(:Statuses, :count => 1)
41
+ assert_equal ['a'], @twitter.get_range(:Statuses, :key_count => 1).keys
42
42
  end
43
43
 
44
44
  def test_inserting_array_for_indices
@@ -43,7 +43,7 @@ class CassandraTest < Test::Unit::TestCase
43
43
  hash = OrderedHash['b', '', 'c', '', 'd', '', 'a', '']
44
44
  @twitter.insert(:Users, key, hash)
45
45
  assert_equal(hash.keys.sort, @twitter.get(:Users, key).keys)
46
- assert_equal(hash.timestamps.keys.sort, @twitter.get(:Users, key).timestamps.keys.sort)
46
+ assert_equal(hash.timestamps.keys.sort, @twitter.get(:Users, key).timestamps.keys)
47
47
  assert_not_equal(hash.keys, @twitter.get(:Users, key).keys)
48
48
  end
49
49
 
@@ -190,24 +190,79 @@ class CassandraTest < Test::Unit::TestCase
190
190
  assert_nil @twitter.get(:StatusRelationships, 'bogus', 'user_timelines', columns.keys.first)
191
191
  end
192
192
 
193
+ def test_get_range_with_key_range
194
+ skip('This test requires the use of OrderPreservingPartitioner on the cluster to work properly.')
195
+ k = key
196
+ @twitter.insert(:Statuses, k + '2', {'body' => '1'})
197
+ @twitter.insert(:Statuses, k + '3', {'body' => '1'})
198
+ @twitter.insert(:Statuses, k + '4', {'body' => '1'})
199
+ @twitter.insert(:Statuses, k + '5', {'body' => '1'})
200
+ @twitter.insert(:Statuses, k + '6', {'body' => '1'})
201
+ assert_equal([k + '3', k + '4', k + '5'], @twitter.get_range(:Statuses, :start_key => k + '3', :finish_key => k + '5').keys)
202
+ end
193
203
 
194
- #TODO: add a OPP keyspace for this
195
- # def test_get_range
196
- # @twitter.insert(:Statuses, '2', {'body' => '1'})
197
- # @twitter.insert(:Statuses, '3', {'body' => '1'})
198
- # @twitter.insert(:Statuses, '4', {'body' => '1'})
199
- # @twitter.insert(:Statuses, '5', {'body' => '1'})
200
- # @twitter.insert(:Statuses, '6', {'body' => '1'})
201
- # assert_equal(['3', '4', '5'], @twitter.get_range(:Statuses, :start => '3', :finish => '5'))
202
- # end
204
+ def test_get_range
205
+ # make sure that deleted rows are not included in the iteration
206
+ 10.times do |i|
207
+ @twitter.insert(:Statuses, i.to_s, {'body' => '1'})
208
+ @twitter.insert(:Statuses, i.to_s + '_delete_me', {'test' => 'value'})
209
+ @twitter.remove(:Statuses, i.to_s + '_delete_me')
210
+ end
203
211
 
204
- def test_get_range_count
205
- @twitter.insert(:Statuses, '2', {'body' => '1'})
206
- @twitter.insert(:Statuses, '3', {'body' => '1'})
207
- @twitter.insert(:Statuses, '4', {'body' => '1'})
208
- @twitter.insert(:Statuses, '5', {'body' => '1'})
209
- @twitter.insert(:Statuses, '6', {'body' => '1'})
210
- assert_equal(3, @twitter.get_range(:Statuses, :count => 3).size)
212
+ assert_equal(4, @twitter.get_range_keys(:Statuses, :key_count => 4).size)
213
+ end
214
+
215
+ def test_each_key
216
+ k = key
217
+ keys_yielded = []
218
+
219
+ 10.times do |i|
220
+ @twitter.insert(:Statuses, k + i.to_s, {"body-#{i.to_s}" => 'v'})
221
+ end
222
+
223
+ # make sure that deleted rows are not included in the iteration
224
+ @twitter.insert(:Statuses, k + '_delete_me', {'test' => 'value'})
225
+ @twitter.remove(:Statuses, k + '_delete_me')
226
+
227
+ @twitter.each_key(:Statuses) do |key|
228
+ keys_yielded << key
229
+ end
230
+
231
+ assert_equal 10, keys_yielded.length
232
+ end
233
+
234
+ def test_each
235
+ k = key
236
+ key_columns = {}
237
+
238
+ 10.times do |i|
239
+ key_columns[k + i.to_s] = {"body-#{i.to_s}" => 'v', 'single_column_lookup' => "value = #{i.to_s}"}
240
+ @twitter.insert(:Statuses, k + i.to_s, key_columns[k + i.to_s])
241
+ end
242
+
243
+ keys_yielded = []
244
+ @twitter.each(:Statuses, :batch_size => 5) do |key, columns|
245
+ assert_equal key_columns[key], columns
246
+ keys_yielded << key
247
+ end
248
+
249
+ assert_equal 10, keys_yielded.length
250
+
251
+ keys_yielded = []
252
+ @twitter.each(:Statuses, :key_count => 7, :batch_size => 5) do |key, columns|
253
+ assert_equal key_columns[key], columns
254
+ keys_yielded << key
255
+ end
256
+
257
+ assert_equal 7, keys_yielded.length, 'each limits to specified count'
258
+
259
+ keys_yielded = []
260
+ @twitter.each(:Statuses, :columns => ['single_column_lookup'], :batch_size => 5) do |key, columns|
261
+ assert_equal key_columns[key].reject {|k,v| k != 'single_column_lookup'}, columns
262
+ keys_yielded << key
263
+ end
264
+
265
+ assert_equal 10, keys_yielded.length
211
266
  end
212
267
 
213
268
  def test_multi_get
@@ -329,9 +384,10 @@ class CassandraTest < Test::Unit::TestCase
329
384
  end
330
385
 
331
386
  def test_count_keys
332
- @twitter.insert(:Statuses, key + "1", {'body' => '1'})
333
- @twitter.insert(:Statuses, key + "2", {'body' => '2'})
334
- @twitter.insert(:Statuses, key + "3", {'body' => '3'})
387
+ k = key
388
+ @twitter.insert(:Statuses, k + "1", {'body' => '1'})
389
+ @twitter.insert(:Statuses, k + "2", {'body' => '2'})
390
+ @twitter.insert(:Statuses, k + "3", {'body' => '3'})
335
391
  assert_equal 3, @twitter.count_range(:Statuses)
336
392
  end
337
393
 
@@ -1,4 +1,4 @@
1
- CASSANDRA_VERSION = ENV['CASSANDRA_VERSION'] || '0.7'
1
+ CASSANDRA_VERSION ||= ENV['CASSANDRA_VERSION'] || '0.7'
2
2
 
3
3
  require 'test/unit'
4
4
  require "#{File.expand_path(File.dirname(__FILE__))}/../lib/cassandra/#{CASSANDRA_VERSION}"
@@ -9,7 +9,7 @@ begin
9
9
  rescue Thrift::TransportException => e
10
10
  #FIXME Make server automatically start if not running
11
11
  if e.message =~ /Could not connect/
12
- puts "*** Please start the Cassandra server by running 'rake cassandra'. ***"
12
+ puts "*** Please start the Cassandra server by running 'rake cassandra'. ***"
13
13
  exit 1
14
14
  end
15
15
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cassandra
3
3
  version: !ruby/object:Gem::Version
4
- hash: 55
4
+ hash: 51
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 10
8
+ - 11
9
9
  - 0
10
- version: 0.10.0
10
+ version: 0.11.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Evan Weaver, Ryan King
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-04-28 00:00:00 Z
18
+ date: 2011-05-18 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: thrift_client