cassilds 0.9.2 → 0.12.1

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.
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