dynamodb_framework 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/dynamodb_framework/dynamodb_index.rb +119 -0
- data/lib/dynamodb_framework/dynamodb_query.rb +111 -0
- data/lib/dynamodb_framework/dynamodb_repository.rb +37 -7
- data/lib/dynamodb_framework/dynamodb_table.rb +114 -0
- data/lib/dynamodb_framework/version.rb +1 -1
- data/lib/dynamodb_framework.rb +20 -0
- data/spec/dynamodb_index_spec.rb +212 -0
- data/spec/dynamodb_migration_manager_spec.rb +134 -0
- data/spec/dynamodb_namespace_migration_manager_spec.rb +134 -0
- data/spec/dynamodb_query_spec.rb +87 -0
- data/spec/dynamodb_repository_spec.rb +306 -0
- data/spec/dynamodb_table_manager_spec.rb +156 -0
- data/spec/dynamodb_table_spec.rb +245 -0
- data/spec/example_index.rb +45 -0
- data/spec/example_table.rb +41 -0
- data/spec/hash_helper_spec.rb +129 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/test_item.rb +6 -0
- data/spec/test_migration_script1.rb +24 -0
- data/spec/test_migration_script2.rb +24 -0
- metadata +35 -25
- data/.gitignore +0 -14
- data/.idea/.name +0 -1
- data/.idea/.rakeTasks +0 -7
- data/.idea/encodings.xml +0 -6
- data/.idea/misc.xml +0 -33
- data/.idea/modules.xml +0 -8
- data/.idea/vcs.xml +0 -6
- data/.rspec +0 -3
- data/CODE_OF_CONDUCT.md +0 -49
- data/Gemfile +0 -12
- data/LICENSE.txt +0 -21
- data/README.md +0 -394
- data/Rakefile +0 -2
- data/dynamodb_framework.gemspec +0 -29
- data/script/cleanup.sh +0 -6
- data/script/container_loop.sh +0 -6
- data/script/docker-compose.yml +0 -5
- data/script/restart.sh +0 -3
- data/script/start.sh +0 -4
- data/script/stop.sh +0 -2
- data/yard.sh +0 -3
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe DynamoDbFramework::TableManager do
|
4
|
+
|
5
|
+
let(:store) do
|
6
|
+
DynamoDbFramework::Store.new({ endpoint: DYNAMODB_STORE_ENDPOINT, aws_region: 'eu-west-1' })
|
7
|
+
end
|
8
|
+
|
9
|
+
subject do
|
10
|
+
DynamoDbFramework::TableManager.new(store)
|
11
|
+
end
|
12
|
+
|
13
|
+
attributes_builder = DynamoDbFramework::AttributesBuilder.new
|
14
|
+
|
15
|
+
before do
|
16
|
+
attributes_builder = DynamoDbFramework::AttributesBuilder.new
|
17
|
+
attributes_builder.add(:id, :S)
|
18
|
+
|
19
|
+
subject.create('update_throughput', attributes_builder.attributes, :id)
|
20
|
+
|
21
|
+
subject.create('add_index', attributes_builder.attributes, :id)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'can create, check exists & drop tables' do
|
25
|
+
|
26
|
+
exists = subject.exists?('create_drop_test')
|
27
|
+
|
28
|
+
if exists
|
29
|
+
subject.drop('create_drop_test')
|
30
|
+
end
|
31
|
+
|
32
|
+
subject.create('create_drop_test', attributes_builder.attributes, :id)
|
33
|
+
|
34
|
+
subject.drop('create_drop_test')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'can create a table with a hash key and a range key' do
|
38
|
+
|
39
|
+
exists = subject.exists?('dual_key')
|
40
|
+
|
41
|
+
if exists
|
42
|
+
subject.drop('dual_key')
|
43
|
+
end
|
44
|
+
|
45
|
+
subject.create('dual_key', attributes_builder.attributes, :id)
|
46
|
+
|
47
|
+
subject.drop('dual_key')
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'can create a table with a global secondary index' do
|
52
|
+
|
53
|
+
exists = subject.exists?('index_test')
|
54
|
+
|
55
|
+
if exists
|
56
|
+
subject.drop('index_test')
|
57
|
+
end
|
58
|
+
|
59
|
+
global_indexes = []
|
60
|
+
index1 = subject.create_global_index('index1', :name, :number)
|
61
|
+
global_indexes.push(index1)
|
62
|
+
|
63
|
+
builder = DynamoDbFramework::AttributesBuilder.new
|
64
|
+
builder.add(:id, :S)
|
65
|
+
builder.add(:name, :S)
|
66
|
+
builder.add(:number, :N)
|
67
|
+
|
68
|
+
subject.create('index_test', builder.attributes, :id, nil, 20, 10, global_indexes)
|
69
|
+
|
70
|
+
subject.drop('index_test')
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'can update the throughput of a table' do
|
75
|
+
|
76
|
+
subject.update_throughput('update_throughput', 30, 30)
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'can add a global index to an existing table' do
|
81
|
+
|
82
|
+
builder = DynamoDbFramework::AttributesBuilder.new
|
83
|
+
builder.add(:id, :S)
|
84
|
+
builder.add(:name, :S)
|
85
|
+
|
86
|
+
index = subject.create_global_index('new_index', :name, nil)
|
87
|
+
subject.add_index('add_index', builder.attributes, index)
|
88
|
+
|
89
|
+
has_index = subject.has_index?('add_index', 'new_index')
|
90
|
+
|
91
|
+
expect(has_index).to eq(true)
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'can update the throughput of a global secondary index' do
|
96
|
+
|
97
|
+
exists = subject.exists?('update_index_throughput_test')
|
98
|
+
|
99
|
+
if exists
|
100
|
+
subject.drop('update_index_throughput_test')
|
101
|
+
end
|
102
|
+
|
103
|
+
global_indexes = []
|
104
|
+
index1 = subject.create_global_index('index1', :name, :number)
|
105
|
+
global_indexes.push(index1)
|
106
|
+
|
107
|
+
builder = DynamoDbFramework::AttributesBuilder.new
|
108
|
+
builder.add(:id, :S)
|
109
|
+
builder.add(:name, :S)
|
110
|
+
builder.add(:number, :N)
|
111
|
+
|
112
|
+
subject.create('update_index_throughput_test', builder.attributes, :id, nil, 20, 10, global_indexes)
|
113
|
+
|
114
|
+
subject.update_index_throughput('update_index_throughput_test', 'index1', 50, 50)
|
115
|
+
|
116
|
+
subject.drop('update_index_throughput_test')
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'can drop an existing global secondary index' do
|
121
|
+
|
122
|
+
exists = subject.exists?('drop_index_test')
|
123
|
+
|
124
|
+
if exists
|
125
|
+
subject.drop('drop_index_test')
|
126
|
+
end
|
127
|
+
|
128
|
+
global_indexes = []
|
129
|
+
index1 = subject.create_global_index('index1', :name, :number)
|
130
|
+
global_indexes.push(index1)
|
131
|
+
|
132
|
+
builder = DynamoDbFramework::AttributesBuilder.new
|
133
|
+
builder.add(:id, :S)
|
134
|
+
builder.add(:name, :S)
|
135
|
+
builder.add(:number, :N)
|
136
|
+
|
137
|
+
subject.create('drop_index_test', builder.attributes, :id, nil, 20, 10, global_indexes)
|
138
|
+
|
139
|
+
subject.drop_index('drop_index_test', 'index1')
|
140
|
+
|
141
|
+
has_index = subject.has_index?('drop_index_test', 'index1')
|
142
|
+
|
143
|
+
subject.drop('drop_index_test')
|
144
|
+
|
145
|
+
expect(has_index).to eq(false)
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
after do
|
150
|
+
|
151
|
+
subject.drop('update_throughput')
|
152
|
+
subject.drop('add_index')
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
RSpec.describe DynamoDbFramework::Table do
|
2
|
+
|
3
|
+
let(:store) do
|
4
|
+
DynamoDbFramework::Store.new({ endpoint: DYNAMODB_STORE_ENDPOINT, aws_region: 'eu-west-1' })
|
5
|
+
end
|
6
|
+
|
7
|
+
let(:table_manager) do
|
8
|
+
DynamoDbFramework::TableManager.new(store)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#create' do
|
12
|
+
context 'when a valid table class calls the create method' do
|
13
|
+
context 'with a range key' do
|
14
|
+
let(:table_name) { ExampleTable.config[:table_name] }
|
15
|
+
before do
|
16
|
+
table_manager.drop(table_name)
|
17
|
+
end
|
18
|
+
it 'should create the table' do
|
19
|
+
expect(table_manager.exists?(table_name)).to be false
|
20
|
+
ExampleTable.create(store: store)
|
21
|
+
expect(table_manager.exists?(table_name)).to be true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'without a range key' do
|
26
|
+
let(:table_name) { ExampleTableWithoutRangeKey.config[:table_name] }
|
27
|
+
before do
|
28
|
+
table_manager.drop(table_name)
|
29
|
+
end
|
30
|
+
it 'should create the table' do
|
31
|
+
expect(table_manager.exists?(table_name)).to be false
|
32
|
+
ExampleTableWithoutRangeKey.create(store: store)
|
33
|
+
expect(table_manager.exists?(table_name)).to be true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
context 'when an invalid table class calls the create method' do
|
38
|
+
context 'without a table_name specified' do
|
39
|
+
it 'should raise an exception' do
|
40
|
+
expect{ ExampleTableWithoutTableName.create(store: store) }.to raise_error(DynamoDbFramework::Table::InvalidConfigException)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
context 'without a partition_key specified' do
|
44
|
+
it 'should raise an exception' do
|
45
|
+
expect{ ExampleTableWithoutPartitionKey.create(store: store) }.to raise_error(DynamoDbFramework::Table::InvalidConfigException)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#update' do
|
52
|
+
context 'when a valid table class calls the update method' do
|
53
|
+
let(:table_name) { ExampleTable.config[:table_name] }
|
54
|
+
before do
|
55
|
+
table_manager.drop(table_name)
|
56
|
+
ExampleTable.create(store: store)
|
57
|
+
end
|
58
|
+
it 'should update the table' do
|
59
|
+
ExampleTable.update(store: store, read_capacity: 50, write_capacity: 50)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
context 'when an invalid table class calls the update method' do
|
63
|
+
context 'without a table_name specified' do
|
64
|
+
it 'should raise an exception' do
|
65
|
+
expect{ ExampleTableWithoutTableName.update(store: store, read_capacity: 50, write_capacity: 50) }.to raise_error(DynamoDbFramework::Table::InvalidConfigException)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#drop' do
|
72
|
+
context 'when a valid table class calls the drop method' do
|
73
|
+
let(:table_name) { ExampleTable.config[:table_name] }
|
74
|
+
before do
|
75
|
+
table_manager.drop(table_name)
|
76
|
+
ExampleTable.create(store: store)
|
77
|
+
end
|
78
|
+
it 'should drop the table' do
|
79
|
+
ExampleTable.drop(store: store)
|
80
|
+
expect(table_manager.exists?(table_name)).to be false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
context 'when an invalid table class calls the drop method' do
|
84
|
+
context 'without a table_name specified' do
|
85
|
+
it 'should raise an exception' do
|
86
|
+
expect{ ExampleTableWithoutTableName.drop(store: store) }.to raise_error(DynamoDbFramework::Table::InvalidConfigException)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#exists?' do
|
93
|
+
context 'when a table already exists' do
|
94
|
+
let(:table_name) { ExampleTable.config[:table_name] }
|
95
|
+
before do
|
96
|
+
table_manager.drop(table_name)
|
97
|
+
ExampleTable.create(store: store)
|
98
|
+
end
|
99
|
+
it 'should return true' do
|
100
|
+
expect(ExampleTable.exists?(store: store)).to be true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
context 'when a table does NOT already exist' do
|
104
|
+
let(:table_name) { ExampleTable.config[:table_name] }
|
105
|
+
before do
|
106
|
+
table_manager.drop(table_name)
|
107
|
+
end
|
108
|
+
it 'should return false' do
|
109
|
+
expect(ExampleTable.exists?(store: store)).to be false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#query' do
|
115
|
+
|
116
|
+
let(:repository) do
|
117
|
+
DynamoDbFramework::Repository.new(store)
|
118
|
+
end
|
119
|
+
|
120
|
+
let(:table_name) { ExampleTable2.config[:table_name] }
|
121
|
+
|
122
|
+
def create_query_item(name, number)
|
123
|
+
item = TestItem.new
|
124
|
+
item.id = SecureRandom.uuid
|
125
|
+
item.name = name
|
126
|
+
item.timestamp = Time.now
|
127
|
+
item.number = number
|
128
|
+
repository.table_name = table_name
|
129
|
+
repository.put(item)
|
130
|
+
end
|
131
|
+
|
132
|
+
before do
|
133
|
+
table_manager.drop(table_name)
|
134
|
+
ExampleTable2.create(store: store)
|
135
|
+
|
136
|
+
create_query_item('name 1', 1)
|
137
|
+
create_query_item('name 1', 2)
|
138
|
+
create_query_item('name 1', 3)
|
139
|
+
create_query_item('name 1', 4)
|
140
|
+
create_query_item('name 2', 1)
|
141
|
+
create_query_item('name 2', 2)
|
142
|
+
create_query_item('name 2', 3)
|
143
|
+
create_query_item('name 3', 1)
|
144
|
+
create_query_item('name 3', 2)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should return the expected items' do
|
148
|
+
results = ExampleTable2.query(partition: 'name 1')
|
149
|
+
.number.gt_eq(1)
|
150
|
+
.and
|
151
|
+
.number.lt_eq(5)
|
152
|
+
.execute(store: store)
|
153
|
+
expect(results.length).to eq 4
|
154
|
+
end
|
155
|
+
context 'when limit is specified' do
|
156
|
+
it 'should return the expected items' do
|
157
|
+
results = ExampleTable2.query(partition: 'name 1')
|
158
|
+
.number.gt_eq(1)
|
159
|
+
.and
|
160
|
+
.number.lt_eq(5)
|
161
|
+
.execute(store: store, limit: 1)
|
162
|
+
expect(results.length).to eq 1
|
163
|
+
end
|
164
|
+
end
|
165
|
+
context 'when count is specified' do
|
166
|
+
it 'should return the expected count' do
|
167
|
+
count = ExampleTable2.query(partition: 'name 1')
|
168
|
+
.number.gt_eq(1)
|
169
|
+
.and
|
170
|
+
.number.lt_eq(5)
|
171
|
+
.execute(store: store, count: 4)
|
172
|
+
expect(count).to eq 4
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe '#all' do
|
178
|
+
let(:repository) do
|
179
|
+
DynamoDbFramework::Repository.new(store)
|
180
|
+
end
|
181
|
+
|
182
|
+
let(:table_name) { ExampleTable2.config[:table_name] }
|
183
|
+
|
184
|
+
def create_query_item(name, number)
|
185
|
+
item = TestItem.new
|
186
|
+
item.id = SecureRandom.uuid
|
187
|
+
item.name = name
|
188
|
+
item.timestamp = Time.now
|
189
|
+
item.number = number
|
190
|
+
repository.table_name = table_name
|
191
|
+
repository.put(item)
|
192
|
+
end
|
193
|
+
|
194
|
+
before do
|
195
|
+
table_manager.drop(table_name)
|
196
|
+
ExampleTable2.create(store: store)
|
197
|
+
|
198
|
+
create_query_item('name 1', 1)
|
199
|
+
create_query_item('name 1', 2)
|
200
|
+
create_query_item('name 1', 3)
|
201
|
+
create_query_item('name 1', 4)
|
202
|
+
create_query_item('name 2', 1)
|
203
|
+
create_query_item('name 2', 2)
|
204
|
+
create_query_item('name 2', 3)
|
205
|
+
create_query_item('name 3', 1)
|
206
|
+
create_query_item('name 3', 2)
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'should return all items' do
|
210
|
+
results = ExampleTable2.all(store: store)
|
211
|
+
expect(results.length).to eq 9
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe '#CRUD' do
|
216
|
+
let(:repository) do
|
217
|
+
DynamoDbFramework::Repository.new(store)
|
218
|
+
end
|
219
|
+
|
220
|
+
let(:table_name) { ExampleTable.config[:table_name] }
|
221
|
+
|
222
|
+
let(:item) do
|
223
|
+
item = TestItem.new
|
224
|
+
item.id = SecureRandom.uuid
|
225
|
+
item.name = 'abc'
|
226
|
+
item.timestamp = Time.now
|
227
|
+
item.number = 1
|
228
|
+
item
|
229
|
+
end
|
230
|
+
|
231
|
+
let(:table_name) { ExampleTable.config[:table_name] }
|
232
|
+
before do
|
233
|
+
table_manager.drop(table_name)
|
234
|
+
ExampleTable.create(store: store)
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'should add, get and delete the item to the table' do
|
238
|
+
ExampleTable.put_item(store: store, item: item)
|
239
|
+
expect(ExampleTable.get_item(store: store, partition: item.id, range: item.timestamp)).not_to be_nil
|
240
|
+
ExampleTable.delete_item(store: store, partition: item.id, range: item.timestamp)
|
241
|
+
expect(ExampleTable.get_item(store: store, partition: item.id, range: item.timestamp)).to be_nil
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class ExampleIndex
|
2
|
+
extend DynamoDbFramework::Index
|
3
|
+
|
4
|
+
index_name 'example_index'
|
5
|
+
table ExampleTable
|
6
|
+
partition_key :name, :S
|
7
|
+
range_key :id, :S
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
class ExampleIndexWithoutIndexName
|
12
|
+
extend DynamoDbFramework::Index
|
13
|
+
|
14
|
+
table ExampleTable
|
15
|
+
partition_key :name, :S
|
16
|
+
range_key :id, :S
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class ExampleIndexWithoutTable
|
21
|
+
extend DynamoDbFramework::Index
|
22
|
+
|
23
|
+
index_name 'example_index'
|
24
|
+
partition_key :name, :S
|
25
|
+
range_key :id, :S
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
class ExampleIndexWithoutPartitionKey
|
30
|
+
extend DynamoDbFramework::Index
|
31
|
+
|
32
|
+
table ExampleTable
|
33
|
+
index_name 'example_index'
|
34
|
+
range_key :id, :S
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
class ExampleIndexWithoutRangeKey
|
39
|
+
extend DynamoDbFramework::Index
|
40
|
+
|
41
|
+
index_name 'example_index'
|
42
|
+
table ExampleTable
|
43
|
+
partition_key :name, :S
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class ExampleTable
|
2
|
+
extend DynamoDbFramework::Table
|
3
|
+
|
4
|
+
table_name 'example'
|
5
|
+
partition_key :id, :S
|
6
|
+
range_key :timestamp, :N
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
class ExampleTable2
|
11
|
+
extend DynamoDbFramework::Table
|
12
|
+
|
13
|
+
table_name 'example2'
|
14
|
+
partition_key :name, :S
|
15
|
+
range_key :id, :S
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
class ExampleTableWithoutTableName
|
20
|
+
extend DynamoDbFramework::Table
|
21
|
+
|
22
|
+
partition_key :id, :S
|
23
|
+
range_key :timestamp, :N
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class ExampleTableWithoutPartitionKey
|
28
|
+
extend DynamoDbFramework::Table
|
29
|
+
|
30
|
+
table_name 'example'
|
31
|
+
range_key :timestamp, :N
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
class ExampleTableWithoutRangeKey
|
36
|
+
extend DynamoDbFramework::Table
|
37
|
+
|
38
|
+
table_name 'example'
|
39
|
+
partition_key :id, :S
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe DynamoDbFramework::HashHelper do
|
4
|
+
describe '#to_hash' do
|
5
|
+
let(:service_klass) do
|
6
|
+
Class.new do
|
7
|
+
attr_accessor :code, :created
|
8
|
+
end
|
9
|
+
end
|
10
|
+
let(:account_klass) do
|
11
|
+
Class.new do
|
12
|
+
attr_accessor :name, :email, :services
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:current_time ) { Time.now }
|
17
|
+
let(:name ) { 'Service User' }
|
18
|
+
let(:email ) { 'service.user@sage,com' }
|
19
|
+
let(:hr_service_code ) { 'HR' }
|
20
|
+
let(:hr_service_created ) { current_time.to_i }
|
21
|
+
let(:crm_service_code ) { 'CRM' }
|
22
|
+
let(:crm_service_created) { current_time.to_i }
|
23
|
+
|
24
|
+
let(:hr_service) do
|
25
|
+
service_klass.new.tap do |obj|
|
26
|
+
obj.code = hr_service_code
|
27
|
+
obj.created = hr_service_created
|
28
|
+
end
|
29
|
+
end
|
30
|
+
let(:crm_service) do
|
31
|
+
service_klass.new.tap do |obj|
|
32
|
+
obj.code = crm_service_code
|
33
|
+
obj.created = crm_service_created
|
34
|
+
end
|
35
|
+
end
|
36
|
+
let(:account) do
|
37
|
+
account_klass.new.tap do |obj|
|
38
|
+
obj.name = name
|
39
|
+
obj.email = email
|
40
|
+
obj.services = [hr_service, crm_service]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when given a hash' do
|
45
|
+
let(:obj) do
|
46
|
+
{
|
47
|
+
name: name,
|
48
|
+
email: email
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
it { expect(subject.to_hash(obj)).to eq(obj) }
|
53
|
+
|
54
|
+
context 'and one item in the hash is nil' do
|
55
|
+
let(:name) { nil }
|
56
|
+
let(:expected) { { email: email } }
|
57
|
+
|
58
|
+
it { expect(subject.to_hash(obj)).to eq(expected) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'when all attributes are present' do
|
63
|
+
let(:expected) do
|
64
|
+
{
|
65
|
+
name: "Service User",
|
66
|
+
email: "service.user@sage,com",
|
67
|
+
services: [
|
68
|
+
{ code: hr_service_code , created: hr_service_created },
|
69
|
+
{ code: crm_service_code, created: crm_service_created}
|
70
|
+
]
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
it { expect(subject.to_hash(account)).to eq(expected) }
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when parent obj has nil attribute' do
|
78
|
+
let(:name) { nil }
|
79
|
+
let(:expected) do
|
80
|
+
{
|
81
|
+
email: "service.user@sage,com",
|
82
|
+
services: [
|
83
|
+
{ code: hr_service_code , created: hr_service_created },
|
84
|
+
{ code: crm_service_code, created: crm_service_created}
|
85
|
+
]
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
it { expect(subject.to_hash(account)).to eq(expected) }
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when child objects have nil attributes' do
|
93
|
+
let(:hr_service_code ) { nil }
|
94
|
+
let(:crm_service_created) { nil }
|
95
|
+
|
96
|
+
let(:expected) do
|
97
|
+
{
|
98
|
+
name: name,
|
99
|
+
email: email,
|
100
|
+
services: [
|
101
|
+
{ created: hr_service_created },
|
102
|
+
{ code: crm_service_code}
|
103
|
+
]
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
it { expect(subject.to_hash(account)).to eq(expected) }
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'when parent and child objects have nil attributes' do
|
111
|
+
let(:email ) { nil }
|
112
|
+
let(:hr_service_code ) { nil }
|
113
|
+
let(:crm_service_created) { nil }
|
114
|
+
|
115
|
+
let(:expected) do
|
116
|
+
{
|
117
|
+
name: name,
|
118
|
+
services: [
|
119
|
+
{ created: hr_service_created },
|
120
|
+
{ code: crm_service_code}
|
121
|
+
]
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
it { expect(subject.to_hash(account)).to eq(expected) }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
it { expect({a: 1, b: nil}.reject{|k, v| v.nil?}).to eq({a: 1}) }
|
129
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler"
|
3
|
+
require 'aws-sdk-core'
|
4
|
+
require 'dynamodb_framework'
|
5
|
+
require_relative '../spec/test_migration_script1'
|
6
|
+
require_relative '../spec/test_migration_script2'
|
7
|
+
require_relative '../spec/test_item.rb'
|
8
|
+
require_relative '../spec/example_table'
|
9
|
+
require_relative '../spec/example_index'
|
10
|
+
require 'pry'
|
11
|
+
|
12
|
+
require 'simplecov'
|
13
|
+
SimpleCov.start do
|
14
|
+
add_filter '/spec/'
|
15
|
+
end
|
16
|
+
|
17
|
+
DYNAMODB_STORE_ENDPOINT = 'http://dynamodb:8000'
|
18
|
+
|
19
|
+
Aws.config[:credentials] = Aws::Credentials.new('test_key', 'test_secret')
|
20
|
+
Aws.config[:region] = 'eu-west-1'
|
21
|
+
|
22
|
+
RSpec.configure do |config|
|
23
|
+
config.expect_with :rspec do |expectations|
|
24
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
25
|
+
end
|
26
|
+
|
27
|
+
config.mock_with :rspec do |mocks|
|
28
|
+
mocks.verify_partial_doubles = true
|
29
|
+
end
|
30
|
+
|
31
|
+
config.order = :defined
|
32
|
+
end
|
33
|
+
|
34
|
+
DynamoDbFramework.logger.level = Logger::ERROR
|
data/spec/test_item.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
class TestMigrationScript1 < DynamoDbFramework::MigrationScript
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
@timestamp = '20160318110710'
|
5
|
+
@namespace = 'test_namespace'
|
6
|
+
@store = DynamoDbFramework::Store.new({ endpoint: DYNAMODB_STORE_ENDPOINT, aws_region: 'eu-west-1' })
|
7
|
+
@table_manager = DynamoDbFramework::TableManager.new(@store)
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply
|
11
|
+
|
12
|
+
builder = DynamoDbFramework::AttributesBuilder.new
|
13
|
+
builder.add({ name: :id, type: :string, key: :hash })
|
14
|
+
@table_manager.create_table({ name: 'test1', attributes: builder.attributes })
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def undo
|
19
|
+
|
20
|
+
@table_manager.drop('test1')
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class TestMigrationScript2 < DynamoDbFramework::MigrationScript
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
@timestamp = '20160318110730'
|
5
|
+
@namespace = 'test_namespace'
|
6
|
+
@store = DynamoDbFramework::Store.new({ endpoint: DYNAMODB_STORE_ENDPOINT, aws_region: 'eu-west-1' })
|
7
|
+
@table_manager = DynamoDbFramework::TableManager.new(@store)
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply
|
11
|
+
|
12
|
+
builder = DynamoDbFramework::AttributesBuilder.new
|
13
|
+
builder.add(:id, :S)
|
14
|
+
@table_manager.create('test2', builder.attributes, :id)
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def undo
|
19
|
+
|
20
|
+
@table_manager.drop('test2')
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|