dynamoid 3.4.1 → 3.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/lib/dynamoid/adapter.rb +2 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +23 -23
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/batch_get_item.rb +2 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +1 -1
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb +1 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +1 -3
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb +1 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +3 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +3 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb +1 -1
- data/lib/dynamoid/config.rb +2 -3
- data/lib/dynamoid/criteria.rb +1 -1
- data/lib/dynamoid/criteria/chain.rb +37 -12
- data/lib/dynamoid/criteria/ignored_conditions_detector.rb +2 -3
- data/lib/dynamoid/criteria/key_fields_detector.rb +7 -8
- data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +2 -2
- data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +0 -1
- data/lib/dynamoid/dirty.rb +50 -50
- data/lib/dynamoid/document.rb +2 -1
- data/lib/dynamoid/fields.rb +14 -1
- data/lib/dynamoid/finders.rb +4 -4
- data/lib/dynamoid/indexes.rb +2 -2
- data/lib/dynamoid/persistence.rb +32 -6
- data/lib/dynamoid/persistence/upsert.rb +0 -1
- data/lib/dynamoid/tasks.rb +3 -1
- data/lib/dynamoid/type_casting.rb +0 -2
- data/lib/dynamoid/version.rb +1 -1
- metadata +40 -56
- data/.coveralls.yml +0 -1
- data/.document +0 -5
- data/.gitignore +0 -74
- data/.rspec +0 -2
- data/.rubocop.yml +0 -71
- data/.rubocop_todo.yml +0 -55
- data/.travis.yml +0 -44
- data/Appraisals +0 -22
- data/Gemfile +0 -8
- data/Rakefile +0 -46
- data/Vagrantfile +0 -29
- data/docker-compose.yml +0 -7
- data/dynamoid.gemspec +0 -57
- data/gemfiles/rails_4_2.gemfile +0 -9
- data/gemfiles/rails_5_0.gemfile +0 -8
- data/gemfiles/rails_5_1.gemfile +0 -8
- data/gemfiles/rails_5_2.gemfile +0 -8
- data/gemfiles/rails_6_0.gemfile +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16a6980d441040611894ad405ce797b6ef655e9e2730b010d72ff3e65771129f
|
4
|
+
data.tar.gz: 1ca556953abc411f0b7e2fd5e5c74518a7da4381b86449b2f49e81d9f76ee0a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71856592a8a381b27517682c6ce7bb48047de11dc2fbb17c175af629d3ec7e2b63895e9b24c943b57a93e47db0b1de390454b5a89d71899a59c9208a79e0595e
|
7
|
+
data.tar.gz: 8cd759df57475c7566ef0ceae781d21eb443cb1dcd0f6da0f3eaa778fe6a3abeac8865a1198a2dbd2f435eec2cb5317b47ce5e5bd5b9dadbe7537a412053492b
|
data/CHANGELOG.md
CHANGED
@@ -11,6 +11,30 @@
|
|
11
11
|
---
|
12
12
|
|
13
13
|
|
14
|
+
|
15
|
+
# 3.5 / 2020-04-04
|
16
|
+
|
17
|
+
|
18
|
+
## Features
|
19
|
+
* Feature: [#405](https://github.com/Dynamoid/dynamoid/pull/405) Added `update!` class method (@UrsaDK)
|
20
|
+
* Feature: [#408](https://github.com/Dynamoid/dynamoid/pull/408) Added `ActiveSupport` load hook on `Dynamoid` load (@aaronmallen)
|
21
|
+
* Feature: [#422](https://github.com/Dynamoid/dynamoid/pull/422) Added `.pluck` method
|
22
|
+
|
23
|
+
Fixes:
|
24
|
+
* Fix: [#410](https://github.com/Dynamoid/dynamoid/pull/410) Fixed creating GSI when table uses on-demand capacity provisioning (@icy-arctic-fox)
|
25
|
+
* Fix: [#414](https://github.com/Dynamoid/dynamoid/pull/414) Fixed lazy table creation
|
26
|
+
* Fix: [#415](https://github.com/Dynamoid/dynamoid/pull/415) Fixed RubyDoc comment (@walkersumida)
|
27
|
+
* Fix: [#420](https://github.com/Dynamoid/dynamoid/pull/420) Fixed `#persisted?` for deleted/destroyed models
|
28
|
+
|
29
|
+
Improvements:
|
30
|
+
* Improvement: [#416](https://github.com/Dynamoid/dynamoid/pull/416) Improved speed of Adapter's `truncate` method. It now uses `#batch_delete_item` method (@TheSmartnik)
|
31
|
+
* Improvement: [#421](https://github.com/Dynamoid/dynamoid/pull/421) Added `touch: false` option of the #save method
|
32
|
+
* Improvement: [#423](https://github.com/Dynamoid/dynamoid/pull/423) Added warning when generated for a field methods override existing ones
|
33
|
+
|
34
|
+
---
|
35
|
+
|
36
|
+
|
37
|
+
|
14
38
|
# 3.4.1
|
15
39
|
|
16
40
|
## Fixes
|
data/lib/dynamoid/adapter.rb
CHANGED
@@ -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
|
6
|
+
require 'dynamoid/adapter_plugin/aws_sdk_v3'
|
7
7
|
|
8
8
|
# encoding: utf-8
|
9
9
|
module Dynamoid
|
@@ -94,7 +94,7 @@ module Dynamoid
|
|
94
94
|
#
|
95
95
|
# @param [String] table the name of the table to write the object to
|
96
96
|
# @param [Array] ids to delete, can also be a string of just one id
|
97
|
-
# @param [
|
97
|
+
# @param [Hash] range_key of the record to delete, can also be a string of just one range_key
|
98
98
|
#
|
99
99
|
def delete(table, ids, options = {})
|
100
100
|
range_key = options[:range_key] # array of range keys that matches the ids passed in
|
@@ -61,6 +61,25 @@ module Dynamoid
|
|
61
61
|
|
62
62
|
attr_reader :table_cache
|
63
63
|
|
64
|
+
# Build an array of values for Condition
|
65
|
+
# Is used in ScanFilter and QueryFilter
|
66
|
+
# https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html
|
67
|
+
# @params [String] operator: value of RANGE_MAP or FIELD_MAP hash, e.g. "EQ", "LT" etc
|
68
|
+
# @params [Object] value: scalar value or array/set
|
69
|
+
def self.attribute_value_list(operator, value)
|
70
|
+
# For BETWEEN and IN operators we should keep value as is (it should be already an array)
|
71
|
+
# NULL and NOT_NULL require absence of attribute list
|
72
|
+
# For all the other operators we wrap the value with array
|
73
|
+
# https://docs.aws.amazon.com/en_us/amazondynamodb/latest/developerguide/LegacyConditionalParameters.Conditions.html
|
74
|
+
if %w[BETWEEN IN].include?(operator)
|
75
|
+
[value].flatten
|
76
|
+
elsif %w[NULL NOT_NULL].include?(operator)
|
77
|
+
nil
|
78
|
+
else
|
79
|
+
[value]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
64
83
|
# Establish the connection to DynamoDB.
|
65
84
|
#
|
66
85
|
# @return [Aws::DynamoDB::Client] the DynamoDB connection
|
@@ -525,11 +544,11 @@ module Dynamoid
|
|
525
544
|
hk = table.hash_key
|
526
545
|
rk = table.range_key
|
527
546
|
|
528
|
-
scan(table_name, {}, {}).flat_map{ |i| i }.
|
529
|
-
|
530
|
-
opts[:range_key] = attributes[rk.to_sym] if rk
|
531
|
-
delete_item(table_name, attributes[hk], opts)
|
547
|
+
ids = scan(table_name, {}, {}).flat_map { |i| i }.map do |attributes|
|
548
|
+
rk ? [attributes[hk], attributes[rk.to_sym]] : attributes[hk]
|
532
549
|
end
|
550
|
+
|
551
|
+
batch_delete_item(table_name => ids)
|
533
552
|
end
|
534
553
|
|
535
554
|
def count(table_name)
|
@@ -587,25 +606,6 @@ module Dynamoid
|
|
587
606
|
end
|
588
607
|
end
|
589
608
|
|
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
609
|
def sanitize_item(attributes)
|
610
610
|
config_value = Dynamoid.config.store_attribute_with_nil_value
|
611
611
|
store_attribute_with_nil_value = config_value.nil? ? false : !!config_value
|
@@ -213,7 +213,7 @@ module Dynamoid
|
|
213
213
|
end
|
214
214
|
|
215
215
|
# Only global secondary indexes have a separate throughput.
|
216
|
-
if index.type == :global_secondary
|
216
|
+
if index.type == :global_secondary && options[:billing_mode] != :on_demand
|
217
217
|
hash[:provisioned_throughput] = {
|
218
218
|
read_capacity_units: index.read_capacity,
|
219
219
|
write_capacity_units: index.write_capacity
|
@@ -29,8 +29,8 @@ module Dynamoid
|
|
29
29
|
request = build_request
|
30
30
|
|
31
31
|
Enumerator.new do |yielder|
|
32
|
-
api_call =
|
33
|
-
client.query(
|
32
|
+
api_call = lambda do |req|
|
33
|
+
client.query(req).tap do |response|
|
34
34
|
yielder << response
|
35
35
|
end
|
36
36
|
end
|
@@ -122,6 +122,7 @@ module Dynamoid
|
|
122
122
|
|
123
123
|
def attributes_to_get
|
124
124
|
return if options[:project].nil?
|
125
|
+
|
125
126
|
options[:project].map(&:to_s)
|
126
127
|
end
|
127
128
|
end
|
@@ -21,8 +21,8 @@ module Dynamoid
|
|
21
21
|
request = build_request
|
22
22
|
|
23
23
|
Enumerator.new do |yielder|
|
24
|
-
api_call =
|
25
|
-
client.scan(
|
24
|
+
api_call = lambda do |req|
|
25
|
+
client.scan(req).tap do |response|
|
26
26
|
yielder << response
|
27
27
|
end
|
28
28
|
end
|
@@ -85,6 +85,7 @@ module Dynamoid
|
|
85
85
|
|
86
86
|
def attributes_to_get
|
87
87
|
return if options[:project].nil?
|
88
|
+
|
88
89
|
options[:project].map(&:to_s)
|
89
90
|
end
|
90
91
|
end
|
@@ -32,7 +32,7 @@ module Dynamoid
|
|
32
32
|
# See: http://docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#describe_table-instance_method
|
33
33
|
rescue Aws::DynamoDB::Errors::ResourceNotFoundException => e
|
34
34
|
case status
|
35
|
-
when :creating
|
35
|
+
when :creating
|
36
36
|
if counter >= Dynamoid::Config.sync_retry_max_times
|
37
37
|
Dynamoid.logger.warn "Waiting on table metadata for #{table_name} (check #{counter})"
|
38
38
|
retry # start over at first line of begin, does not reset counter
|
data/lib/dynamoid/config.rb
CHANGED
@@ -14,9 +14,9 @@ module Dynamoid
|
|
14
14
|
DEFAULT_NAMESPACE = if defined?(Rails)
|
15
15
|
klass = Rails.application.class
|
16
16
|
app_name = Rails::VERSION::MAJOR >= 6 ? klass.module_parent_name : klass.parent_name
|
17
|
-
"dynamoid_#{app_name}_#{Rails.env}"
|
17
|
+
"dynamoid_#{app_name}_#{Rails.env}"
|
18
18
|
else
|
19
|
-
'dynamoid'
|
19
|
+
'dynamoid'
|
20
20
|
end
|
21
21
|
|
22
22
|
extend self
|
@@ -95,6 +95,5 @@ module Dynamoid
|
|
95
95
|
backoff_strategies[backoff].call
|
96
96
|
end
|
97
97
|
end
|
98
|
-
|
99
98
|
end
|
100
99
|
end
|
data/lib/dynamoid/criteria.rb
CHANGED
@@ -8,7 +8,7 @@ module Dynamoid
|
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
10
|
module ClassMethods
|
11
|
-
%i[where all first last each record_limit scan_limit batch start scan_index_forward find_by_pages project].each do |meth|
|
11
|
+
%i[where all first last each record_limit scan_limit batch start scan_index_forward find_by_pages project pluck].each do |meth|
|
12
12
|
# Return a criteria chain in response to a method that will begin or end a chain. For more information,
|
13
13
|
# see Dynamoid::Criteria::Chain.
|
14
14
|
#
|
@@ -102,12 +102,12 @@ module Dynamoid
|
|
102
102
|
ranges = []
|
103
103
|
|
104
104
|
if @key_fields_detector.key_present?
|
105
|
-
Dynamoid.adapter.query(source.table_name, range_query).flat_map{ |i| i }.collect do |hash|
|
105
|
+
Dynamoid.adapter.query(source.table_name, range_query).flat_map { |i| i }.collect do |hash|
|
106
106
|
ids << hash[source.hash_key.to_sym]
|
107
107
|
ranges << hash[source.range_key.to_sym] if source.range_key
|
108
108
|
end
|
109
109
|
else
|
110
|
-
Dynamoid.adapter.scan(source.table_name, scan_query, scan_opts).flat_map{ |i| i }.collect do |hash|
|
110
|
+
Dynamoid.adapter.scan(source.table_name, scan_query, scan_opts).flat_map { |i| i }.collect do |hash|
|
111
111
|
ids << hash[source.hash_key.to_sym]
|
112
112
|
ranges << hash[source.range_key.to_sym] if source.range_key
|
113
113
|
end
|
@@ -164,6 +164,20 @@ module Dynamoid
|
|
164
164
|
self
|
165
165
|
end
|
166
166
|
|
167
|
+
def pluck(*args)
|
168
|
+
fields = args.map(&:to_sym)
|
169
|
+
@project = fields
|
170
|
+
|
171
|
+
if fields.many?
|
172
|
+
items.map do |item|
|
173
|
+
fields.map { |key| Undumping.undump_field(item[key], source.attributes[key]) }
|
174
|
+
end.to_a
|
175
|
+
else
|
176
|
+
key = fields.first
|
177
|
+
items.map { |item| Undumping.undump_field(item[key], source.attributes[key]) }.to_a
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
167
181
|
private
|
168
182
|
|
169
183
|
# The actual records referenced by the association.
|
@@ -172,7 +186,12 @@ module Dynamoid
|
|
172
186
|
#
|
173
187
|
# @since 0.2.0
|
174
188
|
def records
|
175
|
-
pages.lazy.flat_map { |
|
189
|
+
pages.lazy.flat_map { |items, _| items }
|
190
|
+
end
|
191
|
+
|
192
|
+
# Raw items like they are stored before type casting
|
193
|
+
def items
|
194
|
+
raw_pages.lazy.flat_map { |items, _| items }
|
176
195
|
end
|
177
196
|
|
178
197
|
# Arrays of records, sized based on the actual pages produced by DynamoDB
|
@@ -181,11 +200,19 @@ module Dynamoid
|
|
181
200
|
#
|
182
201
|
# @since 3.1.0
|
183
202
|
def pages
|
203
|
+
raw_pages.lazy.map do |items, options|
|
204
|
+
models = items.map { |i| source.from_database(i) }
|
205
|
+
[models, options]
|
206
|
+
end.each
|
207
|
+
end
|
208
|
+
|
209
|
+
# Pages of items before type casting
|
210
|
+
def raw_pages
|
184
211
|
if @key_fields_detector.key_present?
|
185
|
-
|
212
|
+
raw_pages_via_query
|
186
213
|
else
|
187
214
|
issue_scan_warning if Dynamoid::Config.warn_on_scan && query.present?
|
188
|
-
|
215
|
+
raw_pages_via_scan
|
189
216
|
end
|
190
217
|
end
|
191
218
|
|
@@ -194,13 +221,12 @@ module Dynamoid
|
|
194
221
|
# @return [Enumerator] an iterator of the found pages. An array of records
|
195
222
|
#
|
196
223
|
# @since 3.1.0
|
197
|
-
def
|
224
|
+
def raw_pages_via_query
|
198
225
|
Enumerator.new do |y|
|
199
226
|
Dynamoid.adapter.query(source.table_name, range_query).each do |items, metadata|
|
200
|
-
page = items.map { |h| source.from_database(h) }
|
201
227
|
options = metadata.slice(:last_evaluated_key)
|
202
228
|
|
203
|
-
y.yield
|
229
|
+
y.yield items, options
|
204
230
|
end
|
205
231
|
end
|
206
232
|
end
|
@@ -210,13 +236,12 @@ module Dynamoid
|
|
210
236
|
# @return [Enumerator] an iterator of the found pages. An array of records
|
211
237
|
#
|
212
238
|
# @since 3.1.0
|
213
|
-
def
|
239
|
+
def raw_pages_via_scan
|
214
240
|
Enumerator.new do |y|
|
215
241
|
Dynamoid.adapter.scan(source.table_name, scan_query, scan_opts).each do |items, metadata|
|
216
|
-
page = items.map { |h| source.from_database(h) }
|
217
242
|
options = metadata.slice(:last_evaluated_key)
|
218
243
|
|
219
|
-
y.yield
|
244
|
+
y.yield items, options
|
220
245
|
end
|
221
246
|
end
|
222
247
|
end
|
@@ -332,7 +357,7 @@ module Dynamoid
|
|
332
357
|
opts.merge(query_opts).merge(consistent_opts)
|
333
358
|
end
|
334
359
|
|
335
|
-
# TODO casting should be operator aware
|
360
|
+
# TODO: casting should be operator aware
|
336
361
|
# e.g. for NULL operator value should be boolean
|
337
362
|
# and isn't related to an attribute own type
|
338
363
|
def type_cast_condition_parameter(key, value)
|
@@ -24,8 +24,8 @@ module Dynamoid
|
|
24
24
|
def ignored_keys
|
25
25
|
@conditions.keys
|
26
26
|
.group_by(&method(:key_to_field))
|
27
|
-
.select { |
|
28
|
-
.flat_map { |
|
27
|
+
.select { |_, ary| ary.size > 1 }
|
28
|
+
.flat_map { |_, ary| ary[0..-2] }
|
29
29
|
end
|
30
30
|
|
31
31
|
def key_to_field(key)
|
@@ -38,4 +38,3 @@ module Dynamoid
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
@@ -3,7 +3,6 @@
|
|
3
3
|
module Dynamoid #:nodoc:
|
4
4
|
module Criteria
|
5
5
|
class KeyFieldsDetector
|
6
|
-
|
7
6
|
class Query
|
8
7
|
def initialize(query_hash)
|
9
8
|
@query_hash = query_hash
|
@@ -71,8 +70,8 @@ module Dynamoid #:nodoc:
|
|
71
70
|
def match_local_secondary_index
|
72
71
|
return unless @query.contain_with_eq_operator?(@source.hash_key)
|
73
72
|
|
74
|
-
lsi = @source.local_secondary_indexes.values.find do |
|
75
|
-
@query.contain?(
|
73
|
+
lsi = @source.local_secondary_indexes.values.find do |i|
|
74
|
+
@query.contain?(i.range_key)
|
76
75
|
end
|
77
76
|
|
78
77
|
if lsi.present?
|
@@ -90,9 +89,9 @@ module Dynamoid #:nodoc:
|
|
90
89
|
# But only do so if projects ALL attributes otherwise we won't
|
91
90
|
# get back full data
|
92
91
|
def match_global_secondary_index_and_sort_key
|
93
|
-
gsi = @source.global_secondary_indexes.values.find do |
|
94
|
-
@query.contain_with_eq_operator?(
|
95
|
-
@query.contain?(
|
92
|
+
gsi = @source.global_secondary_indexes.values.find do |i|
|
93
|
+
@query.contain_with_eq_operator?(i.hash_key) && i.projected_attributes == :all &&
|
94
|
+
@query.contain?(i.range_key)
|
96
95
|
end
|
97
96
|
|
98
97
|
if gsi.present?
|
@@ -113,8 +112,8 @@ module Dynamoid #:nodoc:
|
|
113
112
|
end
|
114
113
|
|
115
114
|
def match_global_secondary_index
|
116
|
-
gsi = @source.global_secondary_indexes.values.find do |
|
117
|
-
@query.contain_with_eq_operator?(
|
115
|
+
gsi = @source.global_secondary_indexes.values.find do |i|
|
116
|
+
@query.contain_with_eq_operator?(i.hash_key) && i.projected_attributes == :all
|
118
117
|
end
|
119
118
|
|
120
119
|
if gsi.present?
|
@@ -19,8 +19,8 @@ module Dynamoid
|
|
19
19
|
fields_list = @nonexistent_fields.map { |s| "`#{s}`" }.join(', ')
|
20
20
|
count = @nonexistent_fields.size
|
21
21
|
|
22
|
-
|
23
|
-
" field #{
|
22
|
+
'where conditions contain nonexistent' \
|
23
|
+
" field #{'name'.pluralize(count)} #{fields_list}"
|
24
24
|
end
|
25
25
|
|
26
26
|
private
|