dynamini 1.8.2 → 1.9.1
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/.gitignore +7 -0
- data/.rspec +2 -0
- data/.travis.yml +11 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +101 -0
- data/Guardfile +79 -0
- data/LICENSE +22 -0
- data/README.md +214 -0
- data/Rakefile +5 -0
- data/dynamini.gemspec +29 -0
- data/lib/dynamini/base.rb +4 -57
- data/lib/dynamini/batch_operations.rb +51 -0
- data/lib/dynamini/test_client.rb +2 -1
- data/spec/dynamini/base_spec.rb +908 -0
- data/spec/dynamini/batch_operations_spec.rb +77 -0
- data/spec/dynamini/test_client_spec.rb +187 -0
- data/spec/spec_helper.rb +15 -0
- metadata +23 -3
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dynamini::BatchOperations do
|
4
|
+
|
5
|
+
let(:model_attributes) {
|
6
|
+
{
|
7
|
+
name: 'Widget',
|
8
|
+
price: 9.99,
|
9
|
+
id: 'abcd1234',
|
10
|
+
hash_key: '009'
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
let(:model) { Dynamini::Base.new(model_attributes) }
|
15
|
+
|
16
|
+
subject { Dynamini::Base }
|
17
|
+
|
18
|
+
describe '.import' do
|
19
|
+
it 'should generate timestamps for each model' do
|
20
|
+
model1 = Dynamini::Base.new(model_attributes)
|
21
|
+
model2 = Dynamini::Base.new(model_attributes.merge(id: '2'))
|
22
|
+
|
23
|
+
subject.import([model1, model2])
|
24
|
+
|
25
|
+
expect(subject.find(model1.id).updated_at).not_to be_nil
|
26
|
+
expect(subject.find(model1.id).created_at).not_to be_nil
|
27
|
+
expect(subject.find(model2.id).updated_at).not_to be_nil
|
28
|
+
expect(subject.find(model2.id).created_at).not_to be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should call .dynamo_batch_save with batches of 25 models' do
|
32
|
+
models = Array.new(30, model)
|
33
|
+
expect(subject).to receive(:dynamo_batch_save).with(array_including(models[0..24])).ordered
|
34
|
+
expect(subject).to receive(:dynamo_batch_save).with(array_including(models[25..29])).ordered
|
35
|
+
subject.import(models)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '.dynamo_batch_save' do
|
40
|
+
it 'should batch write the models to dynamo' do
|
41
|
+
model2 = Dynamini::Base.new(id: '123')
|
42
|
+
model3 = Dynamini::Base.new(id: '456')
|
43
|
+
Dynamini::Base.dynamo_batch_save([model2, model3])
|
44
|
+
expect(Dynamini::Base.find('123')).to_not be_nil
|
45
|
+
expect(Dynamini::Base.find('456')).to_not be_nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '.batch_find' do
|
50
|
+
before do
|
51
|
+
model.save
|
52
|
+
end
|
53
|
+
context 'when requesting 0 items' do
|
54
|
+
it 'should return an empty array' do
|
55
|
+
expect(Dynamini::Base.batch_find).to eq []
|
56
|
+
end
|
57
|
+
end
|
58
|
+
context 'when requesting 2 items' do
|
59
|
+
it 'should return a 2-length array containing each item' do
|
60
|
+
Dynamini::Base.create(id: '4321')
|
61
|
+
objects = Dynamini::Base.batch_find(['abcd1234', '4321'])
|
62
|
+
expect(objects.length).to eq 2
|
63
|
+
expect(objects.first.id).to eq model.id
|
64
|
+
expect(objects.last.id).to eq '4321'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
context 'when requesting too many items' do
|
68
|
+
it 'should raise an error' do
|
69
|
+
a = []
|
70
|
+
150.times { a << 'foo' }
|
71
|
+
expect { Dynamini::Base.batch_find(a) }.to raise_error StandardError
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dynamini::TestClient do
|
4
|
+
|
5
|
+
let(:table_name) { 'table' }
|
6
|
+
|
7
|
+
describe '#update_item' do
|
8
|
+
|
9
|
+
context 'with hash key ONLY' do
|
10
|
+
it 'should be able to save a record' do
|
11
|
+
test_client = Dynamini::TestClient.new(:hash_key_name)
|
12
|
+
test_client.update_item(table_name: table_name, key: {hash_key_name: 'hash_key_value'}, attribute_updates: {abc: {value: 'abc', action: 'PUT'}})
|
13
|
+
expect(test_client.data[table_name]['hash_key_value']).to eq(abc: 'abc', :hash_key_name => "hash_key_value")
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should be able to update an existing record' do
|
17
|
+
test_client = Dynamini::TestClient.new(:hash_key_name)
|
18
|
+
test_client.update_item(table_name: table_name, key: {hash_key_name: 'hash_key_value'}, attribute_updates: {abc: {value: 'abc', action: 'PUT'}})
|
19
|
+
test_client.update_item(table_name: table_name, key: {hash_key_name: 'hash_key_value'}, attribute_updates: {abc: {value: 'def', action: 'PUT'}})
|
20
|
+
expect(test_client.data[table_name]['hash_key_value']).to eq(abc: 'def', :hash_key_name => "hash_key_value")
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with Hash key and range key' do
|
26
|
+
it 'should be able to save a record' do
|
27
|
+
test_client = Dynamini::TestClient.new(:hash_key_name, :range_key_name)
|
28
|
+
test_client.update_item(table_name: table_name, key: {hash_key_name: 'hash_key_value', range_key_name: 'range_key_value'}, attribute_updates: {abc: {value: 'abc', action: 'PUT'}})
|
29
|
+
expect(test_client.data[table_name]['hash_key_value']['range_key_value']).to eq({abc: 'abc', :hash_key_name => "hash_key_value", :range_key_name => "range_key_value"})
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should update an existing record' do
|
33
|
+
test_client = Dynamini::TestClient.new(:hash_key_name, :range_key_name)
|
34
|
+
test_client.update_item(table_name: table_name, key: {hash_key_name: 'hash_key_value', range_key_name: 'range_key_value'}, attribute_updates: {abc: {value: 'abc', action: 'PUT'}})
|
35
|
+
|
36
|
+
test_client.update_item(table_name: table_name, key: {hash_key_name: 'hash_key_value', range_key_name: 'range_key_value'}, attribute_updates: {abc: {value: 'def', action: 'PUT'}})
|
37
|
+
|
38
|
+
expect(test_client.data[table_name]['hash_key_value']['range_key_value']).to eq({abc: 'def', :hash_key_name => "hash_key_value", :range_key_name => "range_key_value"})
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'invalid args' do
|
44
|
+
it 'should not try to add invalid args for a hash key only table' do
|
45
|
+
test_client = Dynamini::TestClient.new(:hash_key_name)
|
46
|
+
test_client.update_item(table_name: table_name, key: {}, attribute_updates: {abc: {value: 'def', action: 'PUT'}})
|
47
|
+
|
48
|
+
expect(test_client.data[table_name]).to eq({})
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should not try to add invalid args for a hash key and range key table' do
|
52
|
+
test_client = Dynamini::TestClient.new(:hash_key_name, :range_key_name)
|
53
|
+
test_client.update_item(table_name: table_name, key: {}, attribute_updates: {abc: {value: 'def', action: 'PUT'}})
|
54
|
+
|
55
|
+
expect(test_client.data[table_name]).to eq({})
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#get_item' do
|
61
|
+
context 'table with just a hash key' do
|
62
|
+
let(:test_client) { Dynamini::TestClient.new(:hash_key_name) }
|
63
|
+
|
64
|
+
it 'should return the item identified by the hash_key' do
|
65
|
+
test_client.update_item(table_name: table_name, key: {test_client.hash_key_attr => "abc"}, attribute_updates: {test_attr: {value: 'test', action: 'PUT'}})
|
66
|
+
|
67
|
+
expect(test_client.get_item(table_name: table_name, key: {test_client.hash_key_attr => "abc"}).item[:test_attr]).to eq('test')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should returns nil if the item does not exist' do
|
71
|
+
expect(test_client.get_item(table_name: table_name, key: {test_client.hash_key_attr => "abc"}).item).to eq(nil)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should ignore any extra keys in the args' do
|
75
|
+
test_client.update_item(table_name: table_name, key: {test_client.hash_key_attr => "abc"}, attribute_updates: {test_attr: {value: 'test', action: 'PUT'}})
|
76
|
+
|
77
|
+
expect(test_client.get_item(table_name: table_name, key: {test_client.hash_key_attr => "abc", :extra_key => "extra"}).item[:test_attr]).to eq('test')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'table with hash and range key' do
|
82
|
+
let(:test_client) { Dynamini::TestClient.new(:hash_key_name, :range_key_name) }
|
83
|
+
|
84
|
+
it 'should return the item identified by the hash_key' do
|
85
|
+
test_client.update_item(table_name: table_name, key: {test_client.hash_key_attr => "abc", test_client.range_key_attr => 'def'}, attribute_updates: {test_attr: {value: 'test_range', action: 'PUT'}})
|
86
|
+
|
87
|
+
expect(test_client.get_item(table_name: table_name, key: {test_client.hash_key_attr => "abc", test_client.range_key_attr => 'def'}).item[:test_attr]).to eq('test_range')
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should returns nil if the item does not exist' do
|
91
|
+
expect(test_client.get_item(table_name: table_name, key: {test_client.hash_key_attr => "abc", test_client.range_key_attr => 'def'}).item).to eq(nil)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should return nil when only supplied range key' do
|
95
|
+
expect(test_client.get_item(table_name: table_name, key: {test_client.range_key_attr => 'def'}).item).to eq(nil)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#query' do
|
101
|
+
|
102
|
+
let(:test_client) { Dynamini::TestClient.new(:hash_key_field, :range_key_field) }
|
103
|
+
|
104
|
+
before do
|
105
|
+
4.times do |i|
|
106
|
+
test_client.update_item(table_name: table_name, key: {hash_key_field: 'foo', range_key_field: i + 1}, attribute_updates: {abc: {value: 'abc', action: 'PUT'}})
|
107
|
+
end
|
108
|
+
end
|
109
|
+
context 'with LE operator' do
|
110
|
+
it 'should return all items with range key less than or equal to the provided value' do
|
111
|
+
response = test_client.query(
|
112
|
+
table_name: table_name,
|
113
|
+
key_condition_expression: "hash_key_field = :h AND user_id <= :e",
|
114
|
+
expression_attribute_values: {
|
115
|
+
":h" => 'foo',
|
116
|
+
":e" => 2
|
117
|
+
}
|
118
|
+
)
|
119
|
+
expect(response.items.length).to eq(2)
|
120
|
+
expect(response.items.first[:range_key_field]).to eq(1)
|
121
|
+
expect(response.items.last[:range_key_field]).to eq(2)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
context 'with GE operator' do
|
125
|
+
it 'should return all items with range key greater than or equal to the provided value' do
|
126
|
+
response = test_client.query(
|
127
|
+
table_name: table_name,
|
128
|
+
key_condition_expression: "hash_key_field = :h AND user_id >= :s",
|
129
|
+
expression_attribute_values: {
|
130
|
+
":h" => 'foo',
|
131
|
+
":s" => 2
|
132
|
+
}
|
133
|
+
)
|
134
|
+
expect(response.items.length).to eq(3)
|
135
|
+
expect(response.items.first[:range_key_field]).to eq(2)
|
136
|
+
expect(response.items.last[:range_key_field]).to eq(4)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
context 'with BETWEEN operator' do
|
140
|
+
it 'should return all items with range key between the provided values' do
|
141
|
+
response = test_client.query(
|
142
|
+
table_name: table_name,
|
143
|
+
key_condition_expression: "hash_key_field = :h AND user_id BETWEEN :s AND :e",
|
144
|
+
expression_attribute_values: {
|
145
|
+
":h" => 'foo',
|
146
|
+
":s" => 2,
|
147
|
+
":e" => 3
|
148
|
+
}
|
149
|
+
)
|
150
|
+
expect(response.items.length).to eq(2)
|
151
|
+
expect(response.items.first[:range_key_field]).to eq(2)
|
152
|
+
expect(response.items.last[:range_key_field]).to eq(3)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
context 'with no operator' do
|
156
|
+
it 'should return all items with range key between the provided values' do
|
157
|
+
response = test_client.query(
|
158
|
+
table_name: table_name,
|
159
|
+
key_condition_expression: "hash_key_field = :h",
|
160
|
+
expression_attribute_values: {
|
161
|
+
":h" => 'foo'
|
162
|
+
}
|
163
|
+
)
|
164
|
+
expect(response.items.length).to eq(4)
|
165
|
+
expect(response.items.first[:range_key_field]).to eq(1)
|
166
|
+
expect(response.items.last[:range_key_field]).to eq(4)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '#batch_write_item' do
|
172
|
+
let(:test_client) { Dynamini::TestClient.new(:id) }
|
173
|
+
|
174
|
+
it 'should store all items in the table correctly' do
|
175
|
+
item1 = {'foo' => 'bar', 'id' => 1}
|
176
|
+
item2 = {'foo' => 'bar', 'id' => 2}
|
177
|
+
put_requests = [{put_request: {item: item1}},
|
178
|
+
{put_request: {item: item2}}]
|
179
|
+
|
180
|
+
request_options = {request_items: {table_name => put_requests}}
|
181
|
+
|
182
|
+
test_client.batch_write_item(request_options)
|
183
|
+
expect(test_client.data[table_name][1]).to eq(item1)
|
184
|
+
expect(test_client.data[table_name][2]).to eq(item2)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
Bundler.setup
|
3
|
+
|
4
|
+
require 'aws-sdk'
|
5
|
+
require 'pry'
|
6
|
+
require 'fuubar'
|
7
|
+
require 'dynamini'
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
# For running just wanted tests in guard
|
11
|
+
config.filter_run :focus => true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
config.before(:all) { Dynamini::Base.in_memory = true }
|
14
|
+
config.after(:each) { Dynamini::Base.client.reset }
|
15
|
+
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: 1.
|
4
|
+
version: 1.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Ward
|
@@ -130,10 +130,26 @@ executables: []
|
|
130
130
|
extensions: []
|
131
131
|
extra_rdoc_files: []
|
132
132
|
files:
|
133
|
+
- .gitignore
|
134
|
+
- .rspec
|
135
|
+
- .travis.yml
|
136
|
+
- Gemfile
|
137
|
+
- Gemfile.lock
|
138
|
+
- Guardfile
|
139
|
+
- LICENSE
|
140
|
+
- README.md
|
141
|
+
- Rakefile
|
142
|
+
- dynamini.gemspec
|
143
|
+
- lib/.DS_Store
|
133
144
|
- lib/dynamini.rb
|
134
145
|
- lib/dynamini/base.rb
|
146
|
+
- lib/dynamini/batch_operations.rb
|
135
147
|
- lib/dynamini/configuration.rb
|
136
148
|
- lib/dynamini/test_client.rb
|
149
|
+
- spec/dynamini/base_spec.rb
|
150
|
+
- spec/dynamini/batch_operations_spec.rb
|
151
|
+
- spec/dynamini/test_client_spec.rb
|
152
|
+
- spec/spec_helper.rb
|
137
153
|
homepage: https://github.com/47colborne/dynamini
|
138
154
|
licenses:
|
139
155
|
- MIT
|
@@ -154,8 +170,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
170
|
version: '0'
|
155
171
|
requirements: []
|
156
172
|
rubyforge_project:
|
157
|
-
rubygems_version: 2.
|
173
|
+
rubygems_version: 2.2.2
|
158
174
|
signing_key:
|
159
175
|
specification_version: 4
|
160
176
|
summary: DynamoDB interface
|
161
|
-
test_files:
|
177
|
+
test_files:
|
178
|
+
- spec/dynamini/base_spec.rb
|
179
|
+
- spec/dynamini/batch_operations_spec.rb
|
180
|
+
- spec/dynamini/test_client_spec.rb
|
181
|
+
- spec/spec_helper.rb
|