adept_dynamoid 0.5.0.6
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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Dynamoid.gemspec +193 -0
- data/Gemfile +23 -0
- data/Gemfile.lock +86 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +265 -0
- data/Rakefile +62 -0
- data/VERSION +1 -0
- data/doc/.nojekyll +0 -0
- data/doc/Dynamoid.html +312 -0
- data/doc/Dynamoid/Adapter.html +1385 -0
- data/doc/Dynamoid/Adapter/AwsSdk.html +1585 -0
- data/doc/Dynamoid/Adapter/Local.html +1574 -0
- data/doc/Dynamoid/Associations.html +131 -0
- data/doc/Dynamoid/Associations/Association.html +794 -0
- data/doc/Dynamoid/Associations/BelongsTo.html +158 -0
- data/doc/Dynamoid/Associations/ClassMethods.html +723 -0
- data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +164 -0
- data/doc/Dynamoid/Associations/HasMany.html +164 -0
- data/doc/Dynamoid/Associations/HasOne.html +158 -0
- data/doc/Dynamoid/Associations/ManyAssociation.html +1640 -0
- data/doc/Dynamoid/Associations/SingleAssociation.html +598 -0
- data/doc/Dynamoid/Components.html +204 -0
- data/doc/Dynamoid/Config.html +395 -0
- data/doc/Dynamoid/Config/Options.html +609 -0
- data/doc/Dynamoid/Criteria.html +131 -0
- data/doc/Dynamoid/Criteria/Chain.html +1063 -0
- data/doc/Dynamoid/Criteria/ClassMethods.html +98 -0
- data/doc/Dynamoid/Document.html +666 -0
- data/doc/Dynamoid/Document/ClassMethods.html +937 -0
- data/doc/Dynamoid/Errors.html +118 -0
- data/doc/Dynamoid/Errors/DocumentNotValid.html +210 -0
- data/doc/Dynamoid/Errors/Error.html +130 -0
- data/doc/Dynamoid/Errors/InvalidField.html +133 -0
- data/doc/Dynamoid/Errors/MissingRangeKey.html +133 -0
- data/doc/Dynamoid/Fields.html +669 -0
- data/doc/Dynamoid/Fields/ClassMethods.html +309 -0
- data/doc/Dynamoid/Finders.html +128 -0
- data/doc/Dynamoid/Finders/ClassMethods.html +516 -0
- data/doc/Dynamoid/Indexes.html +308 -0
- data/doc/Dynamoid/Indexes/ClassMethods.html +353 -0
- data/doc/Dynamoid/Indexes/Index.html +1104 -0
- data/doc/Dynamoid/Persistence.html +651 -0
- data/doc/Dynamoid/Persistence/ClassMethods.html +670 -0
- data/doc/Dynamoid/Validations.html +399 -0
- data/doc/_index.html +461 -0
- data/doc/class_list.html +47 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +55 -0
- data/doc/css/style.css +322 -0
- data/doc/file.LICENSE.html +66 -0
- data/doc/file.README.html +312 -0
- data/doc/file_list.html +52 -0
- data/doc/frames.html +13 -0
- data/doc/index.html +312 -0
- data/doc/js/app.js +205 -0
- data/doc/js/full_list.js +173 -0
- data/doc/js/jquery.js +16 -0
- data/doc/method_list.html +1238 -0
- data/doc/top-level-namespace.html +105 -0
- data/lib/dynamoid.rb +47 -0
- data/lib/dynamoid/adapter.rb +177 -0
- data/lib/dynamoid/adapter/aws_sdk.rb +223 -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 +36 -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 +243 -0
- data/lib/dynamoid/dirty.rb +41 -0
- data/lib/dynamoid/document.rb +184 -0
- data/lib/dynamoid/errors.rb +28 -0
- data/lib/dynamoid/fields.rb +130 -0
- data/lib/dynamoid/finders.rb +131 -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 +247 -0
- data/lib/dynamoid/validations.rb +36 -0
- data/spec/app/models/address.rb +10 -0
- data/spec/app/models/camel_case.rb +24 -0
- data/spec/app/models/magazine.rb +11 -0
- data/spec/app/models/message.rb +9 -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/dynamoid/adapter/aws_sdk_spec.rb +186 -0
- data/spec/dynamoid/adapter_spec.rb +117 -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 +140 -0
- data/spec/dynamoid/criteria_spec.rb +72 -0
- data/spec/dynamoid/dirty_spec.rb +49 -0
- data/spec/dynamoid/document_spec.rb +118 -0
- data/spec/dynamoid/fields_spec.rb +127 -0
- data/spec/dynamoid/finders_spec.rb +135 -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 +176 -0
- data/spec/dynamoid/validations_spec.rb +36 -0
- data/spec/dynamoid_spec.rb +9 -0
- data/spec/spec_helper.rb +50 -0
- metadata +376 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Dynamoid::Associations::Chain" do
|
|
4
|
+
|
|
5
|
+
before(:each) do
|
|
6
|
+
@time = DateTime.now
|
|
7
|
+
@user = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com', :password => 'Test123')
|
|
8
|
+
@chain = Dynamoid::Criteria::Chain.new(User)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'finds matching index for a query' do
|
|
12
|
+
@chain.query = {:name => 'Josh'}
|
|
13
|
+
@chain.send(:index).should == User.indexes[[:name]]
|
|
14
|
+
|
|
15
|
+
@chain.query = {:email => 'josh@joshsymonds.com'}
|
|
16
|
+
@chain.send(:index).should == User.indexes[[:email]]
|
|
17
|
+
|
|
18
|
+
@chain.query = {:name => 'Josh', :email => 'josh@joshsymonds.com'}
|
|
19
|
+
@chain.send(:index).should == User.indexes[[:email, :name]]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'finds matching index for a range query' do
|
|
23
|
+
@chain.query = {"created_at.gt" => @time - 1.day}
|
|
24
|
+
@chain.send(:index).should == User.indexes[[:created_at]]
|
|
25
|
+
|
|
26
|
+
@chain.query = {:name => 'Josh', "created_at.lt" => @time - 1.day}
|
|
27
|
+
@chain.send(:index).should == User.indexes[[:created_at, :name]]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'does not find an index if there is not an appropriate one' do
|
|
31
|
+
@chain.query = {:password => 'Test123'}
|
|
32
|
+
@chain.send(:index).should be_nil
|
|
33
|
+
|
|
34
|
+
@chain.query = {:password => 'Test123', :created_at => @time}
|
|
35
|
+
@chain.send(:index).should be_nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'returns values for index for a query' do
|
|
39
|
+
@chain.query = {:name => 'Josh'}
|
|
40
|
+
@chain.send(:index_query).should == {:hash_value => 'Josh'}
|
|
41
|
+
|
|
42
|
+
@chain.query = {:email => 'josh@joshsymonds.com'}
|
|
43
|
+
@chain.send(:index_query).should == {:hash_value => 'josh@joshsymonds.com'}
|
|
44
|
+
|
|
45
|
+
@chain.query = {:name => 'Josh', :email => 'josh@joshsymonds.com'}
|
|
46
|
+
@chain.send(:index_query).should == {:hash_value => 'josh@joshsymonds.com.Josh'}
|
|
47
|
+
|
|
48
|
+
@chain.query = {:name => 'Josh', 'created_at.gt' => @time}
|
|
49
|
+
@chain.send(:index_query).should == {:hash_value => 'Josh', :range_greater_than => @time.to_f}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'finds records with an index' do
|
|
53
|
+
@chain.query = {:name => 'Josh'}
|
|
54
|
+
@chain.send(:records_with_index).should == [@user]
|
|
55
|
+
|
|
56
|
+
@chain.query = {:email => 'josh@joshsymonds.com'}
|
|
57
|
+
@chain.send(:records_with_index).should == [@user]
|
|
58
|
+
|
|
59
|
+
@chain.query = {:name => 'Josh', :email => 'josh@joshsymonds.com'}
|
|
60
|
+
@chain.send(:records_with_index).should == [@user]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'returns records with an index for a ranged query' do
|
|
64
|
+
@chain.query = {:name => 'Josh', "created_at.gt" => @time - 1.day}
|
|
65
|
+
@chain.send(:records_with_index).should == [@user]
|
|
66
|
+
|
|
67
|
+
@chain.query = {:name => 'Josh', "created_at.lt" => @time + 1.day}
|
|
68
|
+
@chain.send(:records_with_index).should == [@user]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'finds records without an index' do
|
|
72
|
+
@chain.query = {:password => 'Test123'}
|
|
73
|
+
@chain.send(:records_without_index).should == [@user]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "doesn't crash if it finds a nil id in the index" do
|
|
77
|
+
@chain.query = {:name => 'Josh', "created_at.gt" => @time - 1.day}
|
|
78
|
+
Dynamoid::Adapter.expects(:query).
|
|
79
|
+
with("dynamoid_tests_index_user_created_ats_and_names", kind_of(Hash)).
|
|
80
|
+
returns([{ids: nil}, {ids: Set.new([42])}])
|
|
81
|
+
@chain.send(:ids_from_index).should == Set.new([42])
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'defines each' do
|
|
85
|
+
@chain.query = {:name => 'Josh'}
|
|
86
|
+
@chain.each {|u| u.update_attribute(:name, 'Justin')}
|
|
87
|
+
|
|
88
|
+
User.find(@user.id).name.should == 'Justin'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'includes Enumerable' do
|
|
92
|
+
@chain.query = {:name => 'Josh'}
|
|
93
|
+
|
|
94
|
+
@chain.collect {|u| u.name}.should == ['Josh']
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 'finds range querys' do
|
|
98
|
+
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
|
99
|
+
@chain.query = { :tweet_id => 'test' }
|
|
100
|
+
@chain.send(:range?).should be_true
|
|
101
|
+
|
|
102
|
+
@chain.query = {:tweet_id => 'test', :group => 'xx'}
|
|
103
|
+
@chain.send(:range?).should be_true
|
|
104
|
+
|
|
105
|
+
@chain.query = { :group => 'xx' }
|
|
106
|
+
@chain.send(:range?).should be_false
|
|
107
|
+
|
|
108
|
+
@chain.query = { :group => 'xx', :msg => 'hai' }
|
|
109
|
+
@chain.send(:range?).should be_false
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
context 'range queries' do
|
|
113
|
+
before do
|
|
114
|
+
@tweet1 = Tweet.create(:tweet_id => "x", :group => "one")
|
|
115
|
+
@tweet2 = Tweet.create(:tweet_id => "x", :group => "two")
|
|
116
|
+
@tweet3 = Tweet.create(:tweet_id => "xx", :group => "two")
|
|
117
|
+
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'finds tweets with a simple range query' do
|
|
121
|
+
@chain.query = { :tweet_id => "x" }
|
|
122
|
+
@chain.send(:records_with_range).size.should == 2
|
|
123
|
+
@chain.all.size.should == 2
|
|
124
|
+
@chain.limit(1).size.should == 1
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it 'finds tweets with a start' do
|
|
128
|
+
@chain.query = { :tweet_id => "x" }
|
|
129
|
+
@chain.start(@tweet1)
|
|
130
|
+
@chain.all.should =~ [@tweet2]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'finds one specific tweet' do
|
|
134
|
+
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
|
135
|
+
@chain.query = { :tweet_id => "xx", :group => "two" }
|
|
136
|
+
@chain.send(:records_with_range).should == [@tweet3]
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Dynamoid::Criteria" do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
@user1 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
|
|
7
|
+
@user2 = User.create(:name => 'Justin', :email => 'justin@joshsymonds.com')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'finds first using where' do
|
|
11
|
+
User.where(:name => 'Josh').first.should == @user1
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'finds all using where' do
|
|
15
|
+
User.where(:name => 'Josh').all.should == [@user1]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'returns all records' do
|
|
19
|
+
User.all.should =~ [@user1, @user2]
|
|
20
|
+
User.all.first.new_record.should be_false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'returns empty attributes for where' do
|
|
24
|
+
Magazine.where(:name => 'Josh').all.should == []
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'returns empty attributes for all' do
|
|
28
|
+
Magazine.all.should == []
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'passes each to all members' do
|
|
32
|
+
User.each do |u|
|
|
33
|
+
u.id.should == @user1.id || @user2.id
|
|
34
|
+
u.new_record.should be_false
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'returns n records' do
|
|
39
|
+
User.limit(1).size.should eq(1)
|
|
40
|
+
5.times { |i| User.create(:name => 'Josh', :email => 'josh_#{i}@joshsymonds.com') }
|
|
41
|
+
User.where(:name => 'Josh').all.size.should == 6
|
|
42
|
+
User.where(:name => 'Josh').limit(2).size.should == 2
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# TODO This test is broken using the AWS SDK adapter.
|
|
46
|
+
#it 'start with a record' do
|
|
47
|
+
# 5.times { |i| User.create(:name => 'Josh', :email => 'josh_#{i}@joshsymonds.com') }
|
|
48
|
+
# all = User.all
|
|
49
|
+
# User.start(all[3]).all.should eq(all[4..-1])
|
|
50
|
+
#
|
|
51
|
+
# all = User.where(:name => 'Josh').all
|
|
52
|
+
# User.where(:name => 'Josh').start(all[3]).all.should eq(all[4..-1])
|
|
53
|
+
#end
|
|
54
|
+
|
|
55
|
+
it 'send consistent option to adapter' do
|
|
56
|
+
Dynamoid::Adapter.expects(:get_item).with { |table_name, key, options| options[:consistent_read] == true }
|
|
57
|
+
User.where(:name => 'x').consistent.first
|
|
58
|
+
|
|
59
|
+
Dynamoid::Adapter.expects(:query).with { |table_name, options| options[:consistent_read] == true }.returns([])
|
|
60
|
+
Tweet.where(:tweet_id => 'xx', :group => 'two').consistent.all
|
|
61
|
+
|
|
62
|
+
Dynamoid::Adapter.expects(:query).with { |table_name, options| options[:consistent_read] == false }.returns([])
|
|
63
|
+
Tweet.where(:tweet_id => 'xx', :group => 'two').all
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'raises exception when consistent_read is used with scan' do
|
|
67
|
+
expect do
|
|
68
|
+
User.where(:password => 'password').consistent.first
|
|
69
|
+
end.to raise_error(Dynamoid::Errors::InvalidQuery)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe 'Dynamoid::Dirty' do
|
|
4
|
+
|
|
5
|
+
context 'changes' do
|
|
6
|
+
it 'should be empty' do
|
|
7
|
+
tweet = Tweet.new
|
|
8
|
+
tweet.msg_changed?.should be_false
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'should not be empty' do
|
|
12
|
+
tweet = Tweet.new(:tweet_id => "1", :group => 'abc')
|
|
13
|
+
tweet.changed?.should be_true
|
|
14
|
+
tweet.group_was.should be_nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'should be empty when loaded from database' do
|
|
18
|
+
Tweet.create!(:tweet_id => "1", :group => 'abc')
|
|
19
|
+
tweet = Tweet.where(:tweet_id => "1", :group => 'abc').first
|
|
20
|
+
tweet.changed?.should be_false
|
|
21
|
+
tweet.group = 'abc'
|
|
22
|
+
tweet.reload
|
|
23
|
+
tweet.changed?.should be_false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'track changes after saves' do
|
|
27
|
+
tweet = Tweet.new(:tweet_id => "1", :group => 'abc')
|
|
28
|
+
tweet.save!
|
|
29
|
+
tweet.changed?.should be_false
|
|
30
|
+
|
|
31
|
+
tweet.user_name = 'xyz'
|
|
32
|
+
tweet.user_name_changed?.should be_true
|
|
33
|
+
tweet.user_name_was.should be_nil
|
|
34
|
+
tweet.save!
|
|
35
|
+
|
|
36
|
+
tweet.user_name_changed?.should be_false
|
|
37
|
+
tweet.user_name = 'abc'
|
|
38
|
+
tweet.user_name_was.should == 'xyz'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'clear changes on save' do
|
|
42
|
+
tweet = Tweet.new(:tweet_id => "1", :group => 'abc')
|
|
43
|
+
tweet.group = 'xyz'
|
|
44
|
+
tweet.group_changed?.should be_true
|
|
45
|
+
tweet.save!
|
|
46
|
+
tweet.group_changed?.should be_false
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
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}
|
|
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}
|
|
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}
|
|
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
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'tests equivalency with itself' do
|
|
59
|
+
@address = Address.create(:city => 'Chicago')
|
|
60
|
+
|
|
61
|
+
@address.should == @address
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'is not equivalent to another document' do
|
|
65
|
+
@address.should_not == Address.create
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'is not equivalent to another object' do
|
|
69
|
+
@address = Address.create(:city => 'Chicago')
|
|
70
|
+
@address.should_not == "test"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "isn't equal to nil" do
|
|
74
|
+
@address = Address.create(:city => 'Chicago')
|
|
75
|
+
@address.should_not == nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'gets errors courtesy of ActiveModel' do
|
|
79
|
+
@address = Address.create(:city => 'Chicago')
|
|
80
|
+
|
|
81
|
+
@address.errors.should be_empty
|
|
82
|
+
@address.errors.full_messages.should be_empty
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'reloads itself and sees persisted changes' do
|
|
86
|
+
@address = Address.create
|
|
87
|
+
|
|
88
|
+
Address.first.update_attributes(:city => 'Chicago')
|
|
89
|
+
|
|
90
|
+
@address.reload.city.should == 'Chicago'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'reloads document with range key' do
|
|
94
|
+
tweet = Tweet.create(:tweet_id => 'x', :group => 'abc')
|
|
95
|
+
tweet.reload.group.should == 'abc'
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'has default table options' do
|
|
99
|
+
@address = Address.create
|
|
100
|
+
|
|
101
|
+
@address.id.should_not be_nil
|
|
102
|
+
Address.table_name.should == 'dynamoid_tests_addresses'
|
|
103
|
+
Address.hash_key.should == :id
|
|
104
|
+
Address.read_capacity.should == 100
|
|
105
|
+
Address.write_capacity.should == 20
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'follows any table options provided to it' do
|
|
109
|
+
@tweet = Tweet.create(:group => 12345)
|
|
110
|
+
|
|
111
|
+
lambda {@tweet.id}.should raise_error(NoMethodError)
|
|
112
|
+
@tweet.tweet_id.should_not be_nil
|
|
113
|
+
Tweet.table_name.should == 'dynamoid_tests_twitters'
|
|
114
|
+
Tweet.hash_key.should == :tweet_id
|
|
115
|
+
Tweet.read_capacity.should == 200
|
|
116
|
+
Tweet.write_capacity.should == 200
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
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
|
|
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 'adds in dirty methods for attributes' do
|
|
79
|
+
@address.city = 'Chicago'
|
|
80
|
+
@address.save
|
|
81
|
+
|
|
82
|
+
@address.city = 'San Francisco'
|
|
83
|
+
|
|
84
|
+
@address.city_was.should == 'Chicago'
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'returns all attributes' do
|
|
88
|
+
Address.attributes.should == {:id=>{:type=>:string}, :created_at=>{:type=>:datetime}, :updated_at=>{:type=>:datetime}, :city=>{:type=>:string}, :options=>{:type=>:serialized}}
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "gives a warning when setting a single value larger than the maximum item size" do
|
|
93
|
+
Dynamoid.logger.expects(:warn).with(regexp_matches(/city field has a length of 66000/))
|
|
94
|
+
Address.new city: ("Ten chars " * 6_600)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
context 'default values for fields' do
|
|
99
|
+
before do
|
|
100
|
+
@clazz = Class.new do
|
|
101
|
+
include Dynamoid::Document
|
|
102
|
+
|
|
103
|
+
field :name, :string, :default => 'x'
|
|
104
|
+
field :uid, :integer, :default => lambda { 42 }
|
|
105
|
+
|
|
106
|
+
def self.name
|
|
107
|
+
'Document'
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@doc = @clazz.new
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'returns default value' do
|
|
116
|
+
@doc.name.should eq('x')
|
|
117
|
+
@doc.uid.should eq(42)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'should save default value' do
|
|
121
|
+
@doc.save!
|
|
122
|
+
@doc.reload.name.should eq('x')
|
|
123
|
+
@doc.uid.should eq(42)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|