sessionm-cassandra 1.0.0
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/CHANGELOG +135 -0
- data/Gemfile +8 -0
- data/LICENSE +202 -0
- data/Manifest +94 -0
- data/README.md +373 -0
- data/Rakefile +195 -0
- data/bin/cassandra_helper +16 -0
- data/conf/0.6/cassandra.in.sh +47 -0
- data/conf/0.6/log4j.properties +38 -0
- data/conf/0.6/schema.json +57 -0
- data/conf/0.6/storage-conf.xml +352 -0
- data/conf/0.7/cassandra.in.sh +46 -0
- data/conf/0.7/cassandra.yaml +336 -0
- data/conf/0.7/log4j-server.properties +41 -0
- data/conf/0.7/schema.json +57 -0
- data/conf/0.7/schema.txt +45 -0
- data/conf/0.8/cassandra.in.sh +41 -0
- data/conf/0.8/cassandra.yaml +61 -0
- data/conf/0.8/log4j-server.properties +40 -0
- data/conf/0.8/schema.json +72 -0
- data/conf/0.8/schema.txt +57 -0
- data/conf/1.0/cassandra.in.sh +41 -0
- data/conf/1.0/cassandra.yaml +415 -0
- data/conf/1.0/log4j-server.properties +40 -0
- data/conf/1.0/schema.json +72 -0
- data/conf/1.0/schema.txt +57 -0
- data/conf/1.1/cassandra.in.sh +41 -0
- data/conf/1.1/cassandra.yaml +567 -0
- data/conf/1.1/log4j-server.properties +44 -0
- data/conf/1.1/schema.json +72 -0
- data/conf/1.1/schema.txt +57 -0
- data/ext/cassandra_native.c +34 -0
- data/ext/extconf.rb +9 -0
- data/lib/cassandra/0.6/cassandra.rb +113 -0
- data/lib/cassandra/0.6/columns.rb +78 -0
- data/lib/cassandra/0.6/protocol.rb +91 -0
- data/lib/cassandra/0.6.rb +7 -0
- data/lib/cassandra/0.7/cassandra.rb +2 -0
- data/lib/cassandra/0.7/columns.rb +4 -0
- data/lib/cassandra/0.7/protocol.rb +5 -0
- data/lib/cassandra/0.7.rb +7 -0
- data/lib/cassandra/0.8/cassandra.rb +51 -0
- data/lib/cassandra/0.8/columns.rb +28 -0
- data/lib/cassandra/0.8/protocol.rb +10 -0
- data/lib/cassandra/0.8.rb +7 -0
- data/lib/cassandra/1.0/cassandra.rb +1 -0
- data/lib/cassandra/1.0/columns.rb +1 -0
- data/lib/cassandra/1.0/protocol.rb +1 -0
- data/lib/cassandra/1.0.rb +7 -0
- data/lib/cassandra/1.1/cassandra.rb +1 -0
- data/lib/cassandra/1.1/columns.rb +1 -0
- data/lib/cassandra/1.1/protocol.rb +1 -0
- data/lib/cassandra/1.1.rb +7 -0
- data/lib/cassandra/array.rb +8 -0
- data/lib/cassandra/batch.rb +41 -0
- data/lib/cassandra/cassandra.rb +1088 -0
- data/lib/cassandra/column_family.rb +3 -0
- data/lib/cassandra/columns.rb +172 -0
- data/lib/cassandra/comparable.rb +28 -0
- data/lib/cassandra/composite.rb +140 -0
- data/lib/cassandra/constants.rb +11 -0
- data/lib/cassandra/debug.rb +9 -0
- data/lib/cassandra/dynamic_composite.rb +96 -0
- data/lib/cassandra/helpers.rb +41 -0
- data/lib/cassandra/keyspace.rb +3 -0
- data/lib/cassandra/long.rb +58 -0
- data/lib/cassandra/mock.rb +525 -0
- data/lib/cassandra/ordered_hash.rb +192 -0
- data/lib/cassandra/protocol.rb +137 -0
- data/lib/cassandra/time.rb +11 -0
- data/lib/cassandra.rb +41 -0
- data/sessionm-cassandra.gemspec +47 -0
- data/test/cassandra_client_test.rb +20 -0
- data/test/cassandra_mock_test.rb +128 -0
- data/test/cassandra_test.rb +1353 -0
- data/test/comparable_types_test.rb +45 -0
- data/test/composite_type_test.rb +64 -0
- data/test/eventmachine_test.rb +42 -0
- data/test/ordered_hash_test.rb +386 -0
- data/test/test_helper.rb +19 -0
- data/vendor/0.6/gen-rb/cassandra.rb +1481 -0
- data/vendor/0.6/gen-rb/cassandra_constants.rb +12 -0
- data/vendor/0.6/gen-rb/cassandra_types.rb +482 -0
- data/vendor/0.7/gen-rb/cassandra.rb +1936 -0
- data/vendor/0.7/gen-rb/cassandra_constants.rb +12 -0
- data/vendor/0.7/gen-rb/cassandra_types.rb +681 -0
- data/vendor/0.8/gen-rb/cassandra.rb +2215 -0
- data/vendor/0.8/gen-rb/cassandra_constants.rb +12 -0
- data/vendor/0.8/gen-rb/cassandra_types.rb +824 -0
- data/vendor/1.0/gen-rb/cassandra.rb +2215 -0
- data/vendor/1.0/gen-rb/cassandra_constants.rb +12 -0
- data/vendor/1.0/gen-rb/cassandra_types.rb +857 -0
- data/vendor/1.1/gen-rb/cassandra.rb +2571 -0
- data/vendor/1.1/gen-rb/cassandra_constants.rb +12 -0
- data/vendor/1.1/gen-rb/cassandra_types.rb +928 -0
- metadata +287 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
class Cassandra
|
2
|
+
module Helpers
|
3
|
+
def extract_and_validate_params(column_family, keys, args, options)
|
4
|
+
options = options.dup
|
5
|
+
column_family = column_family.to_s
|
6
|
+
# Keys
|
7
|
+
[keys].flatten.each do |key|
|
8
|
+
raise ArgumentError, "Key #{key.inspect} must be a String for #{caller[2].inspect}." unless key.is_a?(String)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Options
|
12
|
+
if args.last.is_a?(Hash)
|
13
|
+
extras = args.last.keys - options.keys
|
14
|
+
raise ArgumentError, "Invalid options #{extras.inspect[1..-2]} for #{caller[1]}" if extras.any?
|
15
|
+
options.merge!(args.pop)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Ranges
|
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)
|
21
|
+
klass, sub_klass = column_name_class(column_family), sub_column_name_class(column_family)
|
22
|
+
range_class = column ? sub_klass : klass
|
23
|
+
|
24
|
+
[:start, :finish].each do |opt|
|
25
|
+
options[opt] = options[opt] ? range_class.new(options[opt]).to_s : ''
|
26
|
+
end
|
27
|
+
|
28
|
+
[column_family, s_map(column, klass), s_map(sub_column, sub_klass), options]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Convert stuff to strings.
|
32
|
+
def s_map(el, klass)
|
33
|
+
case el
|
34
|
+
when Array then el.map { |i| s_map(i, klass) }
|
35
|
+
when NilClass then nil
|
36
|
+
else
|
37
|
+
klass.new(el).to_s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
class Cassandra
|
3
|
+
# A temporally-ordered Long class for use in Cassandra column names
|
4
|
+
class Long < Comparable
|
5
|
+
|
6
|
+
# FIXME Should unify with or subclass Cassandra::UUID
|
7
|
+
def initialize(bytes = nil)
|
8
|
+
case bytes
|
9
|
+
when self.class # Long
|
10
|
+
@bytes = bytes.to_s
|
11
|
+
when String
|
12
|
+
case bytes.size
|
13
|
+
when 8 # Raw byte array
|
14
|
+
@bytes = bytes
|
15
|
+
when 18 # Human-readable UUID-like representation; inverse of #to_guid
|
16
|
+
elements = bytes.split("-")
|
17
|
+
raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (malformed UUID-like representation)" if elements.size != 3
|
18
|
+
@bytes = [elements.join].pack('H32')
|
19
|
+
else
|
20
|
+
raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (invalid bytecount)"
|
21
|
+
end
|
22
|
+
when Integer
|
23
|
+
raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (integer out of range)" if bytes < 0 or bytes > 2**64
|
24
|
+
@bytes = [bytes >> 32, bytes % 2**32].pack("NN")
|
25
|
+
when NilClass, Time
|
26
|
+
# Time.stamp is 52 bytes, so we have 12 bytes of entropy left over
|
27
|
+
int = ((bytes || Time).stamp << 12) + rand(2**12)
|
28
|
+
@bytes = [int >> 32, int % 2**32].pack("NN")
|
29
|
+
else
|
30
|
+
raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (unknown source class)"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_i
|
35
|
+
@to_i ||= begin
|
36
|
+
ints = @bytes.unpack("NN")
|
37
|
+
(ints[0] << 32) +
|
38
|
+
ints[1]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_guid
|
43
|
+
"%08x-%04x-%04x" % @bytes.unpack("Nnn")
|
44
|
+
end
|
45
|
+
|
46
|
+
def inspect
|
47
|
+
"<Cassandra::Long##{object_id} time: #{
|
48
|
+
Time.at((to_i >> 12) / 1_000_000).utc.inspect
|
49
|
+
}, usecs: #{
|
50
|
+
(to_i >> 12) % 1_000_000
|
51
|
+
}, jitter: #{
|
52
|
+
to_i % 2**12
|
53
|
+
}, guid: #{
|
54
|
+
to_guid
|
55
|
+
}>"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,525 @@
|
|
1
|
+
class SimpleUUID::UUID
|
2
|
+
def >=(other)
|
3
|
+
(self <=> other) >= 0
|
4
|
+
end
|
5
|
+
|
6
|
+
def <=(other)
|
7
|
+
(self <=> other) <= 0
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Cassandra
|
12
|
+
class Mock
|
13
|
+
include ::Cassandra::Helpers
|
14
|
+
include ::Cassandra::Columns
|
15
|
+
|
16
|
+
attr_reader :keyspace
|
17
|
+
|
18
|
+
def initialize(keyspace, schema)
|
19
|
+
@is_super = {}
|
20
|
+
@keyspace = keyspace
|
21
|
+
@column_name_class = {}
|
22
|
+
@sub_column_name_class = {}
|
23
|
+
@column_name_maker = {}
|
24
|
+
@sub_column_name_maker = {}
|
25
|
+
@indexes = {}
|
26
|
+
@schema = schema[keyspace]
|
27
|
+
clear_keyspace!
|
28
|
+
end
|
29
|
+
|
30
|
+
def disconnect!
|
31
|
+
end
|
32
|
+
|
33
|
+
def clear_keyspace!
|
34
|
+
@data = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear_column_family!(column_family)
|
38
|
+
@data[column_family.to_sym] = OrderedHash.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def default_write_consistency=(value)
|
42
|
+
WRITE_DEFAULTS[:consistency] = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_read_consistency=(value)
|
46
|
+
READ_DEFAULTS[:consistency] = value
|
47
|
+
end
|
48
|
+
|
49
|
+
def insert(column_family, key, hash_or_array, options = {})
|
50
|
+
if @batch
|
51
|
+
@batch << [:insert, column_family, key, hash_or_array, options]
|
52
|
+
else
|
53
|
+
raise ArgumentError if key.nil?
|
54
|
+
if !is_super(column_family)
|
55
|
+
insert_standard(column_family, key, hash_or_array)
|
56
|
+
else
|
57
|
+
insert_super(column_family, key, hash_or_array)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def insert_standard(column_family, key, hash_or_array)
|
63
|
+
old = cf(column_family)[key] || OrderedHash.new
|
64
|
+
cf(column_family)[key] = merge_and_sort(old, hash_or_array)
|
65
|
+
end
|
66
|
+
|
67
|
+
def insert_super(column_family, key, hash)
|
68
|
+
raise ArgumentError unless hash.is_a?(Hash)
|
69
|
+
cf(column_family)[key] ||= OrderedHash.new
|
70
|
+
|
71
|
+
hash.keys.each do |sub_key|
|
72
|
+
old = cf(column_family)[key][sub_key] || OrderedHash.new
|
73
|
+
cf(column_family)[key][sub_key] = merge_and_sort(old, hash[sub_key])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def batch(options={})
|
78
|
+
@batch = Cassandra::Batch.new(self, options)
|
79
|
+
yield
|
80
|
+
flush_batch(options)
|
81
|
+
ensure
|
82
|
+
@batch = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def flush_batch(options)
|
86
|
+
b = @batch
|
87
|
+
@batch = nil
|
88
|
+
b.each do |mutation|
|
89
|
+
send(*mutation)
|
90
|
+
end
|
91
|
+
@batch = b
|
92
|
+
end
|
93
|
+
|
94
|
+
def get(column_family, key, *columns_and_options)
|
95
|
+
column_family, column, sub_column, options =
|
96
|
+
extract_and_validate_params_for_real(column_family, [key], columns_and_options, READ_DEFAULTS)
|
97
|
+
if !is_super(column_family)
|
98
|
+
get_standard(column_family, key, column, options)
|
99
|
+
else
|
100
|
+
get_super(column_family, key, column, sub_column, options)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def get_standard(column_family, key, column, options)
|
105
|
+
columns = cf(column_family)[key] || OrderedHash.new
|
106
|
+
row = columns_to_hash(column_family, columns)
|
107
|
+
|
108
|
+
if column
|
109
|
+
row[column]
|
110
|
+
else
|
111
|
+
row = apply_range(row, column_family, options[:start], options[:finish])
|
112
|
+
row = apply_count(row, options[:count], options[:reversed])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_super(column_family, key, column, sub_column, options)
|
117
|
+
columns = cf(column_family)[key] || OrderedHash.new
|
118
|
+
row = columns_to_hash(column_family, columns)
|
119
|
+
|
120
|
+
if column
|
121
|
+
if sub_column
|
122
|
+
if row[column] &&
|
123
|
+
row[column][sub_column]
|
124
|
+
row[column][sub_column]
|
125
|
+
else
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
else
|
129
|
+
row = row[column] || OrderedHash.new
|
130
|
+
row = apply_range(row, column_family, options[:start], options[:finish], false)
|
131
|
+
row = apply_count(row, options[:count], options[:reversed])
|
132
|
+
end
|
133
|
+
else
|
134
|
+
row
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def exists?(column_family, key, *columns_and_options)
|
139
|
+
column_family, column, sub_column, options = extract_and_validate_params_for_real(column_family, [key], columns_and_options, READ_DEFAULTS)
|
140
|
+
results = get(column_family, key, column, sub_column)
|
141
|
+
|
142
|
+
![{}, nil].include?(results)
|
143
|
+
end
|
144
|
+
|
145
|
+
def multi_get(column_family, keys, *columns_and_options)
|
146
|
+
column_family, column, sub_column, options = extract_and_validate_params_for_real(column_family, keys, columns_and_options, READ_DEFAULTS)
|
147
|
+
keys.inject(OrderedHash.new) do |hash, key|
|
148
|
+
hash[key] = get(column_family, key)
|
149
|
+
hash
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def remove(column_family, key, *columns_and_options)
|
154
|
+
column_family, column, sub_column, options = extract_and_validate_params_for_real(column_family, key, columns_and_options, WRITE_DEFAULTS)
|
155
|
+
if @batch
|
156
|
+
@batch << [:remove, column_family, key, column, sub_column]
|
157
|
+
else
|
158
|
+
if column
|
159
|
+
if sub_column
|
160
|
+
cf(column_family)[key][column].delete(sub_column.to_s) if cf(column_family)[key][column]
|
161
|
+
else
|
162
|
+
cf(column_family)[key].delete(column.to_s) if cf(column_family)[key]
|
163
|
+
end
|
164
|
+
else
|
165
|
+
cf(column_family).delete(key)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def get_columns(column_family, key, *columns_and_options)
|
171
|
+
column_family, columns, sub_columns, options = extract_and_validate_params_for_real(column_family, key, columns_and_options, READ_DEFAULTS)
|
172
|
+
d = get(column_family, key)
|
173
|
+
|
174
|
+
if sub_columns
|
175
|
+
sub_columns.collect do |sub_column|
|
176
|
+
d[columns][sub_column]
|
177
|
+
end
|
178
|
+
else
|
179
|
+
columns.collect do |column|
|
180
|
+
d[column]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def count_columns(column_family, key, *columns_and_options)
|
186
|
+
column_family, columns, sub_columns, options = extract_and_validate_params_for_real(column_family, key, columns_and_options, READ_DEFAULTS)
|
187
|
+
|
188
|
+
get(column_family, key, columns, options).keys.length
|
189
|
+
end
|
190
|
+
|
191
|
+
def multi_get_columns(column_family, keys, columns)
|
192
|
+
keys.inject(OrderedHash.new) do |hash, key|
|
193
|
+
hash[key] = get_columns(column_family, key, columns)
|
194
|
+
hash
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def multi_count_columns(column_family, keys)
|
199
|
+
keys.inject(OrderedHash.new) do |hash, key|
|
200
|
+
hash[key] = count_columns(column_family, key)
|
201
|
+
hash
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def get_range(column_family, options = {}, &blk)
|
206
|
+
column_family, _, _, options = extract_and_validate_params_for_real(column_family, "", [options],
|
207
|
+
READ_DEFAULTS.merge(:start_key => nil,
|
208
|
+
:finish_key => nil,
|
209
|
+
:key_count => 100,
|
210
|
+
:columns => nil,
|
211
|
+
:reversed => false
|
212
|
+
)
|
213
|
+
)
|
214
|
+
res = _get_range(column_family,
|
215
|
+
options[:start_key],
|
216
|
+
options[:finish_key],
|
217
|
+
options[:key_count],
|
218
|
+
options[:columns],
|
219
|
+
options[:start],
|
220
|
+
options[:finish],
|
221
|
+
options[:count],
|
222
|
+
options[:consistency],
|
223
|
+
options[:reversed], &blk)
|
224
|
+
|
225
|
+
if blk.nil?
|
226
|
+
res
|
227
|
+
else
|
228
|
+
nil
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def get_range_keys(column_family, options = {})
|
233
|
+
get_range(column_family,options.merge!(:columns => [])).keys
|
234
|
+
end
|
235
|
+
|
236
|
+
def count_range(column_family, options = {})
|
237
|
+
Hash[get_range(column_family, options).select{|k,v| v.length > 0}].keys.compact.length
|
238
|
+
end
|
239
|
+
|
240
|
+
def each_key(column_family, options = {})
|
241
|
+
each(column_family, options.merge!(:columns => [])) do |key, value|
|
242
|
+
yield key
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def each(column_family, options = {})
|
247
|
+
batch_size = options.delete(:batch_size) || 100
|
248
|
+
count = options.delete(:key_count)
|
249
|
+
yielded_count = 0
|
250
|
+
|
251
|
+
options[:start_key] ||= ''
|
252
|
+
last_key = nil
|
253
|
+
|
254
|
+
while options[:start_key] != last_key && (count.nil? || count > yielded_count)
|
255
|
+
options[:start_key] = last_key
|
256
|
+
res = get_range(column_family, options.merge!(:start_key => last_key, :key_count => batch_size))
|
257
|
+
res.each do |key, columns|
|
258
|
+
next if options[:start_key] == key
|
259
|
+
next if yielded_count == count
|
260
|
+
yield key, columns
|
261
|
+
yielded_count += 1
|
262
|
+
last_key = key
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def create_index(ks_name, cf_name, c_name, v_class)
|
268
|
+
if @indexes[ks_name] &&
|
269
|
+
@indexes[ks_name][cf_name] &&
|
270
|
+
@indexes[ks_name][cf_name][c_name]
|
271
|
+
nil
|
272
|
+
|
273
|
+
else
|
274
|
+
@indexes[ks_name] ||= {}
|
275
|
+
@indexes[ks_name][cf_name] ||= {}
|
276
|
+
@indexes[ks_name][cf_name][c_name] = true
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def drop_index(ks_name, cf_name, c_name)
|
281
|
+
if @indexes[ks_name] &&
|
282
|
+
@indexes[ks_name][cf_name] &&
|
283
|
+
@indexes[ks_name][cf_name][c_name]
|
284
|
+
|
285
|
+
@indexes[ks_name][cf_name].delete(c_name)
|
286
|
+
else
|
287
|
+
nil
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def create_index_expression(c_name, value, op)
|
292
|
+
{:column_name => c_name, :value => value, :comparison => op}
|
293
|
+
end
|
294
|
+
alias :create_idx_expr :create_index_expression
|
295
|
+
|
296
|
+
def create_index_clause(idx_expressions, start = "", count = 100)
|
297
|
+
{:start => start, :index_expressions => idx_expressions, :count => count, :type => :index_clause}
|
298
|
+
end
|
299
|
+
alias :create_idx_clause :create_index_clause
|
300
|
+
|
301
|
+
def get_indexed_slices(column_family, idx_clause, *columns_and_options)
|
302
|
+
column_family, columns, _, options =
|
303
|
+
extract_and_validate_params_for_real(column_family, [], columns_and_options,
|
304
|
+
READ_DEFAULTS.merge(:key_count => 100, :start_key => nil, :key_start => nil))
|
305
|
+
|
306
|
+
start_key = options[:start_key] || options[:key_start] || ""
|
307
|
+
|
308
|
+
unless [Hash, OrderedHash].include?(idx_clause.class) && idx_clause[:type] == :index_clause
|
309
|
+
idx_clause = create_index_clause(idx_clause, start_key, options[:key_count])
|
310
|
+
end
|
311
|
+
|
312
|
+
ret = OrderedHash.new
|
313
|
+
cf(column_family).each do |key, row|
|
314
|
+
next if idx_clause[:start] != '' && key < idx_clause[:start]
|
315
|
+
next if ret.length == idx_clause[:count]
|
316
|
+
|
317
|
+
matches = []
|
318
|
+
idx_clause[:index_expressions].each do |expr|
|
319
|
+
next if row[expr[:column_name]].nil?
|
320
|
+
next unless row[expr[:column_name]].send(expr[:comparison].to_sym, expr[:value])
|
321
|
+
|
322
|
+
matches << expr
|
323
|
+
end
|
324
|
+
|
325
|
+
ret[key] = row if matches.length == idx_clause[:index_expressions].length
|
326
|
+
end
|
327
|
+
|
328
|
+
ret
|
329
|
+
end
|
330
|
+
|
331
|
+
def add(column_family, key, value, *columns_and_options)
|
332
|
+
if @batch
|
333
|
+
@batch << [:add, column_family, key, value, *columns_and_options]
|
334
|
+
else
|
335
|
+
column_family, column, sub_column, options = extract_and_validate_params_for_real(column_family, key, columns_and_options, WRITE_DEFAULTS)
|
336
|
+
|
337
|
+
if is_super(column_family)
|
338
|
+
cf(column_family)[key] ||= OrderedHash.new
|
339
|
+
cf(column_family)[key][column] ||= OrderedHash.new
|
340
|
+
cf(column_family)[key][column][sub_column] ||= 0
|
341
|
+
cf(column_family)[key][column][sub_column] += value
|
342
|
+
else
|
343
|
+
cf(column_family)[key] ||= OrderedHash.new
|
344
|
+
cf(column_family)[key][column] ||= 0
|
345
|
+
cf(column_family)[key][column] += value
|
346
|
+
end
|
347
|
+
|
348
|
+
nil
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def column_families
|
353
|
+
cf_defs = {}
|
354
|
+
schema.each do |key, value|
|
355
|
+
cf_def = Cassandra::ColumnFamily.new
|
356
|
+
|
357
|
+
value.each do |property, property_value|
|
358
|
+
cf_def.send(:"#{property}=", property_value)
|
359
|
+
end
|
360
|
+
|
361
|
+
cf_defs[key] = cf_def
|
362
|
+
end
|
363
|
+
|
364
|
+
cf_defs
|
365
|
+
end
|
366
|
+
|
367
|
+
def schema(load=true)
|
368
|
+
@schema
|
369
|
+
end
|
370
|
+
|
371
|
+
def column_family_property(column_family, key)
|
372
|
+
schema[column_family.to_s][key]
|
373
|
+
end
|
374
|
+
|
375
|
+
def add_column_family(cf)
|
376
|
+
@schema[cf.name.to_s] ||= OrderedHash.new
|
377
|
+
|
378
|
+
cf.instance_variables.each do |var|
|
379
|
+
@schema[cf.name.to_s][var.slice(1..-1)] = cf.instance_variable_get(var)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def update_column_family(cf)
|
384
|
+
return false unless @schema.include?(cf.name.to_s)
|
385
|
+
|
386
|
+
cf.instance_variables.each do |var|
|
387
|
+
@schema[cf.name.to_s][var.slice(1..-1)] = cf.instance_variable_get(var)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
def drop_column_family(column_family_name)
|
392
|
+
@schema.delete(column_family_name)
|
393
|
+
end
|
394
|
+
|
395
|
+
private
|
396
|
+
|
397
|
+
def schema_for_keyspace(keyspace)
|
398
|
+
@schema
|
399
|
+
end
|
400
|
+
|
401
|
+
def _get_range(column_family, start_key, finish_key, key_count, columns, start, finish, count, consistency, reversed, &blk)
|
402
|
+
ret = OrderedHash.new
|
403
|
+
start = to_compare_with_type(start, column_family)
|
404
|
+
finish = to_compare_with_type(finish, column_family)
|
405
|
+
cf(column_family).keys.sort.each do |key|
|
406
|
+
break if ret.keys.size >= key_count
|
407
|
+
if (start_key.nil? || key >= start_key) && (finish_key.nil? || key <= finish_key)
|
408
|
+
if columns
|
409
|
+
#ret[key] = columns.inject(OrderedHash.new){|hash, column_name| hash[column_name] = cf(column_family)[key][column_name]; hash;}
|
410
|
+
selected_hash = OrderedHash.new
|
411
|
+
cf(column_family)[key].each do |k, v|
|
412
|
+
selected_hash.[]=(k, v, cf(column_family)[key].timestamps[k]) if columns.include?(k)
|
413
|
+
end
|
414
|
+
ret[key] = columns_to_hash(column_family, selected_hash)
|
415
|
+
ret[key] = apply_count(ret[key], count, reversed)
|
416
|
+
blk.call(key,ret[key]) unless blk.nil?
|
417
|
+
else
|
418
|
+
#ret[key] = apply_range(cf(column_family)[key], column_family, start, finish, !is_super(column_family))
|
419
|
+
start, finish = finish, start if reversed
|
420
|
+
ret[key] = apply_range(columns_to_hash(column_family, cf(column_family)[key]), column_family, start, finish)
|
421
|
+
ret[key] = apply_count(ret[key], count, reversed)
|
422
|
+
blk.call(key,ret[key]) unless blk.nil?
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
ret
|
427
|
+
end
|
428
|
+
|
429
|
+
def extract_and_validate_params_for_real(column_family, keys, args, options)
|
430
|
+
column_family, columns, sub_column, options = extract_and_validate_params(column_family, keys, args, options)
|
431
|
+
options[:start] = nil if options[:start] == ''
|
432
|
+
options[:finish] = nil if options[:finish] == ''
|
433
|
+
[column_family, to_compare_with_types(columns, column_family), to_compare_with_types(sub_column, column_family, false), options]
|
434
|
+
end
|
435
|
+
|
436
|
+
def to_compare_with_types(column_names, column_family, standard=true)
|
437
|
+
if column_names.is_a?(Array)
|
438
|
+
column_names.collect do |name|
|
439
|
+
to_compare_with_type(name, column_family, standard)
|
440
|
+
end
|
441
|
+
else
|
442
|
+
to_compare_with_type(column_names, column_family, standard)
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def to_compare_with_type(column_name, column_family, standard=true)
|
447
|
+
return column_name if column_name.nil?
|
448
|
+
klass = if standard
|
449
|
+
column_name_class(column_family)
|
450
|
+
else
|
451
|
+
sub_column_name_class(column_family)
|
452
|
+
end
|
453
|
+
|
454
|
+
klass.new(column_name)
|
455
|
+
end
|
456
|
+
|
457
|
+
def cf(column_family)
|
458
|
+
@data[column_family.to_sym] ||= OrderedHash.new
|
459
|
+
end
|
460
|
+
|
461
|
+
def merge_and_sort(old_stuff, new_stuff)
|
462
|
+
if new_stuff.is_a?(Array)
|
463
|
+
new_stuff = new_stuff.inject({}){|h,k| h[k] = nil; h }
|
464
|
+
end
|
465
|
+
|
466
|
+
new_stuff = new_stuff.to_a.inject({}){|h,k| h[k[0].to_s] = k[1]; h }
|
467
|
+
|
468
|
+
new_stuff.each { |k,v| old_stuff.[]=(k, v, (Time.now.to_f * 1000000).to_i) }
|
469
|
+
hash = OrderedHash.new
|
470
|
+
old_stuff.sort{ |a,b| a[0] <=> b[0] }.each do |k, v|
|
471
|
+
hash.[]=(k, v, old_stuff.timestamps[k])
|
472
|
+
end
|
473
|
+
hash
|
474
|
+
end
|
475
|
+
|
476
|
+
def columns_to_hash(column_family, columns)
|
477
|
+
column_class, sub_column_class = column_name_class(column_family), sub_column_name_class(column_family)
|
478
|
+
output = OrderedHash.new
|
479
|
+
|
480
|
+
columns.each do |column_name, value|
|
481
|
+
timestamp = columns.timestamps[column_name]
|
482
|
+
column = column_class.new(column_name)
|
483
|
+
|
484
|
+
if [Hash, OrderedHash].include?(value.class)
|
485
|
+
output[column] ||= OrderedHash.new
|
486
|
+
value.each do |sub_column, sub_column_value|
|
487
|
+
timestamp = value.timestamps[sub_column]
|
488
|
+
output[column].[]=(sub_column_class.new(sub_column), sub_column_value, timestamp)
|
489
|
+
end
|
490
|
+
else
|
491
|
+
output.[]=(column_class.new(column_name), value, timestamp)
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
output
|
496
|
+
end
|
497
|
+
|
498
|
+
def apply_count(row, count, reversed=false)
|
499
|
+
if count
|
500
|
+
keys = row.keys.sort
|
501
|
+
keys = keys.reverse if reversed
|
502
|
+
keys = keys[0...count]
|
503
|
+
keys.inject(OrderedHash.new) do |memo, key|
|
504
|
+
memo.[]=(key, row[key], row.timestamps[key])
|
505
|
+
memo
|
506
|
+
end
|
507
|
+
else
|
508
|
+
row
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
def apply_range(row, column_family, strt, fin, standard=true)
|
513
|
+
start = to_compare_with_type(strt, column_family, standard)
|
514
|
+
finish = to_compare_with_type(fin, column_family, standard)
|
515
|
+
ret = OrderedHash.new
|
516
|
+
row.keys.each do |key|
|
517
|
+
if (start.nil? || key >= start) && (finish.nil? || key <= finish)
|
518
|
+
ret.[]=(key, row[key], row.timestamps[key])
|
519
|
+
end
|
520
|
+
end
|
521
|
+
ret
|
522
|
+
end
|
523
|
+
|
524
|
+
end
|
525
|
+
end
|