sessionm-cassandra_object 2.2.6

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 (83) hide show
  1. data/.gitignore +2 -0
  2. data/CHANGELOG +3 -0
  3. data/Gemfile +2 -0
  4. data/LICENSE +13 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.markdown +12 -0
  7. data/Rakefile +15 -0
  8. data/lib/cassandra_object/associations/one_to_many.rb +146 -0
  9. data/lib/cassandra_object/associations/one_to_one.rb +85 -0
  10. data/lib/cassandra_object/associations.rb +50 -0
  11. data/lib/cassandra_object/attributes.rb +97 -0
  12. data/lib/cassandra_object/base.rb +97 -0
  13. data/lib/cassandra_object/batches.rb +31 -0
  14. data/lib/cassandra_object/callbacks.rb +27 -0
  15. data/lib/cassandra_object/collection.rb +8 -0
  16. data/lib/cassandra_object/connection.rb +29 -0
  17. data/lib/cassandra_object/consistency.rb +31 -0
  18. data/lib/cassandra_object/cursor.rb +90 -0
  19. data/lib/cassandra_object/dirty.rb +32 -0
  20. data/lib/cassandra_object/errors.rb +10 -0
  21. data/lib/cassandra_object/finder_methods.rb +72 -0
  22. data/lib/cassandra_object/generators/migration_generator.rb +31 -0
  23. data/lib/cassandra_object/generators/templates/migration.rb.erb +11 -0
  24. data/lib/cassandra_object/identity/abstract_key_factory.rb +36 -0
  25. data/lib/cassandra_object/identity/custom_key_factory.rb +50 -0
  26. data/lib/cassandra_object/identity/hashed_natural_key_factory.rb +10 -0
  27. data/lib/cassandra_object/identity/key.rb +20 -0
  28. data/lib/cassandra_object/identity/natural_key_factory.rb +51 -0
  29. data/lib/cassandra_object/identity/uuid_key_factory.rb +39 -0
  30. data/lib/cassandra_object/identity.rb +52 -0
  31. data/lib/cassandra_object/log_subscriber.rb +37 -0
  32. data/lib/cassandra_object/migrations/migration.rb +15 -0
  33. data/lib/cassandra_object/migrations.rb +66 -0
  34. data/lib/cassandra_object/mocking.rb +15 -0
  35. data/lib/cassandra_object/persistence.rb +138 -0
  36. data/lib/cassandra_object/railtie.rb +11 -0
  37. data/lib/cassandra_object/schema/migration.rb +106 -0
  38. data/lib/cassandra_object/schema/migration_proxy.rb +25 -0
  39. data/lib/cassandra_object/schema/migrator.rb +213 -0
  40. data/lib/cassandra_object/schema.rb +37 -0
  41. data/lib/cassandra_object/serialization.rb +6 -0
  42. data/lib/cassandra_object/tasks/column_family.rb +90 -0
  43. data/lib/cassandra_object/tasks/keyspace.rb +89 -0
  44. data/lib/cassandra_object/tasks/ks.rake +121 -0
  45. data/lib/cassandra_object/timestamps.rb +19 -0
  46. data/lib/cassandra_object/type.rb +19 -0
  47. data/lib/cassandra_object/types/array_type.rb +16 -0
  48. data/lib/cassandra_object/types/boolean_type.rb +23 -0
  49. data/lib/cassandra_object/types/date_type.rb +20 -0
  50. data/lib/cassandra_object/types/float_type.rb +19 -0
  51. data/lib/cassandra_object/types/hash_type.rb +16 -0
  52. data/lib/cassandra_object/types/integer_type.rb +19 -0
  53. data/lib/cassandra_object/types/set_type.rb +22 -0
  54. data/lib/cassandra_object/types/string_type.rb +16 -0
  55. data/lib/cassandra_object/types/time_type.rb +27 -0
  56. data/lib/cassandra_object/types/time_with_zone_type.rb +18 -0
  57. data/lib/cassandra_object/types/utf8_string_type.rb +18 -0
  58. data/lib/cassandra_object/types.rb +11 -0
  59. data/lib/cassandra_object/validations.rb +46 -0
  60. data/lib/cassandra_object.rb +49 -0
  61. data/sessionm-cassandra_object.gemspec +26 -0
  62. data/test/active_model_test.rb +9 -0
  63. data/test/base_test.rb +28 -0
  64. data/test/batches_test.rb +30 -0
  65. data/test/connection_test.rb +28 -0
  66. data/test/consistency_test.rb +20 -0
  67. data/test/finder_methods_test.rb +49 -0
  68. data/test/identity_test.rb +30 -0
  69. data/test/persistence_test.rb +84 -0
  70. data/test/test_helper.rb +31 -0
  71. data/test/timestamps_test.rb +27 -0
  72. data/test/types/array_type_test.rb +15 -0
  73. data/test/types/boolean_type_test.rb +23 -0
  74. data/test/types/date_type_test.rb +4 -0
  75. data/test/types/float_type_test.rb +4 -0
  76. data/test/types/hash_type_test.rb +4 -0
  77. data/test/types/integer_type_test.rb +18 -0
  78. data/test/types/set_type_test.rb +17 -0
  79. data/test/types/string_type_test.rb +4 -0
  80. data/test/types/time_type_test.rb +4 -0
  81. data/test/types/utf8_string_type_test.rb +4 -0
  82. data/test/validations_test.rb +15 -0
  83. metadata +183 -0
@@ -0,0 +1,90 @@
1
+ module CassandraObject
2
+ class Cursor
3
+ include Consistency
4
+
5
+ def initialize(target_class, column_family, key, super_column, options={})
6
+ @target_class = target_class
7
+ @column_family = column_family
8
+ @key = key.to_s
9
+ @super_column = super_column
10
+ @options = options
11
+ @validators = []
12
+ end
13
+
14
+ def find(number_to_find)
15
+ limit = number_to_find
16
+ objects = CassandraObject::Collection.new
17
+ out_of_keys = false
18
+
19
+ if start_with = @options[:start_after]
20
+ limit += 1
21
+ else
22
+ start_with = nil
23
+ end
24
+
25
+ while objects.size < number_to_find && !out_of_keys
26
+ index_results = connection.get(@column_family, @key, @super_column,
27
+ count: limit,
28
+ start: start_with,
29
+ reversed: @options[:reversed],
30
+ consistency: target_class.thrift_read_consistency)
31
+
32
+ out_of_keys = index_results.size < limit
33
+
34
+ if !start_with.blank?
35
+ index_results.delete(start_with)
36
+ end
37
+
38
+ keys = index_results.keys
39
+ values = index_results.values
40
+
41
+ missing_keys = []
42
+
43
+ results = values.empty? ? {} : @target_class.multi_get(values)
44
+ results.each do |(key, result)|
45
+ if result.nil?
46
+ missing_keys << key
47
+ end
48
+ end
49
+
50
+ unless missing_keys.empty?
51
+ @target_class.multi_get(missing_keys, :quorum=>true).each do |(key, result)|
52
+ index_key = index_results.index(key)
53
+ if result.nil?
54
+ remove(index_key)
55
+ results.delete(key)
56
+ else
57
+ results[key] = result
58
+ end
59
+ end
60
+ end
61
+
62
+ results.values.each do |o|
63
+ if @validators.all? {|v| v.call(o) }
64
+ objects << o
65
+ else
66
+ remove(index_results.index(o.key))
67
+ end
68
+ end
69
+
70
+ start_with = objects.last_column_name = keys.last
71
+ limit = (number_to_find - results.size) + 1
72
+
73
+ end
74
+
75
+ return objects
76
+ end
77
+
78
+ def connection
79
+ @target_class.connection
80
+ end
81
+
82
+ def remove(index_key)
83
+ connection.remove(@column_family, @key, @super_column, index_key, consistency: target_class.thrift_write_consistency)
84
+ end
85
+
86
+ def validator(&validator)
87
+ @validators << validator
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,32 @@
1
+ module CassandraObject
2
+ module Dirty
3
+ extend ActiveSupport::Concern
4
+ include ActiveModel::Dirty
5
+
6
+ # Attempts to +save+ the record and clears changed attributes if successful.
7
+ def save(*) #:nodoc:
8
+ if status = super
9
+ @previously_changed = changes
10
+ @changed_attributes.clear
11
+ end
12
+ status
13
+ end
14
+
15
+ # Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
16
+ def save!(*) #:nodoc:
17
+ super.tap do
18
+ @previously_changed = changes
19
+ @changed_attributes.clear
20
+ end
21
+ end
22
+
23
+ def write_attribute(name, value)
24
+ name = name.to_s
25
+ unless attribute_changed?(name)
26
+ old = read_attribute(name)
27
+ changed_attributes[name] = old if old != value
28
+ end
29
+ super
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,10 @@
1
+ module CassandraObject
2
+ class CasssandraObjectError < StandardError
3
+ end
4
+
5
+ class RecordNotSaved < CasssandraObjectError
6
+ end
7
+
8
+ class RecordNotFound < CasssandraObjectError
9
+ end
10
+ end
@@ -0,0 +1,72 @@
1
+ module CassandraObject
2
+ module FinderMethods
3
+ extend ActiveSupport::Concern
4
+ module ClassMethods
5
+ def find(key)
6
+ if parse_key(key) && attributes = connection.get(column_family, key)
7
+ instantiate(key, attributes)
8
+ else
9
+ raise CassandraObject::RecordNotFound
10
+ end
11
+ end
12
+
13
+ def find_by_id(key)
14
+ find(key)
15
+ rescue CassandraObject::RecordNotFound
16
+ nil
17
+ end
18
+
19
+ def all(options = {})
20
+ limit = options[:limit] || 100
21
+ results = ActiveSupport::Notifications.instrument("get_range.cassandra_object", column_family: column_family, key_count: limit) do
22
+ connection.get_range(column_family, key_count: limit, consistency: thrift_read_consistency)
23
+ end
24
+
25
+ results.map do |k, v|
26
+ v.empty? ? nil : instantiate(k, v)
27
+ end.compact
28
+ end
29
+
30
+ def first(options = {})
31
+ all(options.merge(:limit => 1)).first
32
+ end
33
+
34
+ def find_with_ids(*ids)
35
+ expects_array = ids.first.kind_of?(Array)
36
+ return ids.first if expects_array && ids.first.empty?
37
+
38
+ ids = ids.dup
39
+ ids.flatten!
40
+ ids.compact!
41
+ ids.collect!(&:to_s)
42
+ ids.uniq!
43
+
44
+ #raise RecordNotFound, "Couldn't find #{record_klass.name} without an ID" if ids.empty?
45
+
46
+ results = multi_get(ids).values.compact
47
+
48
+ results.size <= 1 && !expects_array ? results.first : results
49
+ end
50
+
51
+ private
52
+ def multi_get(keys, options={})
53
+ attribute_results = ActiveSupport::Notifications.instrument("multi_get.cassandra_object", column_family: column_family, keys: keys) do
54
+ connection.multi_get(column_family, keys.map(&:to_s), consistency: thrift_read_consistency)
55
+ end
56
+
57
+ attribute_results.inject({}) do |memo, (key, attributes)|
58
+ if attributes.empty?
59
+ memo[key] = nil
60
+ else
61
+ memo[parse_key(key)] = instantiate(key, attributes)
62
+ end
63
+ memo
64
+ end
65
+ end
66
+
67
+ def get(key, options={})
68
+ multi_get([key], options).values.first
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,31 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/named_base'
3
+
4
+ module CassandraObject
5
+ module Generators
6
+ class MigrationGenerator < Rails::Generators::NamedBase
7
+
8
+ source_root File.expand_path("../templates", __FILE__)
9
+
10
+ def self.banner
11
+ "rails g cassandra_object:migration NAME"
12
+ end
13
+
14
+ def self.desc(description = nil)
15
+ <<EOF
16
+ Description:
17
+ Create an empty Cassandra migration file in 'ks/migrate'. Very similar to Rails database migrations.
18
+
19
+ Example:
20
+ `rails g cassandra_object:migration CreateFooColumnFamily`
21
+ EOF
22
+ end
23
+
24
+ def create
25
+ timestamp = Time.now.utc.strftime("%Y%m%d%H%M%S")
26
+ template 'migration.rb.erb', "ks/migrate/#{timestamp}_#{file_name.underscore}.rb"
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ class <%= name %> < CassandraObject::Schema::Migration
2
+
3
+ def self.up
4
+
5
+ end
6
+
7
+ def self.down
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,36 @@
1
+ module CassandraObject
2
+ module Identity
3
+ # Key factories need to support 3 operations
4
+ class AbstractKeyFactory
5
+ # Next key takes an object and returns the key object it should use.
6
+ # object will be ignored with synthetic keys but could be useful with natural ones
7
+ #
8
+ # @param [CassandraObject::Base] the object that needs a new key
9
+ # @return [CassandraObject::Identity::Key] the key
10
+ #
11
+ def next_key(object)
12
+ raise NotImplementedError, "#{self.class.name}#next_key isn't implemented."
13
+ end
14
+
15
+ # Parse should create a new key object from the 'to_param' format
16
+ #
17
+ # @param [String] the result of calling key.to_param
18
+ # @return [CassandraObject::Identity::Key] the parsed key
19
+ #
20
+ def parse(string)
21
+ raise NotImplementedError, "#{self.class.name}#parse isn't implemented."
22
+ end
23
+
24
+
25
+ # create should create a new key object from the cassandra format.
26
+ #
27
+ # @param [String] the result of calling key.to_s
28
+ # @return [CassandraObject::Identity::Key] the key
29
+ #
30
+ def create(string)
31
+ raise NotImplementedError, "#{self.class.name}#create isn't implemented."
32
+ end
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,50 @@
1
+ module CassandraObject
2
+ module Identity
3
+ class CustomKeyFactory < AbstractKeyFactory
4
+ class CustomKey
5
+ include Key
6
+
7
+ attr_reader :value
8
+
9
+ def initialize(value)
10
+ @value = value
11
+ end
12
+
13
+ def to_s
14
+ value
15
+ end
16
+
17
+ def to_param
18
+ value
19
+ end
20
+
21
+ def ==(other)
22
+ other.is_a?(CustomKey) && other.value == value
23
+ end
24
+
25
+ def eql?(other)
26
+ other == self
27
+ end
28
+ end
29
+
30
+ attr_reader :method
31
+
32
+ def initialize(options)
33
+ @method = options[:method]
34
+ end
35
+
36
+ def next_key(object)
37
+ CustomKey.new(object.send(@method))
38
+ end
39
+
40
+ def parse(paramized_key)
41
+ CustomKey.new(paramized_key)
42
+ end
43
+
44
+ def create(paramized_key)
45
+ CustomKey.new(paramized_key)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,10 @@
1
+ require 'digest/sha1'
2
+ module CassandraObject
3
+ module Identity
4
+ class HashedNaturalKeyFactory < NaturalKeyFactory
5
+ def next_key(object)
6
+ NaturalKey.new(Digest::SHA1.hexdigest(attributes.map { |a| object.attributes[a.to_s] }.join(separator)))
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ module CassandraObject
2
+ module Identity
3
+ # An "interface" that keys need to implement
4
+ #
5
+ # You don't have to include this. But, there's no reason I can think of not to.
6
+ #
7
+ module Key
8
+ # to_param should return a nice-readable representation of the key suitable to chuck into URLs
9
+ #
10
+ # @return [String] a nice readable representation of the key suitable for URLs
11
+ def to_param; end
12
+
13
+ # to_s should return the bytes which will be written to cassandra both as keys and values for associations.
14
+ #
15
+ # @return [String] the bytes which will be written to cassandra as keys
16
+ def to_s; end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,51 @@
1
+ module CassandraObject
2
+ module Identity
3
+ class NaturalKeyFactory < AbstractKeyFactory
4
+ class NaturalKey
5
+ include Key
6
+
7
+ attr_reader :value
8
+
9
+ def initialize(value)
10
+ @value = value
11
+ end
12
+
13
+ def to_s
14
+ value
15
+ end
16
+
17
+ def to_param
18
+ value
19
+ end
20
+
21
+ def ==(other)
22
+ other.is_a?(NaturalKey) && other.value == value
23
+ end
24
+
25
+ def eql?(other)
26
+ other == self
27
+ end
28
+ end
29
+
30
+ attr_reader :attributes, :separator
31
+
32
+ def initialize(options)
33
+ @attributes = [*options[:attributes]]
34
+ @separator = options[:separator] || "-"
35
+ end
36
+
37
+ def next_key(object)
38
+ NaturalKey.new(attributes.map { |a| object.attributes[a.to_s] }.join(separator))
39
+ end
40
+
41
+ def parse(paramized_key)
42
+ NaturalKey.new(paramized_key)
43
+ end
44
+
45
+ def create(paramized_key)
46
+ NaturalKey.new(paramized_key)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,39 @@
1
+ module CassandraObject
2
+ module Identity
3
+ # Key factories need to support 3 operations
4
+ class UUIDKeyFactory < AbstractKeyFactory
5
+ class UUID < SimpleUUID::UUID
6
+ include Key
7
+
8
+ def to_param
9
+ to_guid
10
+ end
11
+
12
+ def to_s
13
+ # FIXME - this should probably write the raw bytes
14
+ # but it's very hard to debug without this for now.
15
+ to_guid
16
+ end
17
+ end
18
+
19
+ # Next key takes an object and returns the key object it should use.
20
+ # object will be ignored with synthetic keys but could be useful with natural ones
21
+ def next_key(object)
22
+ UUID.new
23
+ end
24
+
25
+ # Parse should create a new key object from the 'to_param' format
26
+ def parse(string)
27
+ UUID.new(string)
28
+ rescue
29
+ nil
30
+ end
31
+
32
+ # create should create a new key object from the cassandra format.
33
+ def create(string)
34
+ UUID.new(string)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,52 @@
1
+ module CassandraObject
2
+ module Identity
3
+ extend ActiveSupport::Concern
4
+ extend ActiveSupport::Autoload
5
+
6
+ autoload :Key
7
+ autoload :AbstractKeyFactory
8
+ autoload :UUIDKeyFactory
9
+ autoload :NaturalKeyFactory
10
+ autoload :HashedNaturalKeyFactory
11
+ autoload :CustomKeyFactory
12
+
13
+ module ClassMethods
14
+ # Indicate what kind of key the model will have: uuid or natural
15
+ #
16
+ # @param [:uuid, :natural] the type of key
17
+ # @param the options you want to pass along to the key factory (like :attributes => :name, for a natural key).
18
+ #
19
+ def key(name_or_factory = :uuid, *options)
20
+ @key_factory = case name_or_factory
21
+ when :uuid
22
+ UUIDKeyFactory.new
23
+ when :natural
24
+ NaturalKeyFactory.new(*options)
25
+ when :custom
26
+ CustomKeyFactory.new(*options)
27
+ else
28
+ name_or_factory
29
+ end
30
+ end
31
+
32
+ def next_key(object = nil)
33
+ @key_factory.next_key(object).tap do |key|
34
+ raise "Keys may not be nil" if key.nil?
35
+ end
36
+ end
37
+
38
+ def parse_key(string)
39
+ @key_factory.parse(string)
40
+ end
41
+ end
42
+
43
+ def id
44
+ key.to_s
45
+ end
46
+
47
+ def id=(key)
48
+ self.key = self.class.parse_key(key)
49
+ id
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,37 @@
1
+ module CassandraObject
2
+ class LogSubscriber < ActiveSupport::LogSubscriber
3
+ def multi_get(event)
4
+ name = '%s multi_get (%.1fms)' % [event.payload[:column_family], event.duration]
5
+
6
+ debug " #{name} (#{event.payload[:keys].size}) #{event.payload[:keys].join(" ")}"
7
+ end
8
+
9
+ def remove(event)
10
+ name = '%s remove (%.1fms)' % [event.payload[:column_family], event.duration]
11
+
12
+ message = " #{name} #{event.payload[:key]}"
13
+ message << " #{Array(event.payload[:attributes]).inspect}" if event.payload[:attributes]
14
+
15
+ debug message
16
+ end
17
+
18
+ def truncate(event)
19
+ name = '%s truncate (%.1fms)' % [event.payload[:column_family], event.duration]
20
+
21
+ debug " #{name} #{event.payload[:column_family]}"
22
+ end
23
+
24
+ def insert(event)
25
+ name = '%s insert (%.1fms)' % [event.payload[:column_family], event.duration]
26
+
27
+ debug " #{name} #{event.payload[:key]} #{event.payload[:attributes].inspect}"
28
+ end
29
+
30
+ def get_range(event)
31
+ name = '%s get_range (%.1fms)' % [event.payload[:column_family], event.duration]
32
+
33
+ debug " #{name} (#{event.payload[:count]}) '#{event.payload[:start]}' => '#{event.payload[:finish]}'"
34
+ end
35
+ end
36
+ end
37
+ CassandraObject::LogSubscriber.attach_to :cassandra_object
@@ -0,0 +1,15 @@
1
+ module CassandraObject
2
+ module Migrations
3
+ class Migration
4
+ attr_reader :version
5
+ def initialize(version, block)
6
+ @version = version
7
+ @block = block
8
+ end
9
+
10
+ def run(attrs)
11
+ @block.call(attrs)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,66 @@
1
+ module CassandraObject
2
+ module Migrations
3
+ extend ActiveSupport::Concern
4
+ extend ActiveSupport::Autoload
5
+
6
+ included do
7
+ class_inheritable_array :migrations
8
+ class_inheritable_accessor :current_schema_version
9
+ self.current_schema_version = 0
10
+ end
11
+
12
+ autoload :Migration
13
+
14
+ class MigrationNotFoundError < StandardError
15
+ def initialize(record_version, migrations)
16
+ super("Cannot migrate a record from #{record_version.inspect}. Migrations exist for #{migrations.map(&:version)}")
17
+ end
18
+ end
19
+
20
+ module InstanceMethods
21
+ def schema_version
22
+ Integer(@schema_version || self.class.current_schema_version)
23
+ end
24
+ end
25
+
26
+ module ClassMethods
27
+ def migrate(version, &blk)
28
+ write_inheritable_array(:migrations, [Migration.new(version, blk)])
29
+
30
+ if version > self.current_schema_version
31
+ self.current_schema_version = version
32
+ end
33
+ end
34
+
35
+ def instantiate(key, attributes)
36
+ version = attributes.delete('schema_version')
37
+ original_attributes = attributes.dup
38
+ if version == current_schema_version
39
+ return super(key, attributes)
40
+ end
41
+
42
+ versions_to_migrate = ((version.to_i + 1)..current_schema_version)
43
+
44
+ migrations_to_run = versions_to_migrate.map do |v|
45
+ migrations.find {|m| m.version == v}
46
+ end
47
+
48
+ if migrations_to_run.any?(&:nil?)
49
+ raise MigrationNotFoundError.new(version, migrations)
50
+ end
51
+
52
+ migrations_to_run.inject(attributes) do |attrs, migration|
53
+ migration.run(attrs)
54
+ @schema_version = migration.version.to_s
55
+ attrs
56
+ end
57
+
58
+ super(key, attributes).tap do |record|
59
+ original_attributes.diff(attributes).keys.each do |attribute|
60
+ record.attribute_will_change! attribute
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,15 @@
1
+ require 'cassandra/mock'
2
+ module CassandraObject
3
+ module Mocking
4
+ extend ActiveSupport::Concern
5
+ module ClassMethods
6
+ def use_mock!(really=true)
7
+ if really
8
+ self.connection_class = Cassandra::Mock
9
+ else
10
+ self.connection_class = Cassandra
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end