cequel 1.5.0 → 1.6.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +4 -17
  3. data/CHANGELOG.md +8 -0
  4. data/DRIVER_TODO +5 -0
  5. data/Gemfile +4 -0
  6. data/Gemfile.lock +110 -65
  7. data/README.md +4 -3
  8. data/Rakefile +39 -3
  9. data/Vagrantfile +10 -13
  10. data/cequel.gemspec +42 -0
  11. data/lib/cequel.rb +2 -2
  12. data/lib/cequel/metal/data_set.rb +1 -1
  13. data/lib/cequel/metal/keyspace.rb +23 -15
  14. data/lib/cequel/metal/logging.rb +1 -1
  15. data/lib/cequel/metal/request_logger.rb +1 -1
  16. data/lib/cequel/metal/writer.rb +1 -1
  17. data/lib/cequel/record.rb +1 -1
  18. data/lib/cequel/record/association_collection.rb +1 -1
  19. data/lib/cequel/record/associations.rb +1 -1
  20. data/lib/cequel/record/belongs_to_association.rb +1 -1
  21. data/lib/cequel/record/collection.rb +34 -28
  22. data/lib/cequel/record/data_set_builder.rb +1 -1
  23. data/lib/cequel/record/lazy_record_collection.rb +1 -1
  24. data/lib/cequel/record/persistence.rb +4 -2
  25. data/lib/cequel/record/properties.rb +2 -2
  26. data/lib/cequel/record/record_set.rb +1 -1
  27. data/lib/cequel/record/schema.rb +2 -2
  28. data/lib/cequel/record/scoped.rb +1 -1
  29. data/lib/cequel/schema/create_table_dsl.rb +1 -1
  30. data/lib/cequel/schema/keyspace.rb +17 -2
  31. data/lib/cequel/schema/migration_validator.rb +1 -1
  32. data/lib/cequel/schema/update_table_dsl.rb +1 -1
  33. data/lib/cequel/type.rb +5 -5
  34. data/lib/cequel/util.rb +30 -0
  35. data/lib/cequel/uuids.rb +5 -5
  36. data/lib/cequel/version.rb +1 -1
  37. data/spec/examples/metal/keyspace_spec.rb +1 -1
  38. data/spec/examples/record/list_spec.rb +9 -0
  39. data/spec/examples/record/persistence_spec.rb +2 -2
  40. data/spec/examples/schema/keyspace_spec.rb +1 -2
  41. data/spec/examples/schema/table_reader_spec.rb +1 -1
  42. data/spec/examples/spec_helper.rb +3 -0
  43. data/spec/examples/uuids_spec.rb +1 -1
  44. data/spec/support/helpers.rb +7 -5
  45. data/tags +836 -0
  46. metadata +49 -38
data/Vagrantfile CHANGED
@@ -11,7 +11,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
11
11
  # please see the online documentation at vagrantup.com.
12
12
 
13
13
  # Every Vagrant virtual environment requires a box to build off of.
14
- config.vm.box = "precise64"
14
+ config.vm.box = "ubuntu/trusty64"
15
15
 
16
16
  # The url from where the 'config.vm.box' box will be fetched if it
17
17
  # doesn't already exist on the user's system.
@@ -45,13 +45,9 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
45
45
  # backing providers for Vagrant. These expose provider-specific options.
46
46
  # Example for VirtualBox:
47
47
  #
48
- # config.vm.provider :virtualbox do |vb|
49
- # # Don't boot with headless mode
50
- # vb.gui = true
51
- #
52
- # # Use VBoxManage to customize the VM. For example to change memory:
53
- # vb.customize ["modifyvm", :id, "--memory", "1024"]
54
- # end
48
+ config.vm.provider :virtualbox do |vb|
49
+ vb.memory = 1024
50
+ end
55
51
  #
56
52
  # View the documentation for the provider you're using for more
57
53
  # information on available options.
@@ -131,14 +127,15 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
131
127
  echo "start on runlevel [2345]
132
128
  stop on runlevel [06]
133
129
  exec /opt/apache-cassandra-$1/bin/cassandra" > /etc/init/cassandra.conf
134
- sed -i -e 's/rpc_address:.*/rpc_address: 0.0.0.0/' /opt/apache-cassandra-$1/conf/cassandra.yaml
135
- sed -i -e 's/start_native_transport:.*/start_native_transport: true/' /opt/apache-cassandra-$1/conf/cassandra.yaml
136
- sed -i -e 's/start_rpc:.*/start_rpc: true/' /opt/apache-cassandra-$1/conf/cassandra.yaml
130
+ sed -i -e 's/.*broadcast_rpc_address:.*/broadcast_rpc_address: 127.0.0.1/' /opt/apache-cassandra-$1/conf/cassandra.yaml
131
+ sed -i -e 's/^rpc_address:.*/rpc_address: 0.0.0.0/' /opt/apache-cassandra-$1/conf/cassandra.yaml
132
+ sed -i -e 's/^start_native_transport:.*/start_native_transport: true/' /opt/apache-cassandra-$1/conf/cassandra.yaml
133
+ sed -i -e 's/^start_rpc:.*/start_rpc: true/' /opt/apache-cassandra-$1/conf/cassandra.yaml
137
134
  service cassandra start
138
135
  SH
139
136
 
140
- listing = Net::HTTP.get(URI.parse("http://archive.apache.org/dist/cassandra/"))
141
- versions = listing.scan(%r(href="(\d+\.\d+\.\d+)/")).map(&:first).grep(/^(1\.2\.|2\.)/)
137
+ versions = File.read(File.expand_path('../.cassandra-versions', __FILE__)).each_line
138
+ .map(&:strip).grep(/^(1\.2\.|2\.)/)
142
139
  versions.each do |version|
143
140
  java_version = version =~ /^1/ ? '6' : '7'
144
141
  config.vm.define version do |machine|
data/cequel.gemspec ADDED
@@ -0,0 +1,42 @@
1
+ require File.expand_path('../lib/cequel/version', __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'cequel'
5
+ s.version = Cequel::VERSION
6
+ s.authors = [
7
+ 'Mat Brown', 'Aubrey Holland', 'Keenan Brock', 'Insoo Buzz Jung',
8
+ 'Louis Simoneau', 'Peter Williams', 'Kenneth Hoffman', 'Antti Tapio',
9
+ 'Ilya Bazylchuk', 'Dan Cardamore', 'Kei Kusakari', 'Oleh Novosad',
10
+ 'John Smart', 'Angelo Lakra', 'Olivier Lance', 'Tomohiro Nishimura',
11
+ 'Masaki Takahashi', 'G Gordon Worley III', 'Clark Bremer', 'Tamara Temple',
12
+ 'Long On', 'Lucas Mundim'
13
+ ]
14
+ s.homepage = "https://github.com/cequel/cequel"
15
+ s.email = 'mat.a.brown@gmail.com'
16
+ s.license = 'MIT'
17
+ s.summary = 'Full-featured, ActiveModel-compliant ORM for Cassandra using CQL3'
18
+ s.description = <<DESC
19
+ Cequel is an ActiveRecord-like domain model layer for Cassandra that exposes
20
+ the robust data modeling capabilities of CQL3, including parent-child
21
+ relationships via compound primary keys and in-memory atomic manipulation of
22
+ collection columns.
23
+ DESC
24
+
25
+ s.files = Dir['lib/**/*.rb', 'templates/**/*', 'spec/**/*.rb', '[A-Z]*']
26
+ s.test_files = Dir['spec/examples/**/*.rb']
27
+ s.has_rdoc = true
28
+ s.extra_rdoc_files = 'README.md'
29
+ s.required_ruby_version = '>= 1.9'
30
+ s.add_runtime_dependency 'activemodel', '>= 3.1', '< 5.0'
31
+ s.add_runtime_dependency 'cassandra-driver', '~> 1.0'
32
+ s.add_development_dependency 'appraisal', '~> 1.0'
33
+ s.add_development_dependency 'wwtd', '~> 0.5'
34
+ s.add_development_dependency 'rake', '~> 10.1'
35
+ s.add_development_dependency 'rspec', '~> 3.1'
36
+ s.add_development_dependency 'rspec-its', '~> 1.0'
37
+ s.add_development_dependency 'rubocop', '~> 0.28'
38
+ s.add_development_dependency 'timecop', '~> 0.7'
39
+ s.add_development_dependency 'travis', '~> 1.7'
40
+ s.add_development_dependency 'yard', '~> 0.6'
41
+ s.requirements << 'Cassandra >= 1.2.0'
42
+ end
data/lib/cequel.rb CHANGED
@@ -4,13 +4,13 @@ require 'delegate'
4
4
  require 'active_support'
5
5
  require 'active_support/deprecation'
6
6
  require 'active_support/core_ext'
7
- require 'cql'
7
+ require 'cassandra'
8
8
 
9
9
  require 'cequel/errors'
10
+ require 'cequel/util'
10
11
  require 'cequel/metal'
11
12
  require 'cequel/schema'
12
13
  require 'cequel/type'
13
- require 'cequel/util'
14
14
  require 'cequel/uuids'
15
15
  require 'cequel/instrumentation'
16
16
  require 'cequel/record'
@@ -21,7 +21,7 @@ module Cequel
21
21
  #
22
22
  class DataSet
23
23
  include Enumerable
24
- extend Forwardable
24
+ extend Util::Forwardable
25
25
 
26
26
  # @return [Keyspace] keyspace that this data set's table resides in
27
27
  attr_reader :keyspace
@@ -9,7 +9,7 @@ module Cequel
9
9
  # instance.
10
10
  #
11
11
  class Keyspace
12
- extend Forwardable
12
+ extend Util::Forwardable
13
13
  include Logging
14
14
  include MonitorMixin
15
15
 
@@ -154,9 +154,7 @@ module Cequel
154
154
  #
155
155
  def client
156
156
  synchronize do
157
- @client ||= raw_client.tap do |client|
158
- client.use(name) if name
159
- end
157
+ @client ||= cluster.connect(name)
160
158
  end
161
159
  end
162
160
 
@@ -193,8 +191,9 @@ module Cequel
193
191
  log('CQL', statement, *bind_vars) do
194
192
  begin
195
193
  client.execute(sanitize(statement, bind_vars),
196
- consistency || default_consistency)
197
- rescue Cql::NotConnectedError, Ione::Io::ConnectionError
194
+ consistency: consistency || default_consistency)
195
+ rescue Cassandra::Errors::NoHostsAvailable,
196
+ Ione::Io::ConnectionError => e
198
197
  clear_active_connections!
199
198
  raise if retries == 0
200
199
  retries -= 1
@@ -213,8 +212,11 @@ module Cequel
213
212
  if defined? @client
214
213
  remove_instance_variable(:@client)
215
214
  end
216
- if defined? @raw_client
217
- remove_instance_variable(:@raw_client)
215
+ if defined? @client_without_keyspace
216
+ remove_instance_variable(:@client_without_keyspace)
217
+ end
218
+ if defined? @cluster
219
+ remove_instance_variable(:@cluster)
218
220
  end
219
221
  end
220
222
 
@@ -235,7 +237,7 @@ module Cequel
235
237
  CQL
236
238
 
237
239
  log('CQL', statement, [name]) do
238
- raw_client.execute(sanitize(statement, [name])).any?
240
+ client_without_keyspace.execute(sanitize(statement, [name])).any?
239
241
  end
240
242
  end
241
243
 
@@ -249,15 +251,21 @@ module Cequel
249
251
  def_delegator :lock, :synchronize
250
252
  private :lock
251
253
 
252
- def raw_client
254
+ def cluster
253
255
  synchronize do
254
- @raw_client ||= Cql::Client.connect(client_options)
256
+ @cluster ||= Cassandra.cluster(client_options)
257
+ end
258
+ end
259
+
260
+ def client_without_keyspace
261
+ synchronize do
262
+ @client_without_keyspace ||= cluster.connect
255
263
  end
256
264
  end
257
265
 
258
266
  def client_options
259
267
  {hosts: hosts, port: port}.tap do |options|
260
- options[:credentials] = credentials if credentials
268
+ options.merge!(credentials) if credentials
261
269
  end
262
270
  end
263
271
 
@@ -272,9 +280,9 @@ module Cequel
272
280
  def extract_hosts_and_port(configuration)
273
281
  hosts, ports = [], Set[]
274
282
  ports << configuration[:port] if configuration.key?(:port)
275
- Array.wrap(configuration.fetch(
276
- :host, configuration.fetch(:hosts, '127.0.0.1'))).each do |host_port|
277
-
283
+ host_or_hosts =
284
+ configuration.fetch(:host, configuration.fetch(:hosts, '127.0.0.1'))
285
+ Array.wrap(host_or_hosts).each do |host_port|
278
286
  host, port = host_port.split(':')
279
287
  hosts << host
280
288
  if port
@@ -5,7 +5,7 @@ module Cequel
5
5
  # Methods to handle logging for {Keyspace} instances
6
6
  #
7
7
  module Logging
8
- extend Forwardable
8
+ extend Util::Forwardable
9
9
  def_delegators :request_logger, :logger, :logger=, :slowlog_threshold,
10
10
  :slowlog_threshold=
11
11
 
@@ -7,7 +7,7 @@ module Cequel
7
7
  # @api private
8
8
  #
9
9
  class RequestLogger
10
- extend Forwardable
10
+ extend Util::Forwardable
11
11
  # @return [::Logger] An instance of Logger that responds to methods for
12
12
  # standard severity levels
13
13
  attr_accessor :logger
@@ -11,7 +11,7 @@ module Cequel
11
11
  # @api private
12
12
  #
13
13
  class Writer
14
- extend Forwardable
14
+ extend Util::Forwardable
15
15
 
16
16
  #
17
17
  # @param data_set [DataSet] data set to write to
data/lib/cequel/record.rb CHANGED
@@ -78,7 +78,7 @@ module Cequel
78
78
  #
79
79
  module Record
80
80
  extend ActiveSupport::Concern
81
- extend Forwardable
81
+ extend Util::Forwardable
82
82
 
83
83
  included do
84
84
  include Properties
@@ -12,7 +12,7 @@ module Cequel
12
12
  #
13
13
  class AssociationCollection < DelegateClass(RecordSet)
14
14
  include Enumerable
15
- extend Forwardable
15
+ extend Util::Forwardable
16
16
 
17
17
  #
18
18
  # @yield [Record]
@@ -65,7 +65,7 @@ module Cequel
65
65
  # @see Associations
66
66
  #
67
67
  module ClassMethods
68
- include Forwardable
68
+ include Util::Forwardable
69
69
 
70
70
  # @!attribute parent_association
71
71
  # @return [BelongsToAssociation] association declared by
@@ -9,7 +9,7 @@ module Cequel
9
9
  # @since 1.0.0
10
10
  #
11
11
  class BelongsToAssociation
12
- extend Forwardable
12
+ extend Util::Forwardable
13
13
 
14
14
  # @return [Class] child class that declared `belongs_to`
15
15
  attr_reader :owner_class
@@ -53,7 +53,7 @@ module Cequel
53
53
  #
54
54
  module Collection
55
55
  extend ActiveSupport::Concern
56
- extend Forwardable
56
+ extend Util::Forwardable
57
57
 
58
58
  #
59
59
  # @!method loaded?
@@ -137,12 +137,16 @@ module Cequel
137
137
  def to_modify(&block)
138
138
  if loaded?
139
139
  model.__send__("#{column_name}_will_change!")
140
- block.call()
140
+ block.call
141
141
  else modifications << block
142
142
  end
143
143
  self
144
144
  end
145
145
 
146
+ def to_update
147
+ yield unless model.new_record?
148
+ end
149
+
146
150
  def modifications
147
151
  @modifications ||= []
148
152
  end
@@ -231,15 +235,17 @@ module Cequel
231
235
  "indices"
232
236
  end
233
237
 
234
- if count.nil?
235
- updater.list_replace(column_name, first, element)
236
- else
237
- element = Array.wrap(element)
238
- count.times do |i|
239
- if i < element.length
240
- updater.list_replace(column_name, first+i, element[i])
241
- else
242
- deleter.list_remove_at(column_name, first+i)
238
+ to_update do
239
+ if count.nil?
240
+ updater.list_replace(column_name, first, element)
241
+ else
242
+ element = Array.wrap(element)
243
+ count.times do |i|
244
+ if i < element.length
245
+ updater.list_replace(column_name, first+i, element[i])
246
+ else
247
+ deleter.list_remove_at(column_name, first+i)
248
+ end
243
249
  end
244
250
  end
245
251
  end
@@ -253,7 +259,7 @@ module Cequel
253
259
  # @return [List] self
254
260
  #
255
261
  def clear
256
- deleter.delete_columns(column_name)
262
+ to_update { deleter.delete_columns(column_name) }
257
263
  to_modify { super }
258
264
  end
259
265
 
@@ -265,7 +271,7 @@ module Cequel
265
271
  #
266
272
  def concat(array)
267
273
  array = cast_collection(array)
268
- updater.list_append(column_name, array)
274
+ to_update { updater.list_append(column_name, array) }
269
275
  to_modify { super }
270
276
  end
271
277
 
@@ -277,7 +283,7 @@ module Cequel
277
283
  #
278
284
  def delete(object)
279
285
  object = cast_element(object)
280
- updater.list_remove(column_name, object)
286
+ to_update { updater.list_remove(column_name, object) }
281
287
  to_modify { super }
282
288
  end
283
289
 
@@ -288,7 +294,7 @@ module Cequel
288
294
  # @return [List] self
289
295
  #
290
296
  def delete_at(index)
291
- deleter.list_remove_at(column_name, index)
297
+ to_update { deleter.list_remove_at(column_name, index) }
292
298
  to_modify { super }
293
299
  end
294
300
 
@@ -300,7 +306,7 @@ module Cequel
300
306
  #
301
307
  def push(*objects)
302
308
  objects.map! { |object| cast_element(object) }
303
- updater.list_append(column_name, objects)
309
+ to_update { updater.list_append(column_name, objects) }
304
310
  to_modify { super }
305
311
  end
306
312
  alias_method :<<, :push
@@ -314,7 +320,7 @@ module Cequel
314
320
  #
315
321
  def replace(array)
316
322
  array = cast_collection(array)
317
- updater.set(column_name => array)
323
+ to_update { updater.set(column_name => array) }
318
324
  to_modify { super }
319
325
  end
320
326
 
@@ -326,7 +332,7 @@ module Cequel
326
332
  #
327
333
  def unshift(*objects)
328
334
  objects.map!(&method(:cast_element))
329
- updater.list_prepend(column_name, objects.reverse)
335
+ to_update { updater.list_prepend(column_name, objects.reverse) }
330
336
  to_modify { super }
331
337
  end
332
338
  alias_method :prepend, :unshift
@@ -368,7 +374,7 @@ module Cequel
368
374
  #
369
375
  def add(object)
370
376
  object = cast_element(object)
371
- updater.set_add(column_name, object)
377
+ to_update { updater.set_add(column_name, object) }
372
378
  to_modify { super }
373
379
  end
374
380
  alias_method :<<, :add
@@ -380,7 +386,7 @@ module Cequel
380
386
  # @return [Set] self
381
387
  #
382
388
  def clear
383
- deleter.delete_columns(column_name)
389
+ to_update { deleter.delete_columns(column_name) }
384
390
  to_modify { super }
385
391
  end
386
392
 
@@ -392,7 +398,7 @@ module Cequel
392
398
  #
393
399
  def delete(object)
394
400
  object = cast_element(object)
395
- updater.set_remove(column_name, object)
401
+ to_update { updater.set_remove(column_name, object) }
396
402
  to_modify { super }
397
403
  end
398
404
 
@@ -404,7 +410,7 @@ module Cequel
404
410
  #
405
411
  def replace(set)
406
412
  set = cast_collection(set)
407
- updater.set(column_name => set)
413
+ to_update { updater.set(column_name => set) }
408
414
  to_modify { super }
409
415
  end
410
416
  end
@@ -419,7 +425,7 @@ module Cequel
419
425
  #
420
426
  class Map < DelegateClass(::Hash)
421
427
  include Collection
422
- extend Forwardable
428
+ extend Util::Forwardable
423
429
 
424
430
  # These methods involve mutation that cannot be expressed as a CQL
425
431
  # operation, so are not implemented.
@@ -456,7 +462,7 @@ module Cequel
456
462
  #
457
463
  def []=(key, value)
458
464
  key = cast_key(key)
459
- updater.map_update(column_name, key => value)
465
+ to_update { updater.map_update(column_name, key => value) }
460
466
  to_modify { super }
461
467
  end
462
468
  alias_method :store, :[]=
@@ -468,7 +474,7 @@ module Cequel
468
474
  # @return [Map] self
469
475
  #
470
476
  def clear
471
- deleter.delete_columns(column_name)
477
+ to_update { deleter.delete_columns(column_name) }
472
478
  to_modify { super }
473
479
  end
474
480
 
@@ -480,7 +486,7 @@ module Cequel
480
486
  #
481
487
  def delete(key)
482
488
  key = cast_key(key)
483
- deleter.map_remove(column_name, key)
489
+ to_update { deleter.map_remove(column_name, key) }
484
490
  to_modify { super }
485
491
  end
486
492
 
@@ -492,7 +498,7 @@ module Cequel
492
498
  #
493
499
  def merge!(hash)
494
500
  hash = cast_collection(hash)
495
- updater.map_update(column_name, hash)
501
+ to_update { updater.map_update(column_name, hash) }
496
502
  to_modify { super }
497
503
  end
498
504
  alias_method :update, :merge!
@@ -505,7 +511,7 @@ module Cequel
505
511
  #
506
512
  def replace(hash)
507
513
  hash = cast_collection(hash)
508
- updater.set(column_name => hash)
514
+ to_update { updater.set(column_name => hash) }
509
515
  to_modify { super }
510
516
  end
511
517