cassilds 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/CHANGELOG +53 -0
  2. data/LICENSE +202 -0
  3. data/Manifest +45 -0
  4. data/README.rdoc +83 -0
  5. data/Rakefile +9 -0
  6. data/bin/cassandra_helper +16 -0
  7. data/cassandra.gemspec +46 -0
  8. data/conf/cassandra.in.sh +47 -0
  9. data/conf/cassandra.yaml +113 -0
  10. data/conf/log4j.properties +38 -0
  11. data/conf/storage-conf.xml +342 -0
  12. data/lib/cassandra/0.6/cassandra.rb +68 -0
  13. data/lib/cassandra/0.6/columns.rb +35 -0
  14. data/lib/cassandra/0.6/protocol.rb +92 -0
  15. data/lib/cassandra/0.6.rb +7 -0
  16. data/lib/cassandra/0.7/cassandra.rb +272 -0
  17. data/lib/cassandra/0.7/column_family.rb +3 -0
  18. data/lib/cassandra/0.7/columns.rb +67 -0
  19. data/lib/cassandra/0.7/keyspace.rb +3 -0
  20. data/lib/cassandra/0.7/protocol.rb +139 -0
  21. data/lib/cassandra/0.7.rb +7 -0
  22. data/lib/cassandra/array.rb +8 -0
  23. data/lib/cassandra/cassandra.rb +302 -0
  24. data/lib/cassandra/columns.rb +79 -0
  25. data/lib/cassandra/comparable.rb +28 -0
  26. data/lib/cassandra/constants.rb +11 -0
  27. data/lib/cassandra/debug.rb +9 -0
  28. data/lib/cassandra/helpers.rb +40 -0
  29. data/lib/cassandra/long.rb +58 -0
  30. data/lib/cassandra/mock.rb +326 -0
  31. data/lib/cassandra/ordered_hash.rb +200 -0
  32. data/lib/cassandra/time.rb +11 -0
  33. data/lib/cassandra.rb +39 -0
  34. data/test/cassandra_client_test.rb +20 -0
  35. data/test/cassandra_mock_test.rb +73 -0
  36. data/test/cassandra_test.rb +412 -0
  37. data/test/comparable_types_test.rb +45 -0
  38. data/test/eventmachine_test.rb +42 -0
  39. data/test/ordered_hash_test.rb +380 -0
  40. data/test/test_helper.rb +14 -0
  41. data/vendor/0.6/gen-rb/cassandra.rb +1481 -0
  42. data/vendor/0.6/gen-rb/cassandra_constants.rb +12 -0
  43. data/vendor/0.6/gen-rb/cassandra_types.rb +482 -0
  44. data/vendor/0.7/gen-rb/cassandra.rb +1937 -0
  45. data/vendor/0.7/gen-rb/cassandra_constants.rb +12 -0
  46. data/vendor/0.7/gen-rb/cassandra_types.rb +679 -0
  47. metadata +176 -0
@@ -0,0 +1,326 @@
1
+ require 'nokogiri'
2
+
3
+ class SimpleUUID::UUID
4
+ def >=(other)
5
+ (self <=> other) >= 0
6
+ end
7
+
8
+ def <=(other)
9
+ (self <=> other) <= 0
10
+ end
11
+ end
12
+
13
+ class Cassandra
14
+ class Mock
15
+ include ::Cassandra::Helpers
16
+ include ::Cassandra::Columns
17
+
18
+ def initialize(keyspace, storage_xml)
19
+ @keyspace = keyspace
20
+ @column_name_class = {}
21
+ @sub_column_name_class = {}
22
+ @storage_xml = storage_xml
23
+ clear_keyspace!
24
+ end
25
+
26
+ def disconnect!
27
+ end
28
+
29
+ def clear_keyspace!
30
+ @data = {}
31
+ end
32
+
33
+ def clear_column_family!(column_family)
34
+ @data[column_family.to_sym] = OrderedHash.new
35
+ end
36
+
37
+ def insert(column_family, key, hash_or_array, options = {})
38
+ if @batch
39
+ @batch << [:insert, column_family, key, hash_or_array, options]
40
+ else
41
+ raise ArgumentError if key.nil?
42
+ if column_family_type(column_family) == 'Standard'
43
+ insert_standard(column_family, key, hash_or_array)
44
+ else
45
+ insert_super(column_family, key, hash_or_array)
46
+ end
47
+ end
48
+ end
49
+
50
+ def insert_standard(column_family, key, hash_or_array)
51
+ old = cf(column_family)[key] || OrderedHash.new
52
+ cf(column_family)[key] = merge_and_sort(old, hash_or_array)
53
+ end
54
+
55
+ def insert_super(column_family, key, hash)
56
+ raise ArgumentError unless hash.is_a?(Hash)
57
+ cf(column_family)[key] ||= OrderedHash.new
58
+
59
+ hash.keys.each do |sub_key|
60
+ old = cf(column_family)[key][sub_key] || OrderedHash.new
61
+ cf(column_family)[key][sub_key] = merge_and_sort(old, hash[sub_key])
62
+ end
63
+ end
64
+
65
+ def batch
66
+ @batch = []
67
+ yield
68
+ b = @batch
69
+ @batch = nil
70
+ b.each do |mutation|
71
+ send(*mutation)
72
+ end
73
+ ensure
74
+ @batch = nil
75
+ end
76
+
77
+ def get(column_family, key, *columns_and_options)
78
+ column_family, column, sub_column, options =
79
+ extract_and_validate_params_for_real(column_family, [key], columns_and_options, READ_DEFAULTS)
80
+ if column_family_type(column_family) == 'Standard'
81
+ get_standard(column_family, key, column, options)
82
+ else
83
+ get_super(column_family, key, column, sub_column, options)
84
+ end
85
+ end
86
+
87
+ def get_standard(column_family, key, column, options)
88
+ row = cf(column_family)[key] || OrderedHash.new
89
+ if column
90
+ row[column]
91
+ else
92
+ row = apply_range(row, column_family, options[:start], options[:finish])
93
+ apply_count(row, options[:count], options[:reversed])
94
+ end
95
+ end
96
+
97
+ def get_super(column_family, key, column, sub_column, options)
98
+ if column
99
+ if sub_column
100
+ if cf(column_family)[key] &&
101
+ cf(column_family)[key][column] &&
102
+ cf(column_family)[key][column][sub_column]
103
+ cf(column_family)[key][column][sub_column]
104
+ else
105
+ nil
106
+ end
107
+ else
108
+ row = cf(column_family)[key] && cf(column_family)[key][column] ?
109
+ cf(column_family)[key][column] :
110
+ OrderedHash.new
111
+ row = apply_range(row, column_family, options[:start], options[:finish], false)
112
+ apply_count(row, options[:count], options[:reversed])
113
+ end
114
+ elsif cf(column_family)[key]
115
+ cf(column_family)[key]
116
+ else
117
+ OrderedHash.new
118
+ end
119
+ end
120
+
121
+ def exists?(column_family, key, column=nil)
122
+ !!get(column_family, key, column)
123
+ end
124
+
125
+ def multi_get(column_family, keys, *columns_and_options)
126
+ column_family, column, sub_column, options = extract_and_validate_params_for_real(column_family, keys, columns_and_options, READ_DEFAULTS)
127
+ keys.inject(OrderedHash.new) do |hash, key|
128
+ hash[key] = get(column_family, key)
129
+ hash
130
+ end
131
+ end
132
+
133
+ def remove(column_family, key, *columns_and_options)
134
+ column_family, column, sub_column, options = extract_and_validate_params_for_real(column_family, key, columns_and_options, WRITE_DEFAULTS)
135
+ if @batch
136
+ @batch << [:remove, column_family, key, column]
137
+ else
138
+ if column
139
+ if sub_column
140
+ cf(column_family)[key][column].delete(sub_column)
141
+ else
142
+ cf(column_family)[key].delete(column)
143
+ end
144
+ else
145
+ cf(column_family).delete(key)
146
+ end
147
+ end
148
+ end
149
+
150
+ def get_columns(column_family, key, *columns_and_options)
151
+ column_family, columns, sub_columns, options = extract_and_validate_params_for_real(column_family, key, columns_and_options, READ_DEFAULTS)
152
+ d = get(column_family, key)
153
+
154
+
155
+ if sub_columns
156
+ sub_columns.collect do |sub_column|
157
+ d[columns][sub_column]
158
+ end
159
+ else
160
+ columns.collect do |column|
161
+ d[column]
162
+ end
163
+ end
164
+ end
165
+
166
+ def count_columns(column_family, key, column=nil)
167
+ get(column_family, key, column).keys.length
168
+ end
169
+
170
+ def multi_get_columns(column_family, keys, columns)
171
+ keys.inject(OrderedHash.new) do |hash, key|
172
+ hash[key] = get_columns(column_family, key, columns)
173
+ hash
174
+ end
175
+ end
176
+
177
+ def multi_count_columns(column_family, keys)
178
+ keys.inject(OrderedHash.new) do |hash, key|
179
+ hash[key] = count_columns(column_family, key)
180
+ hash
181
+ end
182
+ end
183
+
184
+ def get_range(column_family, options = {})
185
+ column_family, _, _, options = extract_and_validate_params_for_real(column_family, "", [options], READ_DEFAULTS)
186
+ _get_range(column_family, options[:start], options[:finish], options[:count]).keys
187
+ end
188
+
189
+ def count_range(column_family, options={})
190
+ count = 0
191
+ l = []
192
+ start_key = ''
193
+ while (l = get_range(column_family, options.merge(:count => 1000, :start => start_key))).size > 0
194
+ count += l.size
195
+ start_key = l.last.succ
196
+ end
197
+ count
198
+ end
199
+
200
+ def schema(load=true)
201
+ if !load && !@schema
202
+ []
203
+ else
204
+ @schema ||= schema_for_keyspace(@keyspace)
205
+ end
206
+ end
207
+
208
+ private
209
+
210
+ def _get_range(column_family, start, finish, count)
211
+ ret = OrderedHash.new
212
+ start = to_compare_with_type(start, column_family)
213
+ finish = to_compare_with_type(finish, column_family)
214
+ cf(column_family).keys.sort.each do |key|
215
+ break if ret.keys.size >= count
216
+ if (start.nil? || key >= start) && (finish.nil? || key <= finish)
217
+ ret[key] = cf(column_family)[key]
218
+ end
219
+ end
220
+ ret
221
+ end
222
+
223
+ def schema_for_keyspace(keyspace)
224
+ doc = read_storage_xml
225
+ ret = {}
226
+ doc.css("Keyspaces Keyspace[@Name='#{keyspace}']").css('ColumnFamily').each do |cf|
227
+ ret[cf['Name']] = {}
228
+ if cf['CompareSubcolumnsWith']
229
+ ret[cf['Name']]['CompareSubcolumnsWith'] = 'org.apache.cassandra.db.marshal.' + cf['CompareSubcolumnsWith']
230
+ end
231
+ if cf['CompareWith']
232
+ ret[cf['Name']]['CompareWith'] = 'org.apache.cassandra.db.marshal.' + cf['CompareWith']
233
+ end
234
+ if cf['ColumnType'] == 'Super'
235
+ ret[cf['Name']]['Type'] = 'Super'
236
+ else
237
+ ret[cf['Name']]['Type'] = 'Standard'
238
+ end
239
+ end
240
+ ret
241
+ end
242
+
243
+ def read_storage_xml
244
+ @doc ||= Nokogiri::XML(open(@storage_xml))
245
+ end
246
+
247
+ def extract_and_validate_params_for_real(column_family, keys, args, options)
248
+ column_family, columns, sub_column, options = extract_and_validate_params(column_family, keys, args, options)
249
+ options[:start] = nil if options[:start] == ''
250
+ options[:finish] = nil if options[:finish] == ''
251
+ [column_family, to_compare_with_types(columns, column_family), to_compare_with_types(sub_column, column_family, false), options]
252
+ end
253
+
254
+ def to_compare_with_types(column_names, column_family, standard=true)
255
+ if column_names.is_a?(Array)
256
+ column_names.collect do |name|
257
+ to_compare_with_type(name, column_family, standard)
258
+ end
259
+ else
260
+ to_compare_with_type(column_names, column_family, standard)
261
+ end
262
+ end
263
+
264
+ def to_compare_with_type(column_name, column_family, standard=true)
265
+ return column_name if column_name.nil?
266
+ klass = if standard
267
+ schema[column_family.to_s]["CompareWith"]
268
+ else
269
+ schema[column_family.to_s]["CompareSubcolumnsWith"]
270
+ end
271
+
272
+ case klass
273
+ when "org.apache.cassandra.db.marshal.UTF8Type", "org.apache.cassandra.db.marshal.BytesType"
274
+ column_name
275
+ when "org.apache.cassandra.db.marshal.TimeUUIDType"
276
+ SimpleUUID::UUID.new(column_name)
277
+ when "org.apache.cassandra.db.marshal.LongType"
278
+ Long.new(column_name)
279
+ else
280
+ raise "Unknown column family type: #{klass.inspect}"
281
+ end
282
+ end
283
+
284
+ def column_family_type(column_family)
285
+ schema[column_family.to_s]['Type']
286
+ end
287
+
288
+ def cf(column_family)
289
+ @data[column_family.to_sym] ||= OrderedHash.new
290
+ end
291
+
292
+ def merge_and_sort(old_stuff, new_stuff)
293
+ if new_stuff.is_a?(Array)
294
+ new_stuff = new_stuff.inject({}){|h,k| h[k] = nil; h }
295
+ end
296
+ OrderedHash[old_stuff.merge(new_stuff).sort{|a,b| a[0] <=> b[0]}]
297
+ end
298
+
299
+ def apply_count(row, count, reversed=false)
300
+ if count
301
+ keys = row.keys.sort
302
+ keys = keys.reverse if reversed
303
+ keys = keys[0...count]
304
+ keys.inject(OrderedHash.new) do |memo, key|
305
+ memo[key] = row[key]
306
+ memo
307
+ end
308
+ else
309
+ row
310
+ end
311
+ end
312
+
313
+ def apply_range(row, column_family, strt, fin, standard=true)
314
+ start = to_compare_with_type(strt, column_family, standard)
315
+ finish = to_compare_with_type(fin, column_family, standard)
316
+ ret = OrderedHash.new
317
+ row.keys.each do |key|
318
+ if (start.nil? || key >= start) && (finish.nil? || key <= finish)
319
+ ret[key] = row[key]
320
+ end
321
+ end
322
+ ret
323
+ end
324
+
325
+ end
326
+ end
@@ -0,0 +1,200 @@
1
+ # OrderedHash is namespaced to prevent conflicts with other implementations
2
+ class Cassandra
3
+ # Hash is ordered in Ruby 1.9!
4
+ if RUBY_VERSION >= '1.9'
5
+ OrderedHashInt = ::Hash
6
+ else
7
+ class OrderedHashInt < Hash #:nodoc:
8
+ def initialize(*args, &block)
9
+ super
10
+ @keys = []
11
+ end
12
+
13
+ def self.[](*args)
14
+ ordered_hash = new
15
+
16
+ if (args.length == 1 && args.first.is_a?(Array))
17
+ args.first.each do |key_value_pair|
18
+ next unless (key_value_pair.is_a?(Array))
19
+ ordered_hash[key_value_pair[0]] = key_value_pair[1]
20
+ end
21
+
22
+ return ordered_hash
23
+ end
24
+
25
+ unless (args.size % 2 == 0)
26
+ raise ArgumentError.new("odd number of arguments for Hash")
27
+ end
28
+
29
+ args.each_with_index do |val, ind|
30
+ next if (ind % 2 != 0)
31
+ ordered_hash[val] = args[ind + 1]
32
+ end
33
+
34
+ ordered_hash
35
+ end
36
+
37
+ def initialize_copy(other)
38
+ super
39
+ # make a deep copy of keys
40
+ @keys = other.keys
41
+ end
42
+
43
+ def []=(key, value)
44
+ @keys << key if !has_key?(key)
45
+ super
46
+ end
47
+
48
+ def delete(key)
49
+ if has_key? key
50
+ index = @keys.index(key)
51
+ @keys.delete_at index
52
+ end
53
+ super
54
+ end
55
+
56
+ def delete_if
57
+ super
58
+ sync_keys!
59
+ self
60
+ end
61
+
62
+ def reject!
63
+ super
64
+ sync_keys!
65
+ self
66
+ end
67
+
68
+ def reject(&block)
69
+ dup.reject!(&block)
70
+ end
71
+
72
+ def keys
73
+ @keys.dup
74
+ end
75
+
76
+ def values
77
+ @keys.collect { |key| self[key] }
78
+ end
79
+
80
+ def to_hash
81
+ self
82
+ end
83
+
84
+ def to_a
85
+ @keys.map { |key| [ key, self[key] ] }
86
+ end
87
+
88
+ def each_key
89
+ @keys.each { |key| yield key }
90
+ end
91
+
92
+ def each_value
93
+ @keys.each { |key| yield self[key]}
94
+ end
95
+
96
+ def each
97
+ @keys.each {|key| yield [key, self[key]]}
98
+ end
99
+
100
+ alias_method :each_pair, :each
101
+
102
+ def clear
103
+ super
104
+ @keys.clear
105
+ self
106
+ end
107
+
108
+ def shift
109
+ k = @keys.first
110
+ v = delete(k)
111
+ [k, v]
112
+ end
113
+
114
+ def merge!(other_hash)
115
+ other_hash.each {|k,v| self[k] = v }
116
+ self
117
+ end
118
+
119
+ def merge(other_hash)
120
+ dup.merge!(other_hash)
121
+ end
122
+
123
+ # When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
124
+ def replace(other)
125
+ super
126
+ @keys = other.keys
127
+ self
128
+ end
129
+
130
+ private
131
+
132
+ def sync_keys!
133
+ @keys.delete_if {|k| !has_key?(k)}
134
+ end
135
+ end
136
+ end
137
+
138
+ class OrderedHash < OrderedHashInt #:nodoc:
139
+ def initialize(*args, &block)
140
+ @timestamps = Hash.new
141
+ super
142
+ end
143
+
144
+ def initialize_copy(other)
145
+ @timestamps = other.timestamps
146
+ super
147
+ end
148
+
149
+ def []=(key, value, timestamp = nil)
150
+ @timestamps[key] = timestamp
151
+ super(key, value)
152
+ end
153
+
154
+ def delete(key)
155
+ @timestamps.delete(key)
156
+ super
157
+ end
158
+
159
+ def delete_if
160
+ @timestamps.delete_if
161
+ super
162
+ end
163
+
164
+ def reject!
165
+ @timestamps.reject!
166
+ super
167
+ end
168
+
169
+ def timestamps
170
+ @timestamps.dup
171
+ end
172
+
173
+ def clear
174
+ @timestamps.clear
175
+ super
176
+ end
177
+
178
+ def shift
179
+ k, v = super
180
+ @timestamps.delete(k)
181
+ [k, v]
182
+ end
183
+
184
+ def replace(other)
185
+ @timestamps = other.timestamps
186
+ super
187
+ end
188
+
189
+ def inspect
190
+ "#<OrderedHash #{super}--TimeStamps: #{@timestamps.inspect}>"
191
+ end
192
+
193
+ private
194
+
195
+ def sync_keys!
196
+ @timestamps.delete_if {|k,v| !has_key?(k)}
197
+ super
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,11 @@
1
+
2
+ class Time
3
+ def self.stamp
4
+ Time.now.utc.stamp
5
+ end
6
+
7
+ def stamp
8
+ to_i * 1_000_000 + usec
9
+ end
10
+ end
11
+
data/lib/cassandra.rb ADDED
@@ -0,0 +1,39 @@
1
+ require 'rubygems'
2
+ gem 'thrift', '~> 0.5.0'
3
+ require 'thrift'
4
+ gem 'thrift_client', '~> 0.6.0'
5
+ require 'thrift_client'
6
+ gem 'simple_uuid' , '~> 0.1.0'
7
+ require 'simple_uuid'
8
+
9
+ require 'json' unless defined?(JSON)
10
+
11
+ here = File.expand_path(File.dirname(__FILE__))
12
+
13
+ class Cassandra ; end
14
+ unless Cassandra.respond_to?(:VERSION)
15
+ require "#{here}/cassandra/0.7"
16
+ end
17
+
18
+ $LOAD_PATH << "#{here}/../vendor/#{Cassandra.VERSION}/gen-rb"
19
+ require "#{here}/../vendor/#{Cassandra.VERSION}/gen-rb/cassandra"
20
+
21
+ $LOAD_PATH << "#{here}"
22
+
23
+ require 'cassandra/helpers'
24
+ require 'cassandra/array'
25
+ require 'cassandra/time'
26
+ require 'cassandra/comparable'
27
+ require 'cassandra/long'
28
+ require 'cassandra/ordered_hash'
29
+ require 'cassandra/columns'
30
+ require "cassandra/#{Cassandra.VERSION}/columns"
31
+ require "cassandra/#{Cassandra.VERSION}/protocol"
32
+ require "cassandra/cassandra"
33
+ require "cassandra/#{Cassandra.VERSION}/cassandra"
34
+ unless Cassandra.VERSION.eql?("0.6")
35
+ require "cassandra/#{Cassandra.VERSION}/column_family"
36
+ require "cassandra/#{Cassandra.VERSION}/keyspace"
37
+ end
38
+ require 'cassandra/constants'
39
+ require 'cassandra/debug' if ENV['DEBUG']
@@ -0,0 +1,20 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ class CassandraClientTest < Test::Unit::TestCase
4
+ include Cassandra::Constants
5
+
6
+ def setup
7
+ @twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2, :exception_classes => [])
8
+ end
9
+
10
+ def test_client_method_is_called
11
+ assert_nil @twitter.instance_variable_get(:@client)
12
+ @twitter.insert(:Statuses, key, {'1' => 'v', '2' => 'v', '3' => 'v'})
13
+ assert_not_nil @twitter.instance_variable_get(:@client)
14
+ end
15
+
16
+ def key
17
+ caller.first[/`(.*?)'/, 1]
18
+ end
19
+
20
+ end
@@ -0,0 +1,73 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+ require 'cassandra_test'
3
+ require 'cassandra/mock'
4
+
5
+ class CassandraMockTest < CassandraTest
6
+ include Cassandra::Constants
7
+
8
+ def setup
9
+ storage_xml_path = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'conf', 'storage-conf.xml'))
10
+ @twitter = Cassandra::Mock.new('Twitter', storage_xml_path)
11
+ @twitter.clear_keyspace!
12
+
13
+ @blogs = Cassandra::Mock.new('Multiblog', storage_xml_path)
14
+ @blogs.clear_keyspace!
15
+
16
+ @blogs_long = Cassandra::Mock.new('MultiblogLong', storage_xml_path)
17
+ @blogs_long.clear_keyspace!
18
+
19
+ @uuids = (0..6).map {|i| SimpleUUID::UUID.new(Time.at(2**(24+i))) }
20
+ @longs = (0..6).map {|i| Long.new(Time.at(2**(24+i))) }
21
+ end
22
+
23
+ def test_setup
24
+ assert @twitter
25
+ assert @blogs
26
+ assert @blogs_long
27
+ end
28
+
29
+ def test_schema_for_keyspace
30
+ data = {
31
+ "StatusRelationships"=>{
32
+ "CompareSubcolumnsWith"=>"org.apache.cassandra.db.marshal.TimeUUIDType",
33
+ "CompareWith"=>"org.apache.cassandra.db.marshal.UTF8Type",
34
+ "Type"=>"Super"},
35
+ "StatusAudits"=>{
36
+ "CompareWith"=>"org.apache.cassandra.db.marshal.UTF8Type",
37
+ "Type"=>"Standard"},
38
+ "Statuses"=>{
39
+ "CompareWith"=>"org.apache.cassandra.db.marshal.UTF8Type",
40
+ "Type"=>"Standard"},
41
+ "UserRelationships"=>{
42
+ "CompareSubcolumnsWith"=>"org.apache.cassandra.db.marshal.TimeUUIDType",
43
+ "CompareWith"=>"org.apache.cassandra.db.marshal.UTF8Type",
44
+ "Type"=>"Super"},
45
+ "UserAudits"=>{
46
+ "CompareWith"=>"org.apache.cassandra.db.marshal.UTF8Type",
47
+ "Type"=>"Standard"},
48
+ "Users"=>{"CompareWith"=>"org.apache.cassandra.db.marshal.UTF8Type", "Type"=>"Standard"},
49
+ "TimelinishThings"=>
50
+ {"CompareWith"=>"org.apache.cassandra.db.marshal.BytesType", "Type"=>"Standard"}
51
+ }
52
+ stuff = @twitter.send(:schema_for_keyspace, 'Twitter')
53
+ data.keys.each do |k|
54
+ assert_equal data[k], stuff[k], k
55
+ end
56
+ end
57
+
58
+ def test_sorting_row_keys
59
+ @twitter.insert(:Statuses, 'b', {:text => 'foo'})
60
+ @twitter.insert(:Statuses, 'a', {:text => 'foo'})
61
+ assert_equal ['a'], @twitter.get_range(:Statuses, :count => 1)
62
+ end
63
+
64
+ def test_inserting_array_for_indices
65
+ @twitter.insert(:TimelinishThings, 'a', ['1','2'])
66
+ row = @twitter.get(:TimelinishThings, 'a')
67
+ assert_equal({'1' => nil, '2' => nil}, row)
68
+
69
+ assert_raises(ArgumentError) {
70
+ @twitter.insert(:UserRelationships, 'a', ['u1','u2'])
71
+ }
72
+ end
73
+ end