dynamo_record 0.0.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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +31 -0
  6. data/Rakefile +7 -0
  7. data/dynamo_record.gemspec +28 -0
  8. data/lib/dynamo_record/collection.rb +31 -0
  9. data/lib/dynamo_record/config.rb +15 -0
  10. data/lib/dynamo_record/document.rb +32 -0
  11. data/lib/dynamo_record/fields.rb +31 -0
  12. data/lib/dynamo_record/finders.rb +17 -0
  13. data/lib/dynamo_record/persistence.rb +85 -0
  14. data/lib/dynamo_record/query.rb +29 -0
  15. data/lib/dynamo_record/version.rb +3 -0
  16. data/lib/dynamo_record.rb +25 -0
  17. data/spec/app/models/address.rb +5 -0
  18. data/spec/app/models/person.rb +5 -0
  19. data/spec/dynamo_record/collection_spec.rb +21 -0
  20. data/spec/dynamo_record/config_spec.rb +25 -0
  21. data/spec/dynamo_record/document_spec.rb +19 -0
  22. data/spec/dynamo_record/fields_spec.rb +29 -0
  23. data/spec/dynamo_record/finders_spec.rb +20 -0
  24. data/spec/dynamo_record/persistence_spec.rb +89 -0
  25. data/spec/dynamo_record/query_spec.rb +58 -0
  26. data/spec/dynamo_record_spec.rb +5 -0
  27. data/spec/fixtures/vcr_cassettes/DynamoRecord_Document/initializes_from_database.yml +52 -0
  28. data/spec/fixtures/vcr_cassettes/DynamoRecord_Fields/_find/finds_record.yml +52 -0
  29. data/spec/fixtures/vcr_cassettes/DynamoRecord_Fields/_find/when_record_doesn_t_exists/returns_empty_object.yml +52 -0
  30. data/spec/fixtures/vcr_cassettes/DynamoRecord_Persistence/_create_table/with_index/creates_table.yml +52 -0
  31. data/spec/fixtures/vcr_cassettes/DynamoRecord_Persistence/_create_table/without_index/creates_table.yml +52 -0
  32. data/spec/fixtures/vcr_cassettes/DynamoRecord_Persistence/does_not_overwrite_existing_record.yml +103 -0
  33. data/spec/fixtures/vcr_cassettes/DynamoRecord_Persistence/updates_record.yml +150 -0
  34. data/spec/fixtures/vcr_cassettes/DynamoRecord_Query/_all/find_all_records.yml +54 -0
  35. data/spec/fixtures/vcr_cassettes/DynamoRecord_Query/_all/find_all_records_with_limie.yml +52 -0
  36. data/spec/fixtures/vcr_cassettes/DynamoRecord_Query/_all/find_all_records_with_limit.yml +52 -0
  37. data/spec/fixtures/vcr_cassettes/DynamoRecord_Query/_all/paginates_records.yml +52 -0
  38. data/spec/fixtures/vcr_cassettes/DynamoRecord_Query/_all/pagination/enumerates_all_pages.yml +199 -0
  39. data/spec/fixtures/vcr_cassettes/DynamoRecord_Query/_all/pagination/navigates_to_next_page.yml +101 -0
  40. data/spec/fixtures/vcr_cassettes/DynamoRecord_Query/_all/pagination/tells_if_there_is_a_next_page.yml +52 -0
  41. data/spec/fixtures/vcr_cassettes/DynamoRecord_Query/_query/queries_by_condition.yml +53 -0
  42. data/spec/fixtures/vcr_cassettes/DynamoRecord_Query/querying/_where/queries_by_condition.yml +53 -0
  43. data/spec/spec_helper.rb +18 -0
  44. metadata +211 -0
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DynamoRecord::Config do
4
+
5
+ after do
6
+ DynamoRecord::Config.set_defaults
7
+ end
8
+
9
+ it 'has default options' do
10
+ expect(DynamoRecord::Config.region).to eq('us-east-1')
11
+ end
12
+
13
+ it 'sets config options' do
14
+ DynamoRecord.configure do |config|
15
+ config.access_key_id = 'key'
16
+ config.secret_access_key = 'secret'
17
+ config.region = 'region'
18
+ end
19
+
20
+ expect(DynamoRecord::Config.access_key_id).to eq('key')
21
+ expect(DynamoRecord::Config.secret_access_key).to eq('secret')
22
+ expect(DynamoRecord::Config.region).to eq('region')
23
+ end
24
+
25
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DynamoRecord::Document do
4
+
5
+ it 'initializes a new document' do
6
+ class Person
7
+ include DynamoRecord::Document
8
+ end
9
+ person = Person.new
10
+ expect(person.new_record).to be_truthy
11
+ expect(person.attributes).to be_empty
12
+ end
13
+
14
+ it 'initializes from database', :vcr do
15
+ person = Person.find('f9b351b0-d06d-4fff-b8d4-8af162e2b8ba')
16
+ expect(person.new_record).to be_falsy
17
+ end
18
+
19
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DynamoRecord::Fields do
4
+
5
+ it 'has default id primary key field' do
6
+ person = Person.new
7
+ expect(person.id).to be_nil
8
+ end
9
+
10
+ it 'accepts adding fields' do
11
+ expect(Person.attributes).to eq({name: {type: :string, options: {}}})
12
+ end
13
+
14
+ it 'accepts adding fields with index' do
15
+ class City
16
+ include DynamoRecord::Document
17
+
18
+ field :name, :string, index: true
19
+ end
20
+
21
+ expect(City.attributes).to eq({name: {type: :string, options: {index: true}}})
22
+ end
23
+
24
+ it 'initializes with field values' do
25
+ person = Person.new(name: 'A person')
26
+ expect(person.name).to eq('A person')
27
+ end
28
+
29
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DynamoRecord::Fields, :vcr do
4
+
5
+ describe '#find' do
6
+ it 'finds record' do
7
+ person = Person.find('f9b351b0-d06d-4fff-b8d4-8af162e2b8ba')
8
+ expect(person.id).to eq('f9b351b0-d06d-4fff-b8d4-8af162e2b8ba')
9
+ expect(person.name).to eq('A person')
10
+ end
11
+
12
+ context 'when record doesn\'t exists' do
13
+ it 'returns empty object' do
14
+ person = Person.find('not here')
15
+ expect(person.id).to be_nil
16
+ end
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DynamoRecord::Persistence, :vcr do
4
+
5
+ it 'has table name' do
6
+ expect(Person.table_name).to eq('people')
7
+ end
8
+
9
+ describe 'namespace' do
10
+ before do
11
+ DynamoRecord.configure do |config|
12
+ config.namespace = 'namespace'
13
+ end
14
+ end
15
+
16
+ after do
17
+ DynamoRecord::Config.set_defaults
18
+ end
19
+
20
+ it 'has table name with namespace' do
21
+ expect(Address.table_name).to eq('namespace_addresses')
22
+ end
23
+ end
24
+
25
+ describe '#create_table' do
26
+ context 'with index' do
27
+ it 'creates table' do
28
+ class IndexCity
29
+ include DynamoRecord::Document
30
+
31
+ field :name, :string, index: true
32
+ end
33
+
34
+ IndexCity.create_table
35
+ end
36
+ end
37
+
38
+ context 'without index' do
39
+ it 'creates table' do
40
+ class NoIndexCity
41
+ include DynamoRecord::Document
42
+
43
+ field :name, :string
44
+ end
45
+
46
+ NoIndexCity.create_table
47
+ end
48
+ end
49
+ end
50
+
51
+ it 'saves record' do
52
+ expect(SecureRandom).to receive(:uuid).and_return('a uuid')
53
+ client = spy('client')
54
+ allow(Person).to receive(:client).and_return(client)
55
+
56
+ person = Person.new(name: 'A person')
57
+ person.save
58
+
59
+ expect(client).to have_received(:put_item).
60
+ with({table_name: 'people',
61
+ item: {id: 'a uuid',
62
+ name: 'A person'}})
63
+ expect(person.new_record).to be_falsy
64
+ expect(person.id).to eq('a uuid')
65
+ end
66
+
67
+ it 'does not overwrite existing record' do
68
+ person = Person.new(id: 'f9b351b0-d06d-4fff-b8d4-8af162e2b8ba', name: 'New item')
69
+ expect(person.save).to be_falsy
70
+
71
+ person = Person.find('f9b351b0-d06d-4fff-b8d4-8af162e2b8ba')
72
+ expect(person.name).to_not eq('New item')
73
+ end
74
+
75
+ it 'updates record' do
76
+ DynamoRecord.configure do |config|
77
+ config.access_key_id = 'key'
78
+ config.secret_access_key = 'TfWvbWtJ96DPM+QduJDXVkGKGbwhIyAYpPSnXad1'
79
+ end
80
+
81
+ person = Person.find('f9b351b0-d06d-4fff-b8d4-8af162e2b8ba')
82
+ person.name = 'New name'
83
+ person.save
84
+
85
+ person = Person.find('f9b351b0-d06d-4fff-b8d4-8af162e2b8ba')
86
+ expect(person.name).to eq('New name')
87
+ end
88
+
89
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DynamoRecord::Query, :vcr do
4
+ before do
5
+ DynamoRecord.configure do |config|
6
+ config.access_key_id = 'key'
7
+ config.secret_access_key = 'TfWvbWtJ96DPM+QduJDXVkGKGbwhIyAYpPSnXad1'
8
+ end
9
+ end
10
+
11
+ describe '#all' do
12
+ it 'find all records' do
13
+ people = Person.all
14
+ expect(people.count).to eq(3)
15
+ expect(people.map(&:name)).to eq(['Person 1', 'Person 2', 'Person 3'])
16
+ end
17
+
18
+ it 'find all records with limit' do
19
+ people = Person.all(limit: 1)
20
+ expect(people.count).to eq(1)
21
+ expect(people.map(&:name)).to eq(['Person 1'])
22
+ end
23
+
24
+ describe 'pagination' do
25
+ it 'tells if there is a next page' do
26
+ people = Person.all(limit: 1)
27
+ expect(people.next_page?).to be_truthy
28
+ end
29
+
30
+ it 'navigates to next page' do
31
+ people = Person.all(limit: 1)
32
+ next_page = people.next_page
33
+ expect(next_page.count).to eq(1)
34
+ expect(next_page.map(&:name)).to eq(['Person 2'])
35
+ end
36
+
37
+ it 'enumerates all pages' do
38
+ records = []
39
+ Person.all(limit: 1).each_page do |page|
40
+ records << page
41
+ end
42
+
43
+ expect(records.first.map(&:name)).to eq(['Person 1'])
44
+ expect(records.second.map(&:name)).to eq(['Person 2'])
45
+ expect(records.third.map(&:name)).to eq(['Person 3'])
46
+ end
47
+ end
48
+ end
49
+
50
+ describe 'querying' do
51
+ describe '#where' do
52
+ it 'queries by condition' do
53
+ people = Person.where(name: 'Person 2')
54
+ expect(people.map(&:name)).to eq(['Person 2'])
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DynamoRecord do
4
+
5
+ end
@@ -0,0 +1,52 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://dynamodb.us-east-1.amazonaws.com/
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"TableName":"people","Key":{"id":{"S":"f9b351b0-d06d-4fff-b8d4-8af162e2b8ba"}}}'
9
+ headers:
10
+ Content-Type:
11
+ - application/x-amz-json-1.0
12
+ Accept-Encoding:
13
+ - ''
14
+ User-Agent:
15
+ - aws-sdk-ruby2/2.0.17 ruby/2.1.2 x86_64-darwin14.0
16
+ X-Amz-Target:
17
+ - DynamoDB_20120810.GetItem
18
+ X-Amz-Date:
19
+ - 20141231T072158Z
20
+ Host:
21
+ - dynamodb.us-east-1.amazonaws.com
22
+ X-Amz-Content-Sha256:
23
+ - 11a49d1d6421d3540cf7a7c96423eb631d8b8de996d5069f178a631eea8d8e01
24
+ Authorization:
25
+ - AWS4-HMAC-SHA256 Credential=key/20141231/us-east-1/dynamodb/aws4_request,
26
+ SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-target,
27
+ Signature=c8f303b4b0b133053cc2efe7f669e0fa82522778902adc796497ac947416887b
28
+ Content-Length:
29
+ - '80'
30
+ Accept:
31
+ - "*/*"
32
+ response:
33
+ status:
34
+ code: 200
35
+ message: OK
36
+ headers:
37
+ X-Amzn-Requestid:
38
+ - MGQQ63GBV5B4O1I0QMLAAH6N6BVV4KQNSO5AEMVJF66Q9ASUAAJG
39
+ X-Amz-Crc32:
40
+ - '3221367258'
41
+ Content-Type:
42
+ - application/x-amz-json-1.0
43
+ Content-Length:
44
+ - '84'
45
+ Date:
46
+ - Wed, 31 Dec 2014 07:21:58 GMT
47
+ body:
48
+ encoding: UTF-8
49
+ string: '{"Item":{"name":{"S":"Person 1"},"id":{"S":"f9b351b0-d06d-4fff-b8d4-8af162e2b8ba"}}}'
50
+ http_version:
51
+ recorded_at: Wed, 31 Dec 2014 07:21:59 GMT
52
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,52 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://dynamodb.us-east-1.amazonaws.com/
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"TableName":"people","Key":{"id":{"S":"f9b351b0-d06d-4fff-b8d4-8af162e2b8ba"}}}'
9
+ headers:
10
+ Content-Type:
11
+ - application/x-amz-json-1.0
12
+ Accept-Encoding:
13
+ - ''
14
+ User-Agent:
15
+ - aws-sdk-ruby2/2.0.17 ruby/2.1.2 x86_64-darwin14.0
16
+ X-Amz-Target:
17
+ - DynamoDB_20120810.GetItem
18
+ X-Amz-Date:
19
+ - 20141230T053939Z
20
+ Host:
21
+ - dynamodb.us-east-1.amazonaws.com
22
+ X-Amz-Content-Sha256:
23
+ - 11a49d1d6421d3540cf7a7c96423eb631d8b8de996d5069f178a631eea8d8e01
24
+ Authorization:
25
+ - AWS4-HMAC-SHA256 Credential=key/20141230/us-east-1/dynamodb/aws4_request,
26
+ SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-target,
27
+ Signature=fcf88dcdbfdfaf7823b478e10e402bc05571dfeffe3e39edc588d4199cc2a318
28
+ Content-Length:
29
+ - '80'
30
+ Accept:
31
+ - "*/*"
32
+ response:
33
+ status:
34
+ code: 200
35
+ message: OK
36
+ headers:
37
+ X-Amzn-Requestid:
38
+ - 57MJJPT0NUE6TP8N2IR82EBQO3VV4KQNSO5AEMVJF66Q9ASUAAJG
39
+ X-Amz-Crc32:
40
+ - '3713739097'
41
+ Content-Type:
42
+ - application/x-amz-json-1.0
43
+ Content-Length:
44
+ - '84'
45
+ Date:
46
+ - Tue, 30 Dec 2014 05:39:41 GMT
47
+ body:
48
+ encoding: UTF-8
49
+ string: '{"Item":{"name":{"S":"A person"},"id":{"S":"f9b351b0-d06d-4fff-b8d4-8af162e2b8ba"}}}'
50
+ http_version:
51
+ recorded_at: Tue, 30 Dec 2014 05:39:41 GMT
52
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,52 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://dynamodb.us-east-1.amazonaws.com/
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"TableName":"people","Key":{"id":{"S":"not here"}}}'
9
+ headers:
10
+ Content-Type:
11
+ - application/x-amz-json-1.0
12
+ Accept-Encoding:
13
+ - ''
14
+ User-Agent:
15
+ - aws-sdk-ruby2/2.0.17 ruby/2.1.2 x86_64-darwin14.0
16
+ X-Amz-Target:
17
+ - DynamoDB_20120810.GetItem
18
+ X-Amz-Date:
19
+ - 20141230T053941Z
20
+ Host:
21
+ - dynamodb.us-east-1.amazonaws.com
22
+ X-Amz-Content-Sha256:
23
+ - 56ecdde2214232f92e4332de89eca1b431c5f79599b1bcce3692cd8adf0c7248
24
+ Authorization:
25
+ - AWS4-HMAC-SHA256 Credential=key/20141230/us-east-1/dynamodb/aws4_request,
26
+ SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-target,
27
+ Signature=70c0bfd738358533fa0fe8b4e01e46481bbb8667fd0d7625dfa51a7282694f51
28
+ Content-Length:
29
+ - '52'
30
+ Accept:
31
+ - "*/*"
32
+ response:
33
+ status:
34
+ code: 200
35
+ message: OK
36
+ headers:
37
+ X-Amzn-Requestid:
38
+ - DV8GC4GTLL5EG7QPCKGGFM1SO3VV4KQNSO5AEMVJF66Q9ASUAAJG
39
+ X-Amz-Crc32:
40
+ - '2745614147'
41
+ Content-Type:
42
+ - application/x-amz-json-1.0
43
+ Content-Length:
44
+ - '2'
45
+ Date:
46
+ - Tue, 30 Dec 2014 05:39:41 GMT
47
+ body:
48
+ encoding: UTF-8
49
+ string: "{}"
50
+ http_version:
51
+ recorded_at: Tue, 30 Dec 2014 05:39:42 GMT
52
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,52 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://dynamodb.us-east-1.amazonaws.com/
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"AttributeDefinitions":[{"AttributeName":"id","AttributeType":"S"},{"AttributeName":"name","AttributeType":"S"}],"TableName":"indexcities","KeySchema":[{"AttributeName":"id","KeyType":"HASH"}],"ProvisionedThroughput":{"ReadCapacityUnits":20,"WriteCapacityUnits":20},"GlobalSecondaryIndexes":[{"IndexName":"name-index","KeySchema":[{"AttributeName":"name","KeyType":"HASH"}],"Projection":{"ProjectionType":"ALL"},"ProvisionedThroughput":{"ReadCapacityUnits":20,"WriteCapacityUnits":20}}]}'
9
+ headers:
10
+ Content-Type:
11
+ - application/x-amz-json-1.0
12
+ Accept-Encoding:
13
+ - ''
14
+ User-Agent:
15
+ - aws-sdk-ruby2/2.0.17 ruby/2.1.2 x86_64-darwin14.0
16
+ X-Amz-Target:
17
+ - DynamoDB_20120810.CreateTable
18
+ X-Amz-Date:
19
+ - 20141231T083113Z
20
+ Host:
21
+ - dynamodb.us-east-1.amazonaws.com
22
+ X-Amz-Content-Sha256:
23
+ - c5ded24b57df8f29482ee7457c489a5a5baeca7f0a6560930cf8578822323162
24
+ Authorization:
25
+ - AWS4-HMAC-SHA256 Credential=key/20141231/us-east-1/dynamodb/aws4_request,
26
+ SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-target,
27
+ Signature=51d5a106760691469c0e2a78a36d27baf4335bf57924c4c06fc4c1ac34400593
28
+ Content-Length:
29
+ - '488'
30
+ Accept:
31
+ - "*/*"
32
+ response:
33
+ status:
34
+ code: 200
35
+ message: OK
36
+ headers:
37
+ X-Amzn-Requestid:
38
+ - GSSH5TN95AUJK6QF3FPVHQEUG7VV4KQNSO5AEMVJF66Q9ASUAAJG
39
+ X-Amz-Crc32:
40
+ - '2558175273'
41
+ Content-Type:
42
+ - application/x-amz-json-1.0
43
+ Content-Length:
44
+ - '715'
45
+ Date:
46
+ - Wed, 31 Dec 2014 08:31:14 GMT
47
+ body:
48
+ encoding: UTF-8
49
+ string: '{"TableDescription":{"AttributeDefinitions":[{"AttributeName":"id","AttributeType":"S"},{"AttributeName":"name","AttributeType":"S"}],"CreationDateTime":1.420014674274E9,"GlobalSecondaryIndexes":[{"IndexName":"name-index","IndexSizeBytes":0,"IndexStatus":"CREATING","ItemCount":0,"KeySchema":[{"AttributeName":"name","KeyType":"HASH"}],"Projection":{"ProjectionType":"ALL"},"ProvisionedThroughput":{"NumberOfDecreasesToday":0,"ReadCapacityUnits":20,"WriteCapacityUnits":20}}],"ItemCount":0,"KeySchema":[{"AttributeName":"id","KeyType":"HASH"}],"ProvisionedThroughput":{"NumberOfDecreasesToday":0,"ReadCapacityUnits":20,"WriteCapacityUnits":20},"TableName":"indexcities","TableSizeBytes":0,"TableStatus":"CREATING"}}'
50
+ http_version:
51
+ recorded_at: Wed, 31 Dec 2014 08:31:14 GMT
52
+ recorded_with: VCR 2.9.3