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,135 @@
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
+ it 'should return a array of users' do
122
+ users = (1..10).map { User.create }
123
+ User.find_all(users.map(&:id)).should eq(users)
124
+ end
125
+
126
+ it 'should return a array of tweets' do
127
+ tweets = (1..10).map { |i| Tweet.create(:tweet_id => "#{i}", :group => "group_#{i}") }
128
+ Tweet.find_all(tweets.map { |t| [t.tweet_id, t.group] }).should eq(tweets)
129
+ end
130
+
131
+ it 'should return an empty array' do
132
+ User.find_all([]).should eq([])
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Dynamoid::IdentityMap" do
4
+ before :each do
5
+ Dynamoid::Config.identity_map = true
6
+ end
7
+
8
+ after :each do
9
+ Dynamoid::Config.identity_map = false
10
+ end
11
+
12
+ context 'object identity' do
13
+ it 'maintains a single object' do
14
+ tweet = Tweet.create(:tweet_id => "x", :group => "one")
15
+ tweet1 = Tweet.where(:tweet_id => "x", :group => "one").first
16
+ tweet.should equal(tweet1)
17
+ end
18
+ end
19
+
20
+ context 'cache' do
21
+ it 'uses cache' do
22
+ tweet = Tweet.create(:tweet_id => "x", :group => "one")
23
+ Dynamoid::Adapter.expects(:read).never
24
+ tweet1 = Tweet.find_by_id("x", :range_key => "one")
25
+ tweet.should equal(tweet1)
26
+ end
27
+
28
+ it 'clears cache on delete' do
29
+ tweet = Tweet.create(:tweet_id => "x", :group => "one")
30
+ tweet.delete
31
+ Tweet.find_by_id("x", :range_key => "one").should be_nil
32
+ end
33
+ end
34
+
35
+ context 'clear' do
36
+ it 'clears the identiy map' do
37
+ Tweet.create(:tweet_id => "x", :group => "one")
38
+ Tweet.create(:tweet_id => "x", :group => "two")
39
+
40
+ Tweet.identity_map.size.should eq(2)
41
+ Dynamoid::IdentityMap.clear
42
+ Tweet.identity_map.size.should eq(0)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,104 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Dynamoid::Indexes::Index" do
4
+
5
+ before do
6
+ @time = DateTime.now
7
+ @index = Dynamoid::Indexes::Index.new(User, [:password, :name], :range_key => :created_at)
8
+ end
9
+
10
+ it 'reorders keys alphabetically' do
11
+ @index.sort([:password, :name, :created_at]).should == [:created_at, :name, :password]
12
+ end
13
+
14
+ it 'assigns itself hash keys' do
15
+ @index.hash_keys.should == [:name, :password]
16
+ end
17
+
18
+ it 'assigns itself range keys' do
19
+ @index.range_keys.should == [:created_at]
20
+ end
21
+
22
+ it 'reorders its name automatically' do
23
+ @index.name.should == [:created_at, :name, :password]
24
+ end
25
+
26
+ it 'determines its own table name' do
27
+ @index.table_name.should == 'dynamoid_tests_index_user_created_ats_and_names_and_passwords'
28
+ end
29
+
30
+ it 'raises an error if a field does not exist' do
31
+ lambda {@index = Dynamoid::Indexes::Index.new(User, [:password, :text])}.should raise_error(Dynamoid::Errors::InvalidField)
32
+ end
33
+
34
+ it 'returns values for indexes' do
35
+ @index.values(:name => 'Josh', :password => 'test123', :created_at => @time).should == {:hash_value => 'Josh.test123', :range_value => @time.to_f}
36
+ end
37
+
38
+ it 'ignores values for fields that do not exist' do
39
+ @index.values(:name => 'Josh', :password => 'test123', :created_at => @time, :email => 'josh@joshsymonds.com').should == {:hash_value => 'Josh.test123', :range_value => @time.to_f}
40
+ end
41
+
42
+ it 'substitutes a blank string for a hash value that does not exist' do
43
+ @index.values(:name => 'Josh', :created_at => @time).should == {:hash_value => 'Josh.', :range_value => @time.to_f}
44
+ end
45
+
46
+ it 'substitutes a blank string if both hash values do not exist' do
47
+ @index.values(:created_at => @time).should == {:hash_value => '.', :range_value => @time.to_f}
48
+ end
49
+
50
+ it 'accepts values from an object instead of a hash' do
51
+ @user = User.new(:name => 'Josh', :password => 'test123', :created_at => @time)
52
+
53
+ @index.values(@user).should == {:hash_value => 'Josh.test123', :range_value => @time.to_f}
54
+ end
55
+
56
+ it 'accepts values from an object and returns changed values' do
57
+ @user = User.new(:name => 'Josh', :password => 'test123', :created_at => @time)
58
+ @user.name = 'Justin'
59
+
60
+ @index.values(@user).should == {:hash_value => 'Justin.test123', :range_value => @time.to_f}
61
+ end
62
+
63
+ it 'saves an object to the index it is associated with' do
64
+ @index = Dynamoid::Indexes::Index.new(User, :name)
65
+ @user = User.new(:name => 'Josh', :password => 'test123', :created_at => @time, :id => 'test123')
66
+
67
+ @index.save(@user)
68
+
69
+ Dynamoid::Adapter.read("dynamoid_tests_index_user_names", 'Josh')[:ids].should == Set['test123']
70
+ end
71
+
72
+ it 'saves an object to the index it is associated with with a range' do
73
+ @index = Dynamoid::Indexes::Index.new(User, :name, :range_key => :last_logged_in_at)
74
+ @user = User.create(:name => 'Josh', :last_logged_in_at => @time)
75
+
76
+ @index.save(@user)
77
+
78
+ Dynamoid::Adapter.read("dynamoid_tests_index_user_last_logged_in_ats_and_names", 'Josh', :range_key => @time.to_f)[:ids].should == Set[@user.id]
79
+ end
80
+
81
+ it 'deletes an object from the index it is associated with' do
82
+ @index = Dynamoid::Indexes::Index.new(User, :name)
83
+ @user = User.create(:name => 'Josh', :password => 'test123', :last_logged_in_at => @time, :id => 'test123')
84
+
85
+ @index.save(@user)
86
+ @index.delete(@user)
87
+
88
+ Dynamoid::Adapter.read("dynamoid_tests_index_user_names", 'Josh')[:ids].should be_nil
89
+ end
90
+
91
+ it 'updates an object by removing it from its previous index and adding it to its new one' do
92
+ @index = Dynamoid::Indexes::Index.new(User, :name)
93
+ @user = User.create(:name => 'Josh', :password => 'test123', :last_logged_in_at => @time, :id => 'test123')
94
+
95
+ Dynamoid::Adapter.read("dynamoid_tests_index_user_names", 'Josh')[:ids].should == Set['test123']
96
+ Dynamoid::Adapter.read("dynamoid_tests_index_user_names", 'Justin').should be_nil
97
+
98
+ @user.update_attributes(:name => 'Justin')
99
+
100
+ Dynamoid::Adapter.read("dynamoid_tests_index_user_names", 'Josh')[:ids].should be_nil
101
+ Dynamoid::Adapter.read("dynamoid_tests_index_user_names", 'Justin')[:ids].should == Set['test123']
102
+ end
103
+
104
+ end
@@ -0,0 +1,25 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Dynamoid::Indexes" do
4
+
5
+ it 'adds indexes to the index array' do
6
+ User.indexes.keys.should =~ [[:created_at], [:created_at, :name], [:email], [:email, :name], [:last_logged_in_at, :name], [:name]]
7
+ end
8
+
9
+ it 'saves indexes to their tables' do
10
+ @user = User.new(:name => 'Josh')
11
+
12
+ User.indexes.each {|k, v| v.expects(:save).with(@user).once.returns(true)}
13
+
14
+ @user.save
15
+ end
16
+
17
+ it 'deletes indexes when the object is destroyed' do
18
+ @user = User.create(:name => 'Josh')
19
+
20
+ User.indexes.each {|k, v| v.expects(:delete).with(@user).once.returns(true)}
21
+
22
+ @user.destroy
23
+ end
24
+
25
+ end
@@ -0,0 +1,176 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Dynamoid::Persistence" do
4
+
5
+ before do
6
+ Random.stubs(:rand).with(Dynamoid::Config.partition_size).returns(0)
7
+ @address = Address.new
8
+ end
9
+
10
+ context 'without AWS keys' do
11
+ unless ENV['ACCESS_KEY'] && ENV['SECRET_KEY']
12
+ before do
13
+ Dynamoid::Adapter.delete_table(Address.table_name) if Dynamoid::Adapter.list_tables.include?(Address.table_name)
14
+ end
15
+
16
+ it 'creates a table' do
17
+ Address.create_table(:table_name => Address.table_name)
18
+
19
+ Dynamoid::Adapter.list_tables.should include 'dynamoid_tests_addresses'
20
+ end
21
+
22
+ it 'checks if a table already exists' do
23
+ Address.create_table(:table_name => Address.table_name)
24
+
25
+ Address.table_exists?(Address.table_name).should be_true
26
+ Address.table_exists?('crazytable').should be_false
27
+ end
28
+ end
29
+ end
30
+
31
+ it 'assigns itself an id on save' do
32
+ @address.save
33
+
34
+ Dynamoid::Adapter.read("dynamoid_tests_addresses", @address.id)[:id].should == @address.id
35
+ end
36
+
37
+ it 'assigns itself an id on save only if it does not have one' do
38
+ @address.id = 'test123'
39
+ @address.save
40
+
41
+ Dynamoid::Adapter.read("dynamoid_tests_addresses", 'test123').should_not be_empty
42
+ end
43
+
44
+ it 'has a table name' do
45
+ Address.table_name.should == 'dynamoid_tests_addresses'
46
+ end
47
+
48
+ it 'saves indexes along with itself' do
49
+ @user = User.new(:name => 'Josh')
50
+
51
+ @user.expects(:save_indexes).once.returns(true)
52
+ @user.save
53
+ end
54
+
55
+ it 'deletes an item completely' do
56
+ @user = User.create(:name => 'Josh')
57
+ @user.destroy
58
+
59
+ Dynamoid::Adapter.read("dynamoid_tests_users", @user.id).should be_nil
60
+ end
61
+
62
+ it 'keeps string attributes as strings' do
63
+ @user = User.new(:name => 'Josh')
64
+ @user.send(:dump)[:name].should == 'Josh'
65
+ end
66
+
67
+ it 'dumps datetime attributes' do
68
+ @user = User.create(:name => 'Josh')
69
+ @user.send(:dump)[:name].should == 'Josh'
70
+ end
71
+
72
+ it 'dumps integer attributes' do
73
+ @subscription = Subscription.create(:length => 10)
74
+ @subscription.send(:dump)[:length].should == 10
75
+ end
76
+
77
+ it 'dumps set attributes' do
78
+ @subscription = Subscription.create(:length => 10)
79
+ @magazine = @subscription.magazine.create
80
+
81
+ @subscription.send(:dump)[:magazine_ids].should == Set[@magazine.id]
82
+ end
83
+
84
+ it 'handles nil attributes properly' do
85
+ Address.undump(nil).should be_a(Hash)
86
+ end
87
+
88
+ it 'dumps and undump a serialized field' do
89
+ @address.options = (hash = {:x => [1, 2], "foobar" => 3.14})
90
+ Address.undump(@address.send(:dump))[:options].should == hash
91
+ end
92
+
93
+ it 'loads a hash into a serialized field' do
94
+ hash = {foo: :bar}
95
+ Address.new(options: hash).options.should == hash
96
+ end
97
+
98
+ it 'loads attributes from a hash' do
99
+ @time = DateTime.now
100
+ @hash = {:name => 'Josh', :created_at => @time.to_f}
101
+
102
+ User.undump(@hash)[:name].should == 'Josh'
103
+ User.undump(@hash)[:created_at].to_f == @time.to_f
104
+ end
105
+
106
+ it 'runs the before_create callback only once' do
107
+ CamelCase.any_instance.expects(:doing_before_create).once.returns(true)
108
+
109
+ CamelCase.create
110
+ end
111
+
112
+ it 'runs after save callbacks when doing #create' do
113
+ CamelCase.any_instance.expects(:doing_after_create).once.returns(true)
114
+
115
+ CamelCase.create
116
+ end
117
+
118
+ it 'runs after save callbacks when doing #save' do
119
+ CamelCase.any_instance.expects(:doing_after_create).once.returns(true)
120
+
121
+ CamelCase.new.save
122
+ end
123
+
124
+ it 'works with a HashWithIndifferentAccess' do
125
+ hash = ActiveSupport::HashWithIndifferentAccess.new("city" => "Atlanta")
126
+
127
+ lambda {Address.create(hash)}.should_not raise_error
128
+ end
129
+
130
+ context 'update' do
131
+
132
+ before :each do
133
+ @tweet = Tweet.create(:tweet_id => 1, :group => 'abc', :count => 5, :tags => ['db', 'sql'], :user_name => 'john')
134
+ end
135
+
136
+ it 'support add/delete operation on a field' do
137
+ @tweet.update do |t|
138
+ t.add(:count => 3)
139
+ t.delete(:tags => ['db'])
140
+ end
141
+
142
+ @tweet.count.should eq(8)
143
+ @tweet.tags.to_a.should eq(['sql'])
144
+ end
145
+
146
+ it 'checks the conditions on update' do
147
+ @tweet.update(:if => { :count => 5 }) do |t|
148
+ t.add(:count => 3)
149
+ end.should be_true
150
+
151
+ @tweet.count.should eq(8)
152
+
153
+ @tweet.update(:if => { :count => 5 }) do |t|
154
+ t.add(:count => 3)
155
+ end.should be_false
156
+
157
+ @tweet.count.should eq(8)
158
+
159
+ expect {
160
+ @tweet.update!(:if => { :count => 5 }) do |t|
161
+ t.add(:count => 3)
162
+ end
163
+ }.to raise_error(Dynamoid::Errors::ConditionalCheckFailedException)
164
+ end
165
+
166
+ end
167
+
168
+ context 'delete' do
169
+ it 'deletes model with datetime range key' do
170
+ lambda {
171
+ msg = Message.create!(:message_id => 1, :time => DateTime.now, :text => "Hell yeah")
172
+ msg.destroy
173
+ }.should_not raise_error
174
+ end
175
+ end
176
+ end