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.
Files changed (119) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Dynamoid.gemspec +193 -0
  4. data/Gemfile +23 -0
  5. data/Gemfile.lock +86 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.markdown +265 -0
  8. data/Rakefile +62 -0
  9. data/VERSION +1 -0
  10. data/doc/.nojekyll +0 -0
  11. data/doc/Dynamoid.html +312 -0
  12. data/doc/Dynamoid/Adapter.html +1385 -0
  13. data/doc/Dynamoid/Adapter/AwsSdk.html +1585 -0
  14. data/doc/Dynamoid/Adapter/Local.html +1574 -0
  15. data/doc/Dynamoid/Associations.html +131 -0
  16. data/doc/Dynamoid/Associations/Association.html +794 -0
  17. data/doc/Dynamoid/Associations/BelongsTo.html +158 -0
  18. data/doc/Dynamoid/Associations/ClassMethods.html +723 -0
  19. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +164 -0
  20. data/doc/Dynamoid/Associations/HasMany.html +164 -0
  21. data/doc/Dynamoid/Associations/HasOne.html +158 -0
  22. data/doc/Dynamoid/Associations/ManyAssociation.html +1640 -0
  23. data/doc/Dynamoid/Associations/SingleAssociation.html +598 -0
  24. data/doc/Dynamoid/Components.html +204 -0
  25. data/doc/Dynamoid/Config.html +395 -0
  26. data/doc/Dynamoid/Config/Options.html +609 -0
  27. data/doc/Dynamoid/Criteria.html +131 -0
  28. data/doc/Dynamoid/Criteria/Chain.html +1063 -0
  29. data/doc/Dynamoid/Criteria/ClassMethods.html +98 -0
  30. data/doc/Dynamoid/Document.html +666 -0
  31. data/doc/Dynamoid/Document/ClassMethods.html +937 -0
  32. data/doc/Dynamoid/Errors.html +118 -0
  33. data/doc/Dynamoid/Errors/DocumentNotValid.html +210 -0
  34. data/doc/Dynamoid/Errors/Error.html +130 -0
  35. data/doc/Dynamoid/Errors/InvalidField.html +133 -0
  36. data/doc/Dynamoid/Errors/MissingRangeKey.html +133 -0
  37. data/doc/Dynamoid/Fields.html +669 -0
  38. data/doc/Dynamoid/Fields/ClassMethods.html +309 -0
  39. data/doc/Dynamoid/Finders.html +128 -0
  40. data/doc/Dynamoid/Finders/ClassMethods.html +516 -0
  41. data/doc/Dynamoid/Indexes.html +308 -0
  42. data/doc/Dynamoid/Indexes/ClassMethods.html +353 -0
  43. data/doc/Dynamoid/Indexes/Index.html +1104 -0
  44. data/doc/Dynamoid/Persistence.html +651 -0
  45. data/doc/Dynamoid/Persistence/ClassMethods.html +670 -0
  46. data/doc/Dynamoid/Validations.html +399 -0
  47. data/doc/_index.html +461 -0
  48. data/doc/class_list.html +47 -0
  49. data/doc/css/common.css +1 -0
  50. data/doc/css/full_list.css +55 -0
  51. data/doc/css/style.css +322 -0
  52. data/doc/file.LICENSE.html +66 -0
  53. data/doc/file.README.html +312 -0
  54. data/doc/file_list.html +52 -0
  55. data/doc/frames.html +13 -0
  56. data/doc/index.html +312 -0
  57. data/doc/js/app.js +205 -0
  58. data/doc/js/full_list.js +173 -0
  59. data/doc/js/jquery.js +16 -0
  60. data/doc/method_list.html +1238 -0
  61. data/doc/top-level-namespace.html +105 -0
  62. data/lib/dynamoid.rb +47 -0
  63. data/lib/dynamoid/adapter.rb +177 -0
  64. data/lib/dynamoid/adapter/aws_sdk.rb +223 -0
  65. data/lib/dynamoid/associations.rb +106 -0
  66. data/lib/dynamoid/associations/association.rb +105 -0
  67. data/lib/dynamoid/associations/belongs_to.rb +44 -0
  68. data/lib/dynamoid/associations/has_and_belongs_to_many.rb +40 -0
  69. data/lib/dynamoid/associations/has_many.rb +39 -0
  70. data/lib/dynamoid/associations/has_one.rb +39 -0
  71. data/lib/dynamoid/associations/many_association.rb +191 -0
  72. data/lib/dynamoid/associations/single_association.rb +69 -0
  73. data/lib/dynamoid/components.rb +36 -0
  74. data/lib/dynamoid/config.rb +57 -0
  75. data/lib/dynamoid/config/options.rb +78 -0
  76. data/lib/dynamoid/criteria.rb +29 -0
  77. data/lib/dynamoid/criteria/chain.rb +243 -0
  78. data/lib/dynamoid/dirty.rb +41 -0
  79. data/lib/dynamoid/document.rb +184 -0
  80. data/lib/dynamoid/errors.rb +28 -0
  81. data/lib/dynamoid/fields.rb +130 -0
  82. data/lib/dynamoid/finders.rb +131 -0
  83. data/lib/dynamoid/identity_map.rb +96 -0
  84. data/lib/dynamoid/indexes.rb +69 -0
  85. data/lib/dynamoid/indexes/index.rb +103 -0
  86. data/lib/dynamoid/middleware/identity_map.rb +16 -0
  87. data/lib/dynamoid/persistence.rb +247 -0
  88. data/lib/dynamoid/validations.rb +36 -0
  89. data/spec/app/models/address.rb +10 -0
  90. data/spec/app/models/camel_case.rb +24 -0
  91. data/spec/app/models/magazine.rb +11 -0
  92. data/spec/app/models/message.rb +9 -0
  93. data/spec/app/models/sponsor.rb +8 -0
  94. data/spec/app/models/subscription.rb +12 -0
  95. data/spec/app/models/tweet.rb +12 -0
  96. data/spec/app/models/user.rb +26 -0
  97. data/spec/dynamoid/adapter/aws_sdk_spec.rb +186 -0
  98. data/spec/dynamoid/adapter_spec.rb +117 -0
  99. data/spec/dynamoid/associations/association_spec.rb +194 -0
  100. data/spec/dynamoid/associations/belongs_to_spec.rb +71 -0
  101. data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +47 -0
  102. data/spec/dynamoid/associations/has_many_spec.rb +42 -0
  103. data/spec/dynamoid/associations/has_one_spec.rb +45 -0
  104. data/spec/dynamoid/associations_spec.rb +16 -0
  105. data/spec/dynamoid/config_spec.rb +27 -0
  106. data/spec/dynamoid/criteria/chain_spec.rb +140 -0
  107. data/spec/dynamoid/criteria_spec.rb +72 -0
  108. data/spec/dynamoid/dirty_spec.rb +49 -0
  109. data/spec/dynamoid/document_spec.rb +118 -0
  110. data/spec/dynamoid/fields_spec.rb +127 -0
  111. data/spec/dynamoid/finders_spec.rb +135 -0
  112. data/spec/dynamoid/identity_map_spec.rb +45 -0
  113. data/spec/dynamoid/indexes/index_spec.rb +104 -0
  114. data/spec/dynamoid/indexes_spec.rb +25 -0
  115. data/spec/dynamoid/persistence_spec.rb +176 -0
  116. data/spec/dynamoid/validations_spec.rb +36 -0
  117. data/spec/dynamoid_spec.rb +9 -0
  118. data/spec/spec_helper.rb +50 -0
  119. 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