dynamoid 3.1.0 → 3.2.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 (47) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +18 -0
  3. data/.travis.yml +5 -3
  4. data/CHANGELOG.md +15 -0
  5. data/README.md +113 -63
  6. data/Vagrantfile +2 -2
  7. data/docker-compose.yml +1 -1
  8. data/gemfiles/rails_4_2.gemfile +1 -1
  9. data/gemfiles/rails_5_0.gemfile +1 -1
  10. data/gemfiles/rails_5_1.gemfile +1 -1
  11. data/gemfiles/rails_5_2.gemfile +1 -1
  12. data/lib/dynamoid/adapter.rb +1 -0
  13. data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +26 -395
  14. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +234 -0
  15. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +89 -0
  16. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb +24 -0
  17. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +57 -0
  18. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb +28 -0
  19. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +123 -0
  20. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +85 -0
  21. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/table.rb +52 -0
  22. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb +60 -0
  23. data/lib/dynamoid/associations/has_and_belongs_to_many.rb +1 -0
  24. data/lib/dynamoid/associations/has_many.rb +1 -0
  25. data/lib/dynamoid/associations/has_one.rb +1 -0
  26. data/lib/dynamoid/associations/single_association.rb +1 -0
  27. data/lib/dynamoid/criteria.rb +4 -4
  28. data/lib/dynamoid/criteria/chain.rb +86 -79
  29. data/lib/dynamoid/criteria/ignored_conditions_detector.rb +41 -0
  30. data/lib/dynamoid/criteria/key_fields_detector.rb +61 -0
  31. data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +41 -0
  32. data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +40 -0
  33. data/lib/dynamoid/document.rb +18 -13
  34. data/lib/dynamoid/dumping.rb +52 -40
  35. data/lib/dynamoid/fields.rb +4 -3
  36. data/lib/dynamoid/finders.rb +3 -3
  37. data/lib/dynamoid/persistence.rb +5 -6
  38. data/lib/dynamoid/primary_key_type_mapping.rb +1 -1
  39. data/lib/dynamoid/tasks.rb +1 -0
  40. data/lib/dynamoid/tasks/database.rake +2 -2
  41. data/lib/dynamoid/type_casting.rb +37 -19
  42. data/lib/dynamoid/undumping.rb +53 -42
  43. data/lib/dynamoid/validations.rb +2 -0
  44. data/lib/dynamoid/version.rb +1 -1
  45. metadata +17 -5
  46. data/lib/dynamoid/adapter_plugin/query.rb +0 -144
  47. data/lib/dynamoid/adapter_plugin/scan.rb +0 -107
@@ -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)).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).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
@@ -264,7 +264,7 @@ module Dynamoid
264
264
  attributes = method.to_s.split('_by_').last.split('_and_')
265
265
 
266
266
  chain = Dynamoid::Criteria::Chain.new(self)
267
- chain.query = {}.tap { |h| attributes.each_with_index { |attr, index| h[attr.to_sym] = args[index] } }
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
270
  return chain.all
@@ -18,8 +18,7 @@ module Dynamoid
18
18
 
19
19
  module ClassMethods
20
20
  def table_name
21
- table_base_name = options[:name] || base_class.name.split('::').last
22
- .downcase.pluralize
21
+ table_base_name = options[:name] || base_class.name.split('::').last.downcase.pluralize
23
22
 
24
23
  @table_name ||= [Dynamoid::Config.namespace.to_s, table_base_name].reject(&:empty?).join('_')
25
24
  end
@@ -151,22 +150,22 @@ module Dynamoid
151
150
  end
152
151
  end
153
152
 
154
- # Updates multiple attibutes at once, saving the object once the updates are complete.
153
+ # Updates multiple attributes at once, saving the object once the updates are complete.
155
154
  #
156
155
  # @param [Hash] attributes a hash of attributes to update
157
156
  #
158
157
  # @since 0.2.0
159
158
  def update_attributes(attributes)
160
- attributes.each { |attribute, value| write_attribute(attribute, value) } unless attributes.nil? || attributes.empty?
159
+ attributes.each { |attribute, value| write_attribute(attribute, value) }
161
160
  save
162
161
  end
163
162
 
164
- # Updates multiple attibutes at once, saving the object once the updates are complete.
163
+ # Updates multiple attributes at once, saving the object once the updates are complete.
165
164
  # Raises a Dynamoid::Errors::DocumentNotValid exception if there is vaidation and it fails.
166
165
  #
167
166
  # @param [Hash] attributes a hash of attributes to update
168
167
  def update_attributes!(attributes)
169
- attributes.each { |attribute, value| write_attribute(attribute, value) } unless attributes.nil? || attributes.empty?
168
+ attributes.each { |attribute, value| write_attribute(attribute, value) }
170
169
  save!
171
170
  end
172
171
 
@@ -3,7 +3,7 @@
3
3
  module Dynamoid
4
4
  class PrimaryKeyTypeMapping
5
5
  def self.dynamodb_type(type, options)
6
- if Class === type
6
+ if type.is_a?(Class)
7
7
  type = type.respond_to?(:dynamoid_field_type) ? type.dynamoid_field_type : :string
8
8
  end
9
9
 
@@ -0,0 +1 @@
1
+ load "dynamoid/tasks/database.rake"
@@ -30,12 +30,12 @@ namespace :dynamoid do
30
30
  end
31
31
 
32
32
  msg = "Connection to DynamoDB #{success ? 'OK' : 'FAILED'}"
33
- msg << if Dynamoid.config.endpoint
33
+ msg += if Dynamoid.config.endpoint
34
34
  " at local endpoint '#{Dynamoid.config.endpoint}'"
35
35
  else
36
36
  ' at remote AWS endpoint'
37
37
  end
38
- msg << ", reason being '#{failure_reason}'" unless success
38
+ msg += ", reason being '#{failure_reason}'" unless success
39
39
  puts msg
40
40
  end
41
41
  end
@@ -29,6 +29,7 @@ module Dynamoid
29
29
  when :number then NumberTypeCaster
30
30
  when :set then SetTypeCaster
31
31
  when :array then ArrayTypeCaster
32
+ when :map then MapTypeCaster
32
33
  when :datetime then DateTimeTypeCaster
33
34
  when :date then DateTypeCaster
34
35
  when :raw then RawTypeCaster
@@ -96,7 +97,7 @@ module Dynamoid
96
97
  nil
97
98
  elsif value.is_a?(Float) && !value.finite?
98
99
  nil
99
- elsif !(value.respond_to?(:to_d))
100
+ elsif !value.respond_to?(:to_d)
100
101
  nil
101
102
  else
102
103
  value.to_d
@@ -122,8 +123,6 @@ module Dynamoid
122
123
  value.dup
123
124
  elsif value.respond_to?(:to_set)
124
125
  value.to_set
125
- else
126
- nil
127
126
  end
128
127
  end
129
128
 
@@ -138,20 +137,20 @@ module Dynamoid
138
137
  end
139
138
 
140
139
  def element_type
141
- unless @options[:of].is_a?(Hash)
142
- @options[:of]
143
- else
140
+ if @options[:of].is_a?(Hash)
144
141
  @options[:of].keys.first
142
+ else
143
+ @options[:of]
145
144
  end
146
145
  end
147
146
 
148
147
  def element_options
149
- unless @options[:of].is_a?(Hash)
150
- { type: element_type }
151
- else
148
+ if @options[:of].is_a?(Hash)
152
149
  @options[:of][element_type].dup.tap do |options|
153
150
  options[:type] = element_type
154
151
  end
152
+ else
153
+ { type: element_type }
155
154
  end
156
155
  end
157
156
  end
@@ -174,8 +173,6 @@ module Dynamoid
174
173
  value.dup
175
174
  elsif value.respond_to?(:to_a)
176
175
  value.to_a
177
- else
178
- nil
179
176
  end
180
177
  end
181
178
 
@@ -190,20 +187,36 @@ module Dynamoid
190
187
  end
191
188
 
192
189
  def element_type
193
- unless @options[:of].is_a?(Hash)
194
- @options[:of]
195
- else
190
+ if @options[:of].is_a?(Hash)
196
191
  @options[:of].keys.first
192
+ else
193
+ @options[:of]
197
194
  end
198
195
  end
199
196
 
200
197
  def element_options
201
- unless @options[:of].is_a?(Hash)
202
- { type: element_type }
203
- else
198
+ if @options[:of].is_a?(Hash)
204
199
  @options[:of][element_type].dup.tap do |options|
205
200
  options[:type] = element_type
206
201
  end
202
+ else
203
+ { type: element_type }
204
+ end
205
+ end
206
+ end
207
+
208
+ class MapTypeCaster < Base
209
+ def process(value)
210
+ return nil if value.nil?
211
+
212
+ if value.is_a? Hash
213
+ value
214
+ elsif value.respond_to? :to_hash
215
+ value.to_hash
216
+ elsif value.respond_to? :to_h
217
+ value.to_h
218
+ else
219
+ nil
207
220
  end
208
221
  end
209
222
  end
@@ -213,7 +226,11 @@ module Dynamoid
213
226
  if !value.respond_to?(:to_datetime)
214
227
  nil
215
228
  elsif value.is_a?(String)
216
- dt = DateTime.parse(value) rescue nil
229
+ dt = begin
230
+ DateTime.parse(value)
231
+ rescue StandardError
232
+ nil
233
+ end
217
234
  if dt
218
235
  seconds = string_utc_offset(value) || ApplicationTimeZone.utc_offset
219
236
  offset = seconds_to_offset(seconds)
@@ -243,7 +260,8 @@ module Dynamoid
243
260
  else
244
261
  begin
245
262
  value.to_date
246
- rescue ArgumentError
263
+ rescue StandardError
264
+ nil
247
265
  end
248
266
  end
249
267
  end
@@ -8,7 +8,7 @@ module Dynamoid
8
8
  attributes.symbolize_keys
9
9
  .select { |attribute| attributes_options.key?(attribute) }
10
10
  .each do |attribute, value|
11
- h[attribute] = undump_field(value, attributes_options[attribute])
11
+ h[attribute] = undump_field(value, attributes_options[attribute])
12
12
  end
13
13
  end
14
14
  end
@@ -32,6 +32,7 @@ module Dynamoid
32
32
  when :number then NumberUndumper
33
33
  when :set then SetUndumper
34
34
  when :array then ArrayUndumper
35
+ when :map then MapUndumper
35
36
  when :datetime then DateTimeUndumper
36
37
  when :date then DateUndumper
37
38
  when :raw then RawUndumper
@@ -45,6 +46,35 @@ module Dynamoid
45
46
  end
46
47
  end
47
48
 
49
+ module UndumpHashHelper
50
+ extend self
51
+
52
+ def undump_hash(hash)
53
+ {}.tap do |h|
54
+ hash.each { |key, value| h[key.to_sym] = undump_hash_value(value) }
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def undump_hash_value(val)
61
+ case val
62
+ when BigDecimal
63
+ if Dynamoid::Config.convert_big_decimal
64
+ val.to_f
65
+ else
66
+ val
67
+ end
68
+ when Hash
69
+ undump_hash(val)
70
+ when Array
71
+ val.map { |v| undump_hash_value(v) }
72
+ else
73
+ val
74
+ end
75
+ end
76
+ end
77
+
48
78
  class Base
49
79
  def initialize(options)
50
80
  @options = options
@@ -68,7 +98,7 @@ module Dynamoid
68
98
  end
69
99
 
70
100
  class SetUndumper < Base
71
- ALLOWED_TYPES = [:string, :integer, :number, :date, :datetime, :serialized]
101
+ ALLOWED_TYPES = %i[string integer number date datetime serialized].freeze
72
102
 
73
103
  def process(set)
74
104
  if @options.key?(:of)
@@ -94,26 +124,26 @@ module Dynamoid
94
124
  end
95
125
 
96
126
  def element_type
97
- unless @options[:of].is_a?(Hash)
98
- @options[:of]
99
- else
127
+ if @options[:of].is_a?(Hash)
100
128
  @options[:of].keys.first
129
+ else
130
+ @options[:of]
101
131
  end
102
132
  end
103
133
 
104
134
  def element_options
105
- unless @options[:of].is_a?(Hash)
106
- { type: element_type }
107
- else
135
+ if @options[:of].is_a?(Hash)
108
136
  @options[:of][element_type].dup.tap do |options|
109
137
  options[:type] = element_type
110
138
  end
139
+ else
140
+ { type: element_type }
111
141
  end
112
142
  end
113
143
  end
114
144
 
115
145
  class ArrayUndumper < Base
116
- ALLOWED_TYPES = [:string, :integer, :number, :date, :datetime, :serialized]
146
+ ALLOWED_TYPES = %i[string integer number date datetime serialized].freeze
117
147
 
118
148
  def process(array)
119
149
  if @options.key?(:of)
@@ -139,24 +169,30 @@ module Dynamoid
139
169
  end
140
170
 
141
171
  def element_type
142
- unless @options[:of].is_a?(Hash)
143
- @options[:of]
144
- else
172
+ if @options[:of].is_a?(Hash)
145
173
  @options[:of].keys.first
174
+ else
175
+ @options[:of]
146
176
  end
147
177
  end
148
178
 
149
179
  def element_options
150
- unless @options[:of].is_a?(Hash)
151
- { type: element_type }
152
- else
180
+ if @options[:of].is_a?(Hash)
153
181
  @options[:of][element_type].dup.tap do |options|
154
182
  options[:type] = element_type
155
183
  end
184
+ else
185
+ { type: element_type }
156
186
  end
157
187
  end
158
188
  end
159
189
 
190
+ class MapUndumper < Base
191
+ def process(value)
192
+ UndumpHashHelper.undump_hash(value)
193
+ end
194
+ end
195
+
160
196
  class DateTimeUndumper < Base
161
197
  def process(value)
162
198
  return value if value.is_a?(Date) || value.is_a?(DateTime) || value.is_a?(Time)
@@ -190,36 +226,11 @@ module Dynamoid
190
226
  class RawUndumper < Base
191
227
  def process(value)
192
228
  if value.is_a?(Hash)
193
- undump_hash(value)
229
+ UndumpHashHelper.undump_hash(value)
194
230
  else
195
231
  value
196
232
  end
197
233
  end
198
-
199
- private
200
-
201
- def undump_hash(hash)
202
- {}.tap do |h|
203
- hash.each { |key, value| h[key.to_sym] = undump_hash_value(value) }
204
- end
205
- end
206
-
207
- def undump_hash_value(val)
208
- case val
209
- when BigDecimal
210
- if Dynamoid::Config.convert_big_decimal
211
- val.to_f
212
- else
213
- val
214
- end
215
- when Hash
216
- undump_hash(val)
217
- when Array
218
- val.map { |v| undump_hash_value(v) }
219
- else
220
- val
221
- end
222
- end
223
234
  end
224
235
 
225
236
  class SerializedUndumper < Base
@@ -233,7 +244,7 @@ module Dynamoid
233
244
  end
234
245
 
235
246
  class BooleanUndumper < Base
236
- STRING_VALUES = ['t', 'f']
247
+ STRING_VALUES = %w[t f].freeze
237
248
 
238
249
  def process(value)
239
250
  store_as_boolean = if @options[:store_as_native_boolean].nil?
@@ -14,6 +14,7 @@ module Dynamoid
14
14
  def save(options = {})
15
15
  options.reverse_merge!(validate: true)
16
16
  return false if options[:validate] && !valid?
17
+
17
18
  super
18
19
  end
19
20
 
@@ -30,6 +31,7 @@ module Dynamoid
30
31
  # @since 0.2.0
31
32
  def save!
32
33
  raise Dynamoid::Errors::DocumentNotValid, self unless valid?
34
+
33
35
  save(validate: false)
34
36
  self
35
37
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dynamoid
4
- VERSION = '3.1.0'
4
+ VERSION = '3.2.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.1.0
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Symonds
@@ -21,7 +21,7 @@ authors:
21
21
  autorequire:
22
22
  bindir: exe
23
23
  cert_chain: []
24
- date: 2018-11-19 00:00:00.000000000 Z
24
+ date: 2019-05-15 00:00:00.000000000 Z
25
25
  dependencies:
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activemodel
@@ -240,8 +240,15 @@ files:
240
240
  - lib/dynamoid.rb
241
241
  - lib/dynamoid/adapter.rb
242
242
  - lib/dynamoid/adapter_plugin/aws_sdk_v3.rb
243
- - lib/dynamoid/adapter_plugin/query.rb
244
- - lib/dynamoid/adapter_plugin/scan.rb
243
+ - lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb
244
+ - lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb
245
+ - lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb
246
+ - lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb
247
+ - lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb
248
+ - lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb
249
+ - lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb
250
+ - lib/dynamoid/adapter_plugin/aws_sdk_v3/table.rb
251
+ - lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb
245
252
  - lib/dynamoid/application_time_zone.rb
246
253
  - lib/dynamoid/associations.rb
247
254
  - lib/dynamoid/associations/association.rb
@@ -258,6 +265,10 @@ files:
258
265
  - lib/dynamoid/config/options.rb
259
266
  - lib/dynamoid/criteria.rb
260
267
  - lib/dynamoid/criteria/chain.rb
268
+ - lib/dynamoid/criteria/ignored_conditions_detector.rb
269
+ - lib/dynamoid/criteria/key_fields_detector.rb
270
+ - lib/dynamoid/criteria/nonexistent_fields_detector.rb
271
+ - lib/dynamoid/criteria/overwritten_conditions_detector.rb
261
272
  - lib/dynamoid/dirty.rb
262
273
  - lib/dynamoid/document.rb
263
274
  - lib/dynamoid/dumping.rb
@@ -271,6 +282,7 @@ files:
271
282
  - lib/dynamoid/persistence.rb
272
283
  - lib/dynamoid/primary_key_type_mapping.rb
273
284
  - lib/dynamoid/railtie.rb
285
+ - lib/dynamoid/tasks.rb
274
286
  - lib/dynamoid/tasks/database.rake
275
287
  - lib/dynamoid/tasks/database.rb
276
288
  - lib/dynamoid/type_casting.rb
@@ -297,7 +309,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
297
309
  version: '0'
298
310
  requirements: []
299
311
  rubyforge_project:
300
- rubygems_version: 2.6.14
312
+ rubygems_version: 2.7.6
301
313
  signing_key:
302
314
  specification_version: 4
303
315
  summary: Dynamoid is an ORM for Amazon's DynamoDB