dynamoid 0.7.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -24
  3. data/README.markdown +89 -73
  4. data/Rakefile +10 -36
  5. data/dynamoid.gemspec +56 -191
  6. data/lib/dynamoid.rb +6 -4
  7. data/lib/dynamoid/adapter.rb +64 -150
  8. data/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb +579 -0
  9. data/lib/dynamoid/components.rb +0 -1
  10. data/lib/dynamoid/config.rb +2 -5
  11. data/lib/dynamoid/criteria.rb +1 -1
  12. data/lib/dynamoid/criteria/chain.rb +27 -140
  13. data/lib/dynamoid/document.rb +2 -2
  14. data/lib/dynamoid/errors.rb +30 -9
  15. data/lib/dynamoid/fields.rb +15 -3
  16. data/lib/dynamoid/finders.rb +7 -6
  17. data/lib/dynamoid/identity_map.rb +1 -5
  18. data/lib/dynamoid/persistence.rb +108 -93
  19. metadata +56 -229
  20. data/.document +0 -5
  21. data/.rspec +0 -1
  22. data/.travis.yml +0 -7
  23. data/Gemfile.lock +0 -81
  24. data/Gemfile_activemodel4 +0 -24
  25. data/Gemfile_activemodel4.lock +0 -88
  26. data/VERSION +0 -1
  27. data/doc/.nojekyll +0 -0
  28. data/doc/Dynamoid.html +0 -328
  29. data/doc/Dynamoid/Adapter.html +0 -1872
  30. data/doc/Dynamoid/Adapter/AwsSdk.html +0 -2101
  31. data/doc/Dynamoid/Adapter/Local.html +0 -1574
  32. data/doc/Dynamoid/Associations.html +0 -138
  33. data/doc/Dynamoid/Associations/Association.html +0 -847
  34. data/doc/Dynamoid/Associations/BelongsTo.html +0 -161
  35. data/doc/Dynamoid/Associations/ClassMethods.html +0 -766
  36. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +0 -167
  37. data/doc/Dynamoid/Associations/HasMany.html +0 -167
  38. data/doc/Dynamoid/Associations/HasOne.html +0 -161
  39. data/doc/Dynamoid/Associations/ManyAssociation.html +0 -1684
  40. data/doc/Dynamoid/Associations/SingleAssociation.html +0 -627
  41. data/doc/Dynamoid/Components.html +0 -242
  42. data/doc/Dynamoid/Config.html +0 -412
  43. data/doc/Dynamoid/Config/Options.html +0 -638
  44. data/doc/Dynamoid/Criteria.html +0 -138
  45. data/doc/Dynamoid/Criteria/Chain.html +0 -1471
  46. data/doc/Dynamoid/Criteria/ClassMethods.html +0 -105
  47. data/doc/Dynamoid/Dirty.html +0 -424
  48. data/doc/Dynamoid/Dirty/ClassMethods.html +0 -174
  49. data/doc/Dynamoid/Document.html +0 -1033
  50. data/doc/Dynamoid/Document/ClassMethods.html +0 -1116
  51. data/doc/Dynamoid/Errors.html +0 -125
  52. data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +0 -141
  53. data/doc/Dynamoid/Errors/DocumentNotValid.html +0 -221
  54. data/doc/Dynamoid/Errors/Error.html +0 -137
  55. data/doc/Dynamoid/Errors/InvalidField.html +0 -141
  56. data/doc/Dynamoid/Errors/InvalidQuery.html +0 -131
  57. data/doc/Dynamoid/Errors/MissingRangeKey.html +0 -141
  58. data/doc/Dynamoid/Fields.html +0 -686
  59. data/doc/Dynamoid/Fields/ClassMethods.html +0 -438
  60. data/doc/Dynamoid/Finders.html +0 -135
  61. data/doc/Dynamoid/Finders/ClassMethods.html +0 -943
  62. data/doc/Dynamoid/IdentityMap.html +0 -492
  63. data/doc/Dynamoid/IdentityMap/ClassMethods.html +0 -534
  64. data/doc/Dynamoid/Indexes.html +0 -321
  65. data/doc/Dynamoid/Indexes/ClassMethods.html +0 -369
  66. data/doc/Dynamoid/Indexes/Index.html +0 -1142
  67. data/doc/Dynamoid/Middleware.html +0 -115
  68. data/doc/Dynamoid/Middleware/IdentityMap.html +0 -264
  69. data/doc/Dynamoid/Persistence.html +0 -892
  70. data/doc/Dynamoid/Persistence/ClassMethods.html +0 -836
  71. data/doc/Dynamoid/Validations.html +0 -415
  72. data/doc/_index.html +0 -506
  73. data/doc/class_list.html +0 -53
  74. data/doc/css/common.css +0 -1
  75. data/doc/css/full_list.css +0 -57
  76. data/doc/css/style.css +0 -338
  77. data/doc/file.LICENSE.html +0 -73
  78. data/doc/file.README.html +0 -416
  79. data/doc/file_list.html +0 -58
  80. data/doc/frames.html +0 -28
  81. data/doc/index.html +0 -416
  82. data/doc/js/app.js +0 -214
  83. data/doc/js/full_list.js +0 -178
  84. data/doc/js/jquery.js +0 -4
  85. data/doc/method_list.html +0 -1144
  86. data/doc/top-level-namespace.html +0 -112
  87. data/lib/dynamoid/adapter/aws_sdk.rb +0 -287
  88. data/lib/dynamoid/indexes.rb +0 -69
  89. data/lib/dynamoid/indexes/index.rb +0 -103
  90. data/spec/app/models/address.rb +0 -13
  91. data/spec/app/models/camel_case.rb +0 -34
  92. data/spec/app/models/car.rb +0 -6
  93. data/spec/app/models/magazine.rb +0 -11
  94. data/spec/app/models/message.rb +0 -9
  95. data/spec/app/models/nuclear_submarine.rb +0 -5
  96. data/spec/app/models/sponsor.rb +0 -8
  97. data/spec/app/models/subscription.rb +0 -12
  98. data/spec/app/models/tweet.rb +0 -12
  99. data/spec/app/models/user.rb +0 -26
  100. data/spec/app/models/vehicle.rb +0 -7
  101. data/spec/dynamoid/adapter/aws_sdk_spec.rb +0 -376
  102. data/spec/dynamoid/adapter_spec.rb +0 -155
  103. data/spec/dynamoid/associations/association_spec.rb +0 -194
  104. data/spec/dynamoid/associations/belongs_to_spec.rb +0 -71
  105. data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +0 -47
  106. data/spec/dynamoid/associations/has_many_spec.rb +0 -42
  107. data/spec/dynamoid/associations/has_one_spec.rb +0 -45
  108. data/spec/dynamoid/associations_spec.rb +0 -16
  109. data/spec/dynamoid/config_spec.rb +0 -27
  110. data/spec/dynamoid/criteria/chain_spec.rb +0 -210
  111. data/spec/dynamoid/criteria_spec.rb +0 -75
  112. data/spec/dynamoid/dirty_spec.rb +0 -57
  113. data/spec/dynamoid/document_spec.rb +0 -180
  114. data/spec/dynamoid/fields_spec.rb +0 -156
  115. data/spec/dynamoid/finders_spec.rb +0 -147
  116. data/spec/dynamoid/identity_map_spec.rb +0 -45
  117. data/spec/dynamoid/indexes/index_spec.rb +0 -104
  118. data/spec/dynamoid/indexes_spec.rb +0 -25
  119. data/spec/dynamoid/persistence_spec.rb +0 -301
  120. data/spec/dynamoid/validations_spec.rb +0 -36
  121. data/spec/dynamoid_spec.rb +0 -9
  122. data/spec/spec_helper.rb +0 -55
  123. data/spec/support/with_partitioning.rb +0 -15
@@ -1,180 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
- describe "Dynamoid::Document" do
4
-
5
- it 'initializes a new document' do
6
- @address = Address.new
7
-
8
- @address.new_record.should be_true
9
- @address.attributes.should == {:id=>nil, :created_at=>nil, :updated_at=>nil, :city=>nil, :options=>nil, :deliverable => nil, :lock_version => nil}
10
- end
11
-
12
- it 'responds to will_change! methods for all fields' do
13
- @address = Address.new
14
- @address.should respond_to(:id_will_change!)
15
- @address.should respond_to(:options_will_change!)
16
- @address.should respond_to(:created_at_will_change!)
17
- @address.should respond_to(:updated_at_will_change!)
18
- end
19
-
20
- it 'initializes a new document with attributes' do
21
- @address = Address.new(:city => 'Chicago')
22
-
23
- @address.new_record.should be_true
24
-
25
- @address.attributes.should == {:id=>nil, :created_at=>nil, :updated_at=>nil, :city=>"Chicago", :options=>nil, :deliverable => nil, :lock_version => nil}
26
- end
27
-
28
- it 'initializes a new document with a virtual attribute' do
29
- @address = Address.new(:zip_code => '12345')
30
-
31
- @address.new_record.should be_true
32
-
33
- @address.attributes.should == {:id=>nil, :created_at=>nil, :updated_at=>nil, :city=>"Chicago", :options=>nil, :deliverable => nil, :lock_version => nil}
34
- end
35
-
36
- it 'allows interception of write_attribute on load' do
37
- class Model
38
- include Dynamoid::Document
39
- field :city
40
- def city=(value); self[:city] = value.downcase; end
41
- end
42
- Model.new(:city => "Chicago").city.should == "chicago"
43
- end
44
-
45
- it 'creates a new document' do
46
- @address = Address.create(:city => 'Chicago')
47
-
48
- @address.new_record.should be_false
49
- @address.id.should_not be_nil
50
- end
51
-
52
- it 'knows if a document exists or not' do
53
- @address = Address.create(:city => 'Chicago')
54
- Address.exists?(@address.id).should be_true
55
- Address.exists?("does-not-exist").should be_false
56
- Address.exists?(:city => @address.city).should be_true
57
- Address.exists?(:city => "does-not-exist").should be_false
58
- end
59
-
60
- it 'gets errors courtesy of ActiveModel' do
61
- @address = Address.create(:city => 'Chicago')
62
-
63
- @address.errors.should be_empty
64
- @address.errors.full_messages.should be_empty
65
- end
66
-
67
- context '.reload' do
68
- let(:address){ Address.create }
69
- let(:message){ Message.create({:text => 'Nice, supporting datetime range!', :time => Time.now.to_datetime}) }
70
- let(:tweet){ tweet = Tweet.create(:tweet_id => 'x', :group => 'abc') }
71
-
72
- it 'reflects persisted changes' do
73
- address.update_attributes(:city => 'Chicago')
74
- address.reload.city.should == 'Chicago'
75
- end
76
-
77
- it 'uses a :consistent_read' do
78
- Tweet.expects(:find).with(tweet.hash_key, {:range_key => tweet.range_value, :consistent_read => true}).returns(tweet)
79
- tweet.reload
80
- end
81
-
82
- it 'works with range key' do
83
- tweet.reload.group.should == 'abc'
84
- end
85
-
86
- it 'works with a :datetime range key' do
87
- expect { message.reload }.to_not raise_error(ArgumentError)
88
- end
89
- end
90
-
91
- it 'has default table options' do
92
- @address = Address.create
93
-
94
- @address.id.should_not be_nil
95
- Address.table_name.should == 'dynamoid_tests_addresses'
96
- Address.hash_key.should == :id
97
- Address.read_capacity.should == 100
98
- Address.write_capacity.should == 20
99
- end
100
-
101
- it 'follows any table options provided to it' do
102
- @tweet = Tweet.create(:group => 12345)
103
-
104
- lambda {@tweet.id}.should raise_error(NoMethodError)
105
- @tweet.tweet_id.should_not be_nil
106
- Tweet.table_name.should == 'dynamoid_tests_twitters'
107
- Tweet.hash_key.should == :tweet_id
108
- Tweet.read_capacity.should == 200
109
- Tweet.write_capacity.should == 200
110
- end
111
-
112
- shared_examples 'it has equality testing and hashing' do
113
- it 'is equal to itself' do
114
- document.should == document
115
- end
116
-
117
- it 'is equal to another document with the same key(s)' do
118
- document.should == same
119
- end
120
-
121
- it 'is not equal to another document with different key(s)' do
122
- document.should_not == different
123
- end
124
-
125
- it 'is not equal to an object that is not a document' do
126
- document.should_not == 'test'
127
- end
128
-
129
- it 'is not equal to nil' do
130
- document.should_not == nil
131
- end
132
-
133
- it 'hashes documents with the keys to the same value' do
134
- {document => 1}.should have_key(same)
135
- end
136
- end
137
-
138
- context 'without a range key' do
139
- it_behaves_like 'it has equality testing and hashing' do
140
- let(:document) { Address.create(id: 123, city: 'Seattle') }
141
- let(:different) { Address.create(id: 456, city: 'Seattle') }
142
- let(:same) { Address.new(id: 123, city: 'Boston') }
143
- end
144
- end
145
-
146
- context 'with a range key' do
147
- it_behaves_like 'it has equality testing and hashing' do
148
- let(:document){ Tweet.create(:tweet_id => 'x', :group => 'abc', :msg => 'foo') }
149
- let(:different) { Tweet.create(:tweet_id => 'y', :group => 'abc', :msg => 'foo') }
150
- let(:same) { Tweet.new(:tweet_id => 'x', :group => 'abc', :msg => 'bar') }
151
- end
152
-
153
- it 'is not equal to another document with the same hash key but a different range value' do
154
- document = Tweet.create(:tweet_id => 'x', :group => 'abc')
155
- different = Tweet.create(:tweet_id => 'x', :group => 'xyz')
156
-
157
- document.should_not == different
158
- end
159
- end
160
-
161
- context 'single table inheritance' do
162
- it "should have a type" do
163
- Vehicle.new.type.should == "Vehicle"
164
- end
165
-
166
- it "reports the same table name for both base and derived classes" do
167
- Vehicle.table_name.should == Car.table_name
168
- Vehicle.table_name.should == NuclearSubmarine.table_name
169
- end
170
- end
171
-
172
- context '#count' do
173
- it 'returns the number of documents in the table' do
174
- document = Tweet.create(:tweet_id => 'x', :group => 'abc')
175
- different = Tweet.create(:tweet_id => 'x', :group => 'xyz')
176
-
177
- Tweet.count.should == 2
178
- end
179
- end
180
- end
@@ -1,156 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
- describe "Dynamoid::Fields" do
4
-
5
- before do
6
- @address = Address.new
7
- end
8
-
9
- it 'declares read attributes' do
10
- @address.city.should be_nil
11
- end
12
-
13
- it 'declares write attributes' do
14
- @address.city = 'Chicago'
15
- @address.city.should == 'Chicago'
16
- end
17
-
18
- it 'declares a query attribute' do
19
- @address.city?.should be_false
20
-
21
- @address.city = 'Chicago'
22
-
23
- @address.city?.should be_true
24
- end
25
-
26
- it 'automatically declares id' do
27
- lambda {@address.id}.should_not raise_error
28
- end
29
-
30
- it 'automatically declares and fills in created_at and updated_at' do
31
- @address.save
32
-
33
- @address = @address.reload
34
- @address.created_at.should_not be_nil
35
- @address.created_at.class.should == DateTime
36
- @address.updated_at.should_not be_nil
37
- @address.updated_at.class.should == DateTime
38
- end
39
-
40
- context 'with a saved address' do
41
- before do
42
- @address = Address.create(:deliverable => true)
43
- @original_id = @address.id
44
- end
45
-
46
- it 'should write an attribute correctly' do
47
- @address.write_attribute(:city, 'Chicago')
48
- end
49
-
50
- it 'should write an attribute with an alias' do
51
- @address[:city] = 'Chicago'
52
- end
53
-
54
- it 'should read a written attribute' do
55
- @address.write_attribute(:city, 'Chicago')
56
- @address.read_attribute(:city).should == 'Chicago'
57
- end
58
-
59
- it 'should read a written attribute with the alias' do
60
- @address.write_attribute(:city, 'Chicago')
61
- @address[:city].should == 'Chicago'
62
- end
63
-
64
- it 'should update all attributes' do
65
- @address.expects(:save).once.returns(true)
66
- @address.update_attributes(:city => 'Chicago')
67
- @address[:city].should == 'Chicago'
68
- @address.id.should == @original_id
69
- end
70
-
71
- it 'should update one attribute' do
72
- @address.expects(:save).once.returns(true)
73
- @address.update_attribute(:city, 'Chicago')
74
- @address[:city].should == 'Chicago'
75
- @address.id.should == @original_id
76
- end
77
-
78
- it 'should update only created_at when no params are passed' do
79
- @initial_updated_at = @address.updated_at
80
- @address.update_attributes([])
81
- @address.updated_at.should_not == @initial_updated_at
82
- end
83
-
84
- it 'adds in dirty methods for attributes' do
85
- @address.city = 'Chicago'
86
- @address.save
87
-
88
- @address.city = 'San Francisco'
89
-
90
- @address.city_was.should == 'Chicago'
91
- end
92
-
93
- it 'returns all attributes' do
94
- Address.attributes.should == {:id=>{:type=>:string}, :created_at=>{:type=>:datetime}, :updated_at=>{:type=>:datetime}, :city=>{:type=>:string}, :options=>{:type=>:serialized}, :deliverable => {:type => :boolean}, :lock_version => {:type => :integer}}
95
- end
96
- end
97
-
98
- it "gives a warning when setting a single value larger than the maximum item size" do
99
- Dynamoid.logger.expects(:warn).with(regexp_matches(/city field has a length of 66000/))
100
- Address.new city: ("Ten chars " * 6_600)
101
- end
102
-
103
- context '.remove_attribute' do
104
- subject { @address }
105
- before(:each) do
106
- Address.field :foobar
107
- Address.remove_field :foobar
108
- end
109
-
110
- it('should not be in the attributes hash') { Address.attributes.should_not have_key(:foobar) }
111
- it('removes the accessor') { should_not respond_to(:foobar) }
112
- it('removes the writer') { should_not respond_to(:foobar=) }
113
- it('removes the interrogative') { should_not respond_to(:foobar?) }
114
- end
115
-
116
- context 'default values for fields' do
117
- before do
118
- @clazz = Class.new do
119
- include Dynamoid::Document
120
-
121
- field :name, :string, :default => 'x'
122
- field :uid, :integer, :default => lambda { 42 }
123
-
124
- def self.name
125
- 'Document'
126
- end
127
- end
128
-
129
-
130
- @doc = @clazz.new
131
- end
132
-
133
- it 'returns default value' do
134
- @doc.name.should eq('x')
135
- @doc.uid.should eq(42)
136
- end
137
-
138
- it 'should save default value' do
139
- @doc.save!
140
- @doc.reload.name.should eq('x')
141
- @doc.uid.should eq(42)
142
- end
143
- end
144
-
145
- context 'single table inheritance' do
146
- it "has only base class fields on the base class" do
147
- Vehicle.attributes.keys.to_set.should == Set.new([:type, :description, :created_at, :updated_at, :id])
148
- end
149
-
150
- it "has only the base and derived fields on a sub-class" do
151
- #Only NuclearSubmarines have torpedoes
152
- Car.attributes.should_not have_key(:torpedoes)
153
- end
154
- end
155
-
156
- end
@@ -1,147 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
- describe "Dynamoid::Finders" do
4
-
5
- before do
6
- @address = Address.create(:city => 'Chicago')
7
- end
8
-
9
- it 'finds an existing address' do
10
- found = Address.find(@address.id)
11
-
12
- found.should == @address
13
- found.city.should == 'Chicago'
14
- end
15
-
16
- it 'is not a new object' do
17
- found = Address.find(@address.id)
18
-
19
- found.new_record.should_not be_true
20
- end
21
-
22
- it 'returns nil when nothing is found' do
23
- Address.find('1234').should be_nil
24
- end
25
-
26
- it 'finds multiple ids' do
27
- @address2 = Address.create(:city => 'Illinois')
28
-
29
- Address.find(@address.id, @address2.id).should include @address, @address2
30
- end
31
-
32
- it 'sends consistent option to the adapter' do
33
- Dynamoid::Adapter.expects(:get_item).with { |table_name, key, options| options[:consistent_read] == true }
34
- Address.find('x', :consistent_read => true)
35
- end
36
-
37
- context 'with users' do
38
- before do
39
- User.create_indexes
40
- end
41
-
42
- it 'finds using method_missing for attributes' do
43
- array = Address.find_by_city('Chicago')
44
-
45
- array.should == @address
46
- end
47
-
48
- it 'finds using method_missing for multiple attributes' do
49
- @user = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
50
-
51
- array = User.find_all_by_name_and_email('Josh', 'josh@joshsymonds.com')
52
-
53
- array.should == [@user]
54
- end
55
-
56
- it 'finds using method_missing for single attributes and multiple results' do
57
- @user1 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
58
- @user2 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
59
-
60
- array = User.find_all_by_name('Josh')
61
-
62
- array.size.should == 2
63
- array.should include @user1
64
- array.should include @user2
65
- end
66
-
67
- it 'finds using method_missing for multiple attributes and multiple results' do
68
- @user1 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
69
- @user2 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
70
-
71
- array = User.find_all_by_name_and_email('Josh', 'josh@joshsymonds.com')
72
-
73
- array.size.should == 2
74
- array.should include @user1
75
- array.should include @user2
76
- end
77
-
78
- it 'finds using method_missing for multiple attributes and no results' do
79
- @user1 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
80
- @user2 = User.create(:name => 'Justin', :email => 'justin@joshsymonds.com')
81
-
82
- array = User.find_all_by_name_and_email('Gaga','josh@joshsymonds.com')
83
-
84
- array.should be_empty
85
- end
86
-
87
- it 'finds using method_missing for a single attribute and no results' do
88
- @user1 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
89
- @user2 = User.create(:name => 'Justin', :email => 'justin@joshsymonds.com')
90
-
91
- array = User.find_all_by_name('Gaga')
92
-
93
- array.should be_empty
94
- end
95
-
96
- it 'should find on a query that is not indexed' do
97
- @user = User.create(:password => 'Test')
98
-
99
- array = User.find_all_by_password('Test')
100
-
101
- array.should == [@user]
102
- end
103
-
104
- it 'should find on a query on multiple attributes that are not indexed' do
105
- @user = User.create(:password => 'Test', :name => 'Josh')
106
-
107
- array = User.find_all_by_password_and_name('Test', 'Josh')
108
-
109
- array.should == [@user]
110
- end
111
-
112
- it 'should return an empty array when fields exist but nothing is found' do
113
- array = User.find_all_by_password('Test')
114
-
115
- array.should be_empty
116
- end
117
-
118
- end
119
-
120
- context 'find_all' do
121
-
122
- it 'should return a array of users' do
123
- users = (1..10).map { User.create }
124
- User.find_all(users.map(&:id)).should eq(users)
125
- end
126
-
127
- it 'should return a array of tweets' do
128
- tweets = (1..10).map { |i| Tweet.create(:tweet_id => "#{i}", :group => "group_#{i}") }
129
- Tweet.find_all(tweets.map { |t| [t.tweet_id, t.group] }).should eq(tweets)
130
- end
131
-
132
- it 'should return an empty array' do
133
- User.find_all([]).should eq([])
134
- end
135
-
136
- it 'returns empty array when there are no results' do
137
- Address.find_all('bad' + @address.id.to_s).should eq []
138
- end
139
-
140
- it 'passes options to the adapter' do
141
- user_ids = [%w(1 red), %w(1 green)]
142
- Dynamoid::Adapter.expects(:read).with(anything, user_ids, :consistent_read => true)
143
- User.find_all(user_ids, :consistent_read => true)
144
- end
145
-
146
- end
147
- end