dynamoid 3.7.1 → 3.9.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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +246 -244
  3. data/LICENSE.txt +2 -2
  4. data/README.md +134 -55
  5. data/SECURITY.md +17 -0
  6. data/dynamoid.gemspec +66 -0
  7. data/lib/dynamoid/adapter.rb +7 -9
  8. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/batch_get_item.rb +2 -2
  9. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/execute_statement.rb +62 -0
  10. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +29 -15
  11. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +3 -0
  12. data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +73 -59
  13. data/lib/dynamoid/associations/single_association.rb +28 -9
  14. data/lib/dynamoid/components.rb +2 -3
  15. data/lib/dynamoid/criteria/chain.rb +13 -9
  16. data/lib/dynamoid/criteria.rb +6 -7
  17. data/lib/dynamoid/dirty.rb +60 -63
  18. data/lib/dynamoid/document.rb +42 -12
  19. data/lib/dynamoid/errors.rb +2 -0
  20. data/lib/dynamoid/fields.rb +19 -37
  21. data/lib/dynamoid/finders.rb +9 -4
  22. data/lib/dynamoid/indexes.rb +45 -40
  23. data/lib/dynamoid/loadable.rb +6 -1
  24. data/lib/dynamoid/log/formatter.rb +19 -4
  25. data/lib/dynamoid/persistence/import.rb +4 -1
  26. data/lib/dynamoid/persistence/inc.rb +66 -0
  27. data/lib/dynamoid/persistence/save.rb +52 -5
  28. data/lib/dynamoid/persistence/update_fields.rb +1 -1
  29. data/lib/dynamoid/persistence/update_validations.rb +1 -1
  30. data/lib/dynamoid/persistence/upsert.rb +1 -1
  31. data/lib/dynamoid/persistence.rb +149 -61
  32. data/lib/dynamoid/undumping.rb +18 -0
  33. data/lib/dynamoid/validations.rb +6 -0
  34. data/lib/dynamoid/version.rb +1 -1
  35. data/lib/dynamoid.rb +1 -0
  36. metadata +30 -50
@@ -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
@@ -112,8 +113,10 @@ module Dynamoid
112
113
 
113
114
  if created_successfuly && self.options[:expires]
114
115
  attribute = self.options[:expires][:field]
115
- Dynamoid.adapter.update_time_to_live(table_name, attribute)
116
+ Dynamoid.adapter.update_time_to_live(options[:table_name], attribute)
116
117
  end
118
+
119
+ self
117
120
  end
118
121
 
119
122
  # Deletes the table for the model.
@@ -122,8 +125,10 @@ module Dynamoid
122
125
  # is deleted completely.
123
126
  #
124
127
  # Subsequent method calls for the same table will be ignored.
128
+ # @return [Model class] self
125
129
  def delete_table
126
130
  Dynamoid.adapter.delete_table(table_name)
131
+ self
127
132
  end
128
133
 
129
134
  # @private
@@ -365,32 +370,31 @@ module Dynamoid
365
370
  #
366
371
  # User.inc('1', 'Tylor', age: 2)
367
372
  #
373
+ # It's an atomic operation it does not interfere with other write
374
+ # requests.
375
+ #
368
376
  # Uses efficient low-level +UpdateItem+ operation and does only one HTTP
369
377
  # request.
370
378
  #
371
379
  # Doesn't run validations and callbacks. Doesn't update +created_at+ and
372
380
  # +updated_at+ as well.
373
381
  #
382
+ # When `:touch` option is passed the timestamp columns are updating. If
383
+ # attribute names are passed, they are updated along with updated_at
384
+ # attribute:
385
+ #
386
+ # User.inc('1', age: 2, touch: true)
387
+ # User.inc('1', age: 2, touch: :viewed_at)
388
+ # User.inc('1', age: 2, touch: [:viewed_at, :accessed_at])
389
+ #
374
390
  # @param hash_key_value [Scalar value] hash key
375
391
  # @param range_key_value [Scalar value] range key (optional)
376
392
  # @param counters [Hash] value to increase by
393
+ # @option counters [true | Symbol | Array[Symbol]] :touch to update update_at attribute and optionally the specified ones
394
+ # @return [Model class] self
377
395
  def inc(hash_key_value, range_key_value = nil, counters)
378
- options = if range_key
379
- value_casted = TypeCasting.cast_field(range_key_value, attributes[range_key])
380
- value_dumped = Dumping.dump_field(value_casted, attributes[range_key])
381
- { range_key: value_dumped }
382
- else
383
- {}
384
- end
385
-
386
- Dynamoid.adapter.update_item(table_name, hash_key_value, options) do |t|
387
- counters.each do |k, v|
388
- value_casted = TypeCasting.cast_field(v, attributes[k])
389
- value_dumped = Dumping.dump_field(value_casted, attributes[k])
390
-
391
- t.add(k => value_dumped)
392
- end
393
- end
396
+ Inc.call(self, hash_key_value, range_key_value, counters)
397
+ self
394
398
  end
395
399
  end
396
400
 
@@ -400,16 +404,44 @@ module Dynamoid
400
404
  #
401
405
  # post.touch
402
406
  #
403
- # Can update another field in addition with the same timestamp if it's name passed as argument.
407
+ # Can update other fields in addition with the same timestamp if their
408
+ # names passed as arguments.
404
409
  #
405
- # user.touch(:last_login_at)
410
+ # user.touch(:last_login_at, :viewed_at)
406
411
  #
407
- # @param name [Symbol] attribute name to update (optional)
408
- def touch(name = nil)
409
- now = DateTime.now
410
- self.updated_at = now
411
- attributes[name] = now if name
412
- save
412
+ # Some specific value can be used to save:
413
+ #
414
+ # user.touch(time: 1.hour.ago)
415
+ #
416
+ # No validation is performed and only +after_touch+ callback is called.
417
+ #
418
+ # The method must be used on a persisted object, otherwise
419
+ # +Dynamoid::Errors::Error+ will be thrown.
420
+ #
421
+ # @param names [*Symbol] a list of attribute names to update (optional)
422
+ # @param time [Time] datetime value that can be used instead of the current time (optional)
423
+ # @return [Dynamoid::Document] self
424
+ def touch(*names, time: nil)
425
+ if new_record?
426
+ raise Dynamoid::Errors::Error, 'cannot touch on a new or destroyed record object'
427
+ end
428
+
429
+ time_to_assign = time || DateTime.now
430
+
431
+ self.updated_at = time_to_assign
432
+ names.each do |name|
433
+ attributes[name] = time_to_assign
434
+ end
435
+
436
+ attribute_names = names.map(&:to_sym) + [:updated_at]
437
+ attributes_with_values = attributes.slice(*attribute_names)
438
+
439
+ run_callbacks :touch do
440
+ self.class.update_fields(hash_key, range_value, attributes_with_values)
441
+ clear_attribute_changes(attribute_names.map(&:to_s))
442
+ end
443
+
444
+ self
413
445
  end
414
446
 
415
447
  # Is this object persisted in DynamoDB?
@@ -476,18 +508,11 @@ module Dynamoid
476
508
  # @since 0.2.0
477
509
  def save(options = {})
478
510
  self.class.create_table(sync: true)
511
+ create_or_update = new_record? ? :create : :update
479
512
 
480
- @_touch_record = options[:touch]
481
-
482
- if new_record?
483
- run_callbacks(:create) do
484
- run_callbacks(:save) do
485
- Save.call(self)
486
- end
487
- end
488
- else
489
- run_callbacks(:save) do
490
- Save.call(self)
513
+ run_callbacks(:save) do
514
+ run_callbacks(create_or_update) do
515
+ Save.call(self, touch: options[:touch])
491
516
  end
492
517
  end
493
518
  end
@@ -532,21 +557,26 @@ module Dynamoid
532
557
  #
533
558
  # user.update_attribute(:last_name, 'Tylor')
534
559
  #
560
+ # Validation is skipped.
561
+ #
535
562
  # Raises a +Dynamoid::Errors::UnknownAttribute+ exception if any of the
536
563
  # attributes is not on the model
537
564
  #
538
565
  # @param attribute [Symbol] attribute name to update
539
566
  # @param value [Object] the value to assign it
540
567
  # @return [Dynamoid::Document] self
568
+ #
541
569
  # @since 0.2.0
542
570
  def update_attribute(attribute, value)
571
+ # final implementation is in the Dynamoid::Validation module
543
572
  write_attribute(attribute, value)
544
573
  save
574
+ self
545
575
  end
546
576
 
547
577
  # Update a model.
548
578
  #
549
- # Runs validation and callbacks. Reloads all attribute values.
579
+ # Doesn't run validation. Runs only +update+ callbacks. Reloads all attribute values.
550
580
  #
551
581
  # Accepts mandatory block in order to specify operations which will modify
552
582
  # attributes. Supports following operations: +add+, +delete+ and +set+.
@@ -555,7 +585,7 @@ module Dynamoid
555
585
  # collections if attribute is a collection (one of +array+, +set+ or
556
586
  # +map+).
557
587
  #
558
- # user.update do |t|
588
+ # user.update! do |t|
559
589
  # t.add(age: 1, followers_count: 5)
560
590
  # t.add(hobbies: ['skying', 'climbing'])
561
591
  # end
@@ -563,24 +593,28 @@ module Dynamoid
563
593
  # Operation +delete+ is applied to collection attribute types and
564
594
  # substructs one collection from another.
565
595
  #
566
- # user.update do |t|
596
+ # user.update! do |t|
567
597
  # t.delete(hobbies: ['skying'])
568
598
  # end
569
599
  #
570
600
  # Operation +set+ just changes an attribute value:
571
601
  #
572
- # user.update do |t|
602
+ # user.update! do |t|
573
603
  # t.set(age: 21)
574
604
  # end
575
605
  #
576
- # All the operations works like +ADD+, +DELETE+ and +PUT+ actions supported
606
+ # All the operations work like +ADD+, +DELETE+ and +PUT+ actions supported
577
607
  # by +AttributeUpdates+
578
608
  # {parameter}[https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LegacyConditionalParameters.AttributeUpdates.html]
579
609
  # of +UpdateItem+ operation.
580
610
  #
611
+ # It's an atomic operation. So adding or deleting elements in a collection
612
+ # or incrementing or decrementing a numeric field is atomic and does not
613
+ # interfere with other write requests.
614
+ #
581
615
  # Can update a model conditionaly:
582
616
  #
583
- # user.update(if: { age: 20 }) do |t|
617
+ # user.update!(if: { age: 20 }) do |t|
584
618
  # t.add(age: 1)
585
619
  # end
586
620
  #
@@ -593,15 +627,24 @@ module Dynamoid
593
627
  # fail.
594
628
  #
595
629
  # @param conditions [Hash] Conditions on model attributes to make a conditional update (optional)
630
+ # @return [Dynamoid::Document] self
596
631
  def update!(conditions = {})
597
632
  run_callbacks(:update) do
598
- options = range_key ? { range_key: Dumping.dump_field(read_attribute(range_key), self.class.attributes[range_key]) } : {}
633
+ options = {}
634
+ if range_key
635
+ value = read_attribute(range_key)
636
+ attribute_options = self.class.attributes[range_key]
637
+ options[:range_key] = Dumping.dump_field(value, attribute_options)
638
+ end
599
639
 
600
640
  begin
601
- new_attrs = Dynamoid.adapter.update_item(self.class.table_name, hash_key, options.merge(conditions: conditions)) do |t|
641
+ table_name = self.class.table_name
642
+ update_item_options = options.merge(conditions: conditions)
643
+
644
+ new_attrs = Dynamoid.adapter.update_item(table_name, hash_key, update_item_options) do |t|
602
645
  t.add(lock_version: 1) if self.class.attributes[:lock_version]
603
646
 
604
- if Dynamoid::Config.timestamps
647
+ if self.class.timestamps_enabled?
605
648
  time_now = DateTime.now.in_time_zone(Time.zone)
606
649
  time_now_dumped = Dumping.dump_field(time_now, self.class.attributes[:updated_at])
607
650
  t.set(updated_at: time_now_dumped)
@@ -614,11 +657,13 @@ module Dynamoid
614
657
  raise Dynamoid::Errors::StaleObjectError.new(self, 'update')
615
658
  end
616
659
  end
660
+
661
+ self
617
662
  end
618
663
 
619
664
  # Update a model.
620
665
  #
621
- # Runs validation and callbacks. Reloads all attribute values.
666
+ # Doesn't run validation. Runs only +update+ callbacks. Reloads all attribute values.
622
667
  #
623
668
  # Accepts mandatory block in order to specify operations which will modify
624
669
  # attributes. Supports following operations: +add+, +delete+ and +set+.
@@ -639,6 +684,19 @@ module Dynamoid
639
684
  # t.delete(hobbies: ['skying'])
640
685
  # end
641
686
  #
687
+ # If it's applied to a scalar attribute then the item's attribute is
688
+ # removed at all:
689
+ #
690
+ # user.update do |t|
691
+ # t.delete(age: nil)
692
+ # end
693
+ #
694
+ # or even without useless value at all:
695
+ #
696
+ # user.update do |t|
697
+ # t.delete(:age)
698
+ # end
699
+ #
642
700
  # Operation +set+ just changes an attribute value:
643
701
  #
644
702
  # user.update do |t|
@@ -664,6 +722,7 @@ module Dynamoid
664
722
  # fail.
665
723
  #
666
724
  # @param conditions [Hash] Conditions on model attributes to make a conditional update (optional)
725
+ # @return [true|false] - whether conditions are met and updating is successful
667
726
  def update(conditions = {}, &block)
668
727
  update!(conditions, &block)
669
728
  true
@@ -696,14 +755,32 @@ module Dynamoid
696
755
  # user.increment!(:followers_count)
697
756
  # user.increment!(:followers_count, 2)
698
757
  #
699
- # Returns +true+ if a model was saved and +false+ otherwise.
758
+ # Only `attribute` is saved. The model itself is not saved. So any other
759
+ # modified attributes will still be dirty. Validations and callbacks are
760
+ # skipped.
761
+ #
762
+ # When `:touch` option is passed the timestamp columns are updating. If
763
+ # attribute names are passed, they are updated along with updated_at
764
+ # attribute:
765
+ #
766
+ # user.increment!(:followers_count, touch: true)
767
+ # user.increment!(:followers_count, touch: :viewed_at)
768
+ # user.increment!(:followers_count, touch: [:viewed_at, :accessed_at])
700
769
  #
701
770
  # @param attribute [Symbol] attribute name
702
771
  # @param by [Numeric] value to add (optional)
703
- # @return [true|false] whether saved model successfully
704
- def increment!(attribute, by = 1)
772
+ # @param touch [true | Symbol | Array[Symbol]] to update update_at attribute and optionally the specified ones
773
+ # @return [Dynamoid::Document] self
774
+ def increment!(attribute, by = 1, touch: nil)
705
775
  increment(attribute, by)
706
- save
776
+ change = read_attribute(attribute) - (attribute_was(attribute) || 0)
777
+
778
+ run_callbacks :touch do
779
+ self.class.inc(hash_key, range_value, attribute => change, touch: touch)
780
+ clear_attribute_changes(attribute)
781
+ end
782
+
783
+ self
707
784
  end
708
785
 
709
786
  # Change numeric attribute value.
@@ -718,9 +795,7 @@ module Dynamoid
718
795
  # @param by [Numeric] value to subtract (optional)
719
796
  # @return [Dynamoid::Document] self
720
797
  def decrement(attribute, by = 1)
721
- self[attribute] ||= 0
722
- self[attribute] -= by
723
- self
798
+ increment(attribute, -by)
724
799
  end
725
800
 
726
801
  # Change numeric attribute value and save a model.
@@ -731,14 +806,24 @@ module Dynamoid
731
806
  # user.decrement!(:followers_count)
732
807
  # user.decrement!(:followers_count, 2)
733
808
  #
734
- # Returns +true+ if a model was saved and +false+ otherwise.
809
+ # Only `attribute` is saved. The model itself is not saved. So any other
810
+ # modified attributes will still be dirty. Validations and callbacks are
811
+ # skipped.
812
+ #
813
+ # When `:touch` option is passed the timestamp columns are updating. If
814
+ # attribute names are passed, they are updated along with updated_at
815
+ # attribute:
816
+ #
817
+ # user.decrement!(:followers_count, touch: true)
818
+ # user.decrement!(:followers_count, touch: :viewed_at)
819
+ # user.decrement!(:followers_count, touch: [:viewed_at, :accessed_at])
735
820
  #
736
821
  # @param attribute [Symbol] attribute name
737
822
  # @param by [Numeric] value to subtract (optional)
738
- # @return [true|false] whether saved model successfully
739
- def decrement!(attribute, by = 1)
740
- decrement(attribute, by)
741
- save
823
+ # @param touch [true | Symbol | Array[Symbol]] to update update_at attribute and optionally the specified ones
824
+ # @return [Dynamoid::Document] self
825
+ def decrement!(attribute, by = 1, touch: nil)
826
+ increment!(attribute, -by, touch: touch)
742
827
  end
743
828
 
744
829
  # Delete a model.
@@ -748,9 +833,9 @@ module Dynamoid
748
833
  # Supports optimistic locking with the +lock_version+ attribute and doesn't
749
834
  # delete a model if it's already changed.
750
835
  #
751
- # Returns +true+ if deleted successfully and +false+ otherwise.
836
+ # Returns +self+ if deleted successfully and +false+ otherwise.
752
837
  #
753
- # @return [true|false] whether deleted successfully
838
+ # @return [Dynamoid::Document|false] whether deleted successfully
754
839
  # @since 0.2.0
755
840
  def destroy
756
841
  ret = run_callbacks(:destroy) do
@@ -783,6 +868,7 @@ module Dynamoid
783
868
  # Raises +Dynamoid::Errors::StaleObjectError+ exception if cannot delete a
784
869
  # model.
785
870
  #
871
+ # @return [Dynamoid::Document] self
786
872
  # @since 0.2.0
787
873
  def delete
788
874
  options = range_key ? { range_key: Dumping.dump_field(read_attribute(range_key), self.class.attributes[range_key]) } : {}
@@ -803,9 +889,11 @@ module Dynamoid
803
889
 
804
890
  Dynamoid.adapter.delete(self.class.table_name, hash_key, options)
805
891
 
806
- self.class.associations.each do |name, options|
892
+ self.class.associations.each do |name, _options|
807
893
  send(name).disassociate_source
808
894
  end
895
+
896
+ self
809
897
  rescue Dynamoid::Errors::ConditionalCheckFailedException
810
898
  raise Dynamoid::Errors::StaleObjectError.new(self, 'delete')
811
899
  end
@@ -236,9 +236,27 @@ module Dynamoid
236
236
  end
237
237
 
238
238
  class SerializedUndumper < Base
239
+ # We must use YAML.safe_load in Ruby 3.1 to handle serialized Set class
240
+ minimum_ruby_version = ->(version) { Gem::Version.new(RUBY_VERSION) >= Gem::Version.new(version) }
241
+ # Once we drop support for Rubies older than 2.6 we can remove this conditional (with major version bump)!
242
+ # YAML_SAFE_LOAD = minimum_ruby_version.call("2.6")
243
+ # But we don't want to change behavior for Ruby <= 3.0 that has been using the gem, without a major version bump
244
+ YAML_SAFE_LOAD = minimum_ruby_version.call('3.1')
245
+
239
246
  def process(value)
240
247
  if @options[:serializer]
241
248
  @options[:serializer].load(value)
249
+ elsif YAML_SAFE_LOAD
250
+ # The classes listed in permitted classes are added to the default set of "safe loadable" classes.
251
+ # TrueClass
252
+ # FalseClass
253
+ # NilClass
254
+ # Integer
255
+ # Float
256
+ # String
257
+ # Array
258
+ # Hash
259
+ YAML.safe_load(value, permitted_classes: [Symbol, Set, Date, Time, DateTime])
242
260
  else
243
261
  YAML.load(value)
244
262
  end
@@ -38,6 +38,12 @@ module Dynamoid
38
38
  self
39
39
  end
40
40
 
41
+ def update_attribute(attribute, value)
42
+ write_attribute(attribute, value)
43
+ save(validate: false)
44
+ self
45
+ end
46
+
41
47
  module ClassMethods
42
48
  # Override validates_presence_of to handle false values as present.
43
49
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dynamoid
4
- VERSION = '3.7.1'
4
+ VERSION = '3.9.0'
5
5
  end
data/lib/dynamoid.rb CHANGED
@@ -4,6 +4,7 @@ require 'aws-sdk-dynamodb'
4
4
  require 'delegate'
5
5
  require 'time'
6
6
  require 'securerandom'
7
+ require 'set'
7
8
  require 'active_support'
8
9
  require 'active_support/core_ext'
9
10
  require 'active_support/json'
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.7.1
4
+ version: 3.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Symonds
@@ -21,7 +21,7 @@ authors:
21
21
  autorequire:
22
22
  bindir: bin
23
23
  cert_chain: []
24
- date: 2021-06-30 00:00:00.000000000 Z
24
+ date: 2023-04-13 00:00:00.000000000 Z
25
25
  dependencies:
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activemodel
@@ -69,16 +69,16 @@ dependencies:
69
69
  name: appraisal
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - "~>"
72
+ - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: '2.2'
74
+ version: '0'
75
75
  type: :development
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - "~>"
79
+ - - ">="
80
80
  - !ruby/object:Gem::Version
81
- version: '2.2'
81
+ version: '0'
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: bundler
84
84
  requirement: !ruby/object:Gem::Requirement
@@ -93,34 +93,20 @@ dependencies:
93
93
  - - ">="
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
- - !ruby/object:Gem::Dependency
97
- name: coveralls
98
- requirement: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: '0.8'
103
- type: :development
104
- prerelease: false
105
- version_requirements: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - "~>"
108
- - !ruby/object:Gem::Version
109
- version: '0.8'
110
96
  - !ruby/object:Gem::Dependency
111
97
  name: pry
112
98
  requirement: !ruby/object:Gem::Requirement
113
99
  requirements:
114
100
  - - "~>"
115
101
  - !ruby/object:Gem::Version
116
- version: 0.12.0
102
+ version: '0.14'
117
103
  type: :development
118
104
  prerelease: false
119
105
  version_requirements: !ruby/object:Gem::Requirement
120
106
  requirements:
121
107
  - - "~>"
122
108
  - !ruby/object:Gem::Version
123
- version: 0.12.0
109
+ version: '0.14'
124
110
  - !ruby/object:Gem::Dependency
125
111
  name: rake
126
112
  requirement: !ruby/object:Gem::Requirement
@@ -141,63 +127,49 @@ dependencies:
141
127
  requirements:
142
128
  - - "~>"
143
129
  - !ruby/object:Gem::Version
144
- version: '3.9'
130
+ version: '3.12'
145
131
  type: :development
146
132
  prerelease: false
147
133
  version_requirements: !ruby/object:Gem::Requirement
148
134
  requirements:
149
135
  - - "~>"
150
136
  - !ruby/object:Gem::Version
151
- version: '3.9'
152
- - !ruby/object:Gem::Dependency
153
- name: rubocop
154
- requirement: !ruby/object:Gem::Requirement
155
- requirements:
156
- - - ">="
157
- - !ruby/object:Gem::Version
158
- version: '0'
159
- type: :development
160
- prerelease: false
161
- version_requirements: !ruby/object:Gem::Requirement
162
- requirements:
163
- - - ">="
164
- - !ruby/object:Gem::Version
165
- version: '0'
137
+ version: '3.12'
166
138
  - !ruby/object:Gem::Dependency
167
- name: wwtd
139
+ name: rubocop-lts
168
140
  requirement: !ruby/object:Gem::Requirement
169
141
  requirements:
170
142
  - - "~>"
171
143
  - !ruby/object:Gem::Version
172
- version: '1.4'
144
+ version: '10.0'
173
145
  type: :development
174
146
  prerelease: false
175
147
  version_requirements: !ruby/object:Gem::Requirement
176
148
  requirements:
177
149
  - - "~>"
178
150
  - !ruby/object:Gem::Version
179
- version: '1.4'
151
+ version: '10.0'
180
152
  - !ruby/object:Gem::Dependency
181
153
  name: yard
182
154
  requirement: !ruby/object:Gem::Requirement
183
155
  requirements:
184
- - - "~>"
156
+ - - ">="
185
157
  - !ruby/object:Gem::Version
186
- version: '0.9'
158
+ version: '0'
187
159
  type: :development
188
160
  prerelease: false
189
161
  version_requirements: !ruby/object:Gem::Requirement
190
162
  requirements:
191
- - - "~>"
163
+ - - ">="
192
164
  - !ruby/object:Gem::Version
193
- version: '0.9'
165
+ version: '0'
194
166
  description: Dynamoid is an ORM for Amazon's DynamoDB that supports offline development,
195
167
  associations, querying, and everything else you'd expect from an ActiveRecord-style
196
168
  replacement.
197
169
  email:
170
+ - andry.konchin@gmail.com
198
171
  - peter.boling@gmail.com
199
172
  - brian@stellaservice.com
200
- - andry.konchin@gmail.com
201
173
  executables: []
202
174
  extensions: []
203
175
  extra_rdoc_files: []
@@ -205,11 +177,14 @@ files:
205
177
  - CHANGELOG.md
206
178
  - LICENSE.txt
207
179
  - README.md
180
+ - SECURITY.md
181
+ - dynamoid.gemspec
208
182
  - lib/dynamoid.rb
209
183
  - lib/dynamoid/adapter.rb
210
184
  - lib/dynamoid/adapter_plugin/aws_sdk_v3.rb
211
185
  - lib/dynamoid/adapter_plugin/aws_sdk_v3/batch_get_item.rb
212
186
  - lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb
187
+ - lib/dynamoid/adapter_plugin/aws_sdk_v3/execute_statement.rb
213
188
  - lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb
214
189
  - lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb
215
190
  - lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb
@@ -253,6 +228,7 @@ files:
253
228
  - lib/dynamoid/middleware/identity_map.rb
254
229
  - lib/dynamoid/persistence.rb
255
230
  - lib/dynamoid/persistence/import.rb
231
+ - lib/dynamoid/persistence/inc.rb
256
232
  - lib/dynamoid/persistence/save.rb
257
233
  - lib/dynamoid/persistence/update_fields.rb
258
234
  - lib/dynamoid/persistence/update_validations.rb
@@ -270,10 +246,14 @@ homepage: http://github.com/Dynamoid/dynamoid
270
246
  licenses:
271
247
  - MIT
272
248
  metadata:
249
+ homepage_uri: http://github.com/Dynamoid/dynamoid
250
+ source_code_uri: https://github.com/Dynamoid/dynamoid/tree/v3.9.0
251
+ changelog_uri: https://github.com/Dynamoid/dynamoid/blob/v3.9.0/CHANGELOG.md
273
252
  bug_tracker_uri: https://github.com/Dynamoid/dynamoid/issues
274
- changelog_uri: https://github.com/Dynamoid/dynamoid/tree/v3.7.1/CHANGELOG.md
275
- source_code_uri: https://github.com/Dynamoid/dynamoid/tree/v3.7.1
276
- documentation_uri: https://rubydoc.info/gems/dynamoid/3.7.1
253
+ documentation_uri: https://www.rubydoc.info/gems/dynamoid/3.9.0
254
+ funding_uri: https://opencollective.com/dynamoid
255
+ wiki_uri: https://github.com/Dynamoid/dynamoid/wiki
256
+ rubygems_mfa_required: 'true'
277
257
  post_install_message:
278
258
  rdoc_options: []
279
259
  require_paths:
@@ -289,7 +269,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
289
269
  - !ruby/object:Gem::Version
290
270
  version: '0'
291
271
  requirements: []
292
- rubygems_version: 3.2.3
272
+ rubygems_version: 3.4.6
293
273
  signing_key:
294
274
  specification_version: 4
295
275
  summary: Dynamoid is an ORM for Amazon's DynamoDB