dynamini 2.9.5 → 2.9.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +20 -17
- data/README.md +30 -20
- data/dynamini.gemspec +1 -1
- data/lib/dynamini/attributes.rb +2 -1
- data/lib/dynamini/base.rb +1 -1
- data/lib/dynamini/batch_operations.rb +3 -2
- data/lib/dynamini/test_client.rb +0 -1
- data/spec/dynamini/base_spec.rb +34 -0
- data/spec/dynamini/batch_operations_spec.rb +66 -85
- data/spec/dynamini/test_client_spec.rb +83 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 394d8fc8fe9d1d1f6a0380d91009868d82eae552
|
4
|
+
data.tar.gz: 3b831be32226ae1ccdbc2da1b7b11b2f9a5b3e56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d1db9cfb9c089962b23c11204cc6ef9608a4eb46585d051f7d5a40856c40e49a5e9093546a3028d5a72f601930ee903f863d1bf56a2548df1430c59cf637c74
|
7
|
+
data.tar.gz: f9e7a129e6f89b8588520392ccd5509deddf62e4aaaca493f9dca695732775d51a8e113c043f9b3bab8b8fb5aafc5ef5bbef82bc0e23c850cd4e5026002e9750
|
data/Gemfile.lock
CHANGED
@@ -1,29 +1,30 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dynamini (2.9.
|
4
|
+
dynamini (2.9.6)
|
5
5
|
activemodel (>= 3, < 5.0)
|
6
6
|
aws-sdk (~> 2)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
activemodel (4.2.
|
12
|
-
activesupport (= 4.2.
|
11
|
+
activemodel (4.2.9)
|
12
|
+
activesupport (= 4.2.9)
|
13
13
|
builder (~> 3.1)
|
14
|
-
activesupport (4.2.
|
14
|
+
activesupport (4.2.9)
|
15
15
|
i18n (~> 0.7)
|
16
|
-
json (~> 1.7, >= 1.7.7)
|
17
16
|
minitest (~> 5.1)
|
18
17
|
thread_safe (~> 0.3, >= 0.3.4)
|
19
18
|
tzinfo (~> 1.1)
|
20
|
-
aws-sdk (2.
|
21
|
-
aws-sdk-resources (= 2.
|
22
|
-
aws-sdk-core (2.
|
19
|
+
aws-sdk (2.10.45)
|
20
|
+
aws-sdk-resources (= 2.10.45)
|
21
|
+
aws-sdk-core (2.10.45)
|
22
|
+
aws-sigv4 (~> 1.0)
|
23
23
|
jmespath (~> 1.0)
|
24
|
-
aws-sdk-resources (2.
|
25
|
-
aws-sdk-core (= 2.
|
26
|
-
|
24
|
+
aws-sdk-resources (2.10.45)
|
25
|
+
aws-sdk-core (= 2.10.45)
|
26
|
+
aws-sigv4 (1.0.2)
|
27
|
+
builder (3.2.3)
|
27
28
|
coderay (1.1.0)
|
28
29
|
diff-lcs (1.2.5)
|
29
30
|
ffi (1.9.10)
|
@@ -48,15 +49,14 @@ GEM
|
|
48
49
|
guard-shell (0.7.1)
|
49
50
|
guard (>= 2.0.0)
|
50
51
|
guard-compat (~> 1.0)
|
51
|
-
i18n (0.
|
52
|
-
jmespath (1.1
|
53
|
-
json (1.8.3)
|
52
|
+
i18n (0.8.6)
|
53
|
+
jmespath (1.3.1)
|
54
54
|
listen (3.0.3)
|
55
55
|
rb-fsevent (>= 0.9.3)
|
56
56
|
rb-inotify (>= 0.9)
|
57
57
|
lumberjack (1.0.9)
|
58
58
|
method_source (0.8.2)
|
59
|
-
minitest (5.
|
59
|
+
minitest (5.10.3)
|
60
60
|
nenv (0.2.0)
|
61
61
|
notiffany (0.0.8)
|
62
62
|
nenv (~> 0.1)
|
@@ -85,8 +85,8 @@ GEM
|
|
85
85
|
shellany (0.0.1)
|
86
86
|
slop (3.6.0)
|
87
87
|
thor (0.19.1)
|
88
|
-
thread_safe (0.3.
|
89
|
-
tzinfo (1.2.
|
88
|
+
thread_safe (0.3.6)
|
89
|
+
tzinfo (1.2.3)
|
90
90
|
thread_safe (~> 0.1)
|
91
91
|
|
92
92
|
PLATFORMS
|
@@ -99,3 +99,6 @@ DEPENDENCIES
|
|
99
99
|
guard-shell
|
100
100
|
pry (~> 0)
|
101
101
|
rspec (~> 3)
|
102
|
+
|
103
|
+
BUNDLED WITH
|
104
|
+
1.16.0.pre.2
|
data/README.md
CHANGED
@@ -78,7 +78,7 @@ Here's what a sample model looks like. This one includes a range key - sometimes
|
|
78
78
|
|
79
79
|
```ruby
|
80
80
|
class Vehicle < Dynamini::Base
|
81
|
-
set_table_name 'cars
|
81
|
+
set_table_name 'cars' # must match the table name configured in AWS
|
82
82
|
set_hash_key :model # defaults to :id if not set
|
83
83
|
set_range_key :vin # must be set if your AWS table is configured with a range key
|
84
84
|
|
@@ -86,8 +86,16 @@ class Vehicle < Dynamini::Base
|
|
86
86
|
end
|
87
87
|
```
|
88
88
|
|
89
|
+
If you don't use set_table_name, Dynamini will try to find a table with the pluralized, downcased class name. For instance, a Dynamini class called PageView would look for a table called 'page_views'. If you use separate DynamoDB tables for development and production, wrap set_table_name in a conditional to determine the appropriate table when your class initializes. In this example, the production table is 'vehicles' and the development table is 'vehicles-dev':
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
class Vehicle < Dynamini::Base
|
93
|
+
set_table_name 'vehicles-dev' unless Rails.env.production?
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
89
97
|
## Datatype Handling
|
90
|
-
There are a few quirks about how the Dynamo Ruby SDK stores data. It stores numeric values as BigDecimal objects, symbols as strings, and doesn't accept ruby Date or Time objects. To save you from having to convert your data to the correct type before saving and after retrieval, you can use
|
98
|
+
There are a few quirks about how the Dynamo Ruby SDK stores data. It stores numeric values as BigDecimal objects, symbols as strings, and doesn't accept ruby Date or Time objects. To save you from having to convert your data to the correct type before saving and after retrieval, you can use :handle to manage automatic type conversion. This is also where you can specify default values for your attributes. Here's how it works:
|
91
99
|
|
92
100
|
```ruby
|
93
101
|
class Vehicle < Dynamini::Base
|
@@ -98,6 +106,7 @@ end
|
|
98
106
|
car = Vehicle.new(vin: '43H1R')
|
99
107
|
car.top_speed
|
100
108
|
> 80
|
109
|
+
|
101
110
|
car.top_speed = 90
|
102
111
|
car.save
|
103
112
|
Vehicle.find('43H1R').top_speed
|
@@ -105,9 +114,7 @@ Vehicle.find('43H1R').top_speed
|
|
105
114
|
# This would return BigDecimal(90) without the handle helper.
|
106
115
|
```
|
107
116
|
|
108
|
-
|
109
|
-
|
110
|
-
The following datatypes are supported by handle:
|
117
|
+
Dynamini lets you :handle the following types:
|
111
118
|
* :integer
|
112
119
|
* :float
|
113
120
|
* :symbol
|
@@ -118,8 +125,14 @@ The following datatypes are supported by handle:
|
|
118
125
|
* :array
|
119
126
|
* :set
|
120
127
|
|
121
|
-
|
122
|
-
|
128
|
+
Default values aren't actually written to the database when saving your instance. Instead, they define what will be returned when reading an unset or nullified attribute. If you don't provide your own default, the "default default" value depends on the specified type:
|
129
|
+
|
130
|
+
* array: []
|
131
|
+
* set: Set.new
|
132
|
+
* all other types: nil
|
133
|
+
* attribute not handled: nil
|
134
|
+
|
135
|
+
The auto-generated fields updated_at and created_at are intrinsically handled as :time.
|
123
136
|
|
124
137
|
## Enumerable Attributes
|
125
138
|
You can save arrays and sets to your Dynamini model. Optionally, you can have Dynamini perform type conversion on each element of your enumerable. Here's how it works:
|
@@ -288,35 +301,32 @@ Product.find('qwerty').updated_at
|
|
288
301
|
````
|
289
302
|
|
290
303
|
## Testing
|
291
|
-
|
292
|
-
|
293
|
-
To activate this feature, just require the testing module:
|
304
|
+
Dynamini includes an in-memory test client, so you don't have to connect to a real Dynamo instance when running tests. To activate this feature, just require the testing module:
|
294
305
|
```ruby
|
295
306
|
require 'dynamini/testing'
|
296
307
|
```
|
297
|
-
|
308
|
+
Requiring the module replaces all API calls Dynamini makes to AWS with calls to Dynamini::TestClient.
|
298
309
|
|
299
|
-
|
310
|
+
You probably don't want your data to persist between tests, so you'll have to reset the test client to wipe its data:
|
300
311
|
```ruby
|
312
|
+
# in this case Vehicle is our Dynamini subclass
|
301
313
|
Vehicle.client.reset
|
302
314
|
```
|
303
315
|
|
304
|
-
|
316
|
+
Here's an implementation of the above in a typical spec_helper.rb:
|
305
317
|
```ruby
|
306
318
|
require 'dynamini/testing'
|
307
319
|
|
308
320
|
config.after(:each) {
|
309
|
-
Vehicle.client.reset
|
321
|
+
Vehicle.client.reset
|
310
322
|
}
|
311
323
|
```
|
312
324
|
|
313
325
|
## Things to remember
|
314
|
-
* Since DynamoDB is schemaless, your
|
315
|
-
*
|
316
|
-
*
|
317
|
-
* If you
|
318
|
-
* If you use non-numeric strings for your primary key, remember to change your foreign key columns on related ActiveRecord tables to be string type.
|
319
|
-
* You might want to conditionally set the table name for your model based on the Rails.env, enabling separate tables for development and production.
|
326
|
+
* Since DynamoDB is schemaless, Dynamini is designed to allow your instance to respond to any method call that looks like an attribute name, even if you've never referenced it before. For instance, model.i_bet_this_will_raise_an_error will return nil.
|
327
|
+
* Similarly, you can write any arbitrarily-named attribute to your instance without defining its name or properties beforehand.
|
328
|
+
* If you change the primary key value on an instance of your model, then resave it, you'll have two records in your database.
|
329
|
+
* If you have a model with a foreign key attribute that points to your Dynamini model, you can use Rails' :belongs_to association helper normally. (If you use non-numeric strings for your Dynamini hash key, remember to change your foreign key columns on related ActiveRecord tables to be string type.)
|
320
330
|
|
321
331
|
## Contributing
|
322
332
|
|
data/dynamini.gemspec
CHANGED
data/lib/dynamini/attributes.rb
CHANGED
@@ -53,7 +53,8 @@ module Dynamini
|
|
53
53
|
|
54
54
|
def attribute_updates
|
55
55
|
changes.reduce({}) do |updates, (key, value)|
|
56
|
-
|
56
|
+
# TODO: remove this ternary once aws-sdk accepts empty set pull request
|
57
|
+
current_value = value[1].is_a?(Set) && value[1].empty? ? nil : value[1]
|
57
58
|
updates[key] = { action: value[2] || 'PUT' }
|
58
59
|
updates[key][:value] = current_value unless current_value == DELETED_TOKEN
|
59
60
|
updates
|
data/lib/dynamini/base.rb
CHANGED
@@ -53,7 +53,7 @@ module Dynamini
|
|
53
53
|
handle(key, format) if format
|
54
54
|
end
|
55
55
|
|
56
|
-
def set_secondary_index(index_name, args)
|
56
|
+
def set_secondary_index(index_name, args = {})
|
57
57
|
@secondary_index ||= {}
|
58
58
|
@secondary_index[index_name.to_s] = {hash_key_name: args[:hash_key] || hash_key, range_key_name: args[:range_key]}
|
59
59
|
end
|
@@ -69,7 +69,8 @@ module Dynamini
|
|
69
69
|
def dynamo_scan(options)
|
70
70
|
if options[:start_key] && !options[:start_key].is_a?(Hash)
|
71
71
|
if options[:index_name]
|
72
|
-
|
72
|
+
attr = secondary_index[options[:index_name]][:hash_key_name].to_s
|
73
|
+
start_key = { attr => options[:start_key] }
|
73
74
|
else
|
74
75
|
start_key = { hash_key.to_s => options[:start_key] }
|
75
76
|
end
|
@@ -92,7 +93,7 @@ module Dynamini
|
|
92
93
|
raise ArgumentError, 'Must specify segment if specifying total_segments'
|
93
94
|
elsif options[:segment] && !options[:total_segments]
|
94
95
|
raise ArgumentError, 'Must specify total_segments if specifying segment'
|
95
|
-
elsif options[:index_name] && !self.secondary_index[options[:index_name]]
|
96
|
+
elsif options[:index_name] && (!self.secondary_index || !self.secondary_index[options[:index_name]])
|
96
97
|
raise ArgumentError, "Secondary index of #{options[:index_name]} does not exist"
|
97
98
|
end
|
98
99
|
end
|
data/lib/dynamini/test_client.rb
CHANGED
@@ -86,7 +86,6 @@ module Dynamini
|
|
86
86
|
|
87
87
|
def scan(args = {})
|
88
88
|
records = get_table(args[:table_name]).values
|
89
|
-
|
90
89
|
sort_scanned_records!(records, args[:secondary_index_name]) if args[:secondary_index_name]
|
91
90
|
start_index = index_of_start_key(args, records)
|
92
91
|
items = limit_scanned_records(args[:limit], records, start_index)
|
data/spec/dynamini/base_spec.rb
CHANGED
@@ -185,6 +185,40 @@ describe Dynamini::Base do
|
|
185
185
|
model.save
|
186
186
|
end
|
187
187
|
end
|
188
|
+
context 'when an empty set is submitted' do
|
189
|
+
it 'should nullify the set' do
|
190
|
+
expect(model.class.client).to receive(:update_item).with(
|
191
|
+
table_name: 'bases',
|
192
|
+
key: {id: model_attributes[:id]},
|
193
|
+
attribute_updates: hash_including(
|
194
|
+
"foo" => {
|
195
|
+
value: nil,
|
196
|
+
action: 'PUT'
|
197
|
+
}
|
198
|
+
)
|
199
|
+
)
|
200
|
+
model.foo = Set.new
|
201
|
+
model.bar = 4
|
202
|
+
model.save
|
203
|
+
end
|
204
|
+
end
|
205
|
+
context 'when a populated set is submitted' do
|
206
|
+
it 'should submit the set' do
|
207
|
+
expect(model.class.client).to receive(:update_item).with(
|
208
|
+
table_name: 'bases',
|
209
|
+
key: {id: model_attributes[:id]},
|
210
|
+
attribute_updates: hash_including(
|
211
|
+
"foo" => {
|
212
|
+
value: Set.new([1]),
|
213
|
+
action: 'PUT'
|
214
|
+
}
|
215
|
+
)
|
216
|
+
)
|
217
|
+
model.foo = Set.new([1])
|
218
|
+
model.bar = 4
|
219
|
+
model.save
|
220
|
+
end
|
221
|
+
end
|
188
222
|
end
|
189
223
|
|
190
224
|
context 'when failing validation' do
|
@@ -127,103 +127,84 @@ describe Dynamini::BatchOperations do
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
-
class SecBase < Dynamini::Base
|
131
|
-
set_hash_key :id
|
132
|
-
set_secondary_index :sec, hash_key: :sec
|
133
|
-
set_secondary_index :rev, hash_key: :sec
|
134
|
-
end
|
135
|
-
|
136
130
|
describe '.scan' do
|
131
|
+
let(:response) { OpenStruct.new(items: [], last_evaluated_key: {'foo' => 'bar'}) }
|
137
132
|
|
138
133
|
before do
|
139
|
-
|
140
|
-
SecBase.create(id: '124', sec: 'C')
|
141
|
-
SecBase.create(id: '125', sec: 'B')
|
142
|
-
SecBase.create(id: '126', sec: 'A')
|
134
|
+
subject.set_secondary_index :foo_index, hash_key: :foo_attr
|
143
135
|
end
|
144
136
|
|
145
|
-
context '
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
expect(response.items.map { |i| i.id }).to eq(['124', '125'])
|
166
|
-
expect(response.last_evaluated_key).to eq('id' => '125')
|
167
|
-
end
|
168
|
-
end
|
137
|
+
context 'no start key is provided' do
|
138
|
+
it 'passes the request to the client in the correct shape and returns the correct shape' do
|
139
|
+
expect(subject.client).to receive(:scan).with(
|
140
|
+
consistent_read: false,
|
141
|
+
secondary_index_name: 'foo_index',
|
142
|
+
limit: 100,
|
143
|
+
segment: 1,
|
144
|
+
total_segments: 2,
|
145
|
+
table_name: 'bases'
|
146
|
+
).and_return(response)
|
147
|
+
|
148
|
+
expect(
|
149
|
+
subject.scan(
|
150
|
+
consistent_read: false,
|
151
|
+
index_name: 'foo_index',
|
152
|
+
limit: 100,
|
153
|
+
segment: 1,
|
154
|
+
total_segments: 2
|
155
|
+
)
|
156
|
+
).to eq(response)
|
169
157
|
end
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
158
|
+
end
|
159
|
+
context 'a literal start key is provided' do
|
160
|
+
it 'passes the request to the client in the correct shape and returns the correct shape' do
|
161
|
+
expect(subject.client).to receive(:scan).with(
|
162
|
+
consistent_read: false,
|
163
|
+
secondary_index_name: 'foo_index',
|
164
|
+
exclusive_start_key: { 'foo_attr' => 'abc' },
|
165
|
+
limit: 100,
|
166
|
+
segment: 1,
|
167
|
+
total_segments: 2,
|
168
|
+
table_name: 'bases'
|
169
|
+
).and_return(response)
|
170
|
+
|
171
|
+
expect(subject.scan(
|
172
|
+
consistent_read: false,
|
173
|
+
index_name: 'foo_index',
|
174
|
+
start_key: 'abc',
|
175
|
+
limit: 100,
|
176
|
+
segment: 1,
|
177
|
+
total_segments: 2
|
178
|
+
)).to eq(response)
|
185
179
|
end
|
186
180
|
end
|
187
|
-
context '
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
181
|
+
context 'a complex start key is provided' do
|
182
|
+
it 'passes the request to the client in the correct shape and returns the correct shape' do
|
183
|
+
expect(subject.client).to receive(:scan).with(
|
184
|
+
consistent_read: false,
|
185
|
+
secondary_index_name: 'foo_index',
|
186
|
+
exclusive_start_key: { 'foo_attr' => 'abc' },
|
187
|
+
limit: 100,
|
188
|
+
segment: 1,
|
189
|
+
total_segments: 2,
|
190
|
+
table_name: 'bases'
|
191
|
+
).and_return(response)
|
192
|
+
|
193
|
+
expect(subject.scan(
|
194
|
+
consistent_read: false,
|
195
|
+
index_name: 'foo_index',
|
196
|
+
start_key: { 'foo_attr' => 'abc' },
|
197
|
+
limit: 100,
|
198
|
+
segment: 1,
|
199
|
+
total_segments: 2
|
200
|
+
)).to eq(response)
|
203
201
|
end
|
204
|
-
context '
|
205
|
-
|
206
|
-
|
207
|
-
response = SecBase.scan(index_name: 'sec', limit: 3)
|
208
|
-
expect(response.items.map { |i| i.sec }).to eq(%w(A B C))
|
209
|
-
expect(response.last_evaluated_key).to eq('sec' => 'C')
|
210
|
-
end
|
211
|
-
end
|
212
|
-
context 'without a limit' do
|
213
|
-
it 'retrieves the correct items' do
|
214
|
-
response = SecBase.scan(index_name: 'sec')
|
215
|
-
expect(response.items.map { |i| i.sec }).to eq(%w(A B C D))
|
216
|
-
expect(response.last_evaluated_key).to be_nil
|
217
|
-
end
|
202
|
+
context 'with a model with no secondary indices but with a start key' do
|
203
|
+
it 'behaves' do
|
204
|
+
expect{ Dynamini::Base.scan(start_key: '123') }.to_not raise_error
|
218
205
|
end
|
219
206
|
end
|
220
207
|
end
|
221
|
-
|
222
|
-
context 'with a model with no secondary indices but with a start key' do
|
223
|
-
it 'behaves' do
|
224
|
-
expect{ Dynamini::Base.scan(start_key: '123') }.to_not raise_error
|
225
|
-
end
|
226
|
-
end
|
227
208
|
end
|
228
209
|
end
|
229
210
|
|
@@ -470,4 +470,87 @@ describe Dynamini::TestClient do
|
|
470
470
|
expect(result.responses[table_name].first[:id]).to eq('foo')
|
471
471
|
end
|
472
472
|
end
|
473
|
+
|
474
|
+
class SecBase < Dynamini::Base
|
475
|
+
set_hash_key :id
|
476
|
+
set_secondary_index :sec_index, hash_key: :sec
|
477
|
+
end
|
478
|
+
|
479
|
+
describe '.scan' do
|
480
|
+
before do
|
481
|
+
SecBase.create(id: '123', sec: 'D')
|
482
|
+
SecBase.create(id: '124', sec: 'C')
|
483
|
+
SecBase.create(id: '125', sec: 'B')
|
484
|
+
SecBase.create(id: '126', sec: 'A')
|
485
|
+
end
|
486
|
+
|
487
|
+
context 'scanning the primary key' do
|
488
|
+
context 'with an exclusive_start_key' do
|
489
|
+
context 'with a limit' do
|
490
|
+
it 'retrieves the correct items' do
|
491
|
+
response = SecBase.client.scan(exclusive_start_key: {'id' => '124'}, limit: 1, table_name: 'sec_bases')
|
492
|
+
expect(response.items.map { |i| i[:id] }).to eq(['124'])
|
493
|
+
expect(response.last_evaluated_key).to eq('id' => '124')
|
494
|
+
end
|
495
|
+
end
|
496
|
+
context 'without a limit' do
|
497
|
+
it 'retrieves the correct items' do
|
498
|
+
response = SecBase.client.scan(exclusive_start_key: {'id' => '124'}, table_name: 'sec_bases')
|
499
|
+
expect(response.items.map { |i| i[:id] }).to eq(%w(124 125 126))
|
500
|
+
expect(response.last_evaluated_key).to be_nil
|
501
|
+
end
|
502
|
+
end
|
503
|
+
end
|
504
|
+
context 'without an exclusive_start_key' do
|
505
|
+
context 'with a limit' do
|
506
|
+
it 'retrieves the correct items' do
|
507
|
+
response = SecBase.client.scan(limit: 2, table_name: 'sec_bases')
|
508
|
+
expect(response.items.map { |i| i[:id] }).to eq(%w(123 124))
|
509
|
+
expect(response.last_evaluated_key).to eq('id' => '124')
|
510
|
+
end
|
511
|
+
end
|
512
|
+
context 'without a limit' do
|
513
|
+
it 'retrieves the correct items' do
|
514
|
+
response = SecBase.client.scan(table_name: 'sec_bases')
|
515
|
+
expect(response.items.map { |i| i[:id] }).to eq(%w(123 124 125 126))
|
516
|
+
expect(response.last_evaluated_key).to be_nil
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|
521
|
+
context 'scanning a secondary index' do
|
522
|
+
context 'with an exclusive_start_key' do
|
523
|
+
context 'with a limit' do
|
524
|
+
it 'retrieves the correct items' do
|
525
|
+
response = SecBase.client.scan(secondary_index_name: 'sec_index', exclusive_start_key: {'sec' => 'B'}, limit: 2, table_name: 'sec_bases')
|
526
|
+
expect(response.items.map { |i| i['sec'] }).to eq(%w(B C))
|
527
|
+
expect(response.last_evaluated_key).to eq('sec' => 'C')
|
528
|
+
end
|
529
|
+
end
|
530
|
+
context 'without a limit' do
|
531
|
+
it 'retrieves the correct items' do
|
532
|
+
response = SecBase.client.scan(secondary_index_name: 'sec_index', exclusive_start_key: {'sec' => 'B'}, table_name: 'sec_bases')
|
533
|
+
expect(response.items.map { |i| i['sec'] }).to eq(%w(B C D))
|
534
|
+
expect(response.last_evaluated_key).to be_nil
|
535
|
+
end
|
536
|
+
end
|
537
|
+
end
|
538
|
+
context 'without an exclusive_start_key' do
|
539
|
+
context 'with a limit' do
|
540
|
+
it 'retrieves the correct items' do
|
541
|
+
response = SecBase.client.scan(secondary_index_name: 'sec_index', limit: 3, table_name: 'sec_bases')
|
542
|
+
expect(response.items.map { |i| i['sec'] }).to eq(%w(A B C))
|
543
|
+
expect(response.last_evaluated_key).to eq('sec' => 'C')
|
544
|
+
end
|
545
|
+
end
|
546
|
+
context 'without a limit' do
|
547
|
+
it 'retrieves the correct items' do
|
548
|
+
response = SecBase.client.scan(secondary_index_name: 'sec_index', table_name: 'sec_bases')
|
549
|
+
expect(response.items.map { |i| i['sec'] }).to eq(%w(A B C D))
|
550
|
+
expect(response.last_evaluated_key).to be_nil
|
551
|
+
end
|
552
|
+
end
|
553
|
+
end
|
554
|
+
end
|
555
|
+
end
|
473
556
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynamini
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.9.
|
4
|
+
version: 2.9.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Ward
|
@@ -15,7 +15,7 @@ authors:
|
|
15
15
|
autorequire:
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
|
-
date: 2017-09-
|
18
|
+
date: 2017-09-15 00:00:00.000000000 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: activemodel
|