cassandra 0.2.3 → 0.4
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.tar.gz.sig +0 -0
- data/CHANGELOG +12 -0
- data/LICENSE +202 -0
- data/Manifest +24 -17
- data/README +65 -0
- data/Rakefile +13 -0
- data/cassandra.gemspec +22 -117
- data/conf/cassandra.in.sh +55 -0
- data/conf/log4j.properties +38 -0
- data/conf/storage-conf.xml +197 -0
- data/lib/cassandra.rb +21 -159
- data/lib/cassandra/array.rb +8 -0
- data/lib/cassandra/cassandra.rb +315 -0
- data/lib/cassandra/comparable.rb +28 -0
- data/lib/cassandra/constants.rb +8 -0
- data/lib/cassandra/helper.rb +85 -0
- data/lib/cassandra/long.rb +39 -0
- data/lib/cassandra/ordered_hash.rb +135 -0
- data/lib/cassandra/safe_client.rb +21 -0
- data/lib/cassandra/serialization.rb +57 -0
- data/lib/cassandra/time.rb +9 -0
- data/lib/cassandra/uuid.rb +44 -0
- data/quickstart.sh +12 -0
- data/test/cassandra_client_test.rb +302 -0
- data/test/comparable_types_test.rb +44 -0
- data/vendor/gen-rb/cassandra.rb +1138 -0
- data/vendor/gen-rb/cassandra_constants.rb +10 -0
- data/vendor/gen-rb/cassandra_types.rb +239 -0
- metadata +90 -37
- metadata.gz.sig +1 -0
- data/README.rdoc +0 -29
- data/lib/properties.rb +0 -119
- data/lib/tags.rb +0 -89
- data/misc/dan.rb +0 -64
- data/misc/meyer_reset.css +0 -53
- data/site/basic.cssy +0 -12
- data/site/basic.rb +0 -19
- data/site/cssy_title.jpg +0 -0
- data/site/flower.png +0 -0
- data/site/index.mab +0 -22
- data/site/ruby.cssy +0 -15
- data/test/basics.rb +0 -107
- data/test/dan.cssy +0 -160
- data/test/fiddle.css +0 -22
- data/test/fiddle.cssy +0 -34
- data/test/helper.rb +0 -8
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
class Cassandra
|
3
|
+
# A temporally-ordered Long class for use in Cassandra column names
|
4
|
+
class Long < Comparable
|
5
|
+
ENTROPY = 2**12
|
6
|
+
MAX = 2**64
|
7
|
+
|
8
|
+
def initialize(bytes = nil)
|
9
|
+
case bytes
|
10
|
+
when String
|
11
|
+
raise TypeError, "8 bytes required" if bytes.size != 8
|
12
|
+
@bytes = bytes
|
13
|
+
when Integer
|
14
|
+
raise TypeError, "Integer must be between 0 and 2**64" if bytes < 0 or bytes > MAX
|
15
|
+
@bytes = [bytes].pack("Q")
|
16
|
+
when NilClass
|
17
|
+
# Time.stamp is 52 bytes, so we have 12 bytes of entropy left over
|
18
|
+
@bytes = [Time.stamp * ENTROPY + rand(ENTROPY)].pack("Q")
|
19
|
+
else
|
20
|
+
raise TypeError, "Can't convert from #{bytes.class}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_i
|
25
|
+
@to_i ||= @bytes.unpack("Q")[0]
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
ints = @bytes.unpack("Q")
|
30
|
+
"<Cassandra::Long##{object_id} time: #{
|
31
|
+
Time.at((ints[0] / ENTROPY) / 1_000_000).inspect
|
32
|
+
}, usecs: #{
|
33
|
+
(ints[0] / ENTROPY) % 1_000_000
|
34
|
+
}, jitter: #{
|
35
|
+
ints[0] % ENTROPY
|
36
|
+
}>"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
|
2
|
+
class Cassandra
|
3
|
+
# Hash is ordered in Ruby 1.9!
|
4
|
+
if RUBY_VERSION >= '1.9'
|
5
|
+
OrderedHash = ::Hash
|
6
|
+
else
|
7
|
+
# Copyright (c) 2004-2009 David Heinemeier Hansson
|
8
|
+
#
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
10
|
+
# a copy of this software and associated documentation files (the
|
11
|
+
# "Software"), to deal in the Software without restriction, including
|
12
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
13
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
14
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
15
|
+
# the following conditions:
|
16
|
+
#
|
17
|
+
# The above copyright notice and this permission notice shall be
|
18
|
+
# included in all copies or substantial portions of the Software.
|
19
|
+
#
|
20
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
21
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
22
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
23
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
24
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
25
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
26
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
|
+
|
28
|
+
class OrderedHash < Hash
|
29
|
+
require 'enumerator'
|
30
|
+
|
31
|
+
def self.[](*array)
|
32
|
+
hash = new
|
33
|
+
array.each_slice(2) { |key, value| hash[key] = value }
|
34
|
+
hash
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(*args, &block)
|
38
|
+
super
|
39
|
+
@keys = []
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize_copy(other)
|
43
|
+
super
|
44
|
+
# make a deep copy of keys
|
45
|
+
@keys = other.keys
|
46
|
+
end
|
47
|
+
|
48
|
+
def []=(key, value)
|
49
|
+
@keys << key if !has_key?(key)
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
def delete(key)
|
54
|
+
if has_key? key
|
55
|
+
index = @keys.index(key)
|
56
|
+
@keys.delete_at index
|
57
|
+
end
|
58
|
+
super
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete_if
|
62
|
+
super
|
63
|
+
sync_keys!
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def reject!
|
68
|
+
super
|
69
|
+
sync_keys!
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
def reject(&block)
|
74
|
+
dup.reject!(&block)
|
75
|
+
end
|
76
|
+
|
77
|
+
def keys
|
78
|
+
@keys.dup
|
79
|
+
end
|
80
|
+
|
81
|
+
def values
|
82
|
+
@keys.collect { |key| self[key] }
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_hash
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
def each_key
|
90
|
+
@keys.each { |key| yield key }
|
91
|
+
end
|
92
|
+
|
93
|
+
def each_value
|
94
|
+
@keys.each { |key| yield self[key]}
|
95
|
+
end
|
96
|
+
|
97
|
+
def each
|
98
|
+
@keys.each {|key| yield [key, self[key]]}
|
99
|
+
end
|
100
|
+
|
101
|
+
alias_method :each_pair, :each
|
102
|
+
|
103
|
+
def clear
|
104
|
+
super
|
105
|
+
@keys.clear
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
def shift
|
110
|
+
k = @keys.first
|
111
|
+
v = delete(k)
|
112
|
+
[k, v]
|
113
|
+
end
|
114
|
+
|
115
|
+
def merge!(other_hash)
|
116
|
+
other_hash.each {|k,v| self[k] = v }
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
def merge(other_hash)
|
121
|
+
dup.merge!(other_hash)
|
122
|
+
end
|
123
|
+
|
124
|
+
def inspect
|
125
|
+
"#<OrderedHash #{super}>"
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def sync_keys!
|
131
|
+
@keys.delete_if {|k| !has_key?(k)}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
module CassandraThrift
|
3
|
+
module Cassandra
|
4
|
+
class SafeClient
|
5
|
+
def initialize(client, transport)
|
6
|
+
@client = client
|
7
|
+
@transport = transport
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(*args)
|
11
|
+
@client.send(*args)
|
12
|
+
rescue IOError, UnavailableException
|
13
|
+
@transport.close rescue nil
|
14
|
+
@transport.open
|
15
|
+
raise if defined?(once)
|
16
|
+
once = true
|
17
|
+
retry
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
class Cassandra
|
3
|
+
module Serialization
|
4
|
+
module String
|
5
|
+
def self.dump(object);
|
6
|
+
object.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.load(object)
|
10
|
+
object
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Marshal
|
15
|
+
def self.dump(object)
|
16
|
+
::Marshal.dump(object)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.load(object)
|
20
|
+
::Marshal.load(object)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module JSON
|
25
|
+
def self.dump(object)
|
26
|
+
::JSON.dump(object)
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'yajl/json_gem'
|
31
|
+
def self.load(object)
|
32
|
+
::JSON.load(object)
|
33
|
+
end
|
34
|
+
rescue LoadError
|
35
|
+
require 'json/ext'
|
36
|
+
def self.load(object)
|
37
|
+
::JSON.load("[#{object}]").first # :-(
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module CompressedJSON
|
43
|
+
def self.dump(object)
|
44
|
+
Zlib::Deflate.deflate(JSON.dump(object))
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.load(object)
|
48
|
+
JSON.load(Zlib::Inflate.inflate(object))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# module Avro
|
53
|
+
# # Someday!
|
54
|
+
# end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
class Cassandra
|
3
|
+
# A temporally-ordered UUID class for use in Cassandra column names
|
4
|
+
class UUID < Comparable
|
5
|
+
UINT = 2**32
|
6
|
+
LONG = 2**64
|
7
|
+
MAX = 2**128
|
8
|
+
|
9
|
+
def initialize(bytes = nil)
|
10
|
+
case bytes
|
11
|
+
when String
|
12
|
+
raise TypeError, "16 bytes required" if bytes.size != 16
|
13
|
+
@bytes = bytes
|
14
|
+
when Integer
|
15
|
+
raise TypeError, "Integer must be between 0 and 2**128" if bytes < 0 or bytes > MAX
|
16
|
+
@bytes = [bytes / LONG, bytes % LONG].pack("QQ")
|
17
|
+
when NilClass
|
18
|
+
@bytes = [Time.stamp, Process.pid, rand(UINT)].pack("QII")
|
19
|
+
else
|
20
|
+
raise TypeError, "Can't convert from #{bytes.class}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_i
|
25
|
+
@to_i ||= begin
|
26
|
+
ints = @bytes.unpack("QQ")
|
27
|
+
ints[0] * 2**64 + ints[1]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def inspect
|
32
|
+
ints = @bytes.unpack("QII")
|
33
|
+
"<Cassandra::UUID##{object_id} time: #{
|
34
|
+
Time.at(ints[0] / 1_000_000).inspect
|
35
|
+
}, usecs: #{
|
36
|
+
ints[0] % 1_000_000
|
37
|
+
}, pid: #{
|
38
|
+
ints[1]
|
39
|
+
}, jitter: #{
|
40
|
+
ints[2]
|
41
|
+
}>"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/quickstart.sh
ADDED
@@ -0,0 +1,302 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
require "#{File.expand_path(File.dirname(__FILE__))}/../lib/cassandra"
|
4
|
+
|
5
|
+
begin; require 'ruby-debug'; rescue LoadError; end
|
6
|
+
|
7
|
+
class CassandraTest < Test::Unit::TestCase
|
8
|
+
include Cassandra::Constants
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@twitter = Cassandra.new('Twitter', '127.0.0.1')
|
12
|
+
@twitter.clear_keyspace!
|
13
|
+
@blogs = Cassandra.new('Multiblog', '127.0.0.1')
|
14
|
+
@blogs.clear_keyspace!
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_inspect
|
18
|
+
assert_nothing_raised do
|
19
|
+
@blogs.inspect
|
20
|
+
@twitter.inspect
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_connection_reopens
|
25
|
+
assert_raises(NoMethodError) do
|
26
|
+
@twitter.insert(:Statuses, 1, {'body' => 'v'})
|
27
|
+
end
|
28
|
+
assert_nothing_raised do
|
29
|
+
@twitter.insert(:Statuses, key, {'body' => 'v'})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_get_key_name_sorted
|
34
|
+
@twitter.insert(:Users, key, {'body' => 'v', 'user' => 'v'})
|
35
|
+
assert_equal({'body' => 'v', 'user' => 'v'}, @twitter.get(:Users, key))
|
36
|
+
assert_equal({}, @twitter.get(:Users, 'bogus'))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_get_key_name_sorted_preserving_order
|
40
|
+
# In-order hash is preserved
|
41
|
+
hash = OrderedHash['a', nil, 'b', nil, 'c', nil, 'd', nil,]
|
42
|
+
@twitter.insert(:Users, key, hash)
|
43
|
+
assert_equal(hash.keys, @twitter.get(:Users, key).keys)
|
44
|
+
|
45
|
+
@twitter.remove(:Users, key)
|
46
|
+
|
47
|
+
# Out-of-order hash is returned sorted
|
48
|
+
hash = OrderedHash['b', nil, 'c', nil, 'd', nil, 'a', nil]
|
49
|
+
@twitter.insert(:Users, key, hash)
|
50
|
+
assert_equal(hash.keys.sort, @twitter.get(:Users, key).keys)
|
51
|
+
assert_not_equal(hash.keys, @twitter.get(:Users, key).keys)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_get_key_time_sorted
|
55
|
+
@twitter.insert(:Statuses, key, {'body' => 'v', 'user' => 'v'})
|
56
|
+
assert_equal({'body' => 'v', 'user' => 'v'}, @twitter.get(:Statuses, key))
|
57
|
+
assert_equal({}, @twitter.get(:Statuses, 'bogus'))
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_get_value
|
61
|
+
@twitter.insert(:Statuses, key, {'body' => 'v'})
|
62
|
+
assert_equal 'v', @twitter.get(:Statuses, key, 'body')
|
63
|
+
assert_nil @twitter.get(:Statuses, 'bogus', 'body')
|
64
|
+
|
65
|
+
assert @twitter.exists?(:Statuses, key, 'body')
|
66
|
+
assert_nil @twitter.exists?(:Statuses, 'bogus', 'body')
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_get_value_nil
|
70
|
+
@twitter.insert(:Statuses, key, {'body' => nil})
|
71
|
+
assert_nil @twitter.get(:Statuses, key, 'body')
|
72
|
+
assert @twitter.exists?(:Statuses, key, 'body')
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_get_super_key
|
76
|
+
columns = {'user_timelines' => {Long.new => '4', Long.new => '5'}}
|
77
|
+
@twitter.insert(:StatusRelationships, key, columns)
|
78
|
+
assert_equal(columns, @twitter.get(:StatusRelationships, key))
|
79
|
+
assert_equal({}, @twitter.get(:StatusRelationships, 'bogus'))
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_get_several_super_keys
|
83
|
+
columns = {
|
84
|
+
'user_timelines' => {Long.new => 'v1'},
|
85
|
+
'mentions_timelines' => {Long.new => 'v2'}}
|
86
|
+
@twitter.insert(:StatusRelationships, key, columns)
|
87
|
+
|
88
|
+
assert_equal(columns, @twitter.get(:StatusRelationships, key))
|
89
|
+
assert_equal({}, @twitter.get(:StatusRelationships, 'bogus'))
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_get_super_sub_keys_with_limit
|
93
|
+
columns = {Long.new => 'v1'}
|
94
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
|
95
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => {Long.new => 'v2'}})
|
96
|
+
assert_equal(columns, @twitter.get(:StatusRelationships, key, "user_timelines", nil, 1))
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_get_super_sub_keys_with_ranges
|
100
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => {Long.new => 'v1'}})
|
101
|
+
first_column = {Long.new => 'v2'}
|
102
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => first_column})
|
103
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => {Long.new => 'v3', Long.new => 'v4'}})
|
104
|
+
last_column = {Long.new => 'v5'}
|
105
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => last_column})
|
106
|
+
|
107
|
+
keys = @twitter.get(:StatusRelationships, key, "user_timelines").keys
|
108
|
+
assert_equal keys.sort, keys
|
109
|
+
|
110
|
+
assert_equal(first_column, @twitter.get(:StatusRelationships, key, "user_timelines", nil, 1, first_column.keys.first..''))
|
111
|
+
assert_equal(3, @twitter.get(:StatusRelationships, key, "user_timelines", nil, 100, last_column.keys.first..first_column.keys.first).size)
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_get_super_sub_key
|
115
|
+
columns = {Long.new => 'v', Long.new => 'v'}
|
116
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
|
117
|
+
assert_equal(columns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
|
118
|
+
assert_equal({}, @twitter.get(:StatusRelationships, 'bogus', 'user_timelines'))
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_get_super_value
|
122
|
+
columns = {Long.new => 'v'}
|
123
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
|
124
|
+
assert_equal('v', @twitter.get(:StatusRelationships, key, 'user_timelines', columns.keys.first))
|
125
|
+
assert_nil @twitter.get(:StatusRelationships, 'bogus', 'user_timelines', columns.keys.first)
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_get_key_range
|
129
|
+
@twitter.insert(:Statuses, '2', {'body' => '1'})
|
130
|
+
@twitter.insert(:Statuses, '3', {'body' => '1'})
|
131
|
+
@twitter.insert(:Statuses, '4', {'body' => '1'})
|
132
|
+
@twitter.insert(:Statuses, '5', {'body' => '1'})
|
133
|
+
@twitter.insert(:Statuses, '6', {'body' => '1'})
|
134
|
+
assert_equal(['3', '4', '5'], @twitter.get_key_range(:Statuses, '3'..'5'))
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_multi_get
|
138
|
+
@twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
|
139
|
+
@twitter.insert(:Users, key + '2', {'body' => 'v2', 'user' => 'v2'})
|
140
|
+
assert_equal(
|
141
|
+
OrderedHash[key + '1', {'body' => 'v1', 'user' => 'v1'}, key + '2', {'body' => 'v2', 'user' => 'v2'}, 'bogus', {}],
|
142
|
+
@twitter.multi_get(:Users, [key + '1', key + '2', 'bogus']))
|
143
|
+
assert_equal(
|
144
|
+
OrderedHash[key + '2', {'body' => 'v2', 'user' => 'v2'}, 'bogus', {}, key + '1', {'body' => 'v1', 'user' => 'v1'}],
|
145
|
+
@twitter.multi_get(:Users, [key + '2', 'bogus', key + '1']))
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_remove_key
|
149
|
+
@twitter.insert(:Statuses, key, {'body' => 'v'})
|
150
|
+
assert_equal({'body' => 'v'}, @twitter.get(:Statuses, key))
|
151
|
+
|
152
|
+
@twitter.remove(:Statuses, key)
|
153
|
+
assert_equal({}, @twitter.get(:Statuses, key))
|
154
|
+
assert_equal 0, @twitter.count(:Statuses)
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_remove_value
|
158
|
+
@twitter.insert(:Statuses, key, {'body' => 'v'})
|
159
|
+
@twitter.remove(:Statuses, key, 'body')
|
160
|
+
assert_nil @twitter.get(:Statuses, key, 'body')
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_remove_super_key
|
164
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => {Long.new => 'v'}})
|
165
|
+
@twitter.remove(:StatusRelationships, key)
|
166
|
+
assert_equal({}, @twitter.get(:StatusRelationships, key))
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_remove_super_sub_key
|
170
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => {Long.new => 'v'}})
|
171
|
+
@twitter.remove(:StatusRelationships, key, 'user_timelines')
|
172
|
+
assert_equal({}, @twitter.get(:StatusRelationships, key, 'user_timelines'))
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_remove_super_value
|
176
|
+
columns = {Long.new => 'v'}
|
177
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
|
178
|
+
@twitter.remove(:StatusRelationships, key, 'user_timelines', columns.keys.first)
|
179
|
+
assert_nil @twitter.get(:StatusRelationships, key, 'user_timelines', columns.keys.first)
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_clear_column_family
|
183
|
+
@twitter.insert(:Statuses, key + "1", {'body' => '1'})
|
184
|
+
@twitter.insert(:Statuses, key + "2", {'body' => '2'})
|
185
|
+
@twitter.insert(:Statuses, key + "3", {'body' => '3'})
|
186
|
+
@twitter.clear_column_family!(:Statuses)
|
187
|
+
assert_equal 0, @twitter.count(:Statuses)
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_insert_key
|
191
|
+
@twitter.insert(:Statuses, key, {'body' => 'v', 'user' => 'v'})
|
192
|
+
assert_equal({'body' => 'v', 'user' => 'v'}, @twitter.get(:Statuses, key))
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_insert_super_key
|
196
|
+
columns = {Long.new => 'v', Long.new => 'v'}
|
197
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => columns})
|
198
|
+
assert_equal(columns, @twitter.get(:StatusRelationships, key, 'user_timelines'))
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_get_columns
|
202
|
+
@twitter.insert(:Statuses, key, {'body' => 'v1', 'user' => 'v2'})
|
203
|
+
assert_equal(['v1' , 'v2'], @twitter.get_columns(:Statuses, key, ['body', 'user']))
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_get_column_values_super
|
207
|
+
user_columns, mentions_columns = {Long.new => 'v1'}, {Long.new => 'v2'}
|
208
|
+
@twitter.insert(:StatusRelationships, key,
|
209
|
+
{'user_timelines' => user_columns, 'mentions_timelines' => mentions_columns})
|
210
|
+
assert_equal [user_columns, mentions_columns],
|
211
|
+
@twitter.get_columns(:StatusRelationships, key, ['user_timelines', 'mentions_timelines'])
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_multi_get_columns
|
215
|
+
@twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
|
216
|
+
@twitter.insert(:Users, key + '2', {'body' => 'v2', 'user' => 'v2'})
|
217
|
+
assert_equal(
|
218
|
+
OrderedHash[key + '1', ['v1', 'v1'], key + '2', ['v2', 'v2'], 'bogus', [nil, nil]],
|
219
|
+
@twitter.multi_get_columns(:Users, [key + '1', key + '2', 'bogus'], ['body', 'user']))
|
220
|
+
assert_equal(
|
221
|
+
OrderedHash[key + '2', ['v2', 'v2'], 'bogus', [nil, nil], key + '1', ['v1', 'v1']],
|
222
|
+
@twitter.multi_get_columns(:Users, [key + '2', 'bogus', key + '1'], ['body', 'user']))
|
223
|
+
end
|
224
|
+
|
225
|
+
# Not supported
|
226
|
+
# def test_get_columns_super_sub
|
227
|
+
# @twitter.insert(:StatusRelationships, key, {
|
228
|
+
# 'user_timelines' => {Long.new => 'v1'},
|
229
|
+
# 'mentions_timelines' => {Long.new => 'v2'}})
|
230
|
+
# assert_equal ['v1', 'v2'],
|
231
|
+
# @twitter.get_columns(:StatusRelationships, key, 'user_timelines', ['1', key])
|
232
|
+
# end
|
233
|
+
|
234
|
+
def test_count_keys
|
235
|
+
@twitter.insert(:Statuses, key + "1", {'body' => '1'})
|
236
|
+
@twitter.insert(:Statuses, key + "2", {'body' => '2'})
|
237
|
+
@twitter.insert(:Statuses, key + "3", {'body' => '3'})
|
238
|
+
assert_equal 3, @twitter.count(:Statuses)
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_count_columns
|
242
|
+
@twitter.insert(:Statuses, key, {'body' => 'v1', 'user' => 'v2'})
|
243
|
+
assert_equal 2, @twitter.count_columns(:Statuses, key)
|
244
|
+
end
|
245
|
+
|
246
|
+
def test_count_super_columns
|
247
|
+
@twitter.insert(:StatusRelationships, key, {
|
248
|
+
'user_timelines' => {Long.new => 'v1'},
|
249
|
+
'mentions_timelines' => {Long.new => 'v2'}})
|
250
|
+
assert_equal 2, @twitter.count_columns(:StatusRelationships, key)
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_count_super_sub_columns
|
254
|
+
@twitter.insert(:StatusRelationships, key, {'user_timelines' => {Long.new => 'v1', Long.new => 'v2'}})
|
255
|
+
assert_equal 2, @twitter.count_columns(:StatusRelationships, key, 'user_timelines')
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_multi_count_columns
|
259
|
+
@twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
|
260
|
+
@twitter.insert(:Users, key + '2', {'body' => 'v2', 'user' => 'v2'})
|
261
|
+
assert_equal(
|
262
|
+
OrderedHash[key + '1', 2, key + '2', 2, 'bogus', 0],
|
263
|
+
@twitter.multi_count_columns(:Users, [key + '1', key + '2', 'bogus']))
|
264
|
+
assert_equal(
|
265
|
+
OrderedHash[key + '2', 2, 'bogus', 0, key + '1', 2],
|
266
|
+
@twitter.multi_count_columns(:Users, [key + '2', 'bogus', key + '1']))
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_batch_insert
|
270
|
+
@twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
|
271
|
+
|
272
|
+
@twitter.batch do
|
273
|
+
@twitter.insert(:Users, key + '2', {'body' => 'v2', 'user' => 'v2'})
|
274
|
+
@twitter.insert(:Users, key + '3', {'body' => 'bogus', 'user' => 'v3'})
|
275
|
+
@twitter.insert(:Users, key + '3', {'body' => 'v3', 'location' => 'v3'})
|
276
|
+
@twitter.insert(:Statuses, key + '3', {'body' => 'v'})
|
277
|
+
|
278
|
+
assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, key + '1')) # Written
|
279
|
+
assert_equal({}, @twitter.get(:Users, key + '2')) # Not yet written
|
280
|
+
assert_equal({}, @twitter.get(:Statuses, key + '3')) # Not yet written
|
281
|
+
|
282
|
+
@twitter.remove(:Users, key + '1')
|
283
|
+
assert_equal({'body' => 'v1', 'user' => 'v1'}, @twitter.get(:Users, key + '1')) # Not yet removed
|
284
|
+
|
285
|
+
@twitter.remove(:Users, key + '4')
|
286
|
+
@twitter.insert(:Users, key + '4', {'body' => 'v4', 'user' => 'v4'})
|
287
|
+
assert_equal({}, @twitter.get(:Users, key + '4')) # Not yet written
|
288
|
+
end
|
289
|
+
|
290
|
+
assert_equal({'body' => 'v2', 'user' => 'v2'}, @twitter.get(:Users, key + '2')) # Written
|
291
|
+
assert_equal({'body' => 'v3', 'user' => 'v3', 'location' => 'v3'}, @twitter.get(:Users, key + '3')) # Written and compacted
|
292
|
+
assert_equal({'body' => 'v4', 'user' => 'v4'}, @twitter.get(:Users, key + '4')) # Written
|
293
|
+
assert_equal({'body' => 'v'}, @twitter.get(:Statuses, key + '3')) # Written
|
294
|
+
assert_equal({}, @twitter.get(:Users, key + '1')) # Removed
|
295
|
+
end
|
296
|
+
|
297
|
+
private
|
298
|
+
|
299
|
+
def key
|
300
|
+
caller.first[/`(.*?)'/, 1]
|
301
|
+
end
|
302
|
+
end
|