dynamoid 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.rubocop.yml +18 -0
- data/.travis.yml +5 -3
- data/CHANGELOG.md +15 -0
- data/README.md +113 -63
- data/Vagrantfile +2 -2
- data/docker-compose.yml +1 -1
- data/gemfiles/rails_4_2.gemfile +1 -1
- data/gemfiles/rails_5_0.gemfile +1 -1
- data/gemfiles/rails_5_1.gemfile +1 -1
- data/gemfiles/rails_5_2.gemfile +1 -1
- data/lib/dynamoid/adapter.rb +1 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +26 -395
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +234 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +89 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb +24 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +57 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb +28 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +123 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +85 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/table.rb +52 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb +60 -0
- data/lib/dynamoid/associations/has_and_belongs_to_many.rb +1 -0
- data/lib/dynamoid/associations/has_many.rb +1 -0
- data/lib/dynamoid/associations/has_one.rb +1 -0
- data/lib/dynamoid/associations/single_association.rb +1 -0
- data/lib/dynamoid/criteria.rb +4 -4
- data/lib/dynamoid/criteria/chain.rb +86 -79
- data/lib/dynamoid/criteria/ignored_conditions_detector.rb +41 -0
- data/lib/dynamoid/criteria/key_fields_detector.rb +61 -0
- data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +41 -0
- data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +40 -0
- data/lib/dynamoid/document.rb +18 -13
- data/lib/dynamoid/dumping.rb +52 -40
- data/lib/dynamoid/fields.rb +4 -3
- data/lib/dynamoid/finders.rb +3 -3
- data/lib/dynamoid/persistence.rb +5 -6
- data/lib/dynamoid/primary_key_type_mapping.rb +1 -1
- data/lib/dynamoid/tasks.rb +1 -0
- data/lib/dynamoid/tasks/database.rake +2 -2
- data/lib/dynamoid/type_casting.rb +37 -19
- data/lib/dynamoid/undumping.rb +53 -42
- data/lib/dynamoid/validations.rb +2 -0
- data/lib/dynamoid/version.rb +1 -1
- metadata +17 -5
- data/lib/dynamoid/adapter_plugin/query.rb +0 -144
- data/lib/dynamoid/adapter_plugin/scan.rb +0 -107
@@ -1,144 +0,0 @@
|
|
1
|
-
module Dynamoid
|
2
|
-
module AdapterPlugin
|
3
|
-
class Query
|
4
|
-
OPTIONS_KEYS = [
|
5
|
-
:limit, :hash_key, :hash_value, :range_key, :consistent_read, :scan_index_forward,
|
6
|
-
:select, :index_name, :batch_size, :exclusive_start_key, :record_limit, :scan_limit
|
7
|
-
]
|
8
|
-
|
9
|
-
attr_reader :client, :table, :options, :conditions
|
10
|
-
|
11
|
-
def initialize(client, table, opts = {})
|
12
|
-
@client = client
|
13
|
-
@table = table
|
14
|
-
|
15
|
-
opts = opts.symbolize_keys
|
16
|
-
@options = opts.slice(*OPTIONS_KEYS)
|
17
|
-
@conditions = opts.except(*OPTIONS_KEYS)
|
18
|
-
end
|
19
|
-
|
20
|
-
def call
|
21
|
-
request = build_request
|
22
|
-
|
23
|
-
Enumerator.new do |yielder|
|
24
|
-
record_count = 0
|
25
|
-
scan_count = 0
|
26
|
-
|
27
|
-
backoff = Dynamoid.config.backoff ? Dynamoid.config.build_backoff : nil
|
28
|
-
|
29
|
-
loop do
|
30
|
-
# Adjust the limit down if the remaining record and/or scan limit are
|
31
|
-
# lower to obey limits. We can assume the difference won't be
|
32
|
-
# negative due to break statements below but choose smaller limit
|
33
|
-
# which is why we have 2 separate if statements.
|
34
|
-
# NOTE: Adjusting based on record_limit can cause many HTTP requests
|
35
|
-
# being made. We may want to change this behavior, but it affects
|
36
|
-
# filtering on data with potentially large gaps.
|
37
|
-
# Example:
|
38
|
-
# User.where('created_at.gte' => 1.day.ago).record_limit(1000)
|
39
|
-
# Records 1-999 User's that fit criteria
|
40
|
-
# Records 1000-2000 Users's that do not fit criteria
|
41
|
-
# Record 2001 fits criteria
|
42
|
-
# The underlying implementation will have 1 page for records 1-999
|
43
|
-
# then will request with limit 1 for records 1000-2000 (making 1000
|
44
|
-
# requests of limit 1) until hit record 2001.
|
45
|
-
if request[:limit] && record_limit && record_limit - record_count < request[:limit]
|
46
|
-
request[:limit] = record_limit - record_count
|
47
|
-
end
|
48
|
-
if request[:limit] && scan_limit && scan_limit - scan_count < request[:limit]
|
49
|
-
request[:limit] = scan_limit - scan_count
|
50
|
-
end
|
51
|
-
|
52
|
-
response = client.query(request)
|
53
|
-
|
54
|
-
yielder << response
|
55
|
-
|
56
|
-
record_count += response.count
|
57
|
-
break if record_limit && record_count >= record_limit
|
58
|
-
|
59
|
-
scan_count += response.scanned_count
|
60
|
-
break if scan_limit && scan_count >= scan_limit
|
61
|
-
|
62
|
-
if response.last_evaluated_key
|
63
|
-
request[:exclusive_start_key] = response.last_evaluated_key
|
64
|
-
else
|
65
|
-
break
|
66
|
-
end
|
67
|
-
|
68
|
-
backoff.call if backoff
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
def build_request
|
76
|
-
request = options.slice(
|
77
|
-
:consistent_read,
|
78
|
-
:scan_index_forward,
|
79
|
-
:select,
|
80
|
-
:index_name,
|
81
|
-
:exclusive_start_key
|
82
|
-
).compact
|
83
|
-
|
84
|
-
# Deal with various limits and batching
|
85
|
-
batch_size = options[:batch_size]
|
86
|
-
limit = [record_limit, scan_limit, batch_size].compact.min
|
87
|
-
|
88
|
-
request[:limit] = limit if limit
|
89
|
-
request[:table_name] = table.name
|
90
|
-
request[:key_conditions] = key_conditions
|
91
|
-
request[:query_filter] = query_filter
|
92
|
-
|
93
|
-
request
|
94
|
-
end
|
95
|
-
|
96
|
-
def record_limit
|
97
|
-
options[:record_limit]
|
98
|
-
end
|
99
|
-
|
100
|
-
def scan_limit
|
101
|
-
options[:scan_limit]
|
102
|
-
end
|
103
|
-
|
104
|
-
def hash_key_name
|
105
|
-
(options[:hash_key] || table.hash_key)
|
106
|
-
end
|
107
|
-
|
108
|
-
def range_key_name
|
109
|
-
(options[:range_key] || table.range_key)
|
110
|
-
end
|
111
|
-
|
112
|
-
def key_conditions
|
113
|
-
result = {
|
114
|
-
hash_key_name => {
|
115
|
-
comparison_operator: AwsSdkV3::EQ,
|
116
|
-
attribute_value_list: AwsSdkV3.attribute_value_list(AwsSdkV3::EQ, options[:hash_value].freeze)
|
117
|
-
}
|
118
|
-
}
|
119
|
-
|
120
|
-
conditions.slice(*AwsSdkV3::RANGE_MAP.keys).each do |k, _v|
|
121
|
-
op = AwsSdkV3::RANGE_MAP[k]
|
122
|
-
|
123
|
-
result[range_key_name] = {
|
124
|
-
comparison_operator: op,
|
125
|
-
attribute_value_list: AwsSdkV3.attribute_value_list(op, conditions[k].freeze)
|
126
|
-
}
|
127
|
-
end
|
128
|
-
|
129
|
-
result
|
130
|
-
end
|
131
|
-
|
132
|
-
def query_filter
|
133
|
-
conditions.except(*AwsSdkV3::RANGE_MAP.keys).reduce({}) do |result, (attr, cond)|
|
134
|
-
condition = {
|
135
|
-
comparison_operator: AwsSdkV3::FIELD_MAP[cond.keys[0]],
|
136
|
-
attribute_value_list: AwsSdkV3.attribute_value_list(AwsSdkV3::FIELD_MAP[cond.keys[0]], cond.values[0].freeze)
|
137
|
-
}
|
138
|
-
result[attr] = condition
|
139
|
-
result
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
@@ -1,107 +0,0 @@
|
|
1
|
-
module Dynamoid
|
2
|
-
module AdapterPlugin
|
3
|
-
class Scan
|
4
|
-
attr_reader :client, :table, :conditions, :options
|
5
|
-
|
6
|
-
def initialize(client, table, conditions = {}, options = {})
|
7
|
-
@client = client
|
8
|
-
@table = table
|
9
|
-
@conditions = conditions
|
10
|
-
@options = options
|
11
|
-
end
|
12
|
-
|
13
|
-
def call
|
14
|
-
request = build_request
|
15
|
-
|
16
|
-
Enumerator.new do |yielder|
|
17
|
-
record_count = 0
|
18
|
-
scan_count = 0
|
19
|
-
|
20
|
-
backoff = Dynamoid.config.backoff ? Dynamoid.config.build_backoff : nil
|
21
|
-
|
22
|
-
loop do
|
23
|
-
# Adjust the limit down if the remaining record and/or scan limit are
|
24
|
-
# lower to obey limits. We can assume the difference won't be
|
25
|
-
# negative due to break statements below but choose smaller limit
|
26
|
-
# which is why we have 2 separate if statements.
|
27
|
-
# NOTE: Adjusting based on record_limit can cause many HTTP requests
|
28
|
-
# being made. We may want to change this behavior, but it affects
|
29
|
-
# filtering on data with potentially large gaps.
|
30
|
-
# Example:
|
31
|
-
# User.where('created_at.gte' => 1.day.ago).record_limit(1000)
|
32
|
-
# Records 1-999 User's that fit criteria
|
33
|
-
# Records 1000-2000 Users's that do not fit criteria
|
34
|
-
# Record 2001 fits criteria
|
35
|
-
# The underlying implementation will have 1 page for records 1-999
|
36
|
-
# then will request with limit 1 for records 1000-2000 (making 1000
|
37
|
-
# requests of limit 1) until hit record 2001.
|
38
|
-
if request[:limit] && record_limit && record_limit - record_count < request[:limit]
|
39
|
-
request[:limit] = record_limit - record_count
|
40
|
-
end
|
41
|
-
if request[:limit] && scan_limit && scan_limit - scan_count < request[:limit]
|
42
|
-
request[:limit] = scan_limit - scan_count
|
43
|
-
end
|
44
|
-
|
45
|
-
response = client.scan(request)
|
46
|
-
|
47
|
-
yielder << response
|
48
|
-
|
49
|
-
record_count += response.count
|
50
|
-
break if record_limit && record_count >= record_limit
|
51
|
-
|
52
|
-
scan_count += response.scanned_count
|
53
|
-
break if scan_limit && scan_count >= scan_limit
|
54
|
-
|
55
|
-
# Keep pulling if we haven't finished paging in all data
|
56
|
-
if response.last_evaluated_key
|
57
|
-
request[:exclusive_start_key] = response.last_evaluated_key
|
58
|
-
else
|
59
|
-
break
|
60
|
-
end
|
61
|
-
|
62
|
-
backoff.call if backoff
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def build_request
|
70
|
-
request = options.slice(
|
71
|
-
:consistent_read,
|
72
|
-
:exclusive_start_key,
|
73
|
-
:select
|
74
|
-
).compact
|
75
|
-
|
76
|
-
# Deal with various limits and batching
|
77
|
-
batch_size = options[:batch_size]
|
78
|
-
limit = [record_limit, scan_limit, batch_size].compact.min
|
79
|
-
|
80
|
-
request[:limit] = limit if limit
|
81
|
-
request[:table_name] = table.name
|
82
|
-
request[:scan_filter] = scan_filter
|
83
|
-
|
84
|
-
request
|
85
|
-
end
|
86
|
-
|
87
|
-
def record_limit
|
88
|
-
options[:record_limit]
|
89
|
-
end
|
90
|
-
|
91
|
-
def scan_limit
|
92
|
-
options[:scan_limit]
|
93
|
-
end
|
94
|
-
|
95
|
-
def scan_filter
|
96
|
-
conditions.reduce({}) do |result, (attr, cond)|
|
97
|
-
condition = {
|
98
|
-
comparison_operator: AwsSdkV3::FIELD_MAP[cond.keys[0]],
|
99
|
-
attribute_value_list: AwsSdkV3.attribute_value_list(AwsSdkV3::FIELD_MAP[cond.keys[0]], cond.values[0].freeze)
|
100
|
-
}
|
101
|
-
result[attr] = condition
|
102
|
-
result
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|