extendi-cassandra_object 1.0.7 → 1.0.8

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: d93715ace91da1509d264e53261d2a4b7b987cda
4
- data.tar.gz: a479704c0f24f7285e1ef46df855d8fb8410d404
3
+ metadata.gz: 1c695a26258a09bfb86224196d5c93da0818e572
4
+ data.tar.gz: 8468bb80f340fcb1cd5e4961ab990a6d83a21f83
5
5
  SHA512:
6
- metadata.gz: 578aa46f8dd1702f6f7224c427c058804300c01da45a529ab8401ca79bd837117a8001d8f1f7d97dc11c1139ccd58fe8f1a7dd12c59e2f2f49d02644b2209ebb
7
- data.tar.gz: 89ff7cc0bd118cd69d8be51015ab25ba5070ef4f32ccb4798583a1bc646c37756e142e72849140c966794fc32a3e4cda80556d792afa29cad66534484751de4d
6
+ metadata.gz: f29534bf48f32c976755bbc9be2a188812f04124a93c9e307cc68079709b3ba12826bb80f4cdda343f71a46d7bbaf8a32a19c83d459a6b5945d99f796ca4e6f3
7
+ data.tar.gz: 3650b6aa1245a03db2866eae5702514a37118e688876456f6706cda8f96c91cfb85278a6631c3891d625ec6e0eb1e0457479cf537311099711e13bda0ae5c67d
@@ -1,11 +1,16 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.3
4
3
  - 2.4.0
4
+ - 2.4.1
5
+ - 2.4.2
6
+ - 2.5.1
5
7
  env:
6
8
  - CASSANDRA_VERSION=2.1.2
7
9
  - CASSANDRA_VERSION=3.0.10
8
10
  - CASSANDRA_VERSION=3.9
11
+ - CASSANDRA_VERSION=2.1.2 ACTIVEMODEL_VERSION='< 5'
12
+ - CASSANDRA_VERSION=3.0.10 ACTIVEMODEL_VERSION='< 5'
13
+ - CASSANDRA_VERSION=3.9 ACTIVEMODEL_VERSION='< 5'
9
14
 
10
15
  jdk:
11
16
  - oraclejdk8
@@ -20,4 +25,5 @@ before_install:
20
25
  install:
21
26
  - ccm create -n 1 -v $CASSANDRA_VERSION -i 127.0.0. -s -b test-cluster
22
27
  - ccm start
28
+ - if [ -n "$ACTIVEMODEL_VERSION" ];then bundle add activemodel --version "$ACTIVEMODEL_VERSION"; fi
23
29
  - bundle install
data/README.md CHANGED
@@ -190,3 +190,9 @@ cql_response return an hash where the key is the model key and values is an hash
190
190
  Widget.cql_response([:name, :color])
191
191
  Widget.cql_response.limit(10)
192
192
  ```
193
+
194
+ ## Running tests on MacOS
195
+
196
+ * Run a cassandra node on localhost (i.e. `ccm start` if CCM is used)
197
+ * Increase the limit of open files with `ulimit -Sn 2048`
198
+ * Run the tests by running the default rake task or `bundle exec rake test`
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'extendi-cassandra_object'
5
- s.version = '1.0.7'
5
+ s.version = '1.0.8'
6
6
  s.description = 'Cassandra ActiveModel'
7
7
  s.summary = 'Cassandra ActiveModel'
8
8
  s.authors = ['Duccio Giovannelli', 'gotime']
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
17
17
  s.test_files = `git ls-files -- {test}/*`.split("\n")
18
18
  s.require_paths = ['lib']
19
19
 
20
- s.add_runtime_dependency('activemodel', '>= 3.0')
20
+ s.add_runtime_dependency('activemodel', '<= 5.2')
21
21
  s.add_runtime_dependency('cassandra-driver', '>= 3.1.0')
22
22
  s.add_runtime_dependency('lz4-ruby', '>= 0.3.3')
23
23
 
@@ -1,6 +1,7 @@
1
1
  require 'active_support/all'
2
2
  require 'active_model'
3
3
  require 'cassandra_object/errors'
4
+ require 'initializers/cassandra'
4
5
 
5
6
  module CassandraObject
6
7
  extend ActiveSupport::Autoload
@@ -77,7 +77,9 @@ module CassandraObject
77
77
  :ssl,
78
78
  :timeout,
79
79
  :trace,
80
- :username
80
+ :username,
81
+ :heartbeat_interval,
82
+ :idle_timeout
81
83
  ])
82
84
 
83
85
  {
@@ -85,16 +87,23 @@ module CassandraObject
85
87
  reconnection_policy: 'Cassandra::Reconnection::Policies::%s',
86
88
  retry_policy: 'Cassandra::Retry::Policies::%s'
87
89
  }.each do |policy_key, class_template|
88
- if cluster_options[policy_key]
89
- cluster_options[policy_key] = (class_template % [policy_key.classify]).constantize
90
+ params = cluster_options[policy_key]
91
+ if params
92
+ if params.is_a?(Hash)
93
+ cluster_options[policy_key] = (class_template % [params[:policy].classify]).constantize.new(*params[:params]||[])
94
+ else
95
+ cluster_options[policy_key] = (class_template % [params.classify]).constantize.new
96
+ end
90
97
  end
91
98
  end
92
99
 
93
100
  # Setting defaults
94
101
  cluster_options.merge!({
95
- consistency: cluster_options[:consistency] || :quorum,
96
- protocol_version: cluster_options[:protocol_version] || 3,
97
- page_size: cluster_options[:page_size] || 10000
102
+ heartbeat_interval: cluster_options[:heartbeat_interval] || 2,
103
+ idle_timeout: cluster_options[:idle_timeout] || 5,
104
+ consistency: cluster_options[:consistency] || :quorum,
105
+ protocol_version: cluster_options[:protocol_version] || 3,
106
+ page_size: cluster_options[:page_size] || 10000
98
107
  })
99
108
  return cluster_options
100
109
  end
@@ -90,7 +90,9 @@ module CassandraObject
90
90
  :ssl,
91
91
  :timeout,
92
92
  :trace,
93
- :username
93
+ :username,
94
+ :heartbeat_interval,
95
+ :idle_timeout
94
96
  ])
95
97
 
96
98
 
@@ -99,17 +101,24 @@ module CassandraObject
99
101
  reconnection_policy: 'Cassandra::Reconnection::Policies::%s',
100
102
  retry_policy: 'Cassandra::Retry::Policies::%s'
101
103
  }.each do |policy_key, class_template|
102
- if cluster_options[policy_key]
103
- cluster_options[policy_key] = (class_template % [policy_key.classify]).constantize
104
+ params = cluster_options[policy_key]
105
+ if params
106
+ if params.is_a?(Hash)
107
+ cluster_options[policy_key] = (class_template % [params[:policy].classify]).constantize.new(*params[:params]||[])
108
+ else
109
+ cluster_options[policy_key] = (class_template % [params.classify]).constantize.new
110
+ end
104
111
  end
105
112
  end
106
113
 
107
114
  # Setting defaults
108
115
  cluster_options.merge!({
109
- max_schema_agreement_wait: 1,
110
- consistency: cluster_options[:consistency]||:quorum,
111
- protocol_version: cluster_options[:protocol_version]||3,
112
- page_size: cluster_options[:page_size] || 10000
116
+ heartbeat_interval: cluster_options[:heartbeat_interval] || 2,
117
+ idle_timeout: cluster_options[:idle_timeout] || 5,
118
+ max_schema_agreement_wait: 1,
119
+ consistency: cluster_options[:consistency]||:quorum,
120
+ protocol_version: cluster_options[:protocol_version]||3,
121
+ page_size: cluster_options[:page_size] || 10000
113
122
  })
114
123
  return cluster_options
115
124
  end
@@ -40,20 +40,20 @@ module CassandraObject
40
40
  end
41
41
 
42
42
  def write_attribute(name, value)
43
- @attributes[name.to_s] = self.class.typecast_attribute(self, name, value)
43
+ @model_attributes[name.to_s] = self.class.typecast_attribute(self, name, value)
44
44
  end
45
45
 
46
46
  def read_attribute(name)
47
- @attributes[name.to_s]
47
+ @model_attributes[name.to_s]
48
48
  end
49
49
 
50
50
  def attribute_exists?(name)
51
- @attributes.key?(name.to_s)
51
+ @model_attributes.key?(name.to_s)
52
52
  end
53
53
 
54
54
  def attributes
55
55
  results = {}
56
- @attributes.each_key do |key|
56
+ @model_attributes.each_key do |key|
57
57
  results[key] = read_attribute(key)
58
58
  end
59
59
  results
@@ -6,30 +6,24 @@ module CassandraObject
6
6
 
7
7
  # Attempts to +save+ the record and clears changed attributes if successful.
8
8
  def save(*) #:nodoc:
9
- if status = super
10
- @previously_changed = changes
11
- @changed_attributes = {}
12
- end
9
+ status = super
10
+ changes_applied
13
11
  status
14
12
  end
15
13
 
16
14
  # <tt>reload</tt> the record and clears changed attributes.
17
15
  def reload
18
- super.tap do
19
- @previously_changed.try :clear
20
- @changed_attributes.try :clear
21
- end
16
+ super
17
+ clear_changes_information
18
+ self
22
19
  end
23
20
 
24
21
  def write_attribute(name, value)
25
22
  name = name.to_s
26
23
  old = read_attribute(name)
27
24
 
25
+ self.send("#{name}_will_change!") unless value == old
28
26
  super
29
-
30
- unless attribute_changed?(name) || old == read_attribute(name)
31
- changed_attributes[name] = old
32
- end
33
27
  end
34
28
  end
35
29
  end
@@ -5,11 +5,11 @@ module CassandraObject
5
5
  def initialize(attributes=nil)
6
6
  @new_record = true
7
7
  @destroyed = false
8
- @attributes = {}
8
+ @model_attributes = {}
9
9
  self.attributes = attributes || {}
10
10
  attribute_definitions.each_value do |definition|
11
11
  unless definition.default.nil? || attribute_exists?(definition.name)
12
- @attributes[definition.name] = definition.default
12
+ @model_attributes[definition.name] = definition.default
13
13
  end
14
14
  end
15
15
 
@@ -17,10 +17,10 @@ module CassandraObject
17
17
  end
18
18
 
19
19
  def initialize_dup(other)
20
- @attributes = other.attributes
21
- @attributes['created_at'] = nil
22
- @attributes['updated_at'] = nil
23
- @attributes.delete(self.class.primary_key)
20
+ @model_attributes = other.attributes
21
+ @model_attributes['created_at'] = nil
22
+ @model_attributes['updated_at'] = nil
23
+ @model_attributes.delete(self.class.primary_key)
24
24
  @id = nil
25
25
  @new_record = true
26
26
  @destroyed = false
@@ -60,4 +60,4 @@ module CassandraObject
60
60
  self == (comparison_object)
61
61
  end
62
62
  end
63
- end
63
+ end
@@ -3,7 +3,7 @@ module CassandraObject
3
3
  def inspect
4
4
  inspection = ["#{self.class.primary_key}: #{id.inspect}"]
5
5
 
6
- @attributes.each do |attribute, value|
6
+ @model_attributes.each do |attribute, value|
7
7
  if value.present?
8
8
  inspection << "#{attribute}: #{attribute_for_inspect(value)}"
9
9
  end
@@ -64,6 +64,7 @@ module CassandraObject
64
64
  end
65
65
 
66
66
  def insert_record(id, attributes)
67
+ attributes = attributes.dup
67
68
  attributes[self._key] = id if self.schema_type == :standard
68
69
  adapter.insert column_family, id, encode_attributes(attributes), self.ttl
69
70
  end
@@ -71,6 +72,7 @@ module CassandraObject
71
72
  def update_record(id, attributes)
72
73
  return if attributes.empty?
73
74
  if self.schema_type == :standard
75
+ attributes = attributes.dup
74
76
  attributes[self._key] = id
75
77
  id = self._key
76
78
  end
@@ -90,7 +92,7 @@ module CassandraObject
90
92
  object.instance_variable_set('@id', id) if id
91
93
  object.instance_variable_set('@new_record', false)
92
94
  object.instance_variable_set('@destroyed', false)
93
- object.instance_variable_set('@attributes', typecast_persisted_attributes(object, attributes))
95
+ object.instance_variable_set('@model_attributes', typecast_persisted_attributes(object, attributes))
94
96
  end
95
97
  end
96
98
 
@@ -172,7 +174,7 @@ module CassandraObject
172
174
 
173
175
  def becomes(klass)
174
176
  became = klass.new
175
- became.instance_variable_set('@attributes', @attributes)
177
+ became.instance_variable_set('@model_attributes', @model_attributes)
176
178
  became.instance_variable_set('@new_record', new_record?)
177
179
  became.instance_variable_set('@destroyed', destroyed?)
178
180
  became
@@ -180,7 +182,7 @@ module CassandraObject
180
182
 
181
183
  def reload
182
184
  clear_belongs_to_cache
183
- @attributes = self.class.find(id).instance_variable_get('@attributes')
185
+ @model_attributes = self.class.find(id).instance_variable_get('@model_attributes')
184
186
  self
185
187
  end
186
188
 
@@ -196,7 +198,7 @@ module CassandraObject
196
198
  end
197
199
 
198
200
  def write(method)
199
- changed_attributes = Hash[changed.map { |attr| [attr, read_attribute(attr)] }]
201
+ changed_attributes = changes.map {|k,change| [k, change.last] }.to_h
200
202
  self.class.send(method, id, changed_attributes)
201
203
  end
202
204
  end
@@ -38,15 +38,15 @@ module CassandraObject
38
38
 
39
39
  def find_one(id)
40
40
  if id.blank?
41
- raise CassandraObject::RecordNotFound, "Couldn't find #{self.name} with key #{id.inspect}"
41
+ not_found(id)
42
42
  elsif self.schema_type == :dynamic_attributes
43
43
  record = where_ids(id).execute
44
- raise CassandraObject::RecordNotFound if record.empty?
44
+ not_found(id) if record.empty?
45
45
  record
46
46
  elsif record = where_ids(id)[0]
47
47
  record
48
48
  else
49
- raise CassandraObject::RecordNotFound
49
+ not_found(id)
50
50
  end
51
51
  end
52
52
 
@@ -56,6 +56,10 @@ module CassandraObject
56
56
  ids = ids.compact.map(&:to_s).uniq
57
57
  where_ids(ids).execute
58
58
  end
59
+
60
+ def not_found(id)
61
+ raise CassandraObject::RecordNotFound, "Couldn't find #{self.name} with key #{id.inspect}"
62
+ end
59
63
  end
60
64
  end
61
65
  end
@@ -10,11 +10,11 @@ module CassandraObject
10
10
  str
11
11
  end
12
12
  end
13
-
13
+
14
14
  def decode(str)
15
15
  begin
16
16
  (str.frozen? ? str.dup : str).force_encoding('UTF-8') if str
17
- rescue Exception => e
17
+ rescue Exception
18
18
  str.to_s
19
19
  end
20
20
  end
@@ -0,0 +1,13 @@
1
+ ## TODO: remove this patch when datastax/ruby-driver release 3.2.3 is out
2
+ require 'ione'
3
+ require 'cassandra'
4
+
5
+ class Cassandra::Protocol::CqlProtocolHandler
6
+ class RequestPromise < Ione::Promise
7
+ old_constructor = instance_method(:initialize)
8
+ define_method(:initialize) do |request, timeout, scheduler|
9
+ @timer = nil
10
+ old_constructor.bind(self).(request, timeout, scheduler)
11
+ end
12
+ end
13
+ end
@@ -13,6 +13,9 @@ CassandraObject::Base.config = {
13
13
  connections_per_local_node: 4,
14
14
  schema_refresh_delay: 0.1,
15
15
  schema_refresh_timeout: 0.1,
16
+ load_balancing_policy: 'RoundRobin',
17
+ reconnection_policy: { policy: 'Constant', params: [5] },
18
+ retry_policy: 'Default',
16
19
  # connections_per_remote_node: nil,
17
20
  # logger: Logger.new($stderr)
18
21
  }
@@ -55,6 +58,13 @@ end
55
58
 
56
59
  module ActiveSupport
57
60
  class TestCase
61
+
62
+ self.test_order = :random
63
+
64
+ def after_setup
65
+ CassandraObject::Base.created_records.clear if CassandraObject::Base.created_records.any?
66
+ end
67
+
58
68
  teardown do
59
69
  if CassandraObject::Base.created_records.any?
60
70
  CassandraObject::Base.delete_after_test
@@ -0,0 +1,37 @@
1
+ module CassandraObject
2
+ ###
3
+ # Force reconnection in test
4
+ ##
5
+ module AdapterExtension
6
+ def execute(*args)
7
+ retries = 0
8
+ begin
9
+ super
10
+ rescue Cassandra::Errors::NoHostsAvailable, Cassandra::Errors::IOError
11
+ @connection = nil
12
+ retries += 1
13
+ retries < 2 ? retry : raise
14
+ end
15
+ end
16
+
17
+ def execute_async(*args)
18
+ retries = 0
19
+ begin
20
+ super
21
+ rescue Cassandra::Errors::NoHostsAvailable, Cassandra::Errors::IOError
22
+ @connection = nil
23
+ retries += 1
24
+ retries < 2 ? retry : raise
25
+ end
26
+ end
27
+ end
28
+
29
+ module Adapters
30
+ class CassandraAdapter < AbstractAdapter
31
+ prepend AdapterExtension
32
+ end
33
+ class CassandraSchemalessAdapter < AbstractAdapter
34
+ prepend AdapterExtension
35
+ end
36
+ end
37
+ end
@@ -5,6 +5,7 @@ require 'rails/test_help'
5
5
  require 'mocha/setup'
6
6
 
7
7
  require 'cassandra_object'
8
+ require 'support/reconnection'
8
9
  require 'support/cassandra'
9
10
  require 'support/issue'
10
11
  require 'support/issue_dynamic'
@@ -16,7 +16,7 @@ class CassandraObject::LogSubscriberTest < CassandraObject::TestCase
16
16
 
17
17
  wait
18
18
 
19
- assert_match 'SELECT * FROM Issues', @logger.logged(:debug)[0]
19
+ assert_match 'SELECT * FROM Issues', @logger.logged(:debug).last
20
20
  end
21
21
 
22
22
  def test_initializes_runtime
@@ -118,17 +118,16 @@ class CassandraObject::PersistenceSchemaTest < CassandraObject::TestCase
118
118
  end
119
119
 
120
120
  test 'ttl' do
121
- issue = IssueSchema.create(title: 'I rule', description: 'lololol', ttl: 1)
121
+ description_test = 'this is the one with ttl'
122
+ issue = IssueSchema.create(title: 'I rule', description: description_test, ttl: 1)
122
123
  assert_nothing_raised do
123
124
  IssueSchema.find(issue.id)
124
125
  end
125
-
126
126
  sleep 2
127
-
128
- assert_raise CassandraObject::RecordNotFound do
129
- IssueSchema.find(issue.id)
127
+ issue = IssueSchema.find(issue.id) rescue nil
128
+ unless issue.nil?
129
+ assert_not_equal issue.description, description_test
130
130
  end
131
-
132
131
  end
133
132
 
134
133
  test 'type tests' do
@@ -139,7 +138,7 @@ class CassandraObject::PersistenceSchemaTest < CassandraObject::TestCase
139
138
 
140
139
  from_db = IssueSchema.find(issue.id)
141
140
  assert_equal Float, from_db.field.class
142
- assert_equal Fixnum, from_db.intero.class
141
+ assert_equal Integer, from_db.intero.class
143
142
  # TODO add other types
144
143
  # byebug
145
144
 
@@ -198,13 +198,17 @@ class CassandraObject::PersistenceTest < CassandraObject::TestCase
198
198
  assert_equal [], Issue.find(ids)
199
199
  end
200
200
 
201
- test 'ttl' do
202
- record = Issue.create({title: 'name', ttl: 1})
201
+ test 'ttl saves' do
202
+ record = Issue.create({title: 'name', ttl: 10})
203
203
  assert_nothing_raised do
204
204
  Issue.find(record.id)
205
205
  end
206
+ end
207
+
208
+ test 'ttl expires' do
209
+ record = Issue.create({title: 'othername', ttl: 2})
206
210
 
207
- sleep 2
211
+ sleep 4
208
212
 
209
213
  assert_raise CassandraObject::RecordNotFound do
210
214
  Issue.find(record.id)
@@ -4,8 +4,8 @@ class CassandraObject::TimestampsTest < CassandraObject::TestCase
4
4
  test 'timestamps set on create' do
5
5
  issue = Issue.create
6
6
 
7
- assert_in_delta Time.now.to_i, issue.created_at.to_i, 3
8
- assert_in_delta Time.now.to_i, issue.updated_at.to_i, 3
7
+ assert_in_delta Time.now.to_i, issue.created_at.to_i, 10
8
+ assert_in_delta Time.now.to_i, issue.updated_at.to_i, 10
9
9
  end
10
10
 
11
11
  test 'updated_at set on change' do
@@ -15,7 +15,7 @@ class CassandraObject::TimestampsTest < CassandraObject::TestCase
15
15
  issue.description = 'lol'
16
16
  issue.save
17
17
 
18
- assert_in_delta Time.now.to_i, issue.updated_at.to_i, 3
18
+ assert_in_delta Time.now.to_i, issue.updated_at.to_i, 10
19
19
  end
20
20
 
21
21
  test 'created_at sets only if nil' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: extendi-cassandra_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Duccio Giovannelli
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-09-20 00:00:00.000000000 Z
12
+ date: 2018-05-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ">="
18
+ - - "<="
19
19
  - !ruby/object:Gem::Version
20
- version: '3.0'
20
+ version: '5.2'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ">="
25
+ - - "<="
26
26
  - !ruby/object:Gem::Version
27
- version: '3.0'
27
+ version: '5.2'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: cassandra-driver
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -132,6 +132,7 @@ files:
132
132
  - lib/cassandra_object/types/time_type.rb
133
133
  - lib/cassandra_object/types/type_helper.rb
134
134
  - lib/cassandra_object/validations.rb
135
+ - lib/initializers/cassandra.rb
135
136
  - test/support/cassandra.rb
136
137
  - test/support/issue.rb
137
138
  - test/support/issue_custom_config.rb
@@ -139,6 +140,7 @@ files:
139
140
  - test/support/issue_schema.rb
140
141
  - test/support/issue_schema_child.rb
141
142
  - test/support/issue_schema_father.rb
143
+ - test/support/reconnection.rb
142
144
  - test/test_helper.rb
143
145
  - test/unit/active_model_test.rb
144
146
  - test/unit/adapters/adapter_test.rb
@@ -201,4 +203,3 @@ signing_key:
201
203
  specification_version: 4
202
204
  summary: Cassandra ActiveModel
203
205
  test_files: []
204
- has_rdoc: