dynamodb_record 0.2.2 → 0.3.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/.rubocop.yml +55 -0
- data/dynamodb_record.gemspec +1 -1
- data/lib/dynamodb_record/associations.rb +76 -27
- data/lib/dynamodb_record/collection.rb +18 -27
- data/lib/dynamodb_record/config.rb +2 -0
- data/lib/dynamodb_record/fields.rb +11 -12
- data/lib/dynamodb_record/finders.rb +1 -0
- data/lib/dynamodb_record/has_and_belongs_to_many_collection.rb +67 -0
- data/lib/dynamodb_record/has_many_collection.rb +50 -0
- data/lib/dynamodb_record/has_many_through_collection.rb +44 -0
- data/lib/dynamodb_record/pager.rb +15 -0
- data/lib/dynamodb_record/persistence.rb +19 -19
- data/lib/dynamodb_record/query.rb +12 -9
- data/lib/dynamodb_record/query_pager.rb +28 -0
- data/lib/dynamodb_record/scan_pager.rb +28 -0
- data/lib/dynamodb_record/version.rb +1 -1
- data/lib/dynamodb_record.rb +6 -0
- data/spec/app/models/authorization.rb +0 -1
- data/spec/app/models/car.rb +9 -0
- data/spec/app/models/insurance.rb +9 -0
- data/spec/app/models/service.rb +8 -0
- data/spec/app/models/user.rb +2 -0
- data/spec/dynamodb_record/association_spec.rb +51 -0
- data/spec/dynamodb_record/document_spec.rb +2 -2
- data/spec/dynamodb_record/fields_spec.rb +21 -15
- data/spec/dynamodb_record/persistence_spec.rb +3 -2
- data/spec/dynamodb_record/query_spec.rb +5 -3
- data/spec/fixtures/vcr_cassettes/DynamodbRecord_Associations/_belongs_to/get_object.yml +105 -0
- data/spec/fixtures/vcr_cassettes/DynamodbRecord_Associations/_has_many/add_list.yml +311 -0
- data/spec/fixtures/vcr_cassettes/DynamodbRecord_Associations/_has_many/create_item.yml +156 -0
- data/spec/fixtures/vcr_cassettes/DynamodbRecord_Associations/_has_many/get_collection.yml +105 -0
- data/spec/fixtures/vcr_cassettes/DynamodbRecord_Associations/has_and_belongs_to_many.yml +157 -0
- data/spec/fixtures/vcr_cassettes/DynamodbRecord_Associations/has_and_belongs_to_many_create.yml +207 -0
- data/spec/fixtures/vcr_cassettes/DynamodbRecord_Associations/has_many_through.yml +157 -0
- data/spec/spec_helper.rb +3 -2
- metadata +23 -24
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DynamodbRecord
|
4
|
+
# +Dynamodb::Page+ is a class that include logic business from paginate
|
5
|
+
class QueryPager < Pager
|
6
|
+
attr_reader :last_evaluated_key, :items, :options
|
7
|
+
|
8
|
+
def initialize(options, klass)
|
9
|
+
super(options, klass)
|
10
|
+
response = @klass.client.query(@options)
|
11
|
+
@items = response.items
|
12
|
+
@last_evaluated_key = response.last_evaluated_key
|
13
|
+
end
|
14
|
+
|
15
|
+
def next_page?
|
16
|
+
last_evaluated_key ? true : false
|
17
|
+
end
|
18
|
+
|
19
|
+
def next_page(last_key = nil)
|
20
|
+
return nil unless next_page?
|
21
|
+
|
22
|
+
@last_evaluated_key = last_key if last_key.present?
|
23
|
+
|
24
|
+
@options.merge!(exclusive_start_key: last_evaluated_key) if next_page?
|
25
|
+
self.class.new(@options, @klass)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DynamodbRecord
|
4
|
+
# +Dynamodb::Page+ is a class that include logic business from paginate
|
5
|
+
class ScanPager < Pager
|
6
|
+
attr_reader :last_evaluated_key, :items, :options
|
7
|
+
|
8
|
+
def initialize(options, klass)
|
9
|
+
super(options, klass)
|
10
|
+
response = @klass.client.scan(@options)
|
11
|
+
@items = response.items
|
12
|
+
@last_evaluated_key = response.last_evaluated_key
|
13
|
+
end
|
14
|
+
|
15
|
+
def next_page?
|
16
|
+
last_evaluated_key ? true : false
|
17
|
+
end
|
18
|
+
|
19
|
+
def next_page(last_key = nil)
|
20
|
+
return nil unless next_page?
|
21
|
+
|
22
|
+
@last_evaluated_key = last_key if last_key.present?
|
23
|
+
|
24
|
+
@options.merge!(exclusive_start_key: last_evaluated_key) if next_page?
|
25
|
+
self.class.new(@options, @klass)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/dynamodb_record.rb
CHANGED
@@ -16,6 +16,12 @@ require 'dynamodb_record/associations'
|
|
16
16
|
require 'dynamodb_record/finders'
|
17
17
|
require 'dynamodb_record/query'
|
18
18
|
require 'dynamodb_record/document'
|
19
|
+
require 'dynamodb_record/pager'
|
20
|
+
require 'dynamodb_record/query_pager'
|
21
|
+
require 'dynamodb_record/scan_pager'
|
22
|
+
require 'dynamodb_record/has_and_belongs_to_many_collection'
|
23
|
+
require 'dynamodb_record/has_many_through_collection'
|
24
|
+
require 'dynamodb_record/has_many_collection'
|
19
25
|
|
20
26
|
module DynamodbRecord
|
21
27
|
extend self
|
data/spec/app/models/user.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe DynamodbRecord::Associations, :vcr do
|
6
|
+
it 'has_and_belongs_to_many' do
|
7
|
+
car = Car.find!('UVX455')
|
8
|
+
users = car.users
|
9
|
+
expect(users.count).to eq(1)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'has_many_through' do
|
13
|
+
service = Service.find('c1')
|
14
|
+
users = service.users
|
15
|
+
expect(users).to be_an(DynamodbRecord::HasManyThroughCollection)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'has_and_belongs_to_many create' do
|
19
|
+
car = Car.find!('UVX455')
|
20
|
+
user = car.users.create!(id: 'hguzman50@gmail.com')
|
21
|
+
expect(user).to be_an(User)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#has_many' do
|
25
|
+
it 'get collection' do
|
26
|
+
car = Car.find!('UVX455')
|
27
|
+
insurances = car.insurances
|
28
|
+
expect(insurances).to be_an(DynamodbRecord::HasManyCollection)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'create item' do
|
32
|
+
car = Car.find!('UVX455')
|
33
|
+
insurance = car.insurances.create!(name: 'fasecolda')
|
34
|
+
expect(insurance).to be_an(Insurance)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'add list' do
|
38
|
+
user = User.find!('hguzman10@gmail.com')
|
39
|
+
car = Car.find!('UVX455')
|
40
|
+
user.cars << car
|
41
|
+
expect(user.cars.count).to eq(1)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#belongs_to' do
|
46
|
+
it 'get object' do
|
47
|
+
insurance = Insurance.find!('12345')
|
48
|
+
expect(insurance.car).to be_an(Car)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -18,10 +18,10 @@ RSpec.describe DynamodbRecord::Document do
|
|
18
18
|
# end
|
19
19
|
|
20
20
|
it 'raises error on unknown field' do
|
21
|
-
expect { User.new({
|
21
|
+
expect { User.new({unknown_field: 'unknown'}) }.to raise_error(NoMethodError)
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'can ignore unknown field' do
|
25
|
-
expect { User.new({
|
25
|
+
expect { User.new({unknown_field: 'unknown'}, true) }.to_not raise_error(NoMethodError)
|
26
26
|
end
|
27
27
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative '../spec_helper'
|
4
4
|
|
5
5
|
RSpec.describe DynamodbRecord::Fields do
|
6
6
|
it 'has default id primary key field' do
|
@@ -9,32 +9,34 @@ RSpec.describe DynamodbRecord::Fields do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'accepts adding fields' do
|
12
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock
|
12
13
|
class Employee
|
13
14
|
include DynamodbRecord::Document
|
14
15
|
|
15
16
|
field :first_name, :string
|
16
17
|
field :last_name, :string
|
17
18
|
end
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
# rubocop:enable Lint/ConstantDefinitionInBlock
|
20
|
+
expect(Employee.attributes).to eq({id: {type: :string, options: {}},
|
21
|
+
first_name: {type: :string, options: {}},
|
22
|
+
last_name: {type: :string, options: {}},
|
23
|
+
created_at: {type: :datetime, options: {}},
|
24
|
+
updated_at: {type: :datetime, options: {}}})
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
27
|
it 'accepts default value' do
|
28
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock
|
28
29
|
class City
|
29
30
|
include DynamodbRecord::Document
|
30
31
|
|
31
32
|
field :population, :integer, default: 0
|
32
33
|
end
|
33
|
-
|
34
|
+
# rubocop:enable Lint/ConstantDefinitionInBlock
|
34
35
|
expect(City.new.population).to eq(0)
|
35
36
|
end
|
36
37
|
|
37
|
-
it '
|
38
|
+
it 'coerce field to its data type when initializing' do
|
39
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock
|
38
40
|
class Record
|
39
41
|
include DynamodbRecord::Document
|
40
42
|
|
@@ -44,10 +46,12 @@ RSpec.describe DynamodbRecord::Fields do
|
|
44
46
|
field :boolean_field, :boolean
|
45
47
|
field :array_field, :array
|
46
48
|
end
|
49
|
+
# rubocop:enable Lint/ConstantDefinitionInBlock
|
47
50
|
|
48
51
|
expect(Record.new(integer_field: '1').integer_field).to be_a(Integer)
|
49
52
|
expect(Record.new(big_decimal_field: '1').big_decimal_field).to be_a(BigDecimal)
|
50
|
-
|
53
|
+
datetime_field = Record.new(datetime_field: '2014-12-25T04:08:25Z').datetime_field
|
54
|
+
expect(datetime_field).to eq(DateTime.parse('2014-12-25T04:08:25Z'))
|
51
55
|
expect(Record.new(boolean_field: 'true').boolean_field).to be_truthy
|
52
56
|
expect(Record.new(array_field: %w[admin assistant]).array_field).to be_truthy
|
53
57
|
end
|
@@ -68,7 +72,7 @@ RSpec.describe DynamodbRecord::Fields do
|
|
68
72
|
describe '#unload' do
|
69
73
|
it 'unloads DateTime into String' do
|
70
74
|
now = DateTime.now
|
71
|
-
attrs = Person.unload({
|
75
|
+
attrs = Person.unload({created_at: now})
|
72
76
|
expect(attrs[:created_at]).to eq(now.iso8601)
|
73
77
|
end
|
74
78
|
end
|
@@ -76,7 +80,7 @@ RSpec.describe DynamodbRecord::Fields do
|
|
76
80
|
describe '#attributes=' do
|
77
81
|
it 'set attributes from hash' do
|
78
82
|
person = Person.new(name: 'A Person', activated: true)
|
79
|
-
person.attributes = {
|
83
|
+
person.attributes = {name: 'Updated Person', activated: false}
|
80
84
|
expect(person.name).to eq('Updated Person')
|
81
85
|
expect(person.activated).to eq(false)
|
82
86
|
end
|
@@ -84,25 +88,27 @@ RSpec.describe DynamodbRecord::Fields do
|
|
84
88
|
|
85
89
|
describe 'keys' do
|
86
90
|
it 'returns table\'s range key' do
|
91
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock
|
87
92
|
class ThreadKey
|
88
93
|
include DynamodbRecord::Document
|
89
94
|
|
90
95
|
field :subject, :string, range_key: true
|
91
96
|
end
|
92
|
-
|
97
|
+
# rubocop:enable Lint/ConstantDefinitionInBlock
|
93
98
|
expect(ThreadKey.range_key).to eq(:subject)
|
94
99
|
end
|
95
100
|
end
|
96
101
|
|
97
102
|
describe 'index' do
|
98
103
|
it 'returns table\'s secondary index' do
|
104
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock
|
99
105
|
class ThreadKey
|
100
106
|
include DynamodbRecord::Document
|
101
107
|
|
102
108
|
field :name, :string, hash_key: true
|
103
109
|
field :subject, :string, index: true
|
104
110
|
end
|
105
|
-
|
111
|
+
# rubocop:enable Lint/ConstantDefinitionInBlock
|
106
112
|
expect(ThreadKey.secondary_indexes).to eq([:subject])
|
107
113
|
end
|
108
114
|
end
|
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
RSpec.describe DynamodbRecord::Persistence, :vcr do
|
4
|
-
|
5
6
|
it 'saves record' do
|
6
7
|
user = User.new(id: 'hguzman10@gmail.com')
|
7
8
|
user.save
|
@@ -44,4 +45,4 @@ RSpec.describe DynamodbRecord::Persistence, :vcr do
|
|
44
45
|
end
|
45
46
|
end
|
46
47
|
end
|
47
|
-
end
|
48
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
2
4
|
|
3
5
|
RSpec.describe DynamodbRecord::Query, :vcr do
|
4
6
|
describe '#all' do
|
@@ -18,8 +20,8 @@ RSpec.describe DynamodbRecord::Query, :vcr do
|
|
18
20
|
it 'returns records by limit' do
|
19
21
|
result = User.where(balance: 0, limit: 1)
|
20
22
|
expect(result.count).to eq(1)
|
21
|
-
expect(result.last_evaluated_key).to eq('
|
23
|
+
expect(result.last_evaluated_key).to eq({'id'=>'hguzman20@gmail.com'})
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
25
|
-
end
|
27
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: http://localhost:8000/
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"TableName":"insurances","Key":{"id":{"S":"12345"}}}'
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- ''
|
12
|
+
Content-Type:
|
13
|
+
- application/x-amz-json-1.0
|
14
|
+
X-Amz-Target:
|
15
|
+
- DynamoDB_20120810.GetItem
|
16
|
+
User-Agent:
|
17
|
+
- aws-sdk-ruby3/3.191.3 ua/2.0 api/dynamodb#1.105.0 os/macos#20 md/x86_64 lang/ruby#3.2.3
|
18
|
+
md/3.2.3 cfg/retry-mode#legacy
|
19
|
+
Host:
|
20
|
+
- localhost:8000
|
21
|
+
X-Amz-Date:
|
22
|
+
- 20240512T015903Z
|
23
|
+
X-Amz-Content-Sha256:
|
24
|
+
- af4fbab2106a31baca5b683427566e6620dff714a4febf67de21d62fe9aff004
|
25
|
+
Authorization:
|
26
|
+
- AWS4-HMAC-SHA256 Credential=key/20240512/us-east-1/dynamodb/aws4_request,
|
27
|
+
SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target,
|
28
|
+
Signature=dc0c15194ac1d51a4ad8984e48a0cc3114c900a6b00e2f4dbe13d1a32a53e894
|
29
|
+
Content-Length:
|
30
|
+
- '53'
|
31
|
+
Accept:
|
32
|
+
- "*/*"
|
33
|
+
response:
|
34
|
+
status:
|
35
|
+
code: 200
|
36
|
+
message: OK
|
37
|
+
headers:
|
38
|
+
Date:
|
39
|
+
- Sun, 12 May 2024 01:59:03 GMT
|
40
|
+
X-Amzn-Requestid:
|
41
|
+
- 20483dcf-8a64-4be9-afd8-a5c35c328725
|
42
|
+
Content-Type:
|
43
|
+
- application/x-amz-json-1.0
|
44
|
+
X-Amz-Crc32:
|
45
|
+
- '4004972195'
|
46
|
+
Content-Length:
|
47
|
+
- '80'
|
48
|
+
Server:
|
49
|
+
- Jetty(11.0.17)
|
50
|
+
body:
|
51
|
+
encoding: UTF-8
|
52
|
+
string: '{"Item":{"name":{"S":"Colcerautos"},"car_id":{"S":"UVX455"},"id":{"S":"12345"}}}'
|
53
|
+
recorded_at: Sun, 12 May 2024 01:59:03 GMT
|
54
|
+
- request:
|
55
|
+
method: post
|
56
|
+
uri: http://localhost:8000/
|
57
|
+
body:
|
58
|
+
encoding: UTF-8
|
59
|
+
string: '{"TableName":"cars","Key":{"id":{"S":"UVX455"}}}'
|
60
|
+
headers:
|
61
|
+
Accept-Encoding:
|
62
|
+
- ''
|
63
|
+
Content-Type:
|
64
|
+
- application/x-amz-json-1.0
|
65
|
+
X-Amz-Target:
|
66
|
+
- DynamoDB_20120810.GetItem
|
67
|
+
User-Agent:
|
68
|
+
- aws-sdk-ruby3/3.191.3 ua/2.0 api/dynamodb#1.105.0 os/macos#20 md/x86_64 lang/ruby#3.2.3
|
69
|
+
md/3.2.3 cfg/retry-mode#legacy
|
70
|
+
Host:
|
71
|
+
- localhost:8000
|
72
|
+
X-Amz-Date:
|
73
|
+
- 20240512T015903Z
|
74
|
+
X-Amz-Content-Sha256:
|
75
|
+
- 53644a2bbab903704867eb87df0fdfe6dd8cb8ac9e1dae5715033d0f636fd592
|
76
|
+
Authorization:
|
77
|
+
- AWS4-HMAC-SHA256 Credential=key/20240512/us-east-1/dynamodb/aws4_request,
|
78
|
+
SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target,
|
79
|
+
Signature=436e2db7a75c43c788be0473b6806936b97b7398f33009895010fa5a3eaee5c4
|
80
|
+
Content-Length:
|
81
|
+
- '48'
|
82
|
+
Accept:
|
83
|
+
- "*/*"
|
84
|
+
response:
|
85
|
+
status:
|
86
|
+
code: 200
|
87
|
+
message: OK
|
88
|
+
headers:
|
89
|
+
Date:
|
90
|
+
- Sun, 12 May 2024 01:59:03 GMT
|
91
|
+
X-Amzn-Requestid:
|
92
|
+
- b464ed64-837b-4632-9b14-93a788d62b8d
|
93
|
+
Content-Type:
|
94
|
+
- application/x-amz-json-1.0
|
95
|
+
X-Amz-Crc32:
|
96
|
+
- '590923779'
|
97
|
+
Content-Length:
|
98
|
+
- '149'
|
99
|
+
Server:
|
100
|
+
- Jetty(11.0.17)
|
101
|
+
body:
|
102
|
+
encoding: UTF-8
|
103
|
+
string: '{"Item":{"marca":{"S":"Chvrolet"},"created_at":{"S":"2024-05-07T14:09:25-05:00"},"id":{"S":"UVX455"},"updated_at":{"S":"2024-05-07T14:09:25-05:00"}}}'
|
104
|
+
recorded_at: Sun, 12 May 2024 01:59:03 GMT
|
105
|
+
recorded_with: VCR 6.2.0
|