dynamoid 3.8.0 → 3.10.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +54 -3
  3. data/README.md +111 -60
  4. data/SECURITY.md +17 -0
  5. data/dynamoid.gemspec +65 -0
  6. data/lib/dynamoid/adapter.rb +20 -13
  7. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +2 -2
  8. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/execute_statement.rb +62 -0
  9. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/filter_expression_convertor.rb +78 -0
  10. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +28 -2
  11. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +3 -0
  12. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/projection_expression_convertor.rb +38 -0
  13. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +46 -61
  14. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +33 -27
  15. data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +116 -70
  16. data/lib/dynamoid/associations/belongs_to.rb +6 -6
  17. data/lib/dynamoid/associations.rb +1 -1
  18. data/lib/dynamoid/components.rb +2 -3
  19. data/lib/dynamoid/config/options.rb +12 -12
  20. data/lib/dynamoid/config.rb +1 -0
  21. data/lib/dynamoid/criteria/chain.rb +101 -138
  22. data/lib/dynamoid/criteria/key_fields_detector.rb +6 -7
  23. data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +2 -2
  24. data/lib/dynamoid/criteria/where_conditions.rb +29 -0
  25. data/lib/dynamoid/dirty.rb +57 -57
  26. data/lib/dynamoid/document.rb +39 -3
  27. data/lib/dynamoid/dumping.rb +2 -2
  28. data/lib/dynamoid/errors.rb +2 -0
  29. data/lib/dynamoid/fields/declare.rb +6 -6
  30. data/lib/dynamoid/fields.rb +9 -27
  31. data/lib/dynamoid/finders.rb +26 -30
  32. data/lib/dynamoid/indexes.rb +7 -10
  33. data/lib/dynamoid/loadable.rb +2 -2
  34. data/lib/dynamoid/log/formatter.rb +19 -4
  35. data/lib/dynamoid/persistence/import.rb +4 -1
  36. data/lib/dynamoid/persistence/inc.rb +66 -0
  37. data/lib/dynamoid/persistence/save.rb +55 -12
  38. data/lib/dynamoid/persistence/update_fields.rb +2 -2
  39. data/lib/dynamoid/persistence/update_validations.rb +2 -2
  40. data/lib/dynamoid/persistence.rb +128 -48
  41. data/lib/dynamoid/type_casting.rb +15 -14
  42. data/lib/dynamoid/undumping.rb +1 -1
  43. data/lib/dynamoid/version.rb +1 -1
  44. metadata +27 -49
  45. data/lib/dynamoid/criteria/ignored_conditions_detector.rb +0 -41
  46. data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +0 -40
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dynamoid
4
+ module Persistence
5
+ # @private
6
+ class Inc
7
+ def self.call(model_class, hash_key, range_key = nil, counters)
8
+ new(model_class, hash_key, range_key, counters).call
9
+ end
10
+
11
+ # rubocop:disable Style/OptionalArguments
12
+ def initialize(model_class, hash_key, range_key = nil, counters)
13
+ @model_class = model_class
14
+ @hash_key = hash_key
15
+ @range_key = range_key
16
+ @counters = counters
17
+ end
18
+ # rubocop:enable Style/OptionalArguments
19
+
20
+ def call
21
+ touch = @counters.delete(:touch)
22
+
23
+ Dynamoid.adapter.update_item(@model_class.table_name, @hash_key, update_item_options) do |t|
24
+ @counters.each do |name, value|
25
+ t.add(name => cast_and_dump_attribute_value(name, value))
26
+ end
27
+
28
+ if touch
29
+ value = DateTime.now.in_time_zone(Time.zone)
30
+
31
+ timestamp_attributes_to_touch(touch).each do |name|
32
+ t.set(name => cast_and_dump_attribute_value(name, value))
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def update_item_options
41
+ if @model_class.range_key
42
+ range_key_options = @model_class.attributes[@model_class.range_key]
43
+ value_casted = TypeCasting.cast_field(@range_key, range_key_options)
44
+ value_dumped = Dumping.dump_field(value_casted, range_key_options)
45
+ { range_key: value_dumped }
46
+ else
47
+ {}
48
+ end
49
+ end
50
+
51
+ def cast_and_dump_attribute_value(name, value)
52
+ value_casted = TypeCasting.cast_field(value, @model_class.attributes[name])
53
+ Dumping.dump_field(value_casted, @model_class.attributes[name])
54
+ end
55
+
56
+ def timestamp_attributes_to_touch(touch)
57
+ return [] unless touch
58
+
59
+ names = []
60
+ names << :updated_at if @model_class.timestamps_enabled?
61
+ names += Array.wrap(touch) if touch != true
62
+ names
63
+ end
64
+ end
65
+ end
66
+ end
@@ -4,24 +4,44 @@ module Dynamoid
4
4
  module Persistence
5
5
  # @private
6
6
  class Save
7
- def self.call(model)
8
- new(model).call
7
+ def self.call(model, **options)
8
+ new(model, **options).call
9
9
  end
10
10
 
11
- def initialize(model)
11
+ def initialize(model, touch: nil)
12
12
  @model = model
13
+ @touch = touch # touch=false means explicit disabling of updating the `updated_at` attribute
13
14
  end
14
15
 
15
16
  def call
16
17
  @model.hash_key = SecureRandom.uuid if @model.hash_key.blank?
17
18
 
19
+ return true unless @model.changed?
20
+
21
+ @model.created_at ||= DateTime.now.in_time_zone(Time.zone) if @model.class.timestamps_enabled?
22
+
23
+ if @model.class.timestamps_enabled? && !@model.updated_at_changed? && !(@touch == false && @model.persisted?)
24
+ @model.updated_at = DateTime.now.in_time_zone(Time.zone)
25
+ end
26
+
18
27
  # Add an optimistic locking check if the lock_version column exists
19
28
  if @model.class.attributes[:lock_version]
20
29
  @model.lock_version = (@model.lock_version || 0) + 1
21
30
  end
22
31
 
23
- attributes_dumped = Dumping.dump_attributes(@model.attributes, @model.class.attributes)
24
- Dynamoid.adapter.write(@model.class.table_name, attributes_dumped, conditions_for_write)
32
+ if @model.new_record?
33
+ attributes_dumped = Dumping.dump_attributes(@model.attributes, @model.class.attributes)
34
+ Dynamoid.adapter.write(@model.class.table_name, attributes_dumped, conditions_for_write)
35
+ else
36
+ attributes_to_persist = @model.attributes.slice(*@model.changed.map(&:to_sym))
37
+
38
+ Dynamoid.adapter.update_item(@model.class.table_name, @model.hash_key, options_to_update_item) do |t|
39
+ attributes_to_persist.each do |name, value|
40
+ value_dumped = Dumping.dump_field(value, @model.class.attributes[name])
41
+ t.set(name => value_dumped)
42
+ end
43
+ end
44
+ end
25
45
 
26
46
  @model.new_record = false
27
47
  true
@@ -48,17 +68,40 @@ module Dynamoid
48
68
  end
49
69
 
50
70
  # Add an optimistic locking check if the lock_version column exists
51
- if @model.class.attributes[:lock_version]
52
- # Uses the original lock_version value from Dirty API
53
- # in case user changed 'lock_version' manually
54
- if @model.changes[:lock_version][0]
55
- conditions[:if] ||= {}
56
- conditions[:if][:lock_version] = @model.changes[:lock_version][0]
57
- end
71
+ # Uses the original lock_version value from Dirty API
72
+ # in case user changed 'lock_version' manually
73
+ if @model.class.attributes[:lock_version] && (@model.changes[:lock_version][0])
74
+ conditions[:if] ||= {}
75
+ conditions[:if][:lock_version] = @model.changes[:lock_version][0]
58
76
  end
59
77
 
60
78
  conditions
61
79
  end
80
+
81
+ def options_to_update_item
82
+ options = {}
83
+
84
+ if @model.class.range_key
85
+ value_dumped = Dumping.dump_field(@model.range_value, @model.class.attributes[@model.class.range_key])
86
+ options[:range_key] = value_dumped
87
+ end
88
+
89
+ conditions = {}
90
+ conditions[:if] ||= {}
91
+ conditions[:if][@model.class.hash_key] = @model.hash_key
92
+
93
+ # Add an optimistic locking check if the lock_version column exists
94
+ # Uses the original lock_version value from Dirty API
95
+ # in case user changed 'lock_version' manually
96
+ if @model.class.attributes[:lock_version] && (@model.changes[:lock_version][0])
97
+ conditions[:if] ||= {}
98
+ conditions[:if][:lock_version] = @model.changes[:lock_version][0]
99
+ end
100
+
101
+ options[:conditions] = conditions
102
+
103
+ options
104
+ end
62
105
  end
63
106
  end
64
107
  end
@@ -54,8 +54,8 @@ module Dynamoid
54
54
  end
55
55
 
56
56
  conditions = @conditions.deep_dup
57
- conditions[:if_exists] ||= {}
58
- conditions[:if_exists][@model_class.hash_key] = @partition_key
57
+ conditions[:if] ||= {}
58
+ conditions[:if][@model_class.hash_key] = @partition_key
59
59
  options[:conditions] = conditions
60
60
 
61
61
  options
@@ -7,9 +7,9 @@ module Dynamoid
7
7
  def self.validate_attributes_exist(model_class, attributes)
8
8
  model_attributes = model_class.attributes.keys
9
9
 
10
- attributes.each do |attr_name, _|
10
+ attributes.each_key do |attr_name|
11
11
  unless model_attributes.include?(attr_name)
12
- raise Dynamoid::Errors::UnknownAttribute.new("Attribute #{attr_name} does not exist in #{model_class}")
12
+ raise Dynamoid::Errors::UnknownAttribute, "Attribute #{attr_name} does not exist in #{model_class}"
13
13
  end
14
14
  end
15
15
  end
@@ -8,6 +8,7 @@ require 'dynamoid/persistence/import'
8
8
  require 'dynamoid/persistence/update_fields'
9
9
  require 'dynamoid/persistence/upsert'
10
10
  require 'dynamoid/persistence/save'
11
+ require 'dynamoid/persistence/inc'
11
12
  require 'dynamoid/persistence/update_validations'
12
13
 
13
14
  # encoding: utf-8
@@ -270,7 +271,7 @@ module Dynamoid
270
271
  # meets the specified conditions. Conditions can be specified as a +Hash+
271
272
  # with +:if+ key:
272
273
  #
273
- # User.update_fields('1', { age: 26 }, if: { version: 1 })
274
+ # User.update_fields('1', { age: 26 }, { if: { version: 1 } })
274
275
  #
275
276
  # Here +User+ model has an integer +version+ field and the document will
276
277
  # be updated only if the +version+ attribute currently has value 1.
@@ -278,6 +279,13 @@ module Dynamoid
278
279
  # If a document with specified hash and range keys doesn't exist or
279
280
  # conditions were specified and failed the method call returns +nil+.
280
281
  #
282
+ # To check if some attribute (or attributes) isn't stored in a DynamoDB
283
+ # item (e.g. it wasn't set explicitly) there is another condition -
284
+ # +unless_exists+:
285
+ #
286
+ # user = User.create(name: 'Tylor')
287
+ # User.update_fields(user.id, { age: 18 }, { unless_exists: [:age] })
288
+ #
281
289
  # +update_fields+ uses the +UpdateItem+ operation so it saves changes and
282
290
  # loads an updated document back with one HTTP request.
283
291
  #
@@ -322,11 +330,18 @@ module Dynamoid
322
330
  # meets the specified conditions. Conditions can be specified as a +Hash+
323
331
  # with +:if+ key:
324
332
  #
325
- # User.upsert('1', { age: 26 }, if: { version: 1 })
333
+ # User.upsert('1', { age: 26 }, { if: { version: 1 } })
326
334
  #
327
335
  # Here +User+ model has an integer +version+ field and the document will
328
336
  # be updated only if the +version+ attribute currently has value 1.
329
337
  #
338
+ # To check if some attribute (or attributes) isn't stored in a DynamoDB
339
+ # item (e.g. it wasn't set explicitly) there is another condition -
340
+ # +unless_exists+:
341
+ #
342
+ # user = User.create(name: 'Tylor')
343
+ # User.upsert(user.id, { age: 18 }, { unless_exists: [:age] })
344
+ #
330
345
  # If conditions were specified and failed the method call returns +nil+.
331
346
  #
332
347
  # +upsert+ uses the +UpdateItem+ operation so it saves changes and loads
@@ -378,28 +393,21 @@ module Dynamoid
378
393
  # Doesn't run validations and callbacks. Doesn't update +created_at+ and
379
394
  # +updated_at+ as well.
380
395
  #
396
+ # When `:touch` option is passed the timestamp columns are updating. If
397
+ # attribute names are passed, they are updated along with updated_at
398
+ # attribute:
399
+ #
400
+ # User.inc('1', age: 2, touch: true)
401
+ # User.inc('1', age: 2, touch: :viewed_at)
402
+ # User.inc('1', age: 2, touch: [:viewed_at, :accessed_at])
403
+ #
381
404
  # @param hash_key_value [Scalar value] hash key
382
405
  # @param range_key_value [Scalar value] range key (optional)
383
406
  # @param counters [Hash] value to increase by
407
+ # @option counters [true | Symbol | Array[Symbol]] :touch to update update_at attribute and optionally the specified ones
384
408
  # @return [Model class] self
385
409
  def inc(hash_key_value, range_key_value = nil, counters)
386
- options = if range_key
387
- value_casted = TypeCasting.cast_field(range_key_value, attributes[range_key])
388
- value_dumped = Dumping.dump_field(value_casted, attributes[range_key])
389
- { range_key: value_dumped }
390
- else
391
- {}
392
- end
393
-
394
- Dynamoid.adapter.update_item(table_name, hash_key_value, options) do |t|
395
- counters.each do |k, v|
396
- value_casted = TypeCasting.cast_field(v, attributes[k])
397
- value_dumped = Dumping.dump_field(value_casted, attributes[k])
398
-
399
- t.add(k => value_dumped)
400
- end
401
- end
402
-
410
+ Inc.call(self, hash_key_value, range_key_value, counters)
403
411
  self
404
412
  end
405
413
  end
@@ -410,17 +418,43 @@ module Dynamoid
410
418
  #
411
419
  # post.touch
412
420
  #
413
- # Can update another field in addition with the same timestamp if it's name passed as argument.
421
+ # Can update other fields in addition with the same timestamp if their
422
+ # names passed as arguments.
423
+ #
424
+ # user.touch(:last_login_at, :viewed_at)
425
+ #
426
+ # Some specific value can be used to save:
427
+ #
428
+ # user.touch(time: 1.hour.ago)
414
429
  #
415
- # user.touch(:last_login_at)
430
+ # No validation is performed and only +after_touch+ callback is called.
416
431
  #
417
- # @param name [Symbol] attribute name to update (optional)
432
+ # The method must be used on a persisted object, otherwise
433
+ # +Dynamoid::Errors::Error+ will be thrown.
434
+ #
435
+ # @param names [*Symbol] a list of attribute names to update (optional)
436
+ # @param time [Time] datetime value that can be used instead of the current time (optional)
418
437
  # @return [Dynamoid::Document] self
419
- def touch(name = nil)
420
- now = DateTime.now
421
- self.updated_at = now
422
- attributes[name] = now if name
423
- save
438
+ def touch(*names, time: nil)
439
+ if new_record?
440
+ raise Dynamoid::Errors::Error, 'cannot touch on a new or destroyed record object'
441
+ end
442
+
443
+ time_to_assign = time || DateTime.now
444
+
445
+ self.updated_at = time_to_assign
446
+ names.each do |name|
447
+ attributes[name] = time_to_assign
448
+ end
449
+
450
+ attribute_names = names.map(&:to_sym) + [:updated_at]
451
+ attributes_with_values = attributes.slice(*attribute_names)
452
+
453
+ run_callbacks :touch do
454
+ self.class.update_fields(hash_key, range_value, attributes_with_values)
455
+ clear_attribute_changes(attribute_names.map(&:to_s))
456
+ end
457
+
424
458
  self
425
459
  end
426
460
 
@@ -487,15 +521,15 @@ module Dynamoid
487
521
  # @return [true|false] Whether saving successful or not
488
522
  # @since 0.2.0
489
523
  def save(options = {})
490
- self.class.create_table(sync: true)
491
-
492
- @_touch_record = options[:touch]
524
+ if Dynamoid.config.create_table_on_save
525
+ self.class.create_table(sync: true)
526
+ end
493
527
 
494
528
  create_or_update = new_record? ? :create : :update
495
529
 
496
- run_callbacks(create_or_update) do
497
- run_callbacks(:save) do
498
- Save.call(self)
530
+ run_callbacks(:save) do
531
+ run_callbacks(create_or_update) do
532
+ Save.call(self, touch: options[:touch])
499
533
  end
500
534
  end
501
535
  end
@@ -540,6 +574,8 @@ module Dynamoid
540
574
  #
541
575
  # user.update_attribute(:last_name, 'Tylor')
542
576
  #
577
+ # Validation is skipped.
578
+ #
543
579
  # Raises a +Dynamoid::Errors::UnknownAttribute+ exception if any of the
544
580
  # attributes is not on the model
545
581
  #
@@ -557,7 +593,7 @@ module Dynamoid
557
593
 
558
594
  # Update a model.
559
595
  #
560
- # Runs validation and callbacks. Reloads all attribute values.
596
+ # Doesn't run validation. Runs only +update+ callbacks. Reloads all attribute values.
561
597
  #
562
598
  # Accepts mandatory block in order to specify operations which will modify
563
599
  # attributes. Supports following operations: +add+, +delete+ and +set+.
@@ -599,6 +635,15 @@ module Dynamoid
599
635
  # t.add(age: 1)
600
636
  # end
601
637
  #
638
+ # To check if some attribute (or attributes) isn't stored in a DynamoDB
639
+ # item (e.g. it wasn't set explicitly) there is another condition -
640
+ # +unless_exists+:
641
+ #
642
+ # user = User.create(name: 'Tylor')
643
+ # user.update!(unless_exists: [:age]) do |t|
644
+ # t.set(age: 18)
645
+ # end
646
+ #
602
647
  # If a document doesn't meet conditions it raises
603
648
  # +Dynamoid::Errors::StaleObjectError+ exception.
604
649
  #
@@ -644,7 +689,7 @@ module Dynamoid
644
689
 
645
690
  # Update a model.
646
691
  #
647
- # Runs validation and callbacks. Reloads all attribute values.
692
+ # Doesn't run validation. Runs only +update+ callbacks. Reloads all attribute values.
648
693
  #
649
694
  # Accepts mandatory block in order to specify operations which will modify
650
695
  # attributes. Supports following operations: +add+, +delete+ and +set+.
@@ -695,6 +740,15 @@ module Dynamoid
695
740
  # t.add(age: 1)
696
741
  # end
697
742
  #
743
+ # To check if some attribute (or attributes) isn't stored in a DynamoDB
744
+ # item (e.g. it wasn't set explicitly) there is another condition -
745
+ # +unless_exists+:
746
+ #
747
+ # user = User.create(name: 'Tylor')
748
+ # user.update(unless_exists: [:age]) do |t|
749
+ # t.set(age: 18)
750
+ # end
751
+ #
698
752
  # If a document doesn't meet conditions it just returns +false+. Otherwise it returns +true+.
699
753
  #
700
754
  # It will increment the +lock_version+ attribute if a table has the column,
@@ -736,14 +790,32 @@ module Dynamoid
736
790
  # user.increment!(:followers_count)
737
791
  # user.increment!(:followers_count, 2)
738
792
  #
739
- # Returns +true+ if a model was saved and +false+ otherwise.
793
+ # Only `attribute` is saved. The model itself is not saved. So any other
794
+ # modified attributes will still be dirty. Validations and callbacks are
795
+ # skipped.
796
+ #
797
+ # When `:touch` option is passed the timestamp columns are updating. If
798
+ # attribute names are passed, they are updated along with updated_at
799
+ # attribute:
800
+ #
801
+ # user.increment!(:followers_count, touch: true)
802
+ # user.increment!(:followers_count, touch: :viewed_at)
803
+ # user.increment!(:followers_count, touch: [:viewed_at, :accessed_at])
740
804
  #
741
805
  # @param attribute [Symbol] attribute name
742
806
  # @param by [Numeric] value to add (optional)
743
- # @return [true|false] whether saved model successfully
744
- def increment!(attribute, by = 1)
807
+ # @param touch [true | Symbol | Array[Symbol]] to update update_at attribute and optionally the specified ones
808
+ # @return [Dynamoid::Document] self
809
+ def increment!(attribute, by = 1, touch: nil)
745
810
  increment(attribute, by)
746
- save
811
+ change = read_attribute(attribute) - (attribute_was(attribute) || 0)
812
+
813
+ run_callbacks :touch do
814
+ self.class.inc(hash_key, range_value, attribute => change, touch: touch)
815
+ clear_attribute_changes(attribute)
816
+ end
817
+
818
+ self
747
819
  end
748
820
 
749
821
  # Change numeric attribute value.
@@ -758,9 +830,7 @@ module Dynamoid
758
830
  # @param by [Numeric] value to subtract (optional)
759
831
  # @return [Dynamoid::Document] self
760
832
  def decrement(attribute, by = 1)
761
- self[attribute] ||= 0
762
- self[attribute] -= by
763
- self
833
+ increment(attribute, -by)
764
834
  end
765
835
 
766
836
  # Change numeric attribute value and save a model.
@@ -771,14 +841,24 @@ module Dynamoid
771
841
  # user.decrement!(:followers_count)
772
842
  # user.decrement!(:followers_count, 2)
773
843
  #
774
- # Returns +true+ if a model was saved and +false+ otherwise.
844
+ # Only `attribute` is saved. The model itself is not saved. So any other
845
+ # modified attributes will still be dirty. Validations and callbacks are
846
+ # skipped.
847
+ #
848
+ # When `:touch` option is passed the timestamp columns are updating. If
849
+ # attribute names are passed, they are updated along with updated_at
850
+ # attribute:
851
+ #
852
+ # user.decrement!(:followers_count, touch: true)
853
+ # user.decrement!(:followers_count, touch: :viewed_at)
854
+ # user.decrement!(:followers_count, touch: [:viewed_at, :accessed_at])
775
855
  #
776
856
  # @param attribute [Symbol] attribute name
777
857
  # @param by [Numeric] value to subtract (optional)
778
- # @return [true|false] whether saved model successfully
779
- def decrement!(attribute, by = 1)
780
- decrement(attribute, by)
781
- save
858
+ # @param touch [true | Symbol | Array[Symbol]] to update update_at attribute and optionally the specified ones
859
+ # @return [Dynamoid::Document] self
860
+ def decrement!(attribute, by = 1, touch: nil)
861
+ increment!(attribute, -by, touch: touch)
782
862
  end
783
863
 
784
864
  # Delete a model.
@@ -844,7 +924,7 @@ module Dynamoid
844
924
 
845
925
  Dynamoid.adapter.delete(self.class.table_name, hash_key, options)
846
926
 
847
- self.class.associations.each do |name, options|
927
+ self.class.associations.each_key do |name|
848
928
  send(name).disassociate_source
849
929
  end
850
930
 
@@ -57,11 +57,12 @@ module Dynamoid
57
57
 
58
58
  class StringTypeCaster < Base
59
59
  def process(value)
60
- if value == true
60
+ case value
61
+ when true
61
62
  't'
62
- elsif value == false
63
+ when false
63
64
  'f'
64
- elsif value.is_a? String
65
+ when String
65
66
  value.dup
66
67
  else
67
68
  value.to_s
@@ -71,6 +72,7 @@ module Dynamoid
71
72
 
72
73
  class IntegerTypeCaster < Base
73
74
  def process(value)
75
+ # rubocop:disable Lint/DuplicateBranch
74
76
  if value == true
75
77
  1
76
78
  elsif value == false
@@ -84,11 +86,13 @@ module Dynamoid
84
86
  else
85
87
  value.to_i
86
88
  end
89
+ # rubocop:enable Lint/DuplicateBranch
87
90
  end
88
91
  end
89
92
 
90
93
  class NumberTypeCaster < Base
91
94
  def process(value)
95
+ # rubocop:disable Lint/DuplicateBranch
92
96
  if value == true
93
97
  1
94
98
  elsif value == false
@@ -104,6 +108,7 @@ module Dynamoid
104
108
  else
105
109
  value.to_d
106
110
  end
111
+ # rubocop:enable Lint/DuplicateBranch
107
112
  end
108
113
  end
109
114
 
@@ -135,7 +140,7 @@ module Dynamoid
135
140
  raise ArgumentError, "Set element type #{element_type} isn't supported"
136
141
  end
137
142
 
138
- set.map { |el| type_caster.process(el) }.to_set
143
+ set.to_set { |el| type_caster.process(el) }
139
144
  end
140
145
 
141
146
  def element_type
@@ -227,10 +232,10 @@ module Dynamoid
227
232
  nil
228
233
  elsif value.is_a?(String)
229
234
  dt = begin
230
- DateTime.parse(value)
231
- rescue StandardError
232
- nil
233
- end
235
+ DateTime.parse(value)
236
+ rescue StandardError
237
+ nil
238
+ end
234
239
  if dt
235
240
  seconds = string_utc_offset(value) || ApplicationTimeZone.utc_offset
236
241
  offset = seconds_to_offset(seconds)
@@ -255,9 +260,7 @@ module Dynamoid
255
260
 
256
261
  class DateTypeCaster < Base
257
262
  def process(value)
258
- if !value.respond_to?(:to_date)
259
- nil
260
- else
263
+ if value.respond_to?(:to_date)
261
264
  begin
262
265
  value.to_date
263
266
  rescue StandardError
@@ -277,10 +280,8 @@ module Dynamoid
277
280
  def process(value)
278
281
  if value == ''
279
282
  nil
280
- elsif [false, 'false', 'FALSE', 0, '0', 'f', 'F', 'off', 'OFF'].include? value
281
- false
282
283
  else
283
- true
284
+ ![false, 'false', 'FALSE', 0, '0', 'f', 'F', 'off', 'OFF'].include? value
284
285
  end
285
286
  end
286
287
  end
@@ -115,7 +115,7 @@ module Dynamoid
115
115
  def process_typed_collection(set)
116
116
  if allowed_type?
117
117
  undumper = Undumping.find_undumper(element_options)
118
- set.map { |el| undumper.process(el) }.to_set
118
+ set.to_set { |el| undumper.process(el) }
119
119
  else
120
120
  raise ArgumentError, "Set element type #{element_type} isn't supported"
121
121
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dynamoid
4
- VERSION = '3.8.0'
4
+ VERSION = '3.10.0'
5
5
  end