dynamoid 3.4.1 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/lib/dynamoid/adapter.rb +2 -2
  4. data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +23 -23
  5. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/batch_get_item.rb +2 -0
  6. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +1 -1
  7. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb +1 -2
  8. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +1 -3
  9. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb +1 -2
  10. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +3 -2
  11. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +3 -2
  12. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb +1 -1
  13. data/lib/dynamoid/config.rb +2 -3
  14. data/lib/dynamoid/criteria.rb +1 -1
  15. data/lib/dynamoid/criteria/chain.rb +37 -12
  16. data/lib/dynamoid/criteria/ignored_conditions_detector.rb +2 -3
  17. data/lib/dynamoid/criteria/key_fields_detector.rb +7 -8
  18. data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +2 -2
  19. data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +0 -1
  20. data/lib/dynamoid/dirty.rb +50 -50
  21. data/lib/dynamoid/document.rb +2 -1
  22. data/lib/dynamoid/fields.rb +14 -1
  23. data/lib/dynamoid/finders.rb +4 -4
  24. data/lib/dynamoid/indexes.rb +2 -2
  25. data/lib/dynamoid/persistence.rb +32 -6
  26. data/lib/dynamoid/persistence/upsert.rb +0 -1
  27. data/lib/dynamoid/tasks.rb +3 -1
  28. data/lib/dynamoid/type_casting.rb +0 -2
  29. data/lib/dynamoid/version.rb +1 -1
  30. metadata +40 -56
  31. data/.coveralls.yml +0 -1
  32. data/.document +0 -5
  33. data/.gitignore +0 -74
  34. data/.rspec +0 -2
  35. data/.rubocop.yml +0 -71
  36. data/.rubocop_todo.yml +0 -55
  37. data/.travis.yml +0 -44
  38. data/Appraisals +0 -22
  39. data/Gemfile +0 -8
  40. data/Rakefile +0 -46
  41. data/Vagrantfile +0 -29
  42. data/docker-compose.yml +0 -7
  43. data/dynamoid.gemspec +0 -57
  44. data/gemfiles/rails_4_2.gemfile +0 -9
  45. data/gemfiles/rails_5_0.gemfile +0 -8
  46. data/gemfiles/rails_5_1.gemfile +0 -8
  47. data/gemfiles/rails_5_2.gemfile +0 -8
  48. data/gemfiles/rails_6_0.gemfile +0 -8
@@ -153,67 +153,67 @@ module Dynamoid
153
153
 
154
154
  private
155
155
 
156
- def changes_include?(attr_name)
157
- attributes_changed_by_setter.include?(attr_name)
158
- end
159
- alias attribute_changed_by_setter? changes_include?
160
-
161
- # Removes current changes and makes them accessible through +previous_changes+.
162
- def changes_applied # :doc:
163
- @previously_changed = changes
164
- @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
165
- end
156
+ def changes_include?(attr_name)
157
+ attributes_changed_by_setter.include?(attr_name)
158
+ end
159
+ alias attribute_changed_by_setter? changes_include?
166
160
 
167
- # Clear all dirty data: current changes and previous changes.
168
- def clear_changes_information # :doc:
169
- @previously_changed = ActiveSupport::HashWithIndifferentAccess.new
170
- @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
171
- end
161
+ # Removes current changes and makes them accessible through +previous_changes+.
162
+ def changes_applied # :doc:
163
+ @previously_changed = changes
164
+ @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
165
+ end
172
166
 
173
- # Handle <tt>*_change</tt> for +method_missing+.
174
- def attribute_change(attr)
175
- [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
176
- end
167
+ # Clear all dirty data: current changes and previous changes.
168
+ def clear_changes_information # :doc:
169
+ @previously_changed = ActiveSupport::HashWithIndifferentAccess.new
170
+ @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
171
+ end
177
172
 
178
- # Handle <tt>*_will_change!</tt> for +method_missing+.
179
- def attribute_will_change!(attr)
180
- return if attribute_changed?(attr)
173
+ # Handle <tt>*_change</tt> for +method_missing+.
174
+ def attribute_change(attr)
175
+ [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
176
+ end
181
177
 
182
- begin
183
- value = __send__(attr)
184
- value = value.duplicable? ? value.clone : value
185
- rescue TypeError, NoMethodError
186
- end
178
+ # Handle <tt>*_will_change!</tt> for +method_missing+.
179
+ def attribute_will_change!(attr)
180
+ return if attribute_changed?(attr)
187
181
 
188
- set_attribute_was(attr, value)
182
+ begin
183
+ value = __send__(attr)
184
+ value = value.duplicable? ? value.clone : value
185
+ rescue TypeError, NoMethodError
189
186
  end
190
187
 
191
- # Handle <tt>restore_*!</tt> for +method_missing+.
192
- def restore_attribute!(attr)
193
- if attribute_changed?(attr)
194
- __send__("#{attr}=", changed_attributes[attr])
195
- clear_attribute_changes([attr])
196
- end
197
- end
188
+ set_attribute_was(attr, value)
189
+ end
198
190
 
199
- # Returns +true+ if attr_name were changed before the model was saved,
200
- # +false+ otherwise.
201
- def previous_changes_include?(attr_name)
202
- previous_changes.include?(attr_name)
191
+ # Handle <tt>restore_*!</tt> for +method_missing+.
192
+ def restore_attribute!(attr)
193
+ if attribute_changed?(attr)
194
+ __send__("#{attr}=", changed_attributes[attr])
195
+ clear_attribute_changes([attr])
203
196
  end
197
+ end
198
+
199
+ # Returns +true+ if attr_name were changed before the model was saved,
200
+ # +false+ otherwise.
201
+ def previous_changes_include?(attr_name)
202
+ previous_changes.include?(attr_name)
203
+ end
204
204
 
205
- # This is necessary because `changed_attributes` might be overridden in
206
- # other implemntations (e.g. in `ActiveRecord`)
207
- alias_method :attributes_changed_by_setter, :changed_attributes # :nodoc:
205
+ # This is necessary because `changed_attributes` might be overridden in
206
+ # other implemntations (e.g. in `ActiveRecord`)
207
+ alias attributes_changed_by_setter changed_attributes # :nodoc:
208
208
 
209
- # Force an attribute to have a particular "before" value
210
- def set_attribute_was(attr, old_value)
211
- attributes_changed_by_setter[attr] = old_value
212
- end
209
+ # Force an attribute to have a particular "before" value
210
+ def set_attribute_was(attr, old_value)
211
+ attributes_changed_by_setter[attr] = old_value
212
+ end
213
213
 
214
- # Remove changes information for the provided attributes.
215
- def clear_attribute_changes(attributes) # :doc:
216
- attributes_changed_by_setter.except!(*attributes)
217
- end
214
+ # Remove changes information for the provided attributes.
215
+ def clear_attribute_changes(attributes) # :doc:
216
+ attributes_changed_by_setter.except!(*attributes)
217
+ end
218
218
  end
219
219
  end
@@ -51,7 +51,6 @@ module Dynamoid #:nodoc:
51
51
  options[:write_capacity] || Dynamoid::Config.write_capacity
52
52
  end
53
53
 
54
-
55
54
  # Returns the billing (capacity) mode for this table.
56
55
  # Could be either :provisioned or :on_demand
57
56
  def capacity_mode
@@ -225,3 +224,5 @@ module Dynamoid #:nodoc:
225
224
  end
226
225
  end
227
226
  end
227
+
228
+ ActiveSupport.run_load_hooks(:dynamoid, Dynamoid::Document)
@@ -55,6 +55,12 @@ module Dynamoid #:nodoc:
55
55
  end
56
56
  self.attributes = attributes.merge(name => { type: type }.merge(options))
57
57
 
58
+ # should be called before `define_attribute_methods` method because it defines a getter itself
59
+ warn_about_method_overriding(name, name)
60
+ warn_about_method_overriding("#{named}=", name)
61
+ warn_about_method_overriding("#{named}?", name)
62
+ warn_about_method_overriding("#{named}_before_type_cast?", name)
63
+
58
64
  define_attribute_method(name) # Dirty API
59
65
 
60
66
  generated_methods.module_eval do
@@ -127,6 +133,12 @@ module Dynamoid #:nodoc:
127
133
  end
128
134
  end
129
135
  end
136
+
137
+ def warn_about_method_overriding(method_name, field_name)
138
+ if self.instance_methods.include?(method_name.to_sym)
139
+ Dynamoid.logger.warn("Method #{method_name} generated for the field #{field_name} overrides already existing method")
140
+ end
141
+ end
130
142
  end
131
143
 
132
144
  # You can access the attributes of an object directly on its attributes method, which is by default an empty hash.
@@ -192,7 +204,8 @@ module Dynamoid #:nodoc:
192
204
  #
193
205
  # @since 0.2.0
194
206
  def set_updated_at
195
- if self.class.timestamps_enabled? && !updated_at_changed?
207
+ # @_touch_record=false means explicit disabling
208
+ if self.class.timestamps_enabled? && !updated_at_changed? && @_touch_record != false
196
209
  self.updated_at = DateTime.now.in_time_zone(Time.zone)
197
210
  end
198
211
  end
@@ -183,7 +183,7 @@ module Dynamoid
183
183
  def find_all_by_composite_key(hash_key, options = {})
184
184
  ActiveSupport::Deprecation.warn('[Dynamoid] .find_all_composite_key is deprecated! Call .where instead of')
185
185
 
186
- Dynamoid.adapter.query(table_name, options.merge(hash_value: hash_key)).flat_map{ |i| i }.collect do |item|
186
+ Dynamoid.adapter.query(table_name, options.merge(hash_value: hash_key)).flat_map { |i| i }.collect do |item|
187
187
  from_database(item)
188
188
  end
189
189
  end
@@ -240,7 +240,7 @@ module Dynamoid
240
240
  opts[range_op_mapped] = range_key_value
241
241
  end
242
242
  dynamo_options = opts.merge(options.reject { |key, _| key == :range })
243
- Dynamoid.adapter.query(table_name, dynamo_options).flat_map{ |i| i }.map do |item|
243
+ Dynamoid.adapter.query(table_name, dynamo_options).flat_map { |i| i }.map do |item|
244
244
  from_database(item)
245
245
  end
246
246
  end
@@ -267,9 +267,9 @@ module Dynamoid
267
267
  chain = chain.where({}.tap { |h| attributes.each_with_index { |attr, index| h[attr.to_sym] = args[index] } })
268
268
 
269
269
  if finder =~ /all/
270
- return chain.all
270
+ chain.all
271
271
  else
272
- return chain.first
272
+ chain.first
273
273
  end
274
274
  else
275
275
  super
@@ -165,8 +165,8 @@ module Dynamoid
165
165
  DEFAULT_PROJECTION_TYPE = :keys_only
166
166
 
167
167
  attr_accessor :name, :dynamoid_class, :type, :hash_key, :range_key,
168
- :hash_key_schema, :range_key_schema, :projected_attributes,
169
- :read_capacity, :write_capacity
168
+ :hash_key_schema, :range_key_schema, :projected_attributes,
169
+ :read_capacity, :write_capacity
170
170
 
171
171
  validate do
172
172
  validate_index_type
@@ -11,8 +11,8 @@ require 'dynamoid/persistence/save'
11
11
 
12
12
  # encoding: utf-8
13
13
  module Dynamoid
14
- # Persistence is responsible for dumping objects to and marshalling objects from the datastore. It tries to reserialize
15
- # values to be of the same type as when they were passed in, based on the fields in the class.
14
+ # # Persistence is responsible for dumping objects to and marshalling objects from the datastore. It tries to reserialize
15
+ # # values to be of the same type as when they were passed in, based on the fields in the class.
16
16
  module Persistence
17
17
  extend ActiveSupport::Concern
18
18
 
@@ -146,6 +146,25 @@ module Dynamoid
146
146
  model
147
147
  end
148
148
 
149
+ # Update document with provided attributes.
150
+ #
151
+ # Instantiates document and saves changes.
152
+ # Runs validations and callbacks. Raises Dynamoid::Errors::DocumentNotValid exception if validation fails.
153
+ #
154
+ # @param [Scalar value] partition key
155
+ # @param [Scalar value] sort key, optional
156
+ # @param [Hash] attributes
157
+ #
158
+ # @return [Dynamoid::Doument] updated document
159
+ #
160
+ # @example Update document
161
+ # Post.update!(101, title: 'New title')
162
+ def update!(hash_key, range_key_value = nil, attrs)
163
+ model = find(hash_key, range_key: range_key_value, consistent_read: true)
164
+ model.update_attributes!(attrs)
165
+ model
166
+ end
167
+
149
168
  # Update document.
150
169
  #
151
170
  # Uses efficient low-level `UpdateItem` API call.
@@ -264,14 +283,16 @@ module Dynamoid
264
283
  #
265
284
  # @since 0.2.0
266
285
  def persisted?
267
- !new_record?
286
+ !(new_record? || @destroyed)
268
287
  end
269
288
 
270
289
  # Run the callbacks and then persist this object in the datastore.
271
290
  #
272
291
  # @since 0.2.0
273
- def save(_options = {})
274
- self.class.create_table
292
+ def save(options = {})
293
+ self.class.create_table(sync: true)
294
+
295
+ @_touch_record = options[:touch]
275
296
 
276
297
  if new_record?
277
298
  run_callbacks(:create) do
@@ -342,7 +363,6 @@ module Dynamoid
342
363
  raise Dynamoid::Errors::StaleObjectError.new(self, 'update')
343
364
  end
344
365
  end
345
-
346
366
  end
347
367
 
348
368
  def update(conditions = {}, &block)
@@ -389,6 +409,9 @@ module Dynamoid
389
409
  ret = run_callbacks(:destroy) do
390
410
  delete
391
411
  end
412
+
413
+ @destroyed = true
414
+
392
415
  ret == false ? false : self
393
416
  end
394
417
 
@@ -413,6 +436,9 @@ module Dynamoid
413
436
  end
414
437
  options[:conditions] = conditions
415
438
  end
439
+
440
+ @destroyed = true
441
+
416
442
  Dynamoid.adapter.delete(self.class.table_name, hash_key, options)
417
443
  rescue Dynamoid::Errors::ConditionalCheckFailedException
418
444
  raise Dynamoid::Errors::StaleObjectError.new(self, 'delete')
@@ -57,4 +57,3 @@ module Dynamoid
57
57
  end
58
58
  end
59
59
  end
60
-
@@ -1 +1,3 @@
1
- load "dynamoid/tasks/database.rake"
1
+ # frozen_string_literal: true
2
+
3
+ load 'dynamoid/tasks/database.rake'
@@ -215,8 +215,6 @@ module Dynamoid
215
215
  value.to_hash
216
216
  elsif value.respond_to? :to_h
217
217
  value.to_h
218
- else
219
- nil
220
218
  end
221
219
  end
222
220
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dynamoid
4
- VERSION = '3.4.1'
4
+ VERSION = '3.5.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynamoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.1
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Symonds
@@ -19,9 +19,9 @@ authors:
19
19
  - Peter Boling
20
20
  - Andrew Konchin
21
21
  autorequire:
22
- bindir: exe
22
+ bindir: bin
23
23
  cert_chain: []
24
- date: 2019-12-02 00:00:00.000000000 Z
24
+ date: 2020-04-04 00:00:00.000000000 Z
25
25
  dependencies:
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activemodel
@@ -43,14 +43,14 @@ dependencies:
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '1'
46
+ version: '1.0'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '1'
53
+ version: '1.0'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: concurrent-ruby
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -83,16 +83,16 @@ dependencies:
83
83
  name: appraisal
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
- - - ">="
86
+ - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '0'
88
+ version: '2.2'
89
89
  type: :development
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - ">="
93
+ - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: '0'
95
+ version: '2.2'
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: bundler
98
98
  requirement: !ruby/object:Gem::Requirement
@@ -111,58 +111,58 @@ dependencies:
111
111
  name: coveralls
112
112
  requirement: !ruby/object:Gem::Requirement
113
113
  requirements:
114
- - - ">="
114
+ - - "~>"
115
115
  - !ruby/object:Gem::Version
116
- version: '0'
116
+ version: '0.8'
117
117
  type: :development
118
118
  prerelease: false
119
119
  version_requirements: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - ">="
121
+ - - "~>"
122
122
  - !ruby/object:Gem::Version
123
- version: '0'
123
+ version: '0.8'
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: pry
126
126
  requirement: !ruby/object:Gem::Requirement
127
127
  requirements:
128
- - - ">="
128
+ - - "~>"
129
129
  - !ruby/object:Gem::Version
130
- version: '0'
130
+ version: 0.12.0
131
131
  type: :development
132
132
  prerelease: false
133
133
  version_requirements: !ruby/object:Gem::Requirement
134
134
  requirements:
135
- - - ">="
135
+ - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: '0'
137
+ version: 0.12.0
138
138
  - !ruby/object:Gem::Dependency
139
139
  name: rake
140
140
  requirement: !ruby/object:Gem::Requirement
141
141
  requirements:
142
- - - ">="
142
+ - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: '0'
144
+ version: '13.0'
145
145
  type: :development
146
146
  prerelease: false
147
147
  version_requirements: !ruby/object:Gem::Requirement
148
148
  requirements:
149
- - - ">="
149
+ - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: '0'
151
+ version: '13.0'
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: rspec
154
154
  requirement: !ruby/object:Gem::Requirement
155
155
  requirements:
156
- - - ">="
156
+ - - "~>"
157
157
  - !ruby/object:Gem::Version
158
- version: '0'
158
+ version: '3.9'
159
159
  type: :development
160
160
  prerelease: false
161
161
  version_requirements: !ruby/object:Gem::Requirement
162
162
  requirements:
163
- - - ">="
163
+ - - "~>"
164
164
  - !ruby/object:Gem::Version
165
- version: '0'
165
+ version: '3.9'
166
166
  - !ruby/object:Gem::Dependency
167
167
  name: rubocop
168
168
  requirement: !ruby/object:Gem::Requirement
@@ -181,63 +181,44 @@ dependencies:
181
181
  name: wwtd
182
182
  requirement: !ruby/object:Gem::Requirement
183
183
  requirements:
184
- - - ">="
184
+ - - "~>"
185
185
  - !ruby/object:Gem::Version
186
- version: '0'
186
+ version: '1.4'
187
187
  type: :development
188
188
  prerelease: false
189
189
  version_requirements: !ruby/object:Gem::Requirement
190
190
  requirements:
191
- - - ">="
191
+ - - "~>"
192
192
  - !ruby/object:Gem::Version
193
- version: '0'
193
+ version: '1.4'
194
194
  - !ruby/object:Gem::Dependency
195
195
  name: yard
196
196
  requirement: !ruby/object:Gem::Requirement
197
197
  requirements:
198
- - - ">="
198
+ - - "~>"
199
199
  - !ruby/object:Gem::Version
200
- version: '0'
200
+ version: '0.9'
201
201
  type: :development
202
202
  prerelease: false
203
203
  version_requirements: !ruby/object:Gem::Requirement
204
204
  requirements:
205
- - - ">="
205
+ - - "~>"
206
206
  - !ruby/object:Gem::Version
207
- version: '0'
207
+ version: '0.9'
208
208
  description: Dynamoid is an ORM for Amazon's DynamoDB that supports offline development,
209
209
  associations, querying, and everything else you'd expect from an ActiveRecord-style
210
210
  replacement.
211
211
  email:
212
212
  - peter.boling@gmail.com
213
213
  - brian@stellaservice.com
214
+ - andry.konchin@gmail.com
214
215
  executables: []
215
216
  extensions: []
216
- extra_rdoc_files:
217
- - LICENSE.txt
218
- - README.md
217
+ extra_rdoc_files: []
219
218
  files:
220
- - ".coveralls.yml"
221
- - ".document"
222
- - ".gitignore"
223
- - ".rspec"
224
- - ".rubocop.yml"
225
- - ".rubocop_todo.yml"
226
- - ".travis.yml"
227
- - Appraisals
228
219
  - CHANGELOG.md
229
- - Gemfile
230
220
  - LICENSE.txt
231
221
  - README.md
232
- - Rakefile
233
- - Vagrantfile
234
- - docker-compose.yml
235
- - dynamoid.gemspec
236
- - gemfiles/rails_4_2.gemfile
237
- - gemfiles/rails_5_0.gemfile
238
- - gemfiles/rails_5_1.gemfile
239
- - gemfiles/rails_5_2.gemfile
240
- - gemfiles/rails_6_0.gemfile
241
222
  - lib/dynamoid.rb
242
223
  - lib/dynamoid/adapter.rb
243
224
  - lib/dynamoid/adapter_plugin/aws_sdk_v3.rb
@@ -296,10 +277,13 @@ files:
296
277
  - lib/dynamoid/undumping.rb
297
278
  - lib/dynamoid/validations.rb
298
279
  - lib/dynamoid/version.rb
299
- homepage: http://github.com/Dynamoid/Dynamoid
280
+ homepage: http://github.com/Dynamoid/dynamoid
300
281
  licenses:
301
282
  - MIT
302
- metadata: {}
283
+ metadata:
284
+ bug_tracker_uri: https://github.com/Dynamoid/dynamoid/issues
285
+ changelog_uri: https://github.com/Dynamoid/dynamoid/tag/v3.5.0/CHANGELOG.md
286
+ source_code_uri: https://github.com/Dynamoid/dynamoid/tree/v3.5.0
303
287
  post_install_message:
304
288
  rdoc_options: []
305
289
  require_paths: