sessionm-cassandra_object 4.0.27 → 4.0.28

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1c93aa37334ac497b7c97b5c0a1c04350502e230
4
- data.tar.gz: 894c0e7ffac48271d0efa1b75defe0c67f7c3b47
3
+ metadata.gz: 23762bc97b24f059702d33a82198651dc12a5849
4
+ data.tar.gz: e5bdeca74f220ad8ade8f35a20b3751efd256eec
5
5
  SHA512:
6
- metadata.gz: 4162a2b08feefbe4ed8cffa60826421344b6982f4e82b31627495dcf2e6dcfbe2f3af4cc666051918a868d2e410a9d97077f34c14e2d651c164206870a24684d
7
- data.tar.gz: 936877179c08b6e3b3ffdf4d74d7384bc3da5e32dbafb29f4d361daa10b2a417be76e20fee99139858a7db7399aa495400112aee04a4882258eef77d9e899c70
6
+ metadata.gz: ffff8841ff8da649d139ddc24d54c0a28bbba823fbe25ec7a00cde71a3685bc33e2ac92b1973a09208f419ef0660a03a2ae840dc008bd4af57ed3f8120399a39
7
+ data.tar.gz: 88af7c90d6177d05afaf0d37f0eee2ecc563dd4ea9a48e3195d587dad18e88768f5f40389be12eedac86554de24c507cca1f14af4f9a33711feb4d79cf301312
@@ -99,8 +99,13 @@ module CassandraObject
99
99
 
100
100
  insert_into_options = ttl ? " USING TTL #{ttl}" : ''
101
101
 
102
+ key_fields = get_key_fields(column_family)
103
+ column_fields = get_column_fields(column_family)
104
+
105
+ key_parts = get_parts(column_family, key, key_fields)
102
106
  insert_query = values.map do |name, value|
103
- " INSERT INTO \"#{column_family}\" (#{KEY_FIELD}, #{NAME_FIELD}, #{VALUE_FIELD}) VALUES (#{escape(key, key_type(column_family))}, #{escape(name, name_type(column_family))}, #{escape(value, value_type(column_family))})#{insert_into_options}"
107
+ column_parts = get_parts(column_family, name, column_fields)
108
+ " INSERT INTO \"#{column_family}\" (#{key_fields.map(&:first).join(', ')}, #{column_fields.map(&:first).join(', ')}, #{VALUE_FIELD}) VALUES (#{key_parts.map { |f, v| escape(v, get_type(column_family, f)) }.join(', ')}, #{column_parts.map { |f, v| escape(v, get_type(column_family, f)) }.join(', ')}, #{escape(value, value_type(column_family))})#{insert_into_options}"
104
109
  end.join("\n")
105
110
 
106
111
  if batch_mode?
@@ -118,12 +123,13 @@ module CassandraObject
118
123
  async = opts.try(:[], :async)
119
124
 
120
125
  columns = columns_options.flatten.compact
126
+ column_fields = get_column_fields(column_family)
121
127
 
122
128
  query =
123
129
  if columns.size == 1
124
- "SELECT #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{KEY_FIELD} = #{escape(key, key_type(column_family))} AND #{NAME_FIELD} = #{escape(columns.first, name_type(column_family))}"
130
+ "SELECT #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{key_clause(column_family, key)} AND #{column_clause(column_family, columns.first)}"
125
131
  else
126
- "SELECT #{NAME_FIELD}, #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{KEY_FIELD} = #{escape(key, key_type(column_family))}"
132
+ "SELECT #{column_fields.map(&:first).join(', ')}, #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{key_clause(column_family, key)}"
127
133
  end
128
134
 
129
135
  result = async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
@@ -132,7 +138,7 @@ module CassandraObject
132
138
  if columns.size == 1
133
139
  result.size > 0 ? result.first[VALUE_FIELD] : nil
134
140
  else
135
- data = result.inject({}) { |hsh, row| hsh[row[NAME_FIELD]] = row[VALUE_FIELD]; hsh }
141
+ data = result.inject({}) { |hsh, row| hsh[column_string(row, column_fields)] = row[VALUE_FIELD]; hsh }
136
142
  columns.size > 0 ? data.slice(*columns.map(&:to_s)) : data
137
143
  end
138
144
  end
@@ -142,7 +148,7 @@ module CassandraObject
142
148
 
143
149
  name_fields = columns.map { |c| escape(c, name_type(column_family)) }.join(', ')
144
150
 
145
- query = "SELECT #{NAME_FIELD}, #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{NAME_FIELD} IN(#{name_fields}) AND #{KEY_FIELD} = #{escape(key, key_type(column_family))}"
151
+ query = "SELECT #{NAME_FIELD}, #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{NAME_FIELD} IN(#{name_fields}) AND #{key_clause(column_family, key)};"
146
152
 
147
153
  result = async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
148
154
  return result if async
@@ -158,7 +164,7 @@ module CassandraObject
158
164
 
159
165
  name_fields = columns.map { |c| "'#{c}'" }.join(', ')
160
166
 
161
- query = "SELECT #{NAME_FIELD}, #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{NAME_FIELD} IN(#{name_fields}) AND #{KEY_FIELD} = #{escape(key, key_type(column_family))}"
167
+ query = "SELECT #{NAME_FIELD}, #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{NAME_FIELD} IN(#{name_fields}) AND #{key_clause(column_family, key)};"
162
168
 
163
169
  result = async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
164
170
  return result if async
@@ -176,7 +182,7 @@ module CassandraObject
176
182
  fields = [fields] unless fields.is_a?(Array)
177
183
 
178
184
  fields.each do |field|
179
- query = "UPDATE \"#{column_family}\" SET #{VALUE_FIELD} = #{VALUE_FIELD} + #{by} WHERE #{KEY_FIELD} = #{escape(key, key_type(column_family))} AND #{NAME_FIELD} = #{escape(field, name_type(column_family))};"
185
+ query = "UPDATE \"#{column_family}\" SET #{VALUE_FIELD} = #{VALUE_FIELD} + #{by} WHERE #{key_clause(column_family, key)} AND #{column_clause(column_family, field)};"
180
186
  async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
181
187
  end
182
188
  end
@@ -186,7 +192,7 @@ module CassandraObject
186
192
  fields = [fields] unless fields.is_a?(Array)
187
193
 
188
194
  hash.each do |field, by|
189
- query = "UPDATE \"#{column_family}\" SET #{VALUE_FIELD} = #{VALUE_FIELD} + #{by} WHERE #{KEY_FIELD} = #{escape(key, key_type(column_family))} AND #{NAME_FIELD} = #{escape(field, name_type(column_family))};"
195
+ query = "UPDATE \"#{column_family}\" SET #{VALUE_FIELD} = #{VALUE_FIELD} + #{by} WHERE #{key_clause(column_family, key)} AND #{column_clause(column_family, field)};"
190
196
  async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
191
197
  end
192
198
  end
@@ -197,9 +203,9 @@ module CassandraObject
197
203
 
198
204
  query =
199
205
  if args.first.nil? || args.first.is_a?(Hash)
200
- "DELETE FROM \"#{column_family}\" WHERE #{KEY_FIELD} = #{escape(key, key_type(column_family))};"
206
+ "DELETE FROM \"#{column_family}\" WHERE #{key_clause(column_family, key)};"
201
207
  else
202
- "DELETE \"#{column_family}\" WHERE #{KEY_FIELD} = #{escape(key, key_type(column_family))} AND #{NAME_FIELD} = #{escape(args.first, name_type(column_family))};"
208
+ "DELETE FROM \"#{column_family}\" WHERE #{key_clause(column_family, key)} AND #{column_clause(column_family, args.first)};"
203
209
  end
204
210
 
205
211
  async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
@@ -227,15 +233,21 @@ module CassandraObject
227
233
  def get_slice(column_family, key, column, start, finish, count, reversed, consistency, opts={})
228
234
  opts[:consistency] = consistency
229
235
 
230
- query = "SELECT * FROM \"#{column_family}\" WHERE #{KEY_FIELD} = #{escape(key, key_type(column_family))}"
231
- query << " AND #{NAME_FIELD} = #{escape(column, name_type(column_family))}" if column
232
- query << " AND #{NAME_FIELD} >= #{escape(start, name_type(column_family))}" unless start.empty?
233
- query << " AND #{NAME_FIELD} <= #{escape(finish, name_type(column_family))}" unless finish.empty?
234
- query << " ORDER BY #{NAME_FIELD} #{reverse_comparator(column_family) ? 'ASC' : 'DESC'}" if reversed
236
+ column_fields = get_column_fields(column_family)
237
+
238
+ query = "SELECT #{column_fields.map(&:first).join(', ')}, #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{key_clause(column_family, key)}"
239
+ query << " AND #{column_clause(column_family, column)}" if column
240
+ query << " AND #{column_clause(column_family, start, '>=')}" unless start.empty?
241
+ query << " AND #{column_clause(column_family, finish, '<=')}" unless finish.empty?
242
+ if reversed
243
+ direction = reverse_comparator(column_family) ? 'ASC' : 'DESC'
244
+ query << " ORDER BY "
245
+ query << column_fields.map { |f, _| "#{f} #{direction}" }.join(', ')
246
+ end
235
247
  query << " LIMIT #{count}"
236
248
 
237
249
  self.execute(query, execute_options(opts)).inject({}) do |results, row|
238
- results[decode(row[NAME_FIELD], name_type(column_family))] = decode(row[VALUE_FIELD], value_type(column_family))
250
+ results[column_string(row, column_fields)] = decode(row[VALUE_FIELD], value_type(column_family))
239
251
  results
240
252
  end
241
253
  end
@@ -329,32 +341,87 @@ CQL
329
341
  end
330
342
 
331
343
  def key_type(column_family)
332
- self.cluster.keyspace(keyspace).table(column_family).column(KEY_FIELD).type.kind
344
+ get_type(column_family, KEY_FIELD)
333
345
  end
334
346
 
335
347
  def name_type(column_family)
336
- self.cluster.keyspace(keyspace).table(column_family).column(NAME_FIELD).type.kind
348
+ get_type(column_family, NAME_FIELD)
337
349
  end
338
350
 
339
351
  def value_type(column_family)
340
- self.cluster.keyspace(keyspace).table(column_family).column(VALUE_FIELD).type.kind
352
+ get_type(column_family, VALUE_FIELD)
353
+ end
354
+
355
+ def get_type(column_family, field)
356
+ cluster.keyspace(keyspace).table(column_family).column(field).type.kind
357
+ end
358
+
359
+ def get_key_fields(column_family)
360
+ cluster.keyspace(keyspace).table(column_family).columns.select { |c| c.name =~ /^key/ }.map { |c| [c.name, c.type.kind] }
361
+ end
362
+
363
+ def get_column_fields(column_family)
364
+ cluster.keyspace(keyspace).table(column_family).columns.select { |c| c.name =~ /^column/ }.map { |c| [c.name, c.type.kind] }
341
365
  end
342
366
 
343
367
  def reverse_comparator(column_family)
344
368
  self.cluster.keyspace(keyspace).table(column_family).send(:clustering_order).first == :desc
345
369
  end
346
370
 
371
+ def get_parts(column_family, val, fields)
372
+ val =
373
+ if fields.size > 1
374
+ Cassandra::Composite.new_from_packed(val.dup).parts
375
+ else
376
+ [val]
377
+ end
378
+
379
+ fields.each_with_index.map { |(field, type), idx| [field, normalize_composite_key_part(val[idx], type), type] }
380
+ end
381
+
382
+ def key_clause(column_family, val)
383
+ clause(column_family, val, get_key_fields(column_family))
384
+ end
385
+
386
+ def column_clause(column_family, val, operator='=')
387
+ clause(column_family, val, get_column_fields(column_family), operator)
388
+ end
389
+
390
+ def clause(column_family, val, fields, operator='=')
391
+ if operator == '='
392
+ get_parts(column_family, val, fields).map { |field, val, type| "#{field} #{operator} #{escape(val, type)}" }.join(' AND ')
393
+ else
394
+ field, val, type = get_parts(column_family, val, fields).first
395
+ "#{field} #{operator} #{escape(val, type)}"
396
+ end
397
+ end
398
+
347
399
  def escape(str, type)
348
400
  case type
349
401
  when :timeuuid
350
402
  convert_str_to_timeuuid str
351
403
  when :blob
352
404
  convert_str_to_hex str
405
+ when :int, :bigint
406
+ str
353
407
  else
354
408
  "'#{str}'"
355
409
  end
356
410
  end
357
411
 
412
+ def normalize_composite_key_part(val, type)
413
+ case type
414
+ when :timeuuid
415
+ SimpleUUID::UUID.new(val).to_s
416
+ when :int
417
+ val.unpack('N').first
418
+ when :bigint
419
+ Cassandra::Long.new(val).to_i
420
+ else
421
+ val
422
+ end
423
+ end
424
+
358
425
  def decode(val, type)
359
426
  case type
360
427
  when :timeuuid
@@ -373,6 +440,15 @@ CQL
373
440
  def convert_str_to_hex(str)
374
441
  '0x' << str.unpack('H*').first
375
442
  end
443
+
444
+ def column_string(row, fields)
445
+ if fields.size > 1
446
+ parts = fields.map { |f, t| decode(row[f], t) }
447
+ Cassandra::Composite.new(*parts).to_s
448
+ else
449
+ row[NAME_FIELD]
450
+ end
451
+ end
376
452
  end
377
453
  end
378
454
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'sessionm-cassandra_object'
5
- s.version = '4.0.27'
5
+ s.version = '4.0.28'
6
6
  s.description = 'Cassandra ActiveModel'
7
7
  s.summary = 'Cassandra ActiveModel'
8
8
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sessionm-cassandra_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.27
4
+ version: 4.0.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Doug Youch
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-12-05 00:00:00.000000000 Z
12
+ date: 2017-12-06 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Cassandra ActiveModel
15
15
  email: doug@sessionm.com