dynamoid 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +40 -45
- data/README.markdown +55 -25
- data/Rakefile +31 -0
- data/VERSION +1 -1
- data/doc/Dynamoid.html +58 -42
- data/doc/Dynamoid/Adapter.html +666 -179
- data/doc/Dynamoid/Adapter/AwsSdk.html +752 -236
- data/doc/Dynamoid/Associations.html +28 -21
- data/doc/Dynamoid/Associations/Association.html +102 -49
- data/doc/Dynamoid/Associations/BelongsTo.html +28 -25
- data/doc/Dynamoid/Associations/ClassMethods.html +95 -52
- data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +28 -25
- data/doc/Dynamoid/Associations/HasMany.html +28 -25
- data/doc/Dynamoid/Associations/HasOne.html +28 -25
- data/doc/Dynamoid/Associations/ManyAssociation.html +138 -94
- data/doc/Dynamoid/Associations/SingleAssociation.html +67 -38
- data/doc/Dynamoid/Components.html +60 -22
- data/doc/Dynamoid/Config.html +61 -44
- data/doc/Dynamoid/Config/Options.html +90 -61
- data/doc/Dynamoid/Criteria.html +28 -21
- data/doc/Dynamoid/Criteria/Chain.html +508 -100
- data/doc/Dynamoid/Criteria/ClassMethods.html +26 -19
- data/doc/Dynamoid/Dirty.html +424 -0
- data/doc/Dynamoid/Dirty/ClassMethods.html +174 -0
- data/doc/Dynamoid/Document.html +451 -84
- data/doc/Dynamoid/Document/ClassMethods.html +281 -102
- data/doc/Dynamoid/Errors.html +29 -22
- data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +141 -0
- data/doc/Dynamoid/Errors/DocumentNotValid.html +36 -25
- data/doc/Dynamoid/Errors/Error.html +27 -20
- data/doc/Dynamoid/Errors/InvalidField.html +27 -19
- data/doc/Dynamoid/Errors/InvalidQuery.html +131 -0
- data/doc/Dynamoid/Errors/MissingRangeKey.html +27 -19
- data/doc/Dynamoid/Fields.html +94 -77
- data/doc/Dynamoid/Fields/ClassMethods.html +166 -37
- data/doc/Dynamoid/Finders.html +28 -21
- data/doc/Dynamoid/Finders/ClassMethods.html +505 -78
- data/doc/Dynamoid/IdentityMap.html +492 -0
- data/doc/Dynamoid/IdentityMap/ClassMethods.html +534 -0
- data/doc/Dynamoid/Indexes.html +41 -28
- data/doc/Dynamoid/Indexes/ClassMethods.html +45 -29
- data/doc/Dynamoid/Indexes/Index.html +100 -62
- data/doc/Dynamoid/Middleware.html +115 -0
- data/doc/Dynamoid/Middleware/IdentityMap.html +264 -0
- data/doc/Dynamoid/Persistence.html +326 -85
- data/doc/Dynamoid/Persistence/ClassMethods.html +275 -109
- data/doc/Dynamoid/Validations.html +47 -31
- data/doc/_index.html +116 -71
- data/doc/class_list.html +13 -7
- data/doc/css/full_list.css +4 -2
- data/doc/css/style.css +60 -44
- data/doc/file.LICENSE.html +26 -19
- data/doc/file.README.html +152 -48
- data/doc/file_list.html +14 -8
- data/doc/frames.html +20 -5
- data/doc/index.html +152 -48
- data/doc/js/app.js +52 -43
- data/doc/js/full_list.js +14 -9
- data/doc/js/jquery.js +4 -16
- data/doc/method_list.html +446 -540
- data/doc/top-level-namespace.html +27 -20
- data/{Dynamoid.gemspec → dynamoid.gemspec} +21 -8
- data/lib/dynamoid/adapter.rb +11 -10
- data/lib/dynamoid/adapter/aws_sdk.rb +40 -19
- data/lib/dynamoid/components.rb +2 -1
- data/lib/dynamoid/criteria/chain.rb +29 -11
- data/lib/dynamoid/dirty.rb +6 -0
- data/lib/dynamoid/document.rb +34 -19
- data/lib/dynamoid/fields.rb +36 -30
- data/lib/dynamoid/finders.rb +7 -5
- data/lib/dynamoid/persistence.rb +37 -10
- data/spec/app/models/address.rb +2 -0
- data/spec/app/models/camel_case.rb +10 -0
- data/spec/app/models/car.rb +6 -0
- data/spec/app/models/nuclear_submarine.rb +5 -0
- data/spec/app/models/subscription.rb +2 -2
- data/spec/app/models/vehicle.rb +7 -0
- data/spec/dynamoid/adapter/aws_sdk_spec.rb +20 -11
- data/spec/dynamoid/adapter_spec.rb +67 -82
- data/spec/dynamoid/associations/association_spec.rb +30 -30
- data/spec/dynamoid/criteria/chain_spec.rb +56 -9
- data/spec/dynamoid/criteria_spec.rb +3 -0
- data/spec/dynamoid/dirty_spec.rb +8 -0
- data/spec/dynamoid/document_spec.rb +109 -47
- data/spec/dynamoid/fields_spec.rb +32 -3
- data/spec/dynamoid/finders_spec.rb +12 -0
- data/spec/dynamoid/persistence_spec.rb +73 -8
- data/spec/spec_helper.rb +1 -0
- data/spec/support/with_partitioning.rb +15 -0
- metadata +22 -9
@@ -1,17 +1,21 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe Dynamoid::Adapter do
|
4
4
|
|
5
|
+
def test_table; 'dynamoid_tests_TestTable'; end
|
6
|
+
let(:single_id){'123'}
|
7
|
+
let(:many_ids){%w(1 2)}
|
8
|
+
|
5
9
|
before(:all) do
|
6
|
-
|
10
|
+
described_class.create_table(test_table, :id) unless described_class.list_tables.include?(test_table)
|
7
11
|
end
|
8
12
|
|
9
13
|
it 'extends itself automatically' do
|
10
|
-
lambda {
|
14
|
+
lambda {described_class.list_tables}.should_not raise_error
|
11
15
|
end
|
12
|
-
|
13
|
-
it 'raises
|
14
|
-
lambda {
|
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)
|
15
19
|
end
|
16
20
|
|
17
21
|
context 'without partioning' do
|
@@ -25,145 +29,126 @@ describe "Dynamoid::Adapter" do
|
|
25
29
|
end
|
26
30
|
|
27
31
|
it 'writes through the adapter' do
|
28
|
-
|
29
|
-
|
30
|
-
Dynamoid::Adapter.write('dynamoid_tests_TestTable', {:id => '123'})
|
32
|
+
described_class.expects(:put_item).with(test_table, {:id => single_id}, nil).returns(true)
|
33
|
+
described_class.write(test_table, {:id => single_id})
|
31
34
|
end
|
32
35
|
|
33
36
|
it 'reads through the adapter for one ID' do
|
34
|
-
|
35
|
-
|
36
|
-
Dynamoid::Adapter.read('dynamoid_tests_TestTable', '123')
|
37
|
+
described_class.expects(:get_item).with(test_table, single_id, {}).returns(true)
|
38
|
+
described_class.read(test_table, single_id)
|
37
39
|
end
|
38
40
|
|
39
41
|
it 'reads through the adapter for many IDs' do
|
40
|
-
|
41
|
-
|
42
|
-
Dynamoid::Adapter.read('dynamoid_tests_TestTable', ['1', '2'])
|
42
|
+
described_class.expects(:batch_get_item).with({test_table => many_ids}, {}).returns(true)
|
43
|
+
described_class.read(test_table, many_ids)
|
43
44
|
end
|
44
|
-
|
45
|
-
it 'delete through the adapter for one ID' do
|
46
|
-
Dynamoid::Adapter.expects(:delete_item).with('dynamoid_tests_TestTable', '123', {}).returns(nil)
|
47
45
|
|
48
|
-
|
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
49
|
end
|
50
|
-
|
51
|
-
it 'deletes through the adapter for many IDs' do
|
52
|
-
Dynamoid::Adapter.expects(:batch_delete_item).with({'dynamoid_tests_TestTable' => ['1', '2']}).returns(nil)
|
53
50
|
|
54
|
-
|
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)
|
55
54
|
end
|
56
|
-
|
57
|
-
it 'reads through the adapter for one ID and a range key' do
|
58
|
-
Dynamoid::Adapter.expects(:get_item).with('dynamoid_tests_TestTable', '123', :range_key => 2.0).returns(true)
|
59
55
|
|
60
|
-
|
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)
|
61
59
|
end
|
62
|
-
|
63
|
-
it 'reads through the adapter for many IDs and a range key' do
|
64
|
-
Dynamoid::Adapter.expects(:batch_get_item).with({'dynamoid_tests_TestTable' => [['1', 2.0], ['2', 2.0]]}).returns(true)
|
65
60
|
|
66
|
-
|
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)
|
67
64
|
end
|
68
|
-
|
69
|
-
it 'deletes through the adapter for one ID and a range key' do
|
70
|
-
Dynamoid::Adapter.expects(:delete_item).with('dynamoid_tests_TestTable', '123', :range_key => 2.0).returns(nil)
|
71
65
|
|
72
|
-
|
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)
|
73
69
|
end
|
74
|
-
|
75
|
-
it 'deletes through the adapter for many IDs and a range key' do
|
76
|
-
Dynamoid::Adapter.expects(:batch_delete_item).with({'dynamoid_tests_TestTable' => [['1', 2.0], ['2', 2.0]]}).returns(nil)
|
77
70
|
|
78
|
-
|
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])
|
79
74
|
end
|
80
75
|
end
|
81
76
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
Dynamoid::Config.partitioning = true
|
86
|
-
end
|
87
|
-
|
88
|
-
after(:all) do
|
89
|
-
Dynamoid::Config.partitioning = @previous_value
|
90
|
-
end
|
91
|
-
|
77
|
+
configured_with 'partitioning' do
|
78
|
+
let(:partition_range){0...Dynamoid::Config.partition_size}
|
79
|
+
|
92
80
|
it 'writes through the adapter' do
|
93
81
|
Random.expects(:rand).with(Dynamoid::Config.partition_size).once.returns(0)
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
98
86
|
end
|
99
87
|
|
100
88
|
it 'reads through the adapter for one ID' do
|
101
|
-
|
102
|
-
|
103
|
-
Dynamoid::Adapter.read('dynamoid_tests_TestTable', '123')
|
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)
|
104
91
|
end
|
105
92
|
|
106
93
|
it 'reads through the adapter for many IDs' do
|
107
|
-
|
108
|
-
|
109
|
-
Dynamoid::Adapter.read('dynamoid_tests_TestTable', ['1', '2'])
|
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)
|
110
96
|
end
|
111
97
|
|
112
98
|
it 'reads through the adapter for one ID and a range key' do
|
113
|
-
|
114
|
-
|
115
|
-
Dynamoid::Adapter.read('dynamoid_tests_TestTable', '123', :range_key => 2.0)
|
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)
|
116
101
|
end
|
117
102
|
|
118
103
|
it 'reads through the adapter for many IDs and a range key' do
|
119
|
-
|
120
|
-
|
121
|
-
Dynamoid::Adapter.read('dynamoid_tests_TestTable', ['1', '2'], :range_key => 2.0)
|
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)
|
122
106
|
end
|
123
107
|
|
124
108
|
it 'returns an ID with all partitions' do
|
125
|
-
|
109
|
+
described_class.id_with_partitions('1').should =~ partition_range.map{|n| "1.#{n}"}
|
126
110
|
end
|
127
111
|
|
128
112
|
it 'returns an ID and range key with all partitions' do
|
129
|
-
|
113
|
+
described_class.id_with_partitions([['1', 1.0]]).should =~ partition_range.map{|n| ["1.#{n}", 1.0]}
|
130
114
|
end
|
131
115
|
|
132
116
|
it 'returns a result for one partitioned element' do
|
133
117
|
@time = DateTime.now
|
134
|
-
@array =[{:id => '1.0', :updated_at => @time - 6.hours},
|
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}]
|
135
123
|
|
136
|
-
|
124
|
+
described_class.result_for_partition(@array,test_table).should =~ [{:id => '1', :updated_at => @time - 1.hour},
|
125
|
+
{:id => '2', :updated_at => @time}]
|
137
126
|
end
|
138
127
|
|
139
128
|
it 'returns a valid original id and partition number' do
|
140
129
|
@id = "12345.387327.-sdf3"
|
141
130
|
@partition_number = "4"
|
142
|
-
|
131
|
+
described_class.get_original_id_and_partition("#{@id}.#{@partition_number}").should == [@id, @partition_number]
|
143
132
|
end
|
144
133
|
|
145
134
|
it 'delete through the adapter for one ID' do
|
146
|
-
|
147
|
-
|
148
|
-
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', '123')
|
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)
|
149
137
|
end
|
150
138
|
|
151
139
|
it 'deletes through the adapter for many IDs' do
|
152
|
-
|
153
|
-
|
154
|
-
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', ['1', '2'])
|
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)
|
155
142
|
end
|
156
143
|
|
157
144
|
it 'deletes through the adapter for one ID and a range key' do
|
158
|
-
|
159
|
-
|
160
|
-
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', '123', :range_key => 2.0)
|
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)
|
161
147
|
end
|
162
148
|
|
163
149
|
it 'deletes through the adapter for many IDs and a range key' do
|
164
|
-
|
165
|
-
|
166
|
-
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', ['1', '2'], :range_key => [2.0,2.0])
|
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])
|
167
152
|
end
|
168
153
|
end
|
169
154
|
|
@@ -6,30 +6,30 @@ describe "Dynamoid::Associations::Association" do
|
|
6
6
|
Subscription.create_table
|
7
7
|
@magazine = Magazine.create
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
it 'returns an empty array if there are no associations' do
|
11
11
|
@magazine.subscriptions.should be_empty
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
it 'adds an item to an association' do
|
15
15
|
@subscription = Subscription.create
|
16
|
-
|
16
|
+
|
17
17
|
@magazine.subscriptions << @subscription
|
18
18
|
@magazine.subscriptions.size.should == 1
|
19
19
|
@magazine.subscriptions.should include @subscription
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
it 'deletes an item from an association' do
|
23
23
|
@subscription = Subscription.create
|
24
24
|
@magazine.subscriptions << @subscription
|
25
|
-
|
25
|
+
|
26
26
|
@magazine.subscriptions.delete(@subscription)
|
27
27
|
@magazine.subscriptions.size.should == 0
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
it 'creates an item from an association' do
|
31
31
|
@subscription = @magazine.subscriptions.create
|
32
|
-
|
32
|
+
|
33
33
|
@subscription.class.should == Subscription
|
34
34
|
@magazine.subscriptions.size.should == 1
|
35
35
|
@magazine.subscriptions.should include @subscription
|
@@ -38,7 +38,7 @@ describe "Dynamoid::Associations::Association" do
|
|
38
38
|
it 'returns the number of items in the association' do
|
39
39
|
@magazine.subscriptions.create
|
40
40
|
@magazine.subscriptions.size.should == 1
|
41
|
-
|
41
|
+
|
42
42
|
@second = @magazine.subscriptions.create
|
43
43
|
@magazine.subscriptions.size.should == 2
|
44
44
|
|
@@ -48,61 +48,61 @@ describe "Dynamoid::Associations::Association" do
|
|
48
48
|
@magazine.subscriptions = []
|
49
49
|
@magazine.subscriptions.size.should == 0
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
it 'assigns directly via the equals operator' do
|
53
53
|
@subscription = Subscription.create
|
54
54
|
@magazine.subscriptions = [@subscription]
|
55
|
-
|
55
|
+
|
56
56
|
@magazine.subscriptions.should == [@subscription]
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
it 'assigns directly via the equals operator and reflects to the target association' do
|
60
60
|
@subscription = Subscription.create
|
61
61
|
@magazine.subscriptions = [@subscription]
|
62
|
-
|
62
|
+
|
63
63
|
@subscription.magazine.should == @magazine
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
it 'does not assign reflection association if the reflection association does not exist' do
|
67
67
|
@sponsor = Sponsor.create
|
68
|
-
|
68
|
+
|
69
69
|
@subscription = @sponsor.subscriptions.create
|
70
70
|
@subscription.should_not respond_to :sponsor
|
71
71
|
@subscription.should_not respond_to :sponsors
|
72
72
|
@subscription.should_not respond_to :sponsors_ids
|
73
73
|
@subscription.should_not respond_to :sponsor_ids
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
it 'deletes all items from the association' do
|
77
77
|
@magazine.subscriptions << Subscription.create
|
78
78
|
@magazine.subscriptions << Subscription.create
|
79
79
|
@magazine.subscriptions << Subscription.create
|
80
|
-
|
80
|
+
|
81
81
|
@magazine.subscriptions.size.should == 3
|
82
|
-
|
82
|
+
|
83
83
|
@magazine.subscriptions = nil
|
84
84
|
@magazine.subscriptions.size.should == 0
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
it 'uses where inside an association and returns a result' do
|
88
88
|
@included_subscription = @magazine.subscriptions.create(:length => 10)
|
89
89
|
@unincldued_subscription = @magazine.subscriptions.create(:length => 8)
|
90
|
-
|
90
|
+
|
91
91
|
@magazine.subscriptions.where(:length => 10).all.should == [@included_subscription]
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
it 'uses where inside an association and returns an empty set' do
|
95
95
|
@included_subscription = @magazine.subscriptions.create(:length => 10)
|
96
96
|
@unincldued_subscription = @magazine.subscriptions.create(:length => 8)
|
97
|
-
|
97
|
+
|
98
98
|
@magazine.subscriptions.where(:length => 6).all.should be_empty
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
it 'includes enumerable' do
|
102
102
|
@subscription1 = @magazine.subscriptions.create
|
103
103
|
@subscription2 = @magazine.subscriptions.create
|
104
104
|
@subscription3 = @magazine.subscriptions.create
|
105
|
-
|
105
|
+
|
106
106
|
@magazine.subscriptions.collect(&:id).should =~ [@subscription1.id, @subscription2.id, @subscription3.id]
|
107
107
|
end
|
108
108
|
|
@@ -134,41 +134,41 @@ describe "Dynamoid::Associations::Association" do
|
|
134
134
|
#
|
135
135
|
# @magazine.subscriptions.instance_eval { [first, last] }.should == [@subscription1, @subscription3]
|
136
136
|
#end
|
137
|
-
|
137
|
+
|
138
138
|
it 'replaces existing associations when using the setter' do
|
139
139
|
@subscription1 = @magazine.subscriptions.create
|
140
140
|
@subscription2 = @magazine.subscriptions.create
|
141
141
|
@subscription3 = Subscription.create
|
142
|
-
|
142
|
+
|
143
143
|
@subscription1.reload.magazine_ids.should_not be_nil
|
144
144
|
@subscription2.reload.magazine_ids.should_not be_nil
|
145
145
|
|
146
146
|
@magazine.subscriptions = @subscription3
|
147
147
|
@magazine.subscriptions_ids.should == Set[@subscription3.id]
|
148
|
-
|
148
|
+
|
149
149
|
@subscription1.reload.magazine_ids.should be_nil
|
150
150
|
@subscription2.reload.magazine_ids.should be_nil
|
151
151
|
@subscription3.reload.magazine_ids.should == Set[@magazine.id]
|
152
152
|
end
|
153
|
-
|
153
|
+
|
154
154
|
it 'destroys all objects and removes them from the association' do
|
155
155
|
@subscription1 = @magazine.subscriptions.create
|
156
156
|
@subscription2 = @magazine.subscriptions.create
|
157
157
|
@subscription3 = @magazine.subscriptions.create
|
158
158
|
|
159
159
|
@magazine.subscriptions.destroy_all
|
160
|
-
|
160
|
+
|
161
161
|
@magazine.subscriptions.should be_empty
|
162
162
|
Subscription.all.should be_empty
|
163
163
|
end
|
164
|
-
|
164
|
+
|
165
165
|
it 'deletes all objects and removes them from the association' do
|
166
166
|
@subscription1 = @magazine.subscriptions.create
|
167
167
|
@subscription2 = @magazine.subscriptions.create
|
168
168
|
@subscription3 = @magazine.subscriptions.create
|
169
169
|
|
170
170
|
@magazine.subscriptions.delete_all
|
171
|
-
|
171
|
+
|
172
172
|
@magazine.subscriptions.should be_empty
|
173
173
|
Subscription.all.should be_empty
|
174
174
|
end
|
@@ -19,6 +19,11 @@ describe "Dynamoid::Associations::Chain" do
|
|
19
19
|
@chain.send(:index).should == User.indexes[[:email, :name]]
|
20
20
|
end
|
21
21
|
|
22
|
+
it 'makes string symbol for query keys' do
|
23
|
+
@chain.query = {'name' => 'Josh'}
|
24
|
+
@chain.send(:index).should == User.indexes[[:name]]
|
25
|
+
end
|
26
|
+
|
22
27
|
it 'finds matching index for a range query' do
|
23
28
|
@chain.query = {"created_at.gt" => @time - 1.day}
|
24
29
|
@chain.send(:index).should == User.indexes[[:created_at]]
|
@@ -51,26 +56,26 @@ describe "Dynamoid::Associations::Chain" do
|
|
51
56
|
|
52
57
|
it 'finds records with an index' do
|
53
58
|
@chain.query = {:name => 'Josh'}
|
54
|
-
@chain.send(:records_with_index).should ==
|
59
|
+
@chain.send(:records_with_index).should == @user
|
55
60
|
|
56
61
|
@chain.query = {:email => 'josh@joshsymonds.com'}
|
57
|
-
@chain.send(:records_with_index).should ==
|
62
|
+
@chain.send(:records_with_index).should == @user
|
58
63
|
|
59
64
|
@chain.query = {:name => 'Josh', :email => 'josh@joshsymonds.com'}
|
60
|
-
@chain.send(:records_with_index).should ==
|
65
|
+
@chain.send(:records_with_index).should == @user
|
61
66
|
end
|
62
67
|
|
63
68
|
it 'returns records with an index for a ranged query' do
|
64
69
|
@chain.query = {:name => 'Josh', "created_at.gt" => @time - 1.day}
|
65
|
-
@chain.send(:records_with_index).should ==
|
70
|
+
@chain.send(:records_with_index).should == @user
|
66
71
|
|
67
72
|
@chain.query = {:name => 'Josh', "created_at.lt" => @time + 1.day}
|
68
|
-
@chain.send(:records_with_index).should ==
|
73
|
+
@chain.send(:records_with_index).should == @user
|
69
74
|
end
|
70
75
|
|
71
76
|
it 'finds records without an index' do
|
72
77
|
@chain.query = {:password => 'Test123'}
|
73
|
-
@chain.send(:records_without_index).should == [@user]
|
78
|
+
@chain.send(:records_without_index).to_a.should == [@user]
|
74
79
|
end
|
75
80
|
|
76
81
|
it "doesn't crash if it finds a nil id in the index" do
|
@@ -94,14 +99,38 @@ describe "Dynamoid::Associations::Chain" do
|
|
94
99
|
@chain.collect {|u| u.name}.should == ['Josh']
|
95
100
|
end
|
96
101
|
|
97
|
-
it '
|
102
|
+
it 'uses a range query when only a hash key or range key is specified in query' do
|
103
|
+
# Primary key is [hash_key].
|
104
|
+
@chain = Dynamoid::Criteria::Chain.new(Address)
|
105
|
+
@chain.query = {}
|
106
|
+
@chain.send(:range?).should be_false
|
107
|
+
|
108
|
+
@chain = Dynamoid::Criteria::Chain.new(Address)
|
109
|
+
@chain.query = { :id => 'test' }
|
110
|
+
@chain.send(:range?).should be_true
|
111
|
+
|
112
|
+
@chain = Dynamoid::Criteria::Chain.new(Address)
|
113
|
+
@chain.query = { :id => 'test', :city => 'Bucharest' }
|
114
|
+
@chain.send(:range?).should be_false
|
115
|
+
|
116
|
+
# Primary key is [hash_key, range_key].
|
117
|
+
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
118
|
+
@chain.query = { }
|
119
|
+
@chain.send(:range?).should be_false
|
120
|
+
|
98
121
|
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
99
122
|
@chain.query = { :tweet_id => 'test' }
|
100
123
|
@chain.send(:range?).should be_true
|
101
124
|
|
125
|
+
@chain.query = {:tweet_id => 'test', :msg => 'hai'}
|
126
|
+
@chain.send(:range?).should be_false
|
127
|
+
|
102
128
|
@chain.query = {:tweet_id => 'test', :group => 'xx'}
|
103
129
|
@chain.send(:range?).should be_true
|
104
130
|
|
131
|
+
@chain.query = {:tweet_id => 'test', :group => 'xx', :msg => 'hai'}
|
132
|
+
@chain.send(:range?).should be_false
|
133
|
+
|
105
134
|
@chain.query = { :group => 'xx' }
|
106
135
|
@chain.send(:range?).should be_false
|
107
136
|
|
@@ -119,7 +148,7 @@ describe "Dynamoid::Associations::Chain" do
|
|
119
148
|
|
120
149
|
it 'finds tweets with a simple range query' do
|
121
150
|
@chain.query = { :tweet_id => "x" }
|
122
|
-
@chain.send(:records_with_range).size.should == 2
|
151
|
+
@chain.send(:records_with_range).to_a.size.should == 2
|
123
152
|
@chain.all.size.should == 2
|
124
153
|
@chain.limit(1).size.should == 1
|
125
154
|
end
|
@@ -133,7 +162,7 @@ describe "Dynamoid::Associations::Chain" do
|
|
133
162
|
it 'finds one specific tweet' do
|
134
163
|
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
135
164
|
@chain.query = { :tweet_id => "xx", :group => "two" }
|
136
|
-
@chain.send(:records_with_range).should == [@tweet3]
|
165
|
+
@chain.send(:records_with_range).to_a.should == [@tweet3]
|
137
166
|
end
|
138
167
|
end
|
139
168
|
|
@@ -160,4 +189,22 @@ describe "Dynamoid::Associations::Chain" do
|
|
160
189
|
@chain.consistent.all.size.should == 0
|
161
190
|
end
|
162
191
|
end
|
192
|
+
|
193
|
+
context 'batch queries' do
|
194
|
+
before do
|
195
|
+
@tweets = (1..4).map{|count| Tweet.create(:tweet_id => count.to_s, :group => (count % 2).to_s)}
|
196
|
+
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'returns all results' do
|
200
|
+
@chain.batch(2).all.to_a.size.should == @tweets.size
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'throws exception if partitioning is used with batching' do
|
204
|
+
previous_value = Dynamoid::Config.partitioning
|
205
|
+
Dynamoid::Config.partitioning = true
|
206
|
+
expect { @chain.batch(2) }.to raise_error
|
207
|
+
Dynamoid::Config.partitioning = previous_value
|
208
|
+
end
|
209
|
+
end
|
163
210
|
end
|