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,180 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Dynamoid::Document" do
|
|
4
|
+
|
|
5
|
+
it 'initializes a new document' do
|
|
6
|
+
@address = Address.new
|
|
7
|
+
|
|
8
|
+
@address.new_record.should be_true
|
|
9
|
+
@address.attributes.should == {:id=>nil, :created_at=>nil, :updated_at=>nil, :city=>nil, :options=>nil, :deliverable => nil, :lock_version => nil}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'responds to will_change! methods for all fields' do
|
|
13
|
+
@address = Address.new
|
|
14
|
+
@address.should respond_to(:id_will_change!)
|
|
15
|
+
@address.should respond_to(:options_will_change!)
|
|
16
|
+
@address.should respond_to(:created_at_will_change!)
|
|
17
|
+
@address.should respond_to(:updated_at_will_change!)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'initializes a new document with attributes' do
|
|
21
|
+
@address = Address.new(:city => 'Chicago')
|
|
22
|
+
|
|
23
|
+
@address.new_record.should be_true
|
|
24
|
+
|
|
25
|
+
@address.attributes.should == {:id=>nil, :created_at=>nil, :updated_at=>nil, :city=>"Chicago", :options=>nil, :deliverable => nil, :lock_version => nil}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'initializes a new document with a virtual attribute' do
|
|
29
|
+
@address = Address.new(:zip_code => '12345')
|
|
30
|
+
|
|
31
|
+
@address.new_record.should be_true
|
|
32
|
+
|
|
33
|
+
@address.attributes.should == {:id=>nil, :created_at=>nil, :updated_at=>nil, :city=>"Chicago", :options=>nil, :deliverable => nil, :lock_version => nil}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'allows interception of write_attribute on load' do
|
|
37
|
+
class Model
|
|
38
|
+
include Dynamoid::Document
|
|
39
|
+
field :city
|
|
40
|
+
def city=(value); self[:city] = value.downcase; end
|
|
41
|
+
end
|
|
42
|
+
Model.new(:city => "Chicago").city.should == "chicago"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'creates a new document' do
|
|
46
|
+
@address = Address.create(:city => 'Chicago')
|
|
47
|
+
|
|
48
|
+
@address.new_record.should be_false
|
|
49
|
+
@address.id.should_not be_nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'knows if a document exists or not' do
|
|
53
|
+
@address = Address.create(:city => 'Chicago')
|
|
54
|
+
Address.exists?(@address.id).should be_true
|
|
55
|
+
Address.exists?("does-not-exist").should be_false
|
|
56
|
+
Address.exists?(:city => @address.city).should be_true
|
|
57
|
+
Address.exists?(:city => "does-not-exist").should be_false
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'gets errors courtesy of ActiveModel' do
|
|
61
|
+
@address = Address.create(:city => 'Chicago')
|
|
62
|
+
|
|
63
|
+
@address.errors.should be_empty
|
|
64
|
+
@address.errors.full_messages.should be_empty
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context '.reload' do
|
|
68
|
+
let(:address){ Address.create }
|
|
69
|
+
let(:message){ Message.create({:text => 'Nice, supporting datetime range!', :time => Time.now.to_datetime}) }
|
|
70
|
+
let(:tweet){ tweet = Tweet.create(:tweet_id => 'x', :group => 'abc') }
|
|
71
|
+
|
|
72
|
+
it 'reflects persisted changes' do
|
|
73
|
+
address.update_attributes(:city => 'Chicago')
|
|
74
|
+
address.reload.city.should == 'Chicago'
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'uses a :consistent_read' do
|
|
78
|
+
Tweet.expects(:find).with(tweet.hash_key, {:range_key => tweet.range_value, :consistent_read => true}).returns(tweet)
|
|
79
|
+
tweet.reload
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'works with range key' do
|
|
83
|
+
tweet.reload.group.should == 'abc'
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'works with a :datetime range key' do
|
|
87
|
+
expect { message.reload }.to_not raise_error(ArgumentError)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'has default table options' do
|
|
92
|
+
@address = Address.create
|
|
93
|
+
|
|
94
|
+
@address.id.should_not be_nil
|
|
95
|
+
Address.table_name.should == 'dynamoid_tests_addresses'
|
|
96
|
+
Address.hash_key.should == :id
|
|
97
|
+
Address.read_capacity.should == 100
|
|
98
|
+
Address.write_capacity.should == 20
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'follows any table options provided to it' do
|
|
102
|
+
@tweet = Tweet.create(:group => 12345)
|
|
103
|
+
|
|
104
|
+
lambda {@tweet.id}.should raise_error(NoMethodError)
|
|
105
|
+
@tweet.tweet_id.should_not be_nil
|
|
106
|
+
Tweet.table_name.should == 'dynamoid_tests_twitters'
|
|
107
|
+
Tweet.hash_key.should == :tweet_id
|
|
108
|
+
Tweet.read_capacity.should == 200
|
|
109
|
+
Tweet.write_capacity.should == 200
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
shared_examples 'it has equality testing and hashing' do
|
|
113
|
+
it 'is equal to itself' do
|
|
114
|
+
document.should == document
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'is equal to another document with the same key(s)' do
|
|
118
|
+
document.should == same
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'is not equal to another document with different key(s)' do
|
|
122
|
+
document.should_not == different
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it 'is not equal to an object that is not a document' do
|
|
126
|
+
document.should_not == 'test'
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it 'is not equal to nil' do
|
|
130
|
+
document.should_not == nil
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'hashes documents with the keys to the same value' do
|
|
134
|
+
{document => 1}.should have_key(same)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
context 'without a range key' do
|
|
139
|
+
it_behaves_like 'it has equality testing and hashing' do
|
|
140
|
+
let(:document) { Address.create(id: 123, city: 'Seattle') }
|
|
141
|
+
let(:different) { Address.create(id: 456, city: 'Seattle') }
|
|
142
|
+
let(:same) { Address.new(id: 123, city: 'Boston') }
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
context 'with a range key' do
|
|
147
|
+
it_behaves_like 'it has equality testing and hashing' do
|
|
148
|
+
let(:document){ Tweet.create(:tweet_id => 'x', :group => 'abc', :msg => 'foo') }
|
|
149
|
+
let(:different) { Tweet.create(:tweet_id => 'y', :group => 'abc', :msg => 'foo') }
|
|
150
|
+
let(:same) { Tweet.new(:tweet_id => 'x', :group => 'abc', :msg => 'bar') }
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it 'is not equal to another document with the same hash key but a different range value' do
|
|
154
|
+
document = Tweet.create(:tweet_id => 'x', :group => 'abc')
|
|
155
|
+
different = Tweet.create(:tweet_id => 'x', :group => 'xyz')
|
|
156
|
+
|
|
157
|
+
document.should_not == different
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
context 'single table inheritance' do
|
|
162
|
+
it "should have a type" do
|
|
163
|
+
Vehicle.new.type.should == "Vehicle"
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "reports the same table name for both base and derived classes" do
|
|
167
|
+
Vehicle.table_name.should == Car.table_name
|
|
168
|
+
Vehicle.table_name.should == NuclearSubmarine.table_name
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
context '#count' do
|
|
173
|
+
it 'returns the number of documents in the table' do
|
|
174
|
+
document = Tweet.create(:tweet_id => 'x', :group => 'abc')
|
|
175
|
+
different = Tweet.create(:tweet_id => 'x', :group => 'xyz')
|
|
176
|
+
|
|
177
|
+
Tweet.count.should == 2
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Dynamoid::Fields" do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
@address = Address.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'declares read attributes' do
|
|
10
|
+
@address.city.should be_nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'declares write attributes' do
|
|
14
|
+
@address.city = 'Chicago'
|
|
15
|
+
@address.city.should == 'Chicago'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'declares a query attribute' do
|
|
19
|
+
@address.city?.should be_false
|
|
20
|
+
|
|
21
|
+
@address.city = 'Chicago'
|
|
22
|
+
|
|
23
|
+
@address.city?.should be_true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'automatically declares id' do
|
|
27
|
+
lambda {@address.id}.should_not raise_error
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'automatically declares and fills in created_at and updated_at' do
|
|
31
|
+
@address.save
|
|
32
|
+
|
|
33
|
+
@address = @address.reload
|
|
34
|
+
@address.created_at.should_not be_nil
|
|
35
|
+
@address.created_at.class.should == DateTime
|
|
36
|
+
@address.updated_at.should_not be_nil
|
|
37
|
+
@address.updated_at.class.should == DateTime
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context 'with a saved address' do
|
|
41
|
+
before do
|
|
42
|
+
@address = Address.create(:deliverable => true)
|
|
43
|
+
@original_id = @address.id
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'should write an attribute correctly' do
|
|
47
|
+
@address.write_attribute(:city, 'Chicago')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'should write an attribute with an alias' do
|
|
51
|
+
@address[:city] = 'Chicago'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'should read a written attribute' do
|
|
55
|
+
@address.write_attribute(:city, 'Chicago')
|
|
56
|
+
@address.read_attribute(:city).should == 'Chicago'
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'should read a written attribute with the alias' do
|
|
60
|
+
@address.write_attribute(:city, 'Chicago')
|
|
61
|
+
@address[:city].should == 'Chicago'
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'should update all attributes' do
|
|
65
|
+
@address.expects(:save).once.returns(true)
|
|
66
|
+
@address.update_attributes(:city => 'Chicago')
|
|
67
|
+
@address[:city].should == 'Chicago'
|
|
68
|
+
@address.id.should == @original_id
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'should update one attribute' do
|
|
72
|
+
@address.expects(:save).once.returns(true)
|
|
73
|
+
@address.update_attribute(:city, 'Chicago')
|
|
74
|
+
@address[:city].should == 'Chicago'
|
|
75
|
+
@address.id.should == @original_id
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'should update only created_at when no params are passed' do
|
|
79
|
+
@initial_updated_at = @address.updated_at
|
|
80
|
+
@address.update_attributes([])
|
|
81
|
+
@address.updated_at.should_not == @initial_updated_at
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'adds in dirty methods for attributes' do
|
|
85
|
+
@address.city = 'Chicago'
|
|
86
|
+
@address.save
|
|
87
|
+
|
|
88
|
+
@address.city = 'San Francisco'
|
|
89
|
+
|
|
90
|
+
@address.city_was.should == 'Chicago'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'returns all attributes' do
|
|
94
|
+
Address.attributes.should == {:id=>{:type=>:string}, :created_at=>{:type=>:datetime}, :updated_at=>{:type=>:datetime}, :city=>{:type=>:string}, :options=>{:type=>:serialized}, :deliverable => {:type => :boolean}, :lock_version => {:type => :integer}}
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "gives a warning when setting a single value larger than the maximum item size" do
|
|
99
|
+
Dynamoid.logger.expects(:warn).with(regexp_matches(/city field has a length of 66000/))
|
|
100
|
+
Address.new city: ("Ten chars " * 6_600)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context '.remove_attribute' do
|
|
104
|
+
subject { @address }
|
|
105
|
+
before(:each) do
|
|
106
|
+
Address.field :foobar
|
|
107
|
+
Address.remove_field :foobar
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it('should not be in the attributes hash') { Address.attributes.should_not have_key(:foobar) }
|
|
111
|
+
it('removes the accessor') { should_not respond_to(:foobar) }
|
|
112
|
+
it('removes the writer') { should_not respond_to(:foobar=) }
|
|
113
|
+
it('removes the interrogative') { should_not respond_to(:foobar?) }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
context 'default values for fields' do
|
|
117
|
+
before do
|
|
118
|
+
@clazz = Class.new do
|
|
119
|
+
include Dynamoid::Document
|
|
120
|
+
|
|
121
|
+
field :name, :string, :default => 'x'
|
|
122
|
+
field :uid, :integer, :default => lambda { 42 }
|
|
123
|
+
|
|
124
|
+
def self.name
|
|
125
|
+
'Document'
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@doc = @clazz.new
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'returns default value' do
|
|
134
|
+
@doc.name.should eq('x')
|
|
135
|
+
@doc.uid.should eq(42)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'should save default value' do
|
|
139
|
+
@doc.save!
|
|
140
|
+
@doc.reload.name.should eq('x')
|
|
141
|
+
@doc.uid.should eq(42)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
context 'single table inheritance' do
|
|
146
|
+
it "has only base class fields on the base class" do
|
|
147
|
+
Vehicle.attributes.keys.to_set.should == Set.new([:type, :description, :created_at, :updated_at, :id])
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "has only the base and derived fields on a sub-class" do
|
|
151
|
+
#Only NuclearSubmarines have torpedoes
|
|
152
|
+
Car.attributes.should_not have_key(:torpedoes)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Dynamoid::Finders" do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
@address = Address.create(:city => 'Chicago')
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'finds an existing address' do
|
|
10
|
+
found = Address.find(@address.id)
|
|
11
|
+
|
|
12
|
+
found.should == @address
|
|
13
|
+
found.city.should == 'Chicago'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'is not a new object' do
|
|
17
|
+
found = Address.find(@address.id)
|
|
18
|
+
|
|
19
|
+
found.new_record.should_not be_true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'returns nil when nothing is found' do
|
|
23
|
+
Address.find('1234').should be_nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'finds multiple ids' do
|
|
27
|
+
@address2 = Address.create(:city => 'Illinois')
|
|
28
|
+
|
|
29
|
+
Address.find(@address.id, @address2.id).should include @address, @address2
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'sends consistent option to the adapter' do
|
|
33
|
+
Dynamoid::Adapter.expects(:get_item).with { |table_name, key, options| options[:consistent_read] == true }
|
|
34
|
+
Address.find('x', :consistent_read => true)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context 'with users' do
|
|
38
|
+
before do
|
|
39
|
+
User.create_indexes
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'finds using method_missing for attributes' do
|
|
43
|
+
array = Address.find_by_city('Chicago')
|
|
44
|
+
|
|
45
|
+
array.should == @address
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'finds using method_missing for multiple attributes' do
|
|
49
|
+
@user = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
|
|
50
|
+
|
|
51
|
+
array = User.find_all_by_name_and_email('Josh', 'josh@joshsymonds.com')
|
|
52
|
+
|
|
53
|
+
array.should == [@user]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'finds using method_missing for single attributes and multiple results' do
|
|
57
|
+
@user1 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
|
|
58
|
+
@user2 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
|
|
59
|
+
|
|
60
|
+
array = User.find_all_by_name('Josh')
|
|
61
|
+
|
|
62
|
+
array.size.should == 2
|
|
63
|
+
array.should include @user1
|
|
64
|
+
array.should include @user2
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'finds using method_missing for multiple attributes and multiple results' do
|
|
68
|
+
@user1 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
|
|
69
|
+
@user2 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
|
|
70
|
+
|
|
71
|
+
array = User.find_all_by_name_and_email('Josh', 'josh@joshsymonds.com')
|
|
72
|
+
|
|
73
|
+
array.size.should == 2
|
|
74
|
+
array.should include @user1
|
|
75
|
+
array.should include @user2
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'finds using method_missing for multiple attributes and no results' do
|
|
79
|
+
@user1 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
|
|
80
|
+
@user2 = User.create(:name => 'Justin', :email => 'justin@joshsymonds.com')
|
|
81
|
+
|
|
82
|
+
array = User.find_all_by_name_and_email('Gaga','josh@joshsymonds.com')
|
|
83
|
+
|
|
84
|
+
array.should be_empty
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'finds using method_missing for a single attribute and no results' do
|
|
88
|
+
@user1 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
|
|
89
|
+
@user2 = User.create(:name => 'Justin', :email => 'justin@joshsymonds.com')
|
|
90
|
+
|
|
91
|
+
array = User.find_all_by_name('Gaga')
|
|
92
|
+
|
|
93
|
+
array.should be_empty
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'should find on a query that is not indexed' do
|
|
97
|
+
@user = User.create(:password => 'Test')
|
|
98
|
+
|
|
99
|
+
array = User.find_all_by_password('Test')
|
|
100
|
+
|
|
101
|
+
array.should == [@user]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it 'should find on a query on multiple attributes that are not indexed' do
|
|
105
|
+
@user = User.create(:password => 'Test', :name => 'Josh')
|
|
106
|
+
|
|
107
|
+
array = User.find_all_by_password_and_name('Test', 'Josh')
|
|
108
|
+
|
|
109
|
+
array.should == [@user]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'should return an empty array when fields exist but nothing is found' do
|
|
113
|
+
array = User.find_all_by_password('Test')
|
|
114
|
+
|
|
115
|
+
array.should be_empty
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context 'find_all' do
|
|
121
|
+
|
|
122
|
+
it 'should return a array of users' do
|
|
123
|
+
users = (1..10).map { User.create }
|
|
124
|
+
User.find_all(users.map(&:id)).should eq(users)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it 'should return a array of tweets' do
|
|
128
|
+
tweets = (1..10).map { |i| Tweet.create(:tweet_id => "#{i}", :group => "group_#{i}") }
|
|
129
|
+
Tweet.find_all(tweets.map { |t| [t.tweet_id, t.group] }).should eq(tweets)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it 'should return an empty array' do
|
|
133
|
+
User.find_all([]).should eq([])
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'returns empty array when there are no results' do
|
|
137
|
+
Address.find_all('bad' + @address.id.to_s).should eq []
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it 'passes options to the adapter' do
|
|
141
|
+
user_ids = [%w(1 red), %w(1 green)]
|
|
142
|
+
Dynamoid::Adapter.expects(:read).with(anything, user_ids, :consistent_read => true)
|
|
143
|
+
User.find_all(user_ids, :consistent_read => true)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
147
|
+
end
|