cassandra 0.12.1 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/README.md +4 -4
- data/Rakefile +8 -5
- data/cassandra.gemspec +22 -22
- data/conf/0.8/log4j-server.properties +1 -1
- data/conf/0.8/schema.json +4 -1
- data/conf/0.8/schema.txt +6 -6
- data/lib/cassandra.rb +2 -1
- data/lib/cassandra/0.8/cassandra.rb +16 -1
- data/lib/cassandra/0.8/columns.rb +24 -0
- data/lib/cassandra/0.8/protocol.rb +0 -13
- data/lib/cassandra/1.0.rb +7 -0
- data/lib/cassandra/1.0/cassandra.rb +25 -0
- data/lib/cassandra/1.0/columns.rb +28 -0
- data/lib/cassandra/1.0/protocol.rb +12 -0
- data/lib/cassandra/cassandra.rb +12 -8
- data/lib/cassandra/columns.rb +5 -2
- data/lib/cassandra/composite.rb +118 -0
- data/lib/cassandra/mock.rb +18 -6
- data/test/cassandra_mock_test.rb +43 -0
- data/test/cassandra_test.rb +110 -21
- data/test/composite_type_test.rb +29 -0
- data/vendor/0.8/gen-rb/cassandra_constants.rb +1 -1
- data/vendor/0.8/gen-rb/cassandra_types.rb +9 -1
- data/vendor/1.0/gen-rb/cassandra.rb +2215 -0
- data/vendor/1.0/gen-rb/cassandra_constants.rb +12 -0
- data/vendor/1.0/gen-rb/cassandra_types.rb +857 -0
- metadata +75 -90
@@ -0,0 +1,118 @@
|
|
1
|
+
|
2
|
+
class Cassandra
|
3
|
+
class Composite
|
4
|
+
include ::Comparable
|
5
|
+
attr_reader :parts
|
6
|
+
attr_reader :column_slice
|
7
|
+
|
8
|
+
def initialize(*parts)
|
9
|
+
options = {}
|
10
|
+
if parts.last.is_a?(Hash)
|
11
|
+
options = parts.pop
|
12
|
+
end
|
13
|
+
@column_slice = options[:slice]
|
14
|
+
raise ArgumentError if @column_slice != nil && ![:before, :after].include?(@column_slice)
|
15
|
+
|
16
|
+
if parts.length == 1 && parts[0].instance_of?(self.class)
|
17
|
+
@column_slice = parts[0].column_slice
|
18
|
+
@parts = parts[0].parts
|
19
|
+
elsif parts.length == 1 && parts[0].instance_of?(String) && @column_slice.nil? && valid_packed_composite?(parts[0])
|
20
|
+
unpack(parts[0])
|
21
|
+
else
|
22
|
+
@parts = parts
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def [](*args)
|
27
|
+
return @parts[*args]
|
28
|
+
end
|
29
|
+
|
30
|
+
def pack
|
31
|
+
packed = @parts.map do |part|
|
32
|
+
[part.length].pack('n') + part + "\x00"
|
33
|
+
end
|
34
|
+
if @column_slice
|
35
|
+
part = @parts[-1]
|
36
|
+
packed[-1] = [part.length].pack('n') + part + slice_end_of_component
|
37
|
+
end
|
38
|
+
return packed.join('')
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
return pack
|
43
|
+
end
|
44
|
+
|
45
|
+
def <=>(other)
|
46
|
+
if !other.instance_of?(self.class)
|
47
|
+
return @parts.first <=> other
|
48
|
+
end
|
49
|
+
eoc = slice_end_of_component.unpack('c')[0]
|
50
|
+
other_eoc = other.slice_end_of_component.unpack('c')[0]
|
51
|
+
@parts.zip(other.parts).each do |a, b|
|
52
|
+
next if a == b
|
53
|
+
if a.nil? && b.nil?
|
54
|
+
return eoc <=> other_eoc
|
55
|
+
end
|
56
|
+
|
57
|
+
if a.nil?
|
58
|
+
return @column_slice == :after ? 1 : -1
|
59
|
+
end
|
60
|
+
if b.nil?
|
61
|
+
return other.column_slice == :after ? -1 : 1
|
62
|
+
end
|
63
|
+
return -1 if a < b
|
64
|
+
return 1 if a > b
|
65
|
+
end
|
66
|
+
return 0
|
67
|
+
end
|
68
|
+
|
69
|
+
def inspect
|
70
|
+
return "#<Composite:#{@column_slice} #{@parts.inspect}>"
|
71
|
+
end
|
72
|
+
|
73
|
+
def slice_end_of_component
|
74
|
+
return "\x01" if @column_slice == :after
|
75
|
+
return "\xFF" if @column_slice == :before
|
76
|
+
return "\x00"
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def unpack(packed_string)
|
81
|
+
parts = []
|
82
|
+
end_of_component = nil
|
83
|
+
while packed_string.length > 0
|
84
|
+
length = packed_string.slice(0, 2).unpack('n')[0]
|
85
|
+
parts << packed_string.slice(2, length)
|
86
|
+
end_of_component = packed_string.slice(2 + length, 1)
|
87
|
+
|
88
|
+
packed_string = packed_string.slice(3 + length, packed_string.length)
|
89
|
+
end
|
90
|
+
@column_slice = :after if end_of_component == "\x01"
|
91
|
+
@column_slice = :before if end_of_component == "\xFF"
|
92
|
+
@parts = parts
|
93
|
+
end
|
94
|
+
|
95
|
+
def valid_packed_composite?(packed_string)
|
96
|
+
while packed_string.length > 0
|
97
|
+
length = packed_string.slice(0, 2).unpack('n')[0]
|
98
|
+
return false if length.nil? || length + 3 > packed_string.length
|
99
|
+
|
100
|
+
end_of_component = packed_string.slice(2 + length, 1)
|
101
|
+
if length + 3 != packed_string.length
|
102
|
+
return false if end_of_component != "\x00"
|
103
|
+
end
|
104
|
+
|
105
|
+
packed_string = packed_string.slice(3 + length, packed_string.length)
|
106
|
+
end
|
107
|
+
return true
|
108
|
+
end
|
109
|
+
|
110
|
+
def hash
|
111
|
+
return to_s.hash
|
112
|
+
end
|
113
|
+
|
114
|
+
def eql?(other)
|
115
|
+
return to_s == other.to_s
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/cassandra/mock.rb
CHANGED
@@ -393,11 +393,16 @@ class Cassandra
|
|
393
393
|
if (start_key.nil? || key >= start_key) && (finish_key.nil? || key <= finish_key)
|
394
394
|
if columns
|
395
395
|
#ret[key] = columns.inject(OrderedHash.new){|hash, column_name| hash[column_name] = cf(column_family)[key][column_name]; hash;}
|
396
|
-
|
396
|
+
selected_hash = OrderedHash.new
|
397
|
+
cf(column_family)[key].each do |k, v|
|
398
|
+
selected_hash.[]=(k, v, cf(column_family)[key].timestamps[k]) if columns.include?(k)
|
399
|
+
end
|
400
|
+
ret[key] = columns_to_hash(column_family, selected_hash)
|
397
401
|
ret[key] = apply_count(ret[key], count, reversed)
|
398
402
|
blk.call(key,ret[key]) unless blk.nil?
|
399
403
|
else
|
400
404
|
#ret[key] = apply_range(cf(column_family)[key], column_family, start, finish, !is_super(column_family))
|
405
|
+
start, finish = finish, start if reversed
|
401
406
|
ret[key] = apply_range(columns_to_hash(column_family, cf(column_family)[key]), column_family, start, finish)
|
402
407
|
ret[key] = apply_count(ret[key], count, reversed)
|
403
408
|
blk.call(key,ret[key]) unless blk.nil?
|
@@ -446,7 +451,12 @@ class Cassandra
|
|
446
451
|
|
447
452
|
new_stuff = new_stuff.to_a.inject({}){|h,k| h[k[0].to_s] = k[1]; h }
|
448
453
|
|
449
|
-
|
454
|
+
new_stuff.each { |k,v| old_stuff.[]=(k, v, (Time.now.to_f * 1000000).to_i) }
|
455
|
+
hash = OrderedHash.new
|
456
|
+
old_stuff.sort{ |a,b| a[0] <=> b[0] }.each do |k, v|
|
457
|
+
hash.[]=(k, v, old_stuff.timestamps[k])
|
458
|
+
end
|
459
|
+
hash
|
450
460
|
end
|
451
461
|
|
452
462
|
def columns_to_hash(column_family, columns)
|
@@ -454,15 +464,17 @@ class Cassandra
|
|
454
464
|
output = OrderedHash.new
|
455
465
|
|
456
466
|
columns.each do |column_name, value|
|
467
|
+
timestamp = columns.timestamps[column_name]
|
457
468
|
column = column_class.new(column_name)
|
458
469
|
|
459
470
|
if [Hash, OrderedHash].include?(value.class)
|
460
471
|
output[column] ||= OrderedHash.new
|
461
472
|
value.each do |sub_column, sub_column_value|
|
462
|
-
|
473
|
+
timestamp = value.timestamps[sub_column]
|
474
|
+
output[column].[]=(sub_column_class.new(sub_column), sub_column_value, timestamp)
|
463
475
|
end
|
464
476
|
else
|
465
|
-
output[column_class.new(column_name)
|
477
|
+
output.[]=(column_class.new(column_name), value, timestamp)
|
466
478
|
end
|
467
479
|
end
|
468
480
|
|
@@ -475,7 +487,7 @@ class Cassandra
|
|
475
487
|
keys = keys.reverse if reversed
|
476
488
|
keys = keys[0...count]
|
477
489
|
keys.inject(OrderedHash.new) do |memo, key|
|
478
|
-
memo[
|
490
|
+
memo.[]=(key, row[key], row.timestamps[key])
|
479
491
|
memo
|
480
492
|
end
|
481
493
|
else
|
@@ -489,7 +501,7 @@ class Cassandra
|
|
489
501
|
ret = OrderedHash.new
|
490
502
|
row.keys.each do |key|
|
491
503
|
if (start.nil? || key >= start) && (finish.nil? || key <= finish)
|
492
|
-
ret[
|
504
|
+
ret.[]=(key, row[key], row.timestamps[key])
|
493
505
|
end
|
494
506
|
end
|
495
507
|
ret
|
data/test/cassandra_mock_test.rb
CHANGED
@@ -22,6 +22,12 @@ class CassandraMockTest < CassandraTest
|
|
22
22
|
|
23
23
|
@uuids = (0..6).map {|i| SimpleUUID::UUID.new(Time.at(2**(24+i))) }
|
24
24
|
@longs = (0..6).map {|i| Long.new(Time.at(2**(24+i))) }
|
25
|
+
@composites = [
|
26
|
+
Cassandra::Composite.new([5].pack('N'), "zebra"),
|
27
|
+
Cassandra::Composite.new([5].pack('N'), "aardvark"),
|
28
|
+
Cassandra::Composite.new([1].pack('N'), "elephant"),
|
29
|
+
Cassandra::Composite.new([10].pack('N'), "kangaroo"),
|
30
|
+
]
|
25
31
|
end
|
26
32
|
|
27
33
|
def test_setup
|
@@ -57,6 +63,24 @@ class CassandraMockTest < CassandraTest
|
|
57
63
|
end
|
58
64
|
end
|
59
65
|
|
66
|
+
def test_get_range_reversed_slice
|
67
|
+
data = 4.times.map { |i| ["body-#{i.to_s}", "v"] }
|
68
|
+
hash = Cassandra::OrderedHash[data]
|
69
|
+
sliced_hash = Cassandra::OrderedHash[data.reverse[1..-1]]
|
70
|
+
|
71
|
+
@twitter.insert(:Statuses, "all-keys", hash)
|
72
|
+
|
73
|
+
columns = @twitter.get_range(
|
74
|
+
:Statuses,
|
75
|
+
:start => sliced_hash.keys.first,
|
76
|
+
:reversed => true
|
77
|
+
)["all-keys"]
|
78
|
+
|
79
|
+
columns.each do |column|
|
80
|
+
assert_equal sliced_hash.shift, column
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
60
84
|
def test_get_range_count
|
61
85
|
data = 3.times.map { |i| ["body-#{i.to_s}", "v"] }
|
62
86
|
hash = Cassandra::OrderedHash[data]
|
@@ -76,4 +100,23 @@ class CassandraMockTest < CassandraTest
|
|
76
100
|
@twitter.insert(:UserRelationships, 'a', ['u1','u2'])
|
77
101
|
}
|
78
102
|
end
|
103
|
+
|
104
|
+
def test_column_timestamps
|
105
|
+
base_time = Time.now
|
106
|
+
@twitter.insert(:Statuses, "time-key", { "body" => "value" })
|
107
|
+
|
108
|
+
results = @twitter.get(:Statuses, "time-key")
|
109
|
+
assert(results.timestamps["body"] / 1000000 >= base_time.to_i)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_supercolumn_timestamps
|
113
|
+
base_time = Time.now
|
114
|
+
@twitter.insert(:StatusRelationships, "time-key", { "super" => { @uuids[1] => "value" }})
|
115
|
+
|
116
|
+
results = @twitter.get(:StatusRelationships, "time-key")
|
117
|
+
assert_nil(results.timestamps["super"])
|
118
|
+
|
119
|
+
columns = results["super"]
|
120
|
+
assert(columns.timestamps[@uuids[1]] / 1000000 >= base_time.to_i)
|
121
|
+
end
|
79
122
|
end
|
data/test/cassandra_test.rb
CHANGED
@@ -21,6 +21,12 @@ class CassandraTest < Test::Unit::TestCase
|
|
21
21
|
|
22
22
|
@uuids = (0..6).map {|i| SimpleUUID::UUID.new(Time.at(2**(24+i))) }
|
23
23
|
@longs = (0..6).map {|i| Long.new(Time.at(2**(24+i))) }
|
24
|
+
@composites = [
|
25
|
+
Cassandra::Composite.new([5].pack('N'), "zebra"),
|
26
|
+
Cassandra::Composite.new([5].pack('N'), "aardvark"),
|
27
|
+
Cassandra::Composite.new([1].pack('N'), "elephant"),
|
28
|
+
Cassandra::Composite.new([10].pack('N'), "kangaroo"),
|
29
|
+
]
|
24
30
|
end
|
25
31
|
|
26
32
|
def test_inspect
|
@@ -43,7 +49,7 @@ class CassandraTest < Test::Unit::TestCase
|
|
43
49
|
end
|
44
50
|
|
45
51
|
def test_get_key
|
46
|
-
|
52
|
+
|
47
53
|
@twitter.insert(:Users, key, {'body' => 'v', 'user' => 'v'})
|
48
54
|
assert_equal({'body' => 'v', 'user' => 'v'}, @twitter.get(:Users, key))
|
49
55
|
assert_equal(['body', 'user'].sort, @twitter.get(:Users, key).timestamps.keys.sort)
|
@@ -280,35 +286,46 @@ class CassandraTest < Test::Unit::TestCase
|
|
280
286
|
|
281
287
|
def test_get_range_block
|
282
288
|
k = key
|
289
|
+
|
290
|
+
values = {}
|
283
291
|
5.times do |i|
|
284
|
-
|
292
|
+
values[k+i.to_s] = {"body-#{i.to_s}" => 'v'}
|
285
293
|
end
|
286
294
|
|
287
|
-
values
|
295
|
+
values.each {|key, columns| @twitter.insert(:Statuses, key, columns) }
|
288
296
|
|
289
297
|
returned_value = @twitter.get_range(:Statuses, :start_key => k.to_s, :key_count => 5) do |key,columns|
|
290
|
-
expected = values.
|
291
|
-
assert_equal expected
|
292
|
-
assert_equal expected[:columns], columns
|
298
|
+
expected = values.delete(key)
|
299
|
+
assert_equal expected, columns
|
293
300
|
end
|
294
301
|
|
295
|
-
|
302
|
+
assert values.length < 5
|
296
303
|
assert_nil returned_value
|
297
304
|
end
|
298
|
-
|
305
|
+
|
299
306
|
def test_get_range_reversed
|
300
307
|
data = 3.times.map { |i| ["body-#{i.to_s}", "v"] }
|
301
308
|
hash = Cassandra::OrderedHash[data]
|
302
309
|
reversed_hash = Cassandra::OrderedHash[data.reverse]
|
303
|
-
|
310
|
+
|
304
311
|
@twitter.insert(:Statuses, "all-keys", hash)
|
305
|
-
|
312
|
+
|
306
313
|
columns = @twitter.get_range(:Statuses, :reversed => true)["all-keys"]
|
307
314
|
columns.each do |column|
|
308
315
|
assert_equal reversed_hash.shift, column
|
309
316
|
end
|
310
317
|
end
|
311
318
|
|
319
|
+
def test_get_range_with_start_key_and_key_count
|
320
|
+
hash = {"name" => "value"}
|
321
|
+
@twitter.insert(:Statuses, "a-key", hash)
|
322
|
+
@twitter.insert(:Statuses, "b-key", hash)
|
323
|
+
@twitter.insert(:Statuses, "c-key", hash)
|
324
|
+
|
325
|
+
results = @twitter.get_range(:Statuses, :start_key => "b-key", :key_count => 1)
|
326
|
+
assert_equal ["b-key"], results.keys
|
327
|
+
end
|
328
|
+
|
312
329
|
def test_each_key
|
313
330
|
k = key
|
314
331
|
keys_yielded = []
|
@@ -490,12 +507,12 @@ class CassandraTest < Test::Unit::TestCase
|
|
490
507
|
|
491
508
|
def test_count_columns
|
492
509
|
columns = (1..200).inject(Hash.new){|h,v| h['column' + v.to_s] = v.to_s; h;}
|
493
|
-
|
510
|
+
|
494
511
|
@twitter.insert(:Statuses, key, columns)
|
495
512
|
assert_equal 200, @twitter.count_columns(:Statuses, key, :count => 200)
|
496
|
-
assert_equal 100, @twitter.count_columns(:Statuses, key)
|
513
|
+
assert_equal 100, @twitter.count_columns(:Statuses, key)
|
497
514
|
assert_equal 55, @twitter.count_columns(:Statuses, key, :count => 55)
|
498
|
-
|
515
|
+
|
499
516
|
end
|
500
517
|
|
501
518
|
def test_count_super_columns
|
@@ -539,40 +556,43 @@ class CassandraTest < Test::Unit::TestCase
|
|
539
556
|
@twitter.insert(:Users, k + '3', {'body' => 'bogus', 'user' => 'v3'})
|
540
557
|
@twitter.insert(:Users, k + '3', {'body' => 'v3', 'location' => 'v3'})
|
541
558
|
@twitter.insert(:Statuses, k + '3', {'body' => 'v'})
|
559
|
+
@twitter.add(:UserCounters, 'bob', 5, 'tweet_count') if CASSANDRA_VERSION.to_f >= 0.8
|
542
560
|
|
543
561
|
assert_equal({'delete_me' => 'v0', 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # Written
|
544
562
|
assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, k + '1')) # Written
|
545
563
|
assert_equal({}, @twitter.get(:Users, k + '2')) # Not yet written
|
546
564
|
assert_equal({}, @twitter.get(:Statuses, k + '3')) # Not yet written
|
565
|
+
assert_equal({}, @twitter.get(:UserCounters, 'bob')) if CASSANDRA_VERSION.to_f >= 0.8 # Not yet written
|
547
566
|
|
548
|
-
@twitter.remove(:Users, k + '1') # Full row
|
567
|
+
@twitter.remove(:Users, k + '1') # Full row
|
549
568
|
assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, k + '1')) # Not yet removed
|
550
569
|
|
551
570
|
@twitter.remove(:Users, k + '0', 'delete_me') # A single column of the row
|
552
571
|
assert_equal({'delete_me' => 'v0', 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # Not yet removed
|
553
|
-
|
572
|
+
|
554
573
|
@twitter.remove(:Users, k + '4')
|
555
574
|
@twitter.insert(:Users, k + '4', {'body' => 'v4', 'user' => 'v4'})
|
556
575
|
assert_equal({}, @twitter.get(:Users, k + '4')) # Not yet written
|
557
576
|
|
558
577
|
# SuperColumns
|
559
578
|
# Add and delete new sub columns to the user timeline supercolumn
|
560
|
-
@twitter.insert(:StatusRelationships, k, {'user_timelines' => new_subcolumns })
|
579
|
+
@twitter.insert(:StatusRelationships, k, {'user_timelines' => new_subcolumns })
|
561
580
|
@twitter.remove(:StatusRelationships, k, 'user_timelines' , subcolumn_to_delete ) # Delete the first of the initial_subcolumns from the user_timeline supercolumn
|
562
581
|
assert_equal(initial_subcolumns, @twitter.get(:StatusRelationships, k, 'user_timelines')) # No additions or deletes reflected yet
|
563
|
-
# Delete a complete supercolumn
|
582
|
+
# Delete a complete supercolumn
|
564
583
|
@twitter.remove(:StatusRelationships, k, 'dummy_supercolumn' ) # Delete the full dummy supercolumn
|
565
|
-
assert_equal({@uuids[5] => 'value'}, @twitter.get(:StatusRelationships, k, 'dummy_supercolumn')) # dummy supercolumn not yet deleted
|
584
|
+
assert_equal({@uuids[5] => 'value'}, @twitter.get(:StatusRelationships, k, 'dummy_supercolumn')) # dummy supercolumn not yet deleted
|
566
585
|
end
|
567
586
|
|
568
587
|
assert_equal({'body' => 'v2', 'user' => 'v2'}, @twitter.get(:Users, k + '2')) # Written
|
569
588
|
assert_equal({'body' => 'v3', 'user' => 'v3', 'location' => 'v3'}, @twitter.get(:Users, k + '3')) # Written and compacted
|
570
589
|
assert_equal({'body' => 'v4', 'user' => 'v4'}, @twitter.get(:Users, k + '4')) # Written
|
571
590
|
assert_equal({'body' => 'v'}, @twitter.get(:Statuses, k + '3')) # Written
|
591
|
+
assert_equal({'tweet_count' => 5}, @twitter.get(:UserCounters, 'bob')) if CASSANDRA_VERSION.to_f >= 0.8 # Written
|
572
592
|
assert_equal({}, @twitter.get(:Users, k + '1')) # Removed
|
573
|
-
|
593
|
+
|
574
594
|
assert_equal({ 'keep_me' => 'v0'}, @twitter.get(:Users, k + '0')) # 'delete_me' column removed
|
575
|
-
|
595
|
+
|
576
596
|
|
577
597
|
assert_equal({'body' => 'v2', 'user' => 'v2'}.keys.sort, @twitter.get(:Users, k + '2').timestamps.keys.sort) # Written
|
578
598
|
assert_equal({'body' => 'v3', 'user' => 'v3', 'location' => 'v3'}.keys.sort, @twitter.get(:Users, k + '3').timestamps.keys.sort) # Written and compacted
|
@@ -582,7 +602,7 @@ class CassandraTest < Test::Unit::TestCase
|
|
582
602
|
# Final result: initial_subcolumns - initial_subcolumns.first + new_subcolumns
|
583
603
|
resulting_subcolumns = initial_subcolumns.merge(new_subcolumns).reject{|k2,v| k2 == subcolumn_to_delete }
|
584
604
|
assert_equal(resulting_subcolumns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
|
585
|
-
assert_equal({}, @twitter.get(:StatusRelationships, key, 'dummy_supercolumn')) # dummy supercolumn deleted
|
605
|
+
assert_equal({}, @twitter.get(:StatusRelationships, key, 'dummy_supercolumn')) # dummy supercolumn deleted
|
586
606
|
|
587
607
|
end
|
588
608
|
|
@@ -823,6 +843,75 @@ class CassandraTest < Test::Unit::TestCase
|
|
823
843
|
assert_equal(1, @twitter.get(:UserCounterAggregates, 'bob', 'DAU', 'today'))
|
824
844
|
assert_equal(2, @twitter.get(:UserCounterAggregates, 'bob', 'DAU', 'tomorrow'))
|
825
845
|
end
|
846
|
+
|
847
|
+
def test_reading_rows_with_super_column_counter
|
848
|
+
assert_nil @twitter.add(:UserCounterAggregates, 'bob', 1, 'DAU', 'today')
|
849
|
+
assert_nil @twitter.add(:UserCounterAggregates, 'bob', 2, 'DAU', 'tomorrow')
|
850
|
+
result = @twitter.get(:UserCounterAggregates, 'bob')
|
851
|
+
assert_equal(1, result.size)
|
852
|
+
assert_equal(2, result.first.size)
|
853
|
+
assert_equal("DAU", result.first[0])
|
854
|
+
assert_equal(1, result.first[1]["today"])
|
855
|
+
assert_equal(2, result.first[1]["tomorrow"])
|
856
|
+
end
|
857
|
+
|
858
|
+
def test_composite_column_type_conversion
|
859
|
+
columns = {}
|
860
|
+
@composites.each_with_index do |c, index|
|
861
|
+
columns[c] = "value-#{index}"
|
862
|
+
end
|
863
|
+
@type_conversions.insert(:CompositeColumnConversion, key, columns)
|
864
|
+
columns_in_order = [
|
865
|
+
Cassandra::Composite.new([1].pack('N'), "elephant"),
|
866
|
+
Cassandra::Composite.new([5].pack('N'), "aardvark"),
|
867
|
+
Cassandra::Composite.new([5].pack('N'), "zebra"),
|
868
|
+
Cassandra::Composite.new([10].pack('N'), "kangaroo"),
|
869
|
+
]
|
870
|
+
assert_equal(columns_in_order, @type_conversions.get(:CompositeColumnConversion, key).keys)
|
871
|
+
|
872
|
+
column_slice = @type_conversions.get(:CompositeColumnConversion, key,
|
873
|
+
:start => Cassandra::Composite.new([1].pack('N')),
|
874
|
+
:finish => Cassandra::Composite.new([10].pack('N')),
|
875
|
+
).keys
|
876
|
+
assert_equal(columns_in_order[0..-2], column_slice)
|
877
|
+
|
878
|
+
column_slice = @type_conversions.get(:CompositeColumnConversion, key,
|
879
|
+
:start => Cassandra::Composite.new([5].pack('N')),
|
880
|
+
:finish => Cassandra::Composite.new([5].pack('N'), :slice => :after),
|
881
|
+
).keys
|
882
|
+
assert_equal(columns_in_order[1..2], column_slice)
|
883
|
+
|
884
|
+
column_slice = @type_conversions.get(:CompositeColumnConversion, key,
|
885
|
+
:start => Cassandra::Composite.new([5].pack('N'), :slice => :after).to_s,
|
886
|
+
).keys
|
887
|
+
assert_equal([columns_in_order[-1]], column_slice)
|
888
|
+
|
889
|
+
column_slice = @type_conversions.get(:CompositeColumnConversion, key,
|
890
|
+
:finish => Cassandra::Composite.new([10].pack('N'), :slice => :before).to_s,
|
891
|
+
).keys
|
892
|
+
assert_equal(columns_in_order[0..-2], column_slice)
|
893
|
+
|
894
|
+
assert_equal('value-2', @type_conversions.get(:CompositeColumnConversion, key, columns_in_order.first))
|
895
|
+
end
|
896
|
+
end
|
897
|
+
|
898
|
+
def test_column_timestamps
|
899
|
+
base_time = Time.now
|
900
|
+
@twitter.insert(:Statuses, "time-key", { "body" => "value" })
|
901
|
+
|
902
|
+
results = @twitter.get(:Statuses, "time-key")
|
903
|
+
assert(results.timestamps["body"] / 1000000 >= base_time.to_i)
|
904
|
+
end
|
905
|
+
|
906
|
+
def test_supercolumn_timestamps
|
907
|
+
base_time = Time.now
|
908
|
+
@twitter.insert(:StatusRelationships, "time-key", { "super" => { @uuids[1] => "value" }})
|
909
|
+
|
910
|
+
results = @twitter.get(:StatusRelationships, "time-key")
|
911
|
+
assert_nil(results.timestamps["super"])
|
912
|
+
|
913
|
+
columns = results["super"]
|
914
|
+
assert(columns.timestamps[@uuids[1]] / 1000000 >= base_time.to_i)
|
826
915
|
end
|
827
916
|
|
828
917
|
private
|