cassilds 0.9.2 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/CHANGELOG +51 -1
  2. data/LICENSE +0 -0
  3. data/Manifest +25 -7
  4. data/README.md +352 -0
  5. data/Rakefile +169 -1
  6. data/cassilds.gemspec +45 -0
  7. data/conf/{cassandra.in.sh → 0.6/cassandra.in.sh} +0 -0
  8. data/conf/{log4j.properties → 0.6/log4j.properties} +0 -0
  9. data/conf/0.6/schema.json +57 -0
  10. data/conf/{storage-conf.xml → 0.6/storage-conf.xml} +15 -5
  11. data/conf/0.7/cassandra.in.sh +46 -0
  12. data/conf/0.7/cassandra.yaml +336 -0
  13. data/conf/0.7/log4j-server.properties +41 -0
  14. data/conf/0.7/schema.json +57 -0
  15. data/conf/0.7/schema.txt +45 -0
  16. data/conf/0.8/cassandra.in.sh +41 -0
  17. data/conf/0.8/cassandra.yaml +61 -0
  18. data/conf/0.8/log4j-server.properties +40 -0
  19. data/conf/0.8/schema.json +66 -0
  20. data/conf/0.8/schema.txt +51 -0
  21. data/lib/cassandra/0.6/cassandra.rb +58 -13
  22. data/lib/cassandra/0.6/columns.rb +43 -0
  23. data/lib/cassandra/0.6/protocol.rb +16 -18
  24. data/lib/cassandra/0.6.rb +0 -0
  25. data/lib/cassandra/0.7/cassandra.rb +0 -270
  26. data/lib/cassandra/0.7/columns.rb +1 -64
  27. data/lib/cassandra/0.7/protocol.rb +0 -134
  28. data/lib/cassandra/0.7.rb +0 -0
  29. data/lib/cassandra/0.8/cassandra.rb +10 -0
  30. data/lib/cassandra/0.8/columns.rb +4 -0
  31. data/lib/cassandra/0.8/protocol.rb +23 -0
  32. data/lib/cassandra/0.8.rb +7 -0
  33. data/lib/cassandra/array.rb +0 -0
  34. data/lib/cassandra/cassandra.rb +877 -111
  35. data/lib/cassandra/{0.7/column_family.rb → column_family.rb} +0 -0
  36. data/lib/cassandra/columns.rb +72 -6
  37. data/lib/cassandra/comparable.rb +0 -0
  38. data/lib/cassandra/constants.rb +0 -0
  39. data/lib/cassandra/debug.rb +0 -0
  40. data/lib/cassandra/helpers.rb +1 -0
  41. data/lib/cassandra/{0.7/keyspace.rb → keyspace.rb} +0 -0
  42. data/lib/cassandra/long.rb +5 -0
  43. data/lib/cassandra/mock.rb +259 -85
  44. data/lib/cassandra/ordered_hash.rb +10 -18
  45. data/lib/cassandra/protocol.rb +120 -0
  46. data/lib/cassandra/time.rb +0 -0
  47. data/lib/cassandra.rb +6 -7
  48. data/test/cassandra_client_test.rb +0 -0
  49. data/test/cassandra_mock_test.rb +52 -28
  50. data/test/cassandra_test.rb +465 -44
  51. data/test/comparable_types_test.rb +0 -0
  52. data/test/eventmachine_test.rb +30 -30
  53. data/test/ordered_hash_test.rb +6 -0
  54. data/test/test_helper.rb +3 -2
  55. data/vendor/0.6/gen-rb/cassandra.rb +0 -0
  56. data/vendor/0.6/gen-rb/cassandra_constants.rb +0 -0
  57. data/vendor/0.6/gen-rb/cassandra_types.rb +0 -0
  58. data/vendor/0.7/gen-rb/cassandra.rb +0 -0
  59. data/vendor/0.7/gen-rb/cassandra_constants.rb +0 -0
  60. data/vendor/0.7/gen-rb/cassandra_types.rb +4 -2
  61. data/vendor/0.8/gen-rb/cassandra.rb +2215 -0
  62. data/vendor/0.8/gen-rb/cassandra_constants.rb +12 -0
  63. data/vendor/0.8/gen-rb/cassandra_types.rb +816 -0
  64. metadata +50 -27
  65. data/README.rdoc +0 -83
  66. data/cassandra.gemspec +0 -46
  67. data/conf/cassandra.yaml +0 -113
@@ -4,15 +4,15 @@ class Cassandra
4
4
  module Columns #:nodoc:
5
5
 
6
6
  def is_super(column_family)
7
- @is_super[column_family] ||= column_family_property(column_family, 'Type') == "Super"
7
+ @is_super[column_family] ||= column_family_property(column_family, 'column_type') == "Super"
8
8
  end
9
9
 
10
10
  def column_name_class(column_family)
11
- @column_name_class[column_family] ||= column_name_class_for_key(column_family, "CompareWith")
11
+ @column_name_class[column_family] ||= column_name_class_for_key(column_family, "comparator_type")
12
12
  end
13
13
 
14
14
  def sub_column_name_class(column_family)
15
- @sub_column_name_class[column_family] ||= column_name_class_for_key(column_family, "CompareSubcolumnsWith")
15
+ @sub_column_name_class[column_family] ||= column_name_class_for_key(column_family, "subcomparator_type")
16
16
  end
17
17
 
18
18
  private
@@ -29,10 +29,20 @@ class Cassandra
29
29
  end
30
30
 
31
31
  def column_family_property(column_family, key)
32
- unless schema[column_family]
32
+ cfdef = schema.cf_defs.find {|cfdef| cfdef.name == column_family }
33
+ unless cfdef
33
34
  raise AccessError, "Invalid column family \"#{column_family}\""
34
35
  end
35
- schema[column_family][key]
36
+ cfdef.send(key)
37
+ end
38
+
39
+ def multi_key_slices_to_hash(column_family, array, return_empty_rows = false)
40
+ ret = OrderedHash.new
41
+ array.each do |value|
42
+ next if return_empty_rows == false && value.columns.length == 0
43
+ ret[value.key] = columns_to_hash(column_family, value.columns)
44
+ end
45
+ ret
36
46
  end
37
47
 
38
48
  def multi_column_to_hash!(hash)
@@ -64,16 +74,72 @@ class Cassandra
64
74
  def columns_to_hash_for_classes(columns, column_name_class, sub_column_name_class = nil)
65
75
  hash = OrderedHash.new
66
76
  Array(columns).each do |c|
67
- c = c.super_column || c.column if c.is_a?(CassandraThrift::ColumnOrSuperColumn)
77
+ c = c.super_column || c.column || c.counter_column if c.is_a?(CassandraThrift::ColumnOrSuperColumn)
68
78
  case c
69
79
  when CassandraThrift::SuperColumn
70
80
  hash.[]=(column_name_class.new(c.name), columns_to_hash_for_classes(c.columns, sub_column_name_class)) # Pop the class stack, and recurse
71
81
  when CassandraThrift::Column
72
82
  hash.[]=(column_name_class.new(c.name), c.value, c.timestamp)
83
+ when CassandraThrift::CounterColumn
84
+ hash.[]=(column_name_class.new(c.name), c.value, 0)
73
85
  end
74
86
  end
75
87
  hash
76
88
  end
77
89
 
90
+ def _standard_insert_mutation(column_family, column_name, value, timestamp, ttl = nil)
91
+ CassandraThrift::Mutation.new(
92
+ :column_or_supercolumn => CassandraThrift::ColumnOrSuperColumn.new(
93
+ :column => CassandraThrift::Column.new(
94
+ :name => column_name_class(column_family).new(column_name).to_s,
95
+ :value => value,
96
+ :timestamp => timestamp,
97
+ :ttl => ttl
98
+ )
99
+ )
100
+ )
101
+ end
102
+
103
+ def _super_insert_mutation(column_family, super_column_name, sub_columns, timestamp, ttl = nil)
104
+ CassandraThrift::Mutation.new(:column_or_supercolumn =>
105
+ CassandraThrift::ColumnOrSuperColumn.new(
106
+ :super_column => CassandraThrift::SuperColumn.new(
107
+ :name => column_name_class(column_family).new(super_column_name).to_s,
108
+ :columns => sub_columns.collect { |sub_column_name, sub_column_value|
109
+ CassandraThrift::Column.new(
110
+ :name => sub_column_name_class(column_family).new(sub_column_name).to_s,
111
+ :value => sub_column_value.to_s,
112
+ :timestamp => timestamp,
113
+ :ttl => ttl
114
+ )
115
+ }
116
+ )
117
+ )
118
+ )
119
+ end
120
+
121
+ # General info about a deletion object within a mutation
122
+ # timestamp - required. If this is the only param, it will cause deletion of the whole key at that TS
123
+ # supercolumn - opt. If passed, the deletes will only occur within that supercolumn (only subcolumns
124
+ # will be deleted). Otherwise the normal columns will be deleted.
125
+ # predicate - opt. Defines how to match the columns to delete. if supercolumn passed, the slice will
126
+ # be scoped to subcolumns of that supercolumn.
127
+
128
+ # Deletes a single column from the containing key/CF (and possibly supercolumn), at a given timestamp.
129
+ # Although mutations (as opposed to 'remove' calls) support deleting slices and lists of columns in one shot, this is not implemented here.
130
+ # The main reason being that the batch function takes removes, but removes don't have that capability...so we'd need to change the remove
131
+ # methods to use delete mutation calls...although that might have performance implications. We'll leave that refactoring for later.
132
+ def _delete_mutation(cf, column, subcolumn, timestamp, options={})
133
+ deletion_hash = {:timestamp => timestamp}
134
+ if is_super(cf)
135
+ deletion_hash[:super_column] = column if column
136
+ deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [subcolumn]) if subcolumn
137
+ else
138
+ deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [column]) if column
139
+ end
140
+ CassandraThrift::Mutation.new(
141
+ :deletion => CassandraThrift::Deletion.new(deletion_hash)
142
+ )
143
+ end
78
144
  end
79
145
  end
File without changes
File without changes
File without changes
@@ -17,6 +17,7 @@ class Cassandra
17
17
 
18
18
  # Ranges
19
19
  column, sub_column = args[0], args[1]
20
+ raise ArgumentError, "Invalid arguments: subcolumns specified for a non-supercolumn family" if sub_column && !is_super(column_family)
20
21
  klass, sub_klass = column_name_class(column_family), sub_column_name_class(column_family)
21
22
  range_class = column ? sub_klass : klass
22
23
 
File without changes
@@ -39,6 +39,11 @@ class Cassandra
39
39
  end
40
40
  end
41
41
 
42
+ def to_s
43
+ @bytes
44
+ end
45
+ alias :bytes :to_s
46
+
42
47
  def to_guid
43
48
  "%08x-%04x-%04x" % @bytes.unpack("Nnn")
44
49
  end
@@ -1,5 +1,3 @@
1
- require 'nokogiri'
2
-
3
1
  class SimpleUUID::UUID
4
2
  def >=(other)
5
3
  (self <=> other) >= 0
@@ -15,11 +13,15 @@ class Cassandra
15
13
  include ::Cassandra::Helpers
16
14
  include ::Cassandra::Columns
17
15
 
18
- def initialize(keyspace, storage_xml)
16
+ attr_reader :keyspace
17
+
18
+ def initialize(keyspace, schema)
19
+ @is_super = {}
19
20
  @keyspace = keyspace
20
21
  @column_name_class = {}
21
22
  @sub_column_name_class = {}
22
- @storage_xml = storage_xml
23
+ @indexes = {}
24
+ @schema = schema[keyspace]
23
25
  clear_keyspace!
24
26
  end
25
27
 
@@ -34,12 +36,20 @@ class Cassandra
34
36
  @data[column_family.to_sym] = OrderedHash.new
35
37
  end
36
38
 
39
+ def default_write_consistency=(value)
40
+ WRITE_DEFAULTS[:consistency] = value
41
+ end
42
+
43
+ def default_read_consistency=(value)
44
+ READ_DEFAULTS[:consistency] = value
45
+ end
46
+
37
47
  def insert(column_family, key, hash_or_array, options = {})
38
48
  if @batch
39
49
  @batch << [:insert, column_family, key, hash_or_array, options]
40
50
  else
41
51
  raise ArgumentError if key.nil?
42
- if column_family_type(column_family) == 'Standard'
52
+ if !is_super(column_family)
43
53
  insert_standard(column_family, key, hash_or_array)
44
54
  else
45
55
  insert_super(column_family, key, hash_or_array)
@@ -77,7 +87,7 @@ class Cassandra
77
87
  def get(column_family, key, *columns_and_options)
78
88
  column_family, column, sub_column, options =
79
89
  extract_and_validate_params_for_real(column_family, [key], columns_and_options, READ_DEFAULTS)
80
- if column_family_type(column_family) == 'Standard'
90
+ if !is_super(column_family)
81
91
  get_standard(column_family, key, column, options)
82
92
  else
83
93
  get_super(column_family, key, column, sub_column, options)
@@ -85,41 +95,44 @@ class Cassandra
85
95
  end
86
96
 
87
97
  def get_standard(column_family, key, column, options)
88
- row = cf(column_family)[key] || OrderedHash.new
98
+ columns = cf(column_family)[key] || OrderedHash.new
99
+ row = columns_to_hash(column_family, columns)
100
+
89
101
  if column
90
102
  row[column]
91
103
  else
92
104
  row = apply_range(row, column_family, options[:start], options[:finish])
93
- apply_count(row, options[:count], options[:reversed])
105
+ row = apply_count(row, options[:count], options[:reversed])
94
106
  end
95
107
  end
96
108
 
97
109
  def get_super(column_family, key, column, sub_column, options)
110
+ columns = cf(column_family)[key] || OrderedHash.new
111
+ row = columns_to_hash(column_family, columns)
112
+
98
113
  if column
99
114
  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]
115
+ if row[column] &&
116
+ row[column][sub_column]
117
+ row[column][sub_column]
104
118
  else
105
119
  nil
106
120
  end
107
121
  else
108
- row = cf(column_family)[key] && cf(column_family)[key][column] ?
109
- cf(column_family)[key][column] :
110
- OrderedHash.new
122
+ row = row[column] || OrderedHash.new
111
123
  row = apply_range(row, column_family, options[:start], options[:finish], false)
112
- apply_count(row, options[:count], options[:reversed])
124
+ row = apply_count(row, options[:count], options[:reversed])
113
125
  end
114
- elsif cf(column_family)[key]
115
- cf(column_family)[key]
116
126
  else
117
- OrderedHash.new
127
+ row
118
128
  end
119
129
  end
120
130
 
121
- def exists?(column_family, key, column=nil)
122
- !!get(column_family, key, column)
131
+ def exists?(column_family, key, *columns_and_options)
132
+ column_family, column, sub_column, options = extract_and_validate_params_for_real(column_family, [key], columns_and_options, READ_DEFAULTS)
133
+ results = get(column_family, key, column, sub_column)
134
+
135
+ ![{}, nil].include?(results)
123
136
  end
124
137
 
125
138
  def multi_get(column_family, keys, *columns_and_options)
@@ -133,13 +146,13 @@ class Cassandra
133
146
  def remove(column_family, key, *columns_and_options)
134
147
  column_family, column, sub_column, options = extract_and_validate_params_for_real(column_family, key, columns_and_options, WRITE_DEFAULTS)
135
148
  if @batch
136
- @batch << [:remove, column_family, key, column]
149
+ @batch << [:remove, column_family, key, column, sub_column]
137
150
  else
138
151
  if column
139
152
  if sub_column
140
- cf(column_family)[key][column].delete(sub_column)
153
+ cf(column_family)[key][column].delete(sub_column.to_s) if cf(column_family)[key][column]
141
154
  else
142
- cf(column_family)[key].delete(column)
155
+ cf(column_family)[key].delete(column.to_s) if cf(column_family)[key]
143
156
  end
144
157
  else
145
158
  cf(column_family).delete(key)
@@ -151,7 +164,6 @@ class Cassandra
151
164
  column_family, columns, sub_columns, options = extract_and_validate_params_for_real(column_family, key, columns_and_options, READ_DEFAULTS)
152
165
  d = get(column_family, key)
153
166
 
154
-
155
167
  if sub_columns
156
168
  sub_columns.collect do |sub_column|
157
169
  d[columns][sub_column]
@@ -163,8 +175,10 @@ class Cassandra
163
175
  end
164
176
  end
165
177
 
166
- def count_columns(column_family, key, column=nil)
167
- get(column_family, key, column).keys.length
178
+ def count_columns(column_family, key, *columns_and_options)
179
+ column_family, columns, sub_columns, options = extract_and_validate_params_for_real(column_family, key, columns_and_options, READ_DEFAULTS)
180
+
181
+ get(column_family, key, columns, options).keys.length
168
182
  end
169
183
 
170
184
  def multi_get_columns(column_family, keys, columns)
@@ -181,67 +195,217 @@ class Cassandra
181
195
  end
182
196
  end
183
197
 
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
198
+ def get_range(column_family, options = {}, &blk)
199
+ column_family, _, _, options = extract_and_validate_params_for_real(column_family, "", [options],
200
+ READ_DEFAULTS.merge(:start_key => nil,
201
+ :finish_key => nil,
202
+ :key_count => 100,
203
+ :columns => nil,
204
+ :reversed => false
205
+ )
206
+ )
207
+ res = _get_range(column_family,
208
+ options[:start_key],
209
+ options[:finish_key],
210
+ options[:key_count],
211
+ options[:columns],
212
+ options[:start],
213
+ options[:finish],
214
+ options[:count],
215
+ options[:consistency],
216
+ options[:reversed], &blk)
217
+
218
+ if blk.nil?
219
+ res
220
+ else
221
+ nil
222
+ end
223
+ end
224
+
225
+ def get_range_keys(column_family, options = {})
226
+ get_range(column_family,options.merge!(:columns => [])).keys
187
227
  end
188
228
 
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
229
+ def count_range(column_family, options = {})
230
+ Hash[get_range(column_family, options).select{|k,v| v.length > 0}].keys.compact.length
231
+ end
232
+
233
+ def each_key(column_family, options = {})
234
+ each(column_family, options.merge!(:columns => [])) do |key, value|
235
+ yield key
196
236
  end
197
- count
198
237
  end
199
238
 
200
- def schema(load=true)
201
- if !load && !@schema
202
- []
239
+ def each(column_family, options = {})
240
+ batch_size = options.delete(:batch_size) || 100
241
+ count = options.delete(:key_count)
242
+ yielded_count = 0
243
+
244
+ options[:start_key] ||= ''
245
+ last_key = nil
246
+
247
+ while options[:start_key] != last_key && (count.nil? || count > yielded_count)
248
+ options[:start_key] = last_key
249
+ res = get_range(column_family, options.merge!(:start_key => last_key, :key_count => batch_size))
250
+ res.each do |key, columns|
251
+ next if options[:start_key] == key
252
+ next if yielded_count == count
253
+ yield key, columns
254
+ yielded_count += 1
255
+ last_key = key
256
+ end
257
+ end
258
+ end
259
+
260
+ def create_index(ks_name, cf_name, c_name, v_class)
261
+ if @indexes[ks_name] &&
262
+ @indexes[ks_name][cf_name] &&
263
+ @indexes[ks_name][cf_name][c_name]
264
+ nil
265
+
203
266
  else
204
- @schema ||= schema_for_keyspace(@keyspace)
267
+ @indexes[ks_name] ||= {}
268
+ @indexes[ks_name][cf_name] ||= {}
269
+ @indexes[ks_name][cf_name][c_name] = true
205
270
  end
206
271
  end
207
272
 
208
- private
273
+ def drop_index(ks_name, cf_name, c_name)
274
+ if @indexes[ks_name] &&
275
+ @indexes[ks_name][cf_name] &&
276
+ @indexes[ks_name][cf_name][c_name]
209
277
 
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
278
+ @indexes[ks_name][cf_name].delete(c_name)
279
+ else
280
+ nil
219
281
  end
220
- ret
221
282
  end
222
283
 
223
- def schema_for_keyspace(keyspace)
224
- doc = read_storage_xml
284
+ def create_index_expression(c_name, value, op)
285
+ {:column_name => c_name, :value => value, :comparison => op}
286
+ end
287
+ alias :create_idx_expr :create_index_expression
288
+
289
+ def create_index_clause(idx_expressions, start = "", count = 100)
290
+ {:start => start, :index_expressions => idx_expressions, :count => count, :type => :index_clause}
291
+ end
292
+ alias :create_idx_clause :create_index_clause
293
+
294
+ def get_indexed_slices(column_family, idx_clause, *columns_and_options)
295
+ column_family, columns, _, options =
296
+ extract_and_validate_params_for_real(column_family, [], columns_and_options, READ_DEFAULTS.merge(:key_count => 100, :key_start => ""))
297
+
298
+ unless [Hash, OrderedHash].include?(idx_clause.class) && idx_clause[:type] == :index_clause
299
+ idx_clause = create_index_clause(idx_clause, options[:key_start], options[:key_count])
300
+ end
301
+
225
302
  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'
303
+ cf(column_family).each do |key, row|
304
+ next if idx_clause[:start] != '' && key < idx_clause[:start]
305
+ next if ret.length == idx_clause[:count]
306
+
307
+ matches = []
308
+ idx_clause[:index_expressions].each do |expr|
309
+ next if row[expr[:column_name]].nil?
310
+ next unless row[expr[:column_name]].send(expr[:comparison].to_sym, expr[:value])
311
+
312
+ matches << expr
238
313
  end
314
+
315
+ ret[key] = row if matches.length == idx_clause[:index_expressions].length
239
316
  end
317
+
240
318
  ret
241
319
  end
242
320
 
243
- def read_storage_xml
244
- @doc ||= Nokogiri::XML(open(@storage_xml))
321
+ def add(column_family, key, value, *columns_and_options)
322
+ column_family, column, sub_column, options = extract_and_validate_params_for_real(column_family, key, columns_and_options, WRITE_DEFAULTS)
323
+
324
+ if is_super(column_family)
325
+ cf(column_family)[key] ||= OrderedHash.new
326
+ cf(column_family)[key][column] ||= OrderedHash.new
327
+ cf(column_family)[key][column][sub_column] ||= 0
328
+ cf(column_family)[key][column][sub_column] += value
329
+ else
330
+ cf(column_family)[key] ||= OrderedHash.new
331
+ cf(column_family)[key][column] ||= 0
332
+ cf(column_family)[key][column] += value
333
+ end
334
+
335
+ nil
336
+ end
337
+
338
+ def column_families
339
+ cf_defs = {}
340
+ schema.each do |key, value|
341
+ cf_def = Cassandra::ColumnFamily.new
342
+
343
+ value.each do |property, property_value|
344
+ cf_def.send(:"#{property}=", property_value)
345
+ end
346
+
347
+ cf_defs[key] = cf_def
348
+ end
349
+
350
+ cf_defs
351
+ end
352
+
353
+ def schema(load=true)
354
+ @schema
355
+ end
356
+
357
+ def column_family_property(column_family, key)
358
+ schema[column_family.to_s][key]
359
+ end
360
+
361
+ def add_column_family(cf)
362
+ @schema[cf.name.to_s] ||= OrderedHash.new
363
+
364
+ cf.instance_variables.each do |var|
365
+ @schema[cf.name.to_s][var.slice(1..-1)] = cf.instance_variable_get(var)
366
+ end
367
+ end
368
+
369
+ def update_column_family(cf)
370
+ return false unless @schema.include?(cf.name.to_s)
371
+
372
+ cf.instance_variables.each do |var|
373
+ @schema[cf.name.to_s][var.slice(1..-1)] = cf.instance_variable_get(var)
374
+ end
375
+ end
376
+
377
+ def drop_column_family(column_family_name)
378
+ @schema.delete(column_family_name)
379
+ end
380
+
381
+ private
382
+
383
+ def schema_for_keyspace(keyspace)
384
+ @schema
385
+ end
386
+
387
+ def _get_range(column_family, start_key, finish_key, key_count, columns, start, finish, count, consistency, reversed, &blk)
388
+ ret = OrderedHash.new
389
+ start = to_compare_with_type(start, column_family)
390
+ finish = to_compare_with_type(finish, column_family)
391
+ cf(column_family).keys.sort.each do |key|
392
+ break if ret.keys.size >= key_count
393
+ if (start_key.nil? || key >= start_key) && (finish_key.nil? || key <= finish_key)
394
+ if columns
395
+ #ret[key] = columns.inject(OrderedHash.new){|hash, column_name| hash[column_name] = cf(column_family)[key][column_name]; hash;}
396
+ ret[key] = columns_to_hash(column_family, cf(column_family)[key].select{|k,v| columns.include?(k)})
397
+ ret[key] = apply_count(ret[key], count, reversed)
398
+ blk.call(key,ret[key]) unless blk.nil?
399
+ else
400
+ #ret[key] = apply_range(cf(column_family)[key], column_family, start, finish, !is_super(column_family))
401
+ start, finish = finish, start if reversed
402
+ ret[key] = apply_range(columns_to_hash(column_family, cf(column_family)[key]), column_family, start, finish)
403
+ ret[key] = apply_count(ret[key], count, reversed)
404
+ blk.call(key,ret[key]) unless blk.nil?
405
+ end
406
+ end
407
+ end
408
+ ret
245
409
  end
246
410
 
247
411
  def extract_and_validate_params_for_real(column_family, keys, args, options)
@@ -264,25 +428,12 @@ class Cassandra
264
428
  def to_compare_with_type(column_name, column_family, standard=true)
265
429
  return column_name if column_name.nil?
266
430
  klass = if standard
267
- schema[column_family.to_s]["CompareWith"]
431
+ column_name_class(column_family)
268
432
  else
269
- schema[column_family.to_s]["CompareSubcolumnsWith"]
433
+ sub_column_name_class(column_family)
270
434
  end
271
435
 
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']
436
+ klass.new(column_name)
286
437
  end
287
438
 
288
439
  def cf(column_family)
@@ -293,9 +444,32 @@ class Cassandra
293
444
  if new_stuff.is_a?(Array)
294
445
  new_stuff = new_stuff.inject({}){|h,k| h[k] = nil; h }
295
446
  end
447
+
448
+ new_stuff = new_stuff.to_a.inject({}){|h,k| h[k[0].to_s] = k[1]; h }
449
+
296
450
  OrderedHash[old_stuff.merge(new_stuff).sort{|a,b| a[0] <=> b[0]}]
297
451
  end
298
452
 
453
+ def columns_to_hash(column_family, columns)
454
+ column_class, sub_column_class = column_name_class(column_family), sub_column_name_class(column_family)
455
+ output = OrderedHash.new
456
+
457
+ columns.each do |column_name, value|
458
+ column = column_class.new(column_name)
459
+
460
+ if [Hash, OrderedHash].include?(value.class)
461
+ output[column] ||= OrderedHash.new
462
+ value.each do |sub_column, sub_column_value|
463
+ output[column][sub_column_class.new(sub_column)] = sub_column_value
464
+ end
465
+ else
466
+ output[column_class.new(column_name)] = value
467
+ end
468
+ end
469
+
470
+ output
471
+ end
472
+
299
473
  def apply_count(row, count, reversed=false)
300
474
  if count
301
475
  keys = row.keys.sort
@@ -1,9 +1,5 @@
1
1
  # OrderedHash is namespaced to prevent conflicts with other implementations
2
2
  class Cassandra
3
- # Hash is ordered in Ruby 1.9!
4
- if RUBY_VERSION >= '1.9'
5
- OrderedHashInt = ::Hash
6
- else
7
3
  class OrderedHashInt < Hash #:nodoc:
8
4
  def initialize(*args, &block)
9
5
  super
@@ -126,6 +122,10 @@ class Cassandra
126
122
  @keys = other.keys
127
123
  self
128
124
  end
125
+
126
+ def reverse
127
+ OrderedHashInt[self.to_a.reverse]
128
+ end
129
129
 
130
130
  private
131
131
 
@@ -133,11 +133,10 @@ class Cassandra
133
133
  @keys.delete_if {|k| !has_key?(k)}
134
134
  end
135
135
  end
136
- end
137
136
 
138
137
  class OrderedHash < OrderedHashInt #:nodoc:
139
138
  def initialize(*args, &block)
140
- @timestamps = Hash.new
139
+ @timestamps = OrderedHashInt.new
141
140
  super
142
141
  end
143
142
 
@@ -156,13 +155,13 @@ class Cassandra
156
155
  super
157
156
  end
158
157
 
159
- def delete_if
160
- @timestamps.delete_if
158
+ def delete_if(&block)
159
+ @timestamps.delete_if(&block)
161
160
  super
162
161
  end
163
162
 
164
- def reject!
165
- @timestamps.reject!
163
+ def reject!(&block)
164
+ @timestamps.reject!(&block)
166
165
  super
167
166
  end
168
167
 
@@ -189,12 +188,5 @@ class Cassandra
189
188
  def inspect
190
189
  "#<OrderedHash #{super}--TimeStamps: #{@timestamps.inspect}>"
191
190
  end
192
-
193
- private
194
-
195
- def sync_keys!
196
- @timestamps.delete_if {|k,v| !has_key?(k)}
197
- super
198
- end
199
191
  end
200
- end
192
+ end