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,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
|