extendi-cassandra_object 1.0.7 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
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: