dynamoid 3.4.0 → 3.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +94 -3
  3. data/README.md +52 -26
  4. data/lib/dynamoid.rb +1 -0
  5. data/lib/dynamoid/adapter.rb +15 -6
  6. data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +48 -36
  7. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/batch_get_item.rb +13 -1
  8. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +9 -8
  9. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +5 -4
  10. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb +2 -2
  11. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +2 -3
  12. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb +2 -2
  13. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +4 -2
  14. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +6 -3
  15. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/table.rb +1 -0
  16. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb +2 -1
  17. data/lib/dynamoid/application_time_zone.rb +1 -0
  18. data/lib/dynamoid/associations.rb +182 -19
  19. data/lib/dynamoid/associations/association.rb +10 -2
  20. data/lib/dynamoid/associations/belongs_to.rb +2 -1
  21. data/lib/dynamoid/associations/has_and_belongs_to_many.rb +2 -1
  22. data/lib/dynamoid/associations/has_many.rb +2 -1
  23. data/lib/dynamoid/associations/has_one.rb +2 -1
  24. data/lib/dynamoid/associations/many_association.rb +68 -23
  25. data/lib/dynamoid/associations/single_association.rb +31 -4
  26. data/lib/dynamoid/components.rb +1 -0
  27. data/lib/dynamoid/config.rb +5 -5
  28. data/lib/dynamoid/config/backoff_strategies/constant_backoff.rb +1 -0
  29. data/lib/dynamoid/config/backoff_strategies/exponential_backoff.rb +1 -0
  30. data/lib/dynamoid/config/options.rb +1 -0
  31. data/lib/dynamoid/criteria.rb +9 -1
  32. data/lib/dynamoid/criteria/chain.rb +422 -46
  33. data/lib/dynamoid/criteria/ignored_conditions_detector.rb +3 -3
  34. data/lib/dynamoid/criteria/key_fields_detector.rb +32 -11
  35. data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +3 -2
  36. data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +1 -1
  37. data/lib/dynamoid/dirty.rb +119 -64
  38. data/lib/dynamoid/document.rb +125 -43
  39. data/lib/dynamoid/dumping.rb +9 -0
  40. data/lib/dynamoid/dynamodb_time_zone.rb +1 -0
  41. data/lib/dynamoid/errors.rb +2 -0
  42. data/lib/dynamoid/fields.rb +217 -36
  43. data/lib/dynamoid/fields/declare.rb +86 -0
  44. data/lib/dynamoid/finders.rb +69 -32
  45. data/lib/dynamoid/identity_map.rb +6 -0
  46. data/lib/dynamoid/indexes.rb +86 -17
  47. data/lib/dynamoid/loadable.rb +2 -2
  48. data/lib/dynamoid/log/formatter.rb +26 -0
  49. data/lib/dynamoid/middleware/identity_map.rb +1 -0
  50. data/lib/dynamoid/persistence.rb +496 -104
  51. data/lib/dynamoid/persistence/import.rb +1 -0
  52. data/lib/dynamoid/persistence/save.rb +1 -0
  53. data/lib/dynamoid/persistence/update_fields.rb +5 -2
  54. data/lib/dynamoid/persistence/update_validations.rb +18 -0
  55. data/lib/dynamoid/persistence/upsert.rb +5 -3
  56. data/lib/dynamoid/primary_key_type_mapping.rb +1 -0
  57. data/lib/dynamoid/railtie.rb +1 -0
  58. data/lib/dynamoid/tasks.rb +3 -1
  59. data/lib/dynamoid/tasks/database.rb +1 -0
  60. data/lib/dynamoid/type_casting.rb +12 -2
  61. data/lib/dynamoid/undumping.rb +8 -0
  62. data/lib/dynamoid/validations.rb +6 -1
  63. data/lib/dynamoid/version.rb +1 -1
  64. metadata +48 -74
  65. data/.coveralls.yml +0 -1
  66. data/.document +0 -5
  67. data/.gitignore +0 -74
  68. data/.rspec +0 -2
  69. data/.rubocop.yml +0 -71
  70. data/.rubocop_todo.yml +0 -55
  71. data/.travis.yml +0 -44
  72. data/Appraisals +0 -22
  73. data/Gemfile +0 -8
  74. data/Rakefile +0 -46
  75. data/Vagrantfile +0 -29
  76. data/docker-compose.yml +0 -7
  77. data/dynamoid.gemspec +0 -57
  78. data/gemfiles/rails_4_2.gemfile +0 -9
  79. data/gemfiles/rails_5_0.gemfile +0 -8
  80. data/gemfiles/rails_5_1.gemfile +0 -8
  81. data/gemfiles/rails_5_2.gemfile +0 -8
  82. data/gemfiles/rails_6_0.gemfile +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7dd36d27f502c400c3275bf584ce8eba095b32732db1b9567ad9a3ceac64eb50
4
- data.tar.gz: '084f10baa66c9d22febfaa884f410be5222774283d58fda3f237c7b9b204c572'
3
+ metadata.gz: bc5c35cc32f9e77598030b980baff43156095b9480be6984d67e2cb5116fae47
4
+ data.tar.gz: 7b8ff766d64bf83096bf641f7ca641ab15974f451481a215cf63b69597cf4126
5
5
  SHA512:
6
- metadata.gz: 43ac82ed7d651e4b92845bf08f372ca57bf7b3bde0c3f49a3afbc7b6cbd1125574938472d6041627882e82c90379e5063ecd285d0092761cb4a5c209f9041510
7
- data.tar.gz: 2a7f71ed8470bfce21a0b1c761d99681f02bbd797be65b2a4fe21ea72c54b7c22e52571f43ddcbedf980ab24ac26a4b54df1c41fd464f2cc1bdd7ac10817df33
6
+ metadata.gz: 0f4ac62013723a6880583471808d823cdbd4b84944357249a4dbad7b4087cf32bffc53880ec599c2f5fd61b07136ce7f7be05677fdc0aedf80ae3cf3c2b7b0ee
7
+ data.tar.gz: 3da0f1ffa1225c5233032330d6d1b9c5e2da60979770b42faecbd8141fd8bd5b9520767c2cc01beb5cee8a7979996cdaa53c3a03c49815c3b01dd23c8dabbb37
data/CHANGELOG.md CHANGED
@@ -1,12 +1,103 @@
1
1
  # HEAD
2
2
 
3
- ## Breaking
3
+ ---
4
+
5
+
6
+
7
+ # 3.7.1 / 2021-06-30
8
+
9
+ ## Fixes
10
+
11
+ * [#484](https://github.com/Dynamoid/dynamoid/pull/484) Fix model deletion - update cached foreign keys in associated models when delete a model
12
+ * [#492](https://github.com/Dynamoid/dynamoid/pull/492) Fix using `:date` field as an index hash/range key (@yoshida-eth0)
13
+ * [#503](https://github.com/Dynamoid/dynamoid/pull/503) Fix explicit forcing index with `#with_index` method when perform Scan operation (@bmalinconico)
14
+ * [#511](https://github.com/Dynamoid/dynamoid/pull/511) Fix `BatchGetItem` operation when partial result returned (so there are unprocessed keys) and table has a range key. The fix affects `.find_all` method only (@Bajena)
15
+
16
+
17
+
18
+ # 3.7.0 / 2021-02-02
19
+
4
20
 
5
21
  ## Features
6
22
 
23
+ * [#476](https://github.com/Dynamoid/dynamoid/pull/476) Added `#with_index` method to force an index in query (@bmalinconico)
24
+ * [#481](https://github.com/Dynamoid/dynamoid/pull/481) Added `alias` option to the `field` method to declare a field alias and use more conventional name to set and get value
25
+
7
26
  ## Improvements
8
27
 
28
+ * [#482](https://github.com/Dynamoid/dynamoid/pull/482) Support Ruby 3.0 and Rails 6.1
29
+ * [#461](https://github.com/Dynamoid/dynamoid/pull/461) Allow to delete item attribute with `#update` method (@jkirsteins)
30
+ * [#463](https://github.com/Dynamoid/dynamoid/pull/463) Raise `UnknownAttribute` exception when specified not declared attribute name (@AlexGascon)
31
+
32
+ ## Fixes
33
+
34
+ * [#480](https://github.com/Dynamoid/dynamoid/pull/480) Repair `.consistent`/`.delete_all`/`.destroy_all` calls directly on a model class
35
+ * [#484](https://github.com/Dynamoid/dynamoid/pull/484) Fix broken foreign keys after model deleting (@kkan)
36
+ * Fixes in Readme.md: [#470](https://github.com/Dynamoid/dynamoid/pull/470) (@rromanchuk), [#473](https://github.com/Dynamoid/dynamoid/pull/473) (@Rulikkk)
37
+
38
+ ---
39
+
40
+
41
+
42
+ # 3.6.0 / 2020-07-13
43
+
44
+
45
+ ## Features
46
+
47
+ * [#458](https://github.com/Dynamoid/dynamoid/pull/458) Added `binary` field type
48
+ * [#459](https://github.com/Dynamoid/dynamoid/pull/459) Added `log_formatter` config option and changed default logging format
49
+
50
+ ## Improvements
51
+
52
+ * [#423](https://github.com/Dynamoid/dynamoid/pull/423) Added warning when generated for a field methods override existing ones
53
+ * [#429](https://github.com/Dynamoid/dynamoid/pull/429) Added `raise_error` option for `find` method
54
+ * [#440](https://github.com/Dynamoid/dynamoid/pull/440) Optimized performance of `first` method when there are only conditions on key attribute in a query (@mrkamel)
55
+ * [#445](https://github.com/Dynamoid/dynamoid/pull/445) Support `limit` parameter in `first` method (@mrkamel)
56
+ * [#450](https://github.com/Dynamoid/dynamoid/pull/450) Got rid of `null-logger` gem to make Dynamoid dependencies license suitable for commercial use (@yakjuly)
57
+ * [#454](https://github.com/Dynamoid/dynamoid/pull/454) Added block argument to `create`/`create!` methods
58
+ * [#456](https://github.com/Dynamoid/dynamoid/pull/456) Detect when `find` method requires a range key argument and raise `Dynamoid::Errors::MissingRangeKey` exception if it's missing
59
+ * YARD documentation:
60
+ * added missing documentation so now all the public methods are documented
61
+ * hid all the private methods and classes
62
+
63
+ ## Fixes
64
+
65
+ * [#425](https://github.com/Dynamoid/dynamoid/pull/425) Fixed typos in the README.md file (@omarsotillo)
66
+ * [#432](https://github.com/Dynamoid/dynamoid/pull/432) Support tables that use "hash_key" as their partition key name (@remomueller)
67
+ * [#434](https://github.com/Dynamoid/dynamoid/pull/434) Support tables that have attribute with name "range_value"
68
+ * [#453](https://github.com/Dynamoid/dynamoid/pull/453) Fixed issue with using `type` attribute as a GSI hash key
69
+
70
+ ---
71
+
72
+
73
+
74
+ # 3.5.0 / 2020-04-04
75
+
76
+
77
+ ## Features
78
+ * Feature: [#405](https://github.com/Dynamoid/dynamoid/pull/405) Added `update!` class method (@UrsaDK)
79
+ * Feature: [#408](https://github.com/Dynamoid/dynamoid/pull/408) Added `ActiveSupport` load hook on `Dynamoid` load (@aaronmallen)
80
+ * Feature: [#422](https://github.com/Dynamoid/dynamoid/pull/422) Added `.pluck` method
81
+
82
+ ## Fixes:
83
+ * Fix: [#410](https://github.com/Dynamoid/dynamoid/pull/410) Fixed creating GSI when table uses on-demand capacity provisioning (@icy-arctic-fox)
84
+ * Fix: [#414](https://github.com/Dynamoid/dynamoid/pull/414) Fixed lazy table creation
85
+ * Fix: [#415](https://github.com/Dynamoid/dynamoid/pull/415) Fixed RubyDoc comment (@walkersumida)
86
+ * Fix: [#420](https://github.com/Dynamoid/dynamoid/pull/420) Fixed `#persisted?` for deleted/destroyed models
87
+
88
+ ## Improvements:
89
+ * Improvement: [#416](https://github.com/Dynamoid/dynamoid/pull/416) Improved speed of Adapter's `truncate` method. It now uses `#batch_delete_item` method (@TheSmartnik)
90
+ * Improvement: [#421](https://github.com/Dynamoid/dynamoid/pull/421) Added `touch: false` option of the #save method
91
+ * Improvement: [#423](https://github.com/Dynamoid/dynamoid/pull/423) Added warning when generated for a field methods override existing ones
92
+
93
+ ---
94
+
95
+
96
+
97
+ # 3.4.1
98
+
9
99
  ## Fixes
100
+ * Fix: [#398](https://github.com/Dynamoid/dynamoid/pull/398) Fix broken configuration
10
101
 
11
102
  ---
12
103
 
@@ -28,8 +119,8 @@
28
119
 
29
120
  ## Fixes
30
121
 
31
- Fix: [#382](https://github.com/Dynamoid/dynamoid/pull/382) Fixed deprecation warning about `Module#parent_name` in Rails 6 (@tmandke)
32
- Fix: Typos in Readme.md (@romeuhcf)
122
+ * Fix: [#382](https://github.com/Dynamoid/dynamoid/pull/382) Fixed deprecation warning about `Module#parent_name` in Rails 6 (@tmandke)
123
+ * Fix: Typos in Readme.md (@romeuhcf)
33
124
 
34
125
  ---
35
126
 
data/README.md CHANGED
@@ -126,8 +126,8 @@ end
126
126
  Dynamoid supports Ruby >= 2.3 and Rails >= 4.2.
127
127
 
128
128
  Its compatibility is tested against following Ruby versions: 2.3, 2.4,
129
- 2.5 and 2.6, JRuby 9.2.8.0 and against Rails versions: 4.2, 5.0, 5.1,
130
- 5.2 and 6.0.
129
+ 2.5, 2.6, 2.7 and 3.0, JRuby 9.2.x and against Rails versions: 4.2, 5.0, 5.1,
130
+ 5.2, 6.0 and 6.1.
131
131
 
132
132
  ## Setup
133
133
 
@@ -212,16 +212,17 @@ each field. Every field on the object must be included here; if you miss
212
212
  any they'll be completely bypassed during DynamoDB's initialization and
213
213
  will not appear on the model objects.
214
214
 
215
- By default, fields are assumed to be of type `:string`. Other built-in
216
- types are `:integer`, `:number`, `:set`, `:array`, `:map`, `:datetime`,
217
- `date`, `:boolean`, `:raw` and `:serialized`. `array` and `map` match
218
- List and Map DynamoDB types respectively. `raw` type means you can store
219
- Ruby Array, Hash, String and numbers. If built-in types do not suit you,
220
- you can use a custom field type represented by an arbitrary class,
221
- provided that the class supports a compatible serialization interface.
222
- The primary use case for using a custom field type is to represent your
223
- business logic with high-level types, while ensuring portability or
224
- backward-compatibility of the serialized representation.
215
+ By default, fields are assumed to be of type `string`. Other built-in
216
+ types are `integer`, `number`, `set`, `array`, `map`, `datetime`,
217
+ `date`, `boolean`, `binary`, `raw` and `serialized`. `array` and
218
+ `map` match List and Map DynamoDB types respectively. `raw` type means
219
+ you can store Ruby Array, Hash, String and numbers. If built-in types do
220
+ not suit you, you can use a custom field type represented by an
221
+ arbitrary class, provided that the class supports a compatible
222
+ serialization interface. The primary use case for using a custom field
223
+ type is to represent your business logic with high-level types, while
224
+ ensuring portability or backward-compatibility of the serialized
225
+ representation.
225
226
 
226
227
  #### Note on boolean type
227
228
 
@@ -232,7 +233,7 @@ easily achieve this with `store_as_native_boolean` field option:
232
233
 
233
234
  ```ruby
234
235
  class Document
235
- include DynamoId::Document
236
+ include Dynamoid::Document
236
237
 
237
238
  field :active, :boolean, store_as_native_boolean: false
238
239
  end
@@ -246,7 +247,7 @@ strings instead then set `store_as_string` to `true`
246
247
 
247
248
  ```ruby
248
249
  class Document
249
- include DynamoId::Document
250
+ include Dynamoid::Document
250
251
 
251
252
  field :sent_on, :date, store_as_string: true
252
253
  end
@@ -261,7 +262,7 @@ as ISO-8601 formatted strings instead then set `store_as_string` to
261
262
 
262
263
  ```ruby
263
264
  class Document
264
- include DynamoId::Document
265
+ include Dynamoid::Document
265
266
 
266
267
  field :sent_at, :datetime, store_as_string: true
267
268
  end
@@ -293,7 +294,7 @@ types.
293
294
 
294
295
  ```ruby
295
296
  class Document
296
- include DynamoId::Document
297
+ include Dynamoid::Document
297
298
 
298
299
  field :tags, :set, of: :integer
299
300
  end
@@ -305,7 +306,7 @@ elements type:
305
306
 
306
307
  ```ruby
307
308
  class Document
308
- include DynamoId::Document
309
+ include Dynamoid::Document
309
310
 
310
311
  field :values, :set, of: { serialized: { serializer: JSON } }
311
312
  field :dates, :set, of: { date: { store_as_string: true } }
@@ -329,7 +330,7 @@ natively, you should specify element type with `of` option:
329
330
 
330
331
  ```ruby
331
332
  class Document
332
- include DynamoId::Document
333
+ include Dynamoid::Document
333
334
 
334
335
  field :dates, :array, of: :date
335
336
  end
@@ -364,6 +365,26 @@ field :actions_taken, :integer, default: 0
364
365
  field :joined_at, :datetime, default: -> { Time.now }
365
366
  ```
366
367
 
368
+ #### Aliases
369
+
370
+ It might be helpful to define an alias for already existing field when
371
+ naming convention used for a table differs from conventions common in
372
+ Ruby:
373
+
374
+ ```ruby
375
+ field firstName, :string, alias: :first_name
376
+ ```
377
+
378
+ This way there will be generated
379
+ setters/getters/`<name>?`/`<name>_before_type_cast` methods for both
380
+ original field name (`firstName`) and an alias (`first_name`).
381
+
382
+ ```ruby
383
+ user = User.new(first_name: 'Michael')
384
+ user.first_name # => 'Michael'
385
+ user.firstName # => 'Michael'
386
+ ```
387
+
367
388
  #### Custom Types
368
389
 
369
390
  To use a custom type for a field, suppose you have a `Money` type.
@@ -575,7 +596,7 @@ c.my_new_type
575
596
 
576
597
  ### Type casting
577
598
 
578
- Dynamid supports type casting and tries to do it in the most convenient
599
+ Dynamoid supports type casting and tries to do it in the most convenient
579
600
  way. Values for all fields (except custom type) are coerced to declared
580
601
  field types.
581
602
 
@@ -613,7 +634,7 @@ well.
613
634
 
614
635
  ### Dirty API
615
636
 
616
- Dynamoid supports Dirty API which equivalents to [Rails 5.2
637
+ Dynamoid supports Dirty API which is equivalent to [Rails 5.2
617
638
  `ActiveModel::Dirty`](https://api.rubyonrails.org/v5.2/classes/ActiveModel/Dirty.html).
618
639
  There is only one limitation - change in place of field isn't detected
619
640
  automatically.
@@ -631,7 +652,7 @@ u.email = 'josh@joshsymonds.com'
631
652
  u.save
632
653
  ```
633
654
 
634
- Save forces persistence to the datastore: a unique ID is also assigned,
655
+ Save forces persistence to the data store: a unique ID is also assigned,
635
656
  but it is a string and not an auto-incrementing number.
636
657
 
637
658
  ```ruby
@@ -762,7 +783,7 @@ for requesting documents in batches:
762
783
 
763
784
  ```ruby
764
785
  # Do some maintenance on the entire table without flooding DynamoDB
765
- Address.all(batch_size: 100).each { |address| address.do_some_work; sleep(0.01) }
786
+ Address.batch(100).each { |address| address.do_some_work; sleep(0.01) }
766
787
  Address.record_limit(10_000).batch(100).each { … } # Batch specified as part of a chain
767
788
  ```
768
789
 
@@ -1068,7 +1089,7 @@ Listed below are all configuration options.
1068
1089
  * `models_dir` - `dynamoid:create_tables` rake task loads DynamoDb
1069
1090
  models from this directory. Default is `./app/models`.
1070
1091
  * `application_timezone` - Dynamoid converts all `datetime` fields to
1071
- * specified time zone when loads data from the storage.
1092
+ specified time zone when loads data from the storage.
1072
1093
  Acceptable values - `:utc`, `:local` (to use system time zone) and
1073
1094
  time zone name e.g. `Eastern Time (US & Canada)`. Default is `utc`
1074
1095
  * `dynamodb_timezone` - When a datetime field is stored in string format
@@ -1088,6 +1109,11 @@ Listed below are all configuration options.
1088
1109
  `nil`
1089
1110
  * `backoff_strategies`: is a hash and contains all available strategies.
1090
1111
  Default is { constant: ..., exponential: ...}
1112
+ * `log_formatter`: overrides default AWS SDK formatter. There are
1113
+ several canned formatters: `Aws::Log::Formatter.default`,
1114
+ `Aws::Log::Formatter.colored` and `Aws::Log::Formatter.short`. Please
1115
+ look into `Aws::Log::Formatter` AWS SDK documentation in order to
1116
+ provide own formatter.
1091
1117
  * `http_continue_timeout`: The number of seconds to wait for a
1092
1118
  100-continue HTTP response before sending the request body. Default
1093
1119
  option value is `nil`. If not specified effected value is `1`
@@ -1261,7 +1287,7 @@ class User
1261
1287
  end
1262
1288
 
1263
1289
  Dynamoid.config.logger.level = :debug
1264
- Dynamoid.config.endpoint = 'localhost:8000'
1290
+ Dynamoid.config.endpoint = 'http://localhost:8000'
1265
1291
 
1266
1292
  User.create(name: 'Alex')
1267
1293
 
@@ -1336,12 +1362,12 @@ environment.
1336
1362
 
1337
1363
  If you want to run all the specs that travis runs, use `bundle exec
1338
1364
  wwtd`, but first you will need to setup all the rubies, for each of `%w(
1339
- 2.0.0-p648 2.1.10 2.2.6 2.3.3 2.4.1 jruby-9.1.8.0 )`. When you run
1365
+ 2.3.8 2.4.6 2.5.5 2.6.3 2.7.0 3.0.0 9.2.14.0)`. When you run
1340
1366
  `bundle exec wwtd` it will take care of starting and stopping the local
1341
1367
  dynamodb instance.
1342
1368
 
1343
1369
  ```shell
1344
- rvm use 2.0.0-p648
1370
+ rvm use 3.0.0
1345
1371
  gem install rubygems-update
1346
1372
  gem install bundler
1347
1373
  bundle install
data/lib/dynamoid.rb CHANGED
@@ -57,6 +57,7 @@ module Dynamoid
57
57
  @included_models ||= []
58
58
  end
59
59
 
60
+ # @private
60
61
  def adapter
61
62
  @adapter ||= Adapter.new
62
63
  end
@@ -3,7 +3,7 @@
3
3
  # require only 'concurrent/atom' once this issue is resolved:
4
4
  # https://github.com/ruby-concurrency/concurrent-ruby/pull/377
5
5
  require 'concurrent'
6
- require "dynamoid/adapter_plugin/aws_sdk_v3"
6
+ require 'dynamoid/adapter_plugin/aws_sdk_v3'
7
7
 
8
8
  # encoding: utf-8
9
9
  module Dynamoid
@@ -11,6 +11,7 @@ module Dynamoid
11
11
  # 1) For the rest of Dynamoid, the gateway to DynamoDB.
12
12
  # 2) Allows switching `config.adapter` to ease development of a new adapter.
13
13
  # 3) Caches the list of tables Dynamoid knows about.
14
+ # @private
14
15
  class Adapter
15
16
  def initialize
16
17
  @adapter_ = Concurrent::Atom.new(nil)
@@ -78,8 +79,8 @@ module Dynamoid
78
79
  #
79
80
  # @param [String] table the name of the table to write the object to
80
81
  # @param [Array] ids to fetch, can also be a string of just one id
81
- # @param [Hash] options: Passed to the underlying query. The :range_key option is required whenever the table has a range key,
82
- # unless multiple ids are passed in.
82
+ # @param [Hash] options Passed to the underlying query. The :range_key option is required whenever the table has a range key,
83
+ # unless multiple ids are passed in.
83
84
  #
84
85
  # @since 0.2.0
85
86
  def read(table, ids, options = {}, &blk)
@@ -94,7 +95,9 @@ module Dynamoid
94
95
  #
95
96
  # @param [String] table the name of the table to write the object to
96
97
  # @param [Array] ids to delete, can also be a string of just one id
97
- # @param [Array] range_key of the record to delete, can also be a string of just one range_key
98
+ # @param [Hash] options allowed only +range_key+ - range key or array of
99
+ # range keys of the record to delete, can also be
100
+ # a string of just one range_key, and +conditions+
98
101
  #
99
102
  def delete(table, ids, options = {})
100
103
  range_key = options[:range_key] # array of range keys that matches the ids passed in
@@ -115,7 +118,7 @@ module Dynamoid
115
118
  # Scans a table. Generally quite slow; try to avoid using scan if at all possible.
116
119
  #
117
120
  # @param [String] table the name of the table to write the object to
118
- # @param [Hash] scan_hash a hash of attributes: matching records will be returned by the scan
121
+ # @param [Hash] query a hash of attributes: matching records will be returned by the scan
119
122
  #
120
123
  # @since 0.2.0
121
124
  def scan(table, query = {}, opts = {})
@@ -155,8 +158,14 @@ module Dynamoid
155
158
  #
156
159
  # @since 0.2.0
157
160
  def method_missing(method, *args, &block)
158
- return benchmark(method, *args) { adapter.send(method, *args, &block) } if adapter.respond_to?(method)
161
+ # Don't use keywork arguments delegating (with **kw). It works in
162
+ # different way in different Ruby versions: <= 2.6, 2.7, 3.0 and in some
163
+ # future 3.x versions. Providing that there are no downstream methods
164
+ # with keyword arguments in adapter.
165
+ #
166
+ # https://eregon.me/blog/2019/11/10/the-delegation-challenge-of-ruby27.html
159
167
 
168
+ return benchmark(method, *args) { adapter.send(method, *args, &block) } if adapter.respond_to?(method)
160
169
  super
161
170
  end
162
171
 
@@ -9,8 +9,18 @@ require_relative 'aws_sdk_v3/table'
9
9
  require_relative 'aws_sdk_v3/until_past_table_status'
10
10
 
11
11
  module Dynamoid
12
+ # @private
12
13
  module AdapterPlugin
13
14
  # The AwsSdkV3 adapter provides support for the aws-sdk version 2 for ruby.
15
+
16
+ # Note: Don't use keyword arguments in public methods as far as method
17
+ # calls on adapter are delegated to the plugin.
18
+ #
19
+ # There are breaking changes in Ruby related to delegating keyword
20
+ # arguments so we have decided just to avoid them when use delegation.
21
+ #
22
+ # https://eregon.me/blog/2019/11/10/the-delegation-challenge-of-ruby27.html
23
+
14
24
  class AwsSdkV3
15
25
  EQ = 'EQ'
16
26
  RANGE_MAP = {
@@ -61,6 +71,25 @@ module Dynamoid
61
71
 
62
72
  attr_reader :table_cache
63
73
 
74
+ # Build an array of values for Condition
75
+ # Is used in ScanFilter and QueryFilter
76
+ # https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html
77
+ # @param [String] operator value of RANGE_MAP or FIELD_MAP hash, e.g. "EQ", "LT" etc
78
+ # @param [Object] value scalar value or array/set
79
+ def self.attribute_value_list(operator, value)
80
+ # For BETWEEN and IN operators we should keep value as is (it should be already an array)
81
+ # NULL and NOT_NULL require absence of attribute list
82
+ # For all the other operators we wrap the value with array
83
+ # https://docs.aws.amazon.com/en_us/amazondynamodb/latest/developerguide/LegacyConditionalParameters.Conditions.html
84
+ if %w[BETWEEN IN].include?(operator)
85
+ [value].flatten
86
+ elsif %w[NULL NOT_NULL].include?(operator)
87
+ nil
88
+ else
89
+ [value]
90
+ end
91
+ end
92
+
64
93
  # Establish the connection to DynamoDB.
65
94
  #
66
95
  # @return [Aws::DynamoDB::Client] the DynamoDB connection
@@ -78,23 +107,25 @@ module Dynamoid
78
107
 
79
108
  # if credentials are passed, they already contain access key & secret key
80
109
  if Dynamoid::Config.credentials?
81
- connection_hash[:credentials] = Dynamoid::Config.credentials
110
+ @connection_hash[:credentials] = Dynamoid::Config.credentials
82
111
  else
83
112
  # otherwise, pass access key & secret key for credentials creation
84
113
  if Dynamoid::Config.access_key?
85
- connection_hash[:access_key_id] = Dynamoid::Config.access_key
114
+ @connection_hash[:access_key_id] = Dynamoid::Config.access_key
86
115
  end
87
116
  if Dynamoid::Config.secret_key?
88
- connection_hash[:secret_access_key] = Dynamoid::Config.secret_key
117
+ @connection_hash[:secret_access_key] = Dynamoid::Config.secret_key
89
118
  end
90
119
  end
91
120
 
92
- # https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-core/lib/aws-sdk-core/plugins/logging.rb
93
- # https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-core/lib/aws-sdk-core/log/formatter.rb
94
- formatter = Aws::Log::Formatter.new(':operation | Request :http_request_body | Response :http_response_body')
95
121
  @connection_hash[:logger] = Dynamoid::Config.logger
96
122
  @connection_hash[:log_level] = :debug
97
- @connection_hash[:log_formatter] = formatter
123
+
124
+ # https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-core/lib/aws-sdk-core/plugins/logging.rb
125
+ # https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-core/lib/aws-sdk-core/log/formatter.rb
126
+ if Dynamoid::Config.log_formatter
127
+ @connection_hash[:log_formatter] = Dynamoid::Config.log_formatter
128
+ end
98
129
 
99
130
  @connection_hash
100
131
  end
@@ -122,9 +153,9 @@ module Dynamoid
122
153
  # end
123
154
  #
124
155
  # @param [String] table_name the name of the table
125
- # @param [Array] items to be processed
126
- # @param [Hash] additional options
127
- # @param [Proc] optional block
156
+ # @param [Array] objects to be processed
157
+ # @param [Hash] options additional options
158
+ # @yield [true|false] invokes an optional block with argument - whether there are unprocessed items
128
159
  #
129
160
  # See:
130
161
  # * http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html
@@ -179,9 +210,9 @@ module Dynamoid
179
210
  # end
180
211
  # end
181
212
  #
182
- # @param [Hash] table_ids the hash of tables and IDs to retrieve
213
+ # @param [Hash] table_names_with_ids the hash of tables and IDs to retrieve
183
214
  # @param [Hash] options to be passed to underlying BatchGet call
184
- # @param [Proc] optional block can be passed to handle each batch of items
215
+ # @param [Proc] block optional block can be passed to handle each batch of items
185
216
  #
186
217
  # @return [Hash] a hash where keys are the table names and the values are the retrieved items
187
218
  #
@@ -259,7 +290,7 @@ module Dynamoid
259
290
  false
260
291
  end
261
292
 
262
- def update_time_to_live(table_name:, attribute:)
293
+ def update_time_to_live(table_name, attribute)
263
294
  request = {
264
295
  table_name: table_name,
265
296
  time_to_live_specification: {
@@ -525,11 +556,11 @@ module Dynamoid
525
556
  hk = table.hash_key
526
557
  rk = table.range_key
527
558
 
528
- scan(table_name, {}, {}).flat_map{ |i| i }.each do |attributes|
529
- opts = {}
530
- opts[:range_key] = attributes[rk.to_sym] if rk
531
- delete_item(table_name, attributes[hk], opts)
559
+ ids = scan(table_name, {}, {}).flat_map { |i| i }.map do |attributes|
560
+ rk ? [attributes[hk], attributes[rk.to_sym]] : attributes[hk]
532
561
  end
562
+
563
+ batch_delete_item(table_name => ids)
533
564
  end
534
565
 
535
566
  def count(table_name)
@@ -587,25 +618,6 @@ module Dynamoid
587
618
  end
588
619
  end
589
620
 
590
- # Build an array of values for Condition
591
- # Is used in ScanFilter and QueryFilter
592
- # https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html
593
- # @params [String] operator: value of RANGE_MAP or FIELD_MAP hash, e.g. "EQ", "LT" etc
594
- # @params [Object] value: scalar value or array/set
595
- def self.attribute_value_list(operator, value)
596
- # For BETWEEN and IN operators we should keep value as is (it should be already an array)
597
- # NULL and NOT_NULL require absence of attribute list
598
- # For all the other operators we wrap the value with array
599
- # https://docs.aws.amazon.com/en_us/amazondynamodb/latest/developerguide/LegacyConditionalParameters.Conditions.html
600
- if %w[BETWEEN IN].include?(operator)
601
- [value].flatten
602
- elsif %w[NULL NOT_NULL].include?(operator)
603
- nil
604
- else
605
- [value]
606
- end
607
- end
608
-
609
621
  def sanitize_item(attributes)
610
622
  config_value = Dynamoid.config.store_attribute_with_nil_value
611
623
  store_attribute_with_nil_value = config_value.nil? ? false : !!config_value