dynamoid-moda 0.7.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 +15 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +24 -0
- data/Gemfile.lock +118 -0
- data/Gemfile_activemodel4 +24 -0
- data/Gemfile_activemodel4.lock +88 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +360 -0
- data/Rakefile +93 -0
- data/VERSION +1 -0
- data/doc/.nojekyll +0 -0
- data/doc/Dynamoid.html +328 -0
- data/doc/Dynamoid/Adapter.html +1872 -0
- data/doc/Dynamoid/Adapter/AwsSdk.html +2101 -0
- data/doc/Dynamoid/Adapter/Local.html +1574 -0
- data/doc/Dynamoid/Associations.html +138 -0
- data/doc/Dynamoid/Associations/Association.html +847 -0
- data/doc/Dynamoid/Associations/BelongsTo.html +161 -0
- data/doc/Dynamoid/Associations/ClassMethods.html +766 -0
- data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +167 -0
- data/doc/Dynamoid/Associations/HasMany.html +167 -0
- data/doc/Dynamoid/Associations/HasOne.html +161 -0
- data/doc/Dynamoid/Associations/ManyAssociation.html +1684 -0
- data/doc/Dynamoid/Associations/SingleAssociation.html +627 -0
- data/doc/Dynamoid/Components.html +242 -0
- data/doc/Dynamoid/Config.html +412 -0
- data/doc/Dynamoid/Config/Options.html +638 -0
- data/doc/Dynamoid/Criteria.html +138 -0
- data/doc/Dynamoid/Criteria/Chain.html +1471 -0
- data/doc/Dynamoid/Criteria/ClassMethods.html +105 -0
- data/doc/Dynamoid/Dirty.html +424 -0
- data/doc/Dynamoid/Dirty/ClassMethods.html +174 -0
- data/doc/Dynamoid/Document.html +1033 -0
- data/doc/Dynamoid/Document/ClassMethods.html +1116 -0
- data/doc/Dynamoid/Errors.html +125 -0
- data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +141 -0
- data/doc/Dynamoid/Errors/DocumentNotValid.html +221 -0
- data/doc/Dynamoid/Errors/Error.html +137 -0
- data/doc/Dynamoid/Errors/InvalidField.html +141 -0
- data/doc/Dynamoid/Errors/InvalidQuery.html +131 -0
- data/doc/Dynamoid/Errors/MissingRangeKey.html +141 -0
- data/doc/Dynamoid/Fields.html +686 -0
- data/doc/Dynamoid/Fields/ClassMethods.html +438 -0
- data/doc/Dynamoid/Finders.html +135 -0
- data/doc/Dynamoid/Finders/ClassMethods.html +943 -0
- data/doc/Dynamoid/IdentityMap.html +492 -0
- data/doc/Dynamoid/IdentityMap/ClassMethods.html +534 -0
- data/doc/Dynamoid/Indexes.html +321 -0
- data/doc/Dynamoid/Indexes/ClassMethods.html +369 -0
- data/doc/Dynamoid/Indexes/Index.html +1142 -0
- data/doc/Dynamoid/Middleware.html +115 -0
- data/doc/Dynamoid/Middleware/IdentityMap.html +264 -0
- data/doc/Dynamoid/Persistence.html +892 -0
- data/doc/Dynamoid/Persistence/ClassMethods.html +836 -0
- data/doc/Dynamoid/Validations.html +415 -0
- data/doc/_index.html +506 -0
- data/doc/class_list.html +53 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +338 -0
- data/doc/file.LICENSE.html +73 -0
- data/doc/file.README.html +416 -0
- data/doc/file_list.html +58 -0
- data/doc/frames.html +28 -0
- data/doc/index.html +416 -0
- data/doc/js/app.js +214 -0
- data/doc/js/full_list.js +178 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +1144 -0
- data/doc/top-level-namespace.html +112 -0
- data/dynamoid-moda.gemspec +210 -0
- data/dynamoid.gemspec +208 -0
- data/lib/dynamoid.rb +46 -0
- data/lib/dynamoid/adapter.rb +267 -0
- data/lib/dynamoid/adapter/aws_sdk.rb +309 -0
- data/lib/dynamoid/associations.rb +106 -0
- data/lib/dynamoid/associations/association.rb +105 -0
- data/lib/dynamoid/associations/belongs_to.rb +44 -0
- data/lib/dynamoid/associations/has_and_belongs_to_many.rb +40 -0
- data/lib/dynamoid/associations/has_many.rb +39 -0
- data/lib/dynamoid/associations/has_one.rb +39 -0
- data/lib/dynamoid/associations/many_association.rb +191 -0
- data/lib/dynamoid/associations/single_association.rb +69 -0
- data/lib/dynamoid/components.rb +37 -0
- data/lib/dynamoid/config.rb +57 -0
- data/lib/dynamoid/config/options.rb +78 -0
- data/lib/dynamoid/criteria.rb +29 -0
- data/lib/dynamoid/criteria/chain.rb +326 -0
- data/lib/dynamoid/dirty.rb +47 -0
- data/lib/dynamoid/document.rb +199 -0
- data/lib/dynamoid/errors.rb +28 -0
- data/lib/dynamoid/fields.rb +138 -0
- data/lib/dynamoid/finders.rb +133 -0
- data/lib/dynamoid/identity_map.rb +96 -0
- data/lib/dynamoid/indexes.rb +69 -0
- data/lib/dynamoid/indexes/index.rb +103 -0
- data/lib/dynamoid/middleware/identity_map.rb +16 -0
- data/lib/dynamoid/persistence.rb +292 -0
- data/lib/dynamoid/validations.rb +36 -0
- data/spec/app/models/address.rb +13 -0
- data/spec/app/models/camel_case.rb +34 -0
- data/spec/app/models/car.rb +6 -0
- data/spec/app/models/magazine.rb +11 -0
- data/spec/app/models/message.rb +9 -0
- data/spec/app/models/nuclear_submarine.rb +5 -0
- data/spec/app/models/sponsor.rb +8 -0
- data/spec/app/models/subscription.rb +12 -0
- data/spec/app/models/tweet.rb +12 -0
- data/spec/app/models/user.rb +26 -0
- data/spec/app/models/vehicle.rb +7 -0
- data/spec/dynamoid/adapter/aws_sdk_spec.rb +376 -0
- data/spec/dynamoid/adapter_spec.rb +155 -0
- data/spec/dynamoid/associations/association_spec.rb +194 -0
- data/spec/dynamoid/associations/belongs_to_spec.rb +71 -0
- data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +47 -0
- data/spec/dynamoid/associations/has_many_spec.rb +42 -0
- data/spec/dynamoid/associations/has_one_spec.rb +45 -0
- data/spec/dynamoid/associations_spec.rb +16 -0
- data/spec/dynamoid/config_spec.rb +27 -0
- data/spec/dynamoid/criteria/chain_spec.rb +210 -0
- data/spec/dynamoid/criteria_spec.rb +75 -0
- data/spec/dynamoid/dirty_spec.rb +57 -0
- data/spec/dynamoid/document_spec.rb +180 -0
- data/spec/dynamoid/fields_spec.rb +156 -0
- data/spec/dynamoid/finders_spec.rb +147 -0
- data/spec/dynamoid/identity_map_spec.rb +45 -0
- data/spec/dynamoid/indexes/index_spec.rb +104 -0
- data/spec/dynamoid/indexes_spec.rb +25 -0
- data/spec/dynamoid/persistence_spec.rb +301 -0
- data/spec/dynamoid/validations_spec.rb +36 -0
- data/spec/dynamoid_spec.rb +14 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/support/with_partitioning.rb +15 -0
- metadata +363 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Dynamoid::Adapter do
|
|
4
|
+
|
|
5
|
+
def test_table; 'dynamoid_tests_TestTable'; end
|
|
6
|
+
let(:single_id){'123'}
|
|
7
|
+
let(:many_ids){%w(1 2)}
|
|
8
|
+
|
|
9
|
+
before(:all) do
|
|
10
|
+
described_class.create_table(test_table, :id) unless described_class.list_tables.include?(test_table)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'extends itself automatically' do
|
|
14
|
+
lambda {described_class.list_tables}.should_not raise_error
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'raises NoMethodError if we try a method that is not on the child' do
|
|
18
|
+
lambda {described_class.foobar}.should raise_error(NoMethodError)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'without partioning' do
|
|
22
|
+
before(:all) do
|
|
23
|
+
@previous_value = Dynamoid::Config.partitioning
|
|
24
|
+
Dynamoid::Config.partitioning = false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
after(:all) do
|
|
28
|
+
Dynamoid::Config.partitioning = @previous_value
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'writes through the adapter' do
|
|
32
|
+
described_class.expects(:put_item).with(test_table, {:id => single_id}, nil).returns(true)
|
|
33
|
+
described_class.write(test_table, {:id => single_id})
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'reads through the adapter for one ID' do
|
|
37
|
+
described_class.expects(:get_item).with(test_table, single_id, {}).returns(true)
|
|
38
|
+
described_class.read(test_table, single_id)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'reads through the adapter for many IDs' do
|
|
42
|
+
described_class.expects(:batch_get_item).with({test_table => many_ids}, {}).returns(true)
|
|
43
|
+
described_class.read(test_table, many_ids)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'delete through the adapter for one ID' do
|
|
47
|
+
described_class.expects(:delete_item).with(test_table, single_id, {}).returns(nil)
|
|
48
|
+
described_class.delete(test_table, single_id)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'deletes through the adapter for many IDs' do
|
|
52
|
+
described_class.expects(:batch_delete_item).with({test_table => many_ids}).returns(nil)
|
|
53
|
+
described_class.delete(test_table, many_ids)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'reads through the adapter for one ID and a range key' do
|
|
57
|
+
described_class.expects(:get_item).with(test_table, single_id, :range_key => 2.0).returns(true)
|
|
58
|
+
described_class.read(test_table, single_id, :range_key => 2.0)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'reads through the adapter for many IDs and a range key' do
|
|
62
|
+
described_class.expects(:batch_get_item).with({test_table => [['1', 2.0], ['2', 2.0]]}, {}).returns(true)
|
|
63
|
+
described_class.read(test_table, many_ids, :range_key => 2.0)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'deletes through the adapter for one ID and a range key' do
|
|
67
|
+
described_class.expects(:delete_item).with(test_table, single_id, :range_key => 2.0).returns(nil)
|
|
68
|
+
described_class.delete(test_table, single_id, :range_key => 2.0)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'deletes through the adapter for many IDs and a range key' do
|
|
72
|
+
described_class.expects(:batch_delete_item).with({test_table => [['1', 2.0], ['2', 2.0]]}).returns(nil)
|
|
73
|
+
described_class.delete(test_table, many_ids, :range_key => [2.0,2.0])
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
configured_with 'partitioning' do
|
|
78
|
+
let(:partition_range){0...Dynamoid::Config.partition_size}
|
|
79
|
+
|
|
80
|
+
it 'writes through the adapter' do
|
|
81
|
+
Random.expects(:rand).with(Dynamoid::Config.partition_size).once.returns(0)
|
|
82
|
+
described_class.write(test_table, {:id => 'testid'})
|
|
83
|
+
|
|
84
|
+
described_class.get_item(test_table, 'testid.0')[:id].should == 'testid.0'
|
|
85
|
+
described_class.get_item(test_table, 'testid.0')[:updated_at].should_not be_nil
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'reads through the adapter for one ID' do
|
|
89
|
+
described_class.expects(:batch_get_item).with({test_table => partition_range.map{|n| "123.#{n}"}}, {}).returns({})
|
|
90
|
+
described_class.read(test_table, single_id)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'reads through the adapter for many IDs' do
|
|
94
|
+
described_class.expects(:batch_get_item).with({test_table => partition_range.map{|n| "1.#{n}"} + partition_range.map{|n| "2.#{n}"}}, {}).returns({})
|
|
95
|
+
described_class.read(test_table, many_ids)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'reads through the adapter for one ID and a range key' do
|
|
99
|
+
described_class.expects(:batch_get_item).with({test_table => partition_range.map{|n| ["123.#{n}", 2.0]}}, {}).returns({})
|
|
100
|
+
described_class.read(test_table, single_id, :range_key => 2.0)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'reads through the adapter for many IDs and a range key' do
|
|
104
|
+
described_class.expects(:batch_get_item).with({test_table => partition_range.map{|n| ["1.#{n}", 2.0]} + partition_range.map{|n| ["2.#{n}", 2.0]}}, {}).returns({})
|
|
105
|
+
described_class.read(test_table, many_ids, :range_key => 2.0)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'returns an ID with all partitions' do
|
|
109
|
+
described_class.id_with_partitions('1').should =~ partition_range.map{|n| "1.#{n}"}
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'returns an ID and range key with all partitions' do
|
|
113
|
+
described_class.id_with_partitions([['1', 1.0]]).should =~ partition_range.map{|n| ["1.#{n}", 1.0]}
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'returns a result for one partitioned element' do
|
|
117
|
+
@time = DateTime.now
|
|
118
|
+
@array =[{:id => '1.0', :updated_at => @time - 6.hours},
|
|
119
|
+
{:id => '1.1', :updated_at => @time - 3.hours},
|
|
120
|
+
{:id => '1.2', :updated_at => @time - 1.hour},
|
|
121
|
+
{:id => '1.3', :updated_at => @time - 6.hours},
|
|
122
|
+
{:id => '2.0', :updated_at => @time}]
|
|
123
|
+
|
|
124
|
+
described_class.result_for_partition(@array,test_table).should =~ [{:id => '1', :updated_at => @time - 1.hour},
|
|
125
|
+
{:id => '2', :updated_at => @time}]
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it 'returns a valid original id and partition number' do
|
|
129
|
+
@id = "12345.387327.-sdf3"
|
|
130
|
+
@partition_number = "4"
|
|
131
|
+
described_class.get_original_id_and_partition("#{@id}.#{@partition_number}").should == [@id, @partition_number]
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'delete through the adapter for one ID' do
|
|
135
|
+
described_class.expects(:batch_delete_item).with(test_table => partition_range.map{|n| "123.#{n}"}).returns(nil)
|
|
136
|
+
described_class.delete(test_table, single_id)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it 'deletes through the adapter for many IDs' do
|
|
140
|
+
described_class.expects(:batch_delete_item).with(test_table => partition_range.map{|n| "1.#{n}"} + partition_range.map{|n| "2.#{n}"}).returns(nil)
|
|
141
|
+
described_class.delete(test_table, many_ids)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it 'deletes through the adapter for one ID and a range key' do
|
|
145
|
+
described_class.expects(:batch_delete_item).with(test_table => partition_range.map{|n| ["123.#{n}", 2.0]}).returns(nil)
|
|
146
|
+
described_class.delete(test_table, single_id, :range_key => 2.0)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'deletes through the adapter for many IDs and a range key' do
|
|
150
|
+
described_class.expects(:batch_delete_item).with(test_table => partition_range.map{|n| ["1.#{n}", 2.0]} + partition_range.map{|n| ["2.#{n}", 2.0]}).returns(nil)
|
|
151
|
+
described_class.delete(test_table, many_ids, :range_key => [2.0,2.0])
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
end
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Dynamoid::Associations::Association" do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
Subscription.create_table
|
|
7
|
+
@magazine = Magazine.create
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'returns an empty array if there are no associations' do
|
|
11
|
+
@magazine.subscriptions.should be_empty
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'adds an item to an association' do
|
|
15
|
+
@subscription = Subscription.create
|
|
16
|
+
|
|
17
|
+
@magazine.subscriptions << @subscription
|
|
18
|
+
@magazine.subscriptions.size.should == 1
|
|
19
|
+
@magazine.subscriptions.should include @subscription
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'deletes an item from an association' do
|
|
23
|
+
@subscription = Subscription.create
|
|
24
|
+
@magazine.subscriptions << @subscription
|
|
25
|
+
|
|
26
|
+
@magazine.subscriptions.delete(@subscription)
|
|
27
|
+
@magazine.subscriptions.size.should == 0
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'creates an item from an association' do
|
|
31
|
+
@subscription = @magazine.subscriptions.create
|
|
32
|
+
|
|
33
|
+
@subscription.class.should == Subscription
|
|
34
|
+
@magazine.subscriptions.size.should == 1
|
|
35
|
+
@magazine.subscriptions.should include @subscription
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'returns the number of items in the association' do
|
|
39
|
+
@magazine.subscriptions.create
|
|
40
|
+
@magazine.subscriptions.size.should == 1
|
|
41
|
+
|
|
42
|
+
@second = @magazine.subscriptions.create
|
|
43
|
+
@magazine.subscriptions.size.should == 2
|
|
44
|
+
|
|
45
|
+
@magazine.subscriptions.delete(@second)
|
|
46
|
+
@magazine.subscriptions.size.should == 1
|
|
47
|
+
|
|
48
|
+
@magazine.subscriptions = []
|
|
49
|
+
@magazine.subscriptions.size.should == 0
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'assigns directly via the equals operator' do
|
|
53
|
+
@subscription = Subscription.create
|
|
54
|
+
@magazine.subscriptions = [@subscription]
|
|
55
|
+
|
|
56
|
+
@magazine.subscriptions.should == [@subscription]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'assigns directly via the equals operator and reflects to the target association' do
|
|
60
|
+
@subscription = Subscription.create
|
|
61
|
+
@magazine.subscriptions = [@subscription]
|
|
62
|
+
|
|
63
|
+
@subscription.magazine.should == @magazine
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'does not assign reflection association if the reflection association does not exist' do
|
|
67
|
+
@sponsor = Sponsor.create
|
|
68
|
+
|
|
69
|
+
@subscription = @sponsor.subscriptions.create
|
|
70
|
+
@subscription.should_not respond_to :sponsor
|
|
71
|
+
@subscription.should_not respond_to :sponsors
|
|
72
|
+
@subscription.should_not respond_to :sponsors_ids
|
|
73
|
+
@subscription.should_not respond_to :sponsor_ids
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'deletes all items from the association' do
|
|
77
|
+
@magazine.subscriptions << Subscription.create
|
|
78
|
+
@magazine.subscriptions << Subscription.create
|
|
79
|
+
@magazine.subscriptions << Subscription.create
|
|
80
|
+
|
|
81
|
+
@magazine.subscriptions.size.should == 3
|
|
82
|
+
|
|
83
|
+
@magazine.subscriptions = nil
|
|
84
|
+
@magazine.subscriptions.size.should == 0
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'uses where inside an association and returns a result' do
|
|
88
|
+
@included_subscription = @magazine.subscriptions.create(:length => 10)
|
|
89
|
+
@unincldued_subscription = @magazine.subscriptions.create(:length => 8)
|
|
90
|
+
|
|
91
|
+
@magazine.subscriptions.where(:length => 10).all.should == [@included_subscription]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'uses where inside an association and returns an empty set' do
|
|
95
|
+
@included_subscription = @magazine.subscriptions.create(:length => 10)
|
|
96
|
+
@unincldued_subscription = @magazine.subscriptions.create(:length => 8)
|
|
97
|
+
|
|
98
|
+
@magazine.subscriptions.where(:length => 6).all.should be_empty
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'includes enumerable' do
|
|
102
|
+
@subscription1 = @magazine.subscriptions.create
|
|
103
|
+
@subscription2 = @magazine.subscriptions.create
|
|
104
|
+
@subscription3 = @magazine.subscriptions.create
|
|
105
|
+
|
|
106
|
+
@magazine.subscriptions.collect(&:id).should =~ [@subscription1.id, @subscription2.id, @subscription3.id]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'works for camel-cased associations' do
|
|
110
|
+
@magazine.camel_cases.create.class.should == CamelCase
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'destroys associations' do
|
|
114
|
+
@subscription = Subscription.new
|
|
115
|
+
@magazine.subscriptions.expects(:target).returns([@subscription])
|
|
116
|
+
@subscription.expects(:destroy)
|
|
117
|
+
|
|
118
|
+
@magazine.subscriptions.destroy_all
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'deletes associations' do
|
|
122
|
+
@subscription = Subscription.new
|
|
123
|
+
@magazine.subscriptions.expects(:target).returns([@subscription])
|
|
124
|
+
@subscription.expects(:delete)
|
|
125
|
+
|
|
126
|
+
@magazine.subscriptions.delete_all
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# TODO This test is broken using the AWS SDK adapter.
|
|
130
|
+
#it 'returns the first and last record when they exist' do
|
|
131
|
+
# @subscription1 = @magazine.subscriptions.create
|
|
132
|
+
# @subscription2 = @magazine.subscriptions.create
|
|
133
|
+
# @subscription3 = @magazine.subscriptions.create
|
|
134
|
+
#
|
|
135
|
+
# @magazine.subscriptions.instance_eval { [first, last] }.should == [@subscription1, @subscription3]
|
|
136
|
+
#end
|
|
137
|
+
|
|
138
|
+
it 'replaces existing associations when using the setter' do
|
|
139
|
+
@subscription1 = @magazine.subscriptions.create
|
|
140
|
+
@subscription2 = @magazine.subscriptions.create
|
|
141
|
+
@subscription3 = Subscription.create
|
|
142
|
+
|
|
143
|
+
@subscription1.reload.magazine_ids.should_not be_nil
|
|
144
|
+
@subscription2.reload.magazine_ids.should_not be_nil
|
|
145
|
+
|
|
146
|
+
@magazine.subscriptions = @subscription3
|
|
147
|
+
@magazine.subscriptions_ids.should == Set[@subscription3.id]
|
|
148
|
+
|
|
149
|
+
@subscription1.reload.magazine_ids.should be_nil
|
|
150
|
+
@subscription2.reload.magazine_ids.should be_nil
|
|
151
|
+
@subscription3.reload.magazine_ids.should == Set[@magazine.id]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it 'destroys all objects and removes them from the association' do
|
|
155
|
+
@subscription1 = @magazine.subscriptions.create
|
|
156
|
+
@subscription2 = @magazine.subscriptions.create
|
|
157
|
+
@subscription3 = @magazine.subscriptions.create
|
|
158
|
+
|
|
159
|
+
@magazine.subscriptions.destroy_all
|
|
160
|
+
|
|
161
|
+
@magazine.subscriptions.should be_empty
|
|
162
|
+
Subscription.all.should be_empty
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it 'deletes all objects and removes them from the association' do
|
|
166
|
+
@subscription1 = @magazine.subscriptions.create
|
|
167
|
+
@subscription2 = @magazine.subscriptions.create
|
|
168
|
+
@subscription3 = @magazine.subscriptions.create
|
|
169
|
+
|
|
170
|
+
@magazine.subscriptions.delete_all
|
|
171
|
+
|
|
172
|
+
@magazine.subscriptions.should be_empty
|
|
173
|
+
Subscription.all.should be_empty
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it 'delegates class to the association object' do
|
|
177
|
+
@magazine.sponsor.class.should == nil.class
|
|
178
|
+
@magazine.sponsor.create
|
|
179
|
+
@magazine.sponsor.class.should == Sponsor
|
|
180
|
+
|
|
181
|
+
@magazine.subscriptions.class.should == Array
|
|
182
|
+
@magazine.subscriptions.create
|
|
183
|
+
@magazine.subscriptions.class.should == Array
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it 'loads association one time only' do
|
|
187
|
+
@sponsor = @magazine.sponsor.create
|
|
188
|
+
@magazine.sponsor.expects(:find_target).once.returns(@sponsor)
|
|
189
|
+
|
|
190
|
+
@magazine.sponsor.id
|
|
191
|
+
@magazine.sponsor.id
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Dynamoid::Associations::BelongsTo" do
|
|
4
|
+
|
|
5
|
+
context 'has many' do
|
|
6
|
+
before do
|
|
7
|
+
@subscription = Subscription.create
|
|
8
|
+
@camel_case = CamelCase.create
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'determines nil if it has no associated record' do
|
|
12
|
+
@subscription.magazine.should be_nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'determines target association correctly' do
|
|
16
|
+
@camel_case.magazine.send(:target_association).should == :camel_cases
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
it 'delegates equality to its source record' do
|
|
21
|
+
@magazine = @subscription.magazine.create
|
|
22
|
+
|
|
23
|
+
@subscription.magazine.should == @magazine
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'associates has_many automatically' do
|
|
27
|
+
@magazine = @subscription.magazine.create
|
|
28
|
+
|
|
29
|
+
@magazine.subscriptions.should include @subscription
|
|
30
|
+
|
|
31
|
+
@magazine = Magazine.create
|
|
32
|
+
@user = @magazine.owner.create
|
|
33
|
+
@user.books.size.should == 1
|
|
34
|
+
@user.books.should include @magazine
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'behaves like the object it is trying to be' do
|
|
38
|
+
@magazine = @subscription.magazine.create
|
|
39
|
+
|
|
40
|
+
@subscription.magazine.update_attribute(:title, 'Test Title')
|
|
41
|
+
|
|
42
|
+
Magazine.first.title.should == 'Test Title'
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context 'has one' do
|
|
47
|
+
before do
|
|
48
|
+
@sponsor = Sponsor.create
|
|
49
|
+
@subscription = Subscription.create
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'determins nil if it has no associated record' do
|
|
53
|
+
@sponsor.magazine.should be_nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'delegates equality to its source record' do
|
|
57
|
+
@magazine = @sponsor.magazine.create
|
|
58
|
+
|
|
59
|
+
@sponsor.magazine.should == @magazine
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'associates has_one automatically' do
|
|
63
|
+
@magazine = @sponsor.magazine.create
|
|
64
|
+
|
|
65
|
+
@magazine.sponsor.should == @sponsor
|
|
66
|
+
|
|
67
|
+
@user = @subscription.customer.create
|
|
68
|
+
@user.monthly.should == @subscription
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Dynamoid::Associations::HasAndBelongsToMany" do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
@subscription = Subscription.create
|
|
7
|
+
@camel_case = CamelCase.create
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'determines equality from its records' do
|
|
11
|
+
@user = @subscription.users.create
|
|
12
|
+
|
|
13
|
+
@subscription.users.size.should == 1
|
|
14
|
+
@subscription.users.should include @user
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'determines target association correctly' do
|
|
18
|
+
@subscription.users.send(:target_association).should == :subscriptions
|
|
19
|
+
@camel_case.subscriptions.send(:target_association).should == :camel_cases
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'determines target attribute' do
|
|
23
|
+
@subscription.users.send(:target_attribute).should == :subscriptions_ids
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'associates has_and_belongs_to_many automatically' do
|
|
27
|
+
@user = @subscription.users.create
|
|
28
|
+
|
|
29
|
+
@user.subscriptions.size.should == 1
|
|
30
|
+
@user.subscriptions.should include @subscription
|
|
31
|
+
@subscription.users.size.should == 1
|
|
32
|
+
@subscription.users.should include @user
|
|
33
|
+
|
|
34
|
+
@user = User.create
|
|
35
|
+
@follower = @user.followers.create
|
|
36
|
+
@follower.following.should include @user
|
|
37
|
+
@user.followers.should include @follower
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'disassociates has_and_belongs_to_many automatically' do
|
|
41
|
+
@user = @subscription.users.create
|
|
42
|
+
|
|
43
|
+
@subscription.users.delete(@user)
|
|
44
|
+
@subscription.users.size.should == 0
|
|
45
|
+
@user.subscriptions.size.should == 0
|
|
46
|
+
end
|
|
47
|
+
end
|