dm-core 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/CONTRIBUTING +51 -0
  2. data/FAQ +26 -8
  3. data/Manifest.txt +2 -0
  4. data/Rakefile +2 -1
  5. data/lib/dm-core.rb +8 -3
  6. data/lib/dm-core/adapters/abstract_adapter.rb +2 -2
  7. data/lib/dm-core/adapters/data_objects_adapter.rb +18 -4
  8. data/lib/dm-core/adapters/mysql_adapter.rb +8 -4
  9. data/lib/dm-core/adapters/postgres_adapter.rb +12 -3
  10. data/lib/dm-core/adapters/sqlite3_adapter.rb +1 -1
  11. data/lib/dm-core/associations.rb +1 -0
  12. data/lib/dm-core/associations/many_to_one.rb +7 -1
  13. data/lib/dm-core/associations/one_to_many.rb +1 -1
  14. data/lib/dm-core/associations/relationship.rb +14 -13
  15. data/lib/dm-core/auto_migrations.rb +57 -5
  16. data/lib/dm-core/collection.rb +2 -1
  17. data/lib/dm-core/logger.rb +5 -6
  18. data/lib/dm-core/model.rb +17 -2
  19. data/lib/dm-core/naming_conventions.rb +57 -25
  20. data/lib/dm-core/property.rb +6 -5
  21. data/lib/dm-core/query.rb +20 -16
  22. data/lib/dm-core/resource.rb +24 -7
  23. data/lib/dm-core/version.rb +1 -1
  24. data/script/performance.rb +2 -1
  25. data/script/profile.rb +1 -0
  26. data/spec/integration/association_spec.rb +131 -81
  27. data/spec/integration/association_through_spec.rb +87 -42
  28. data/spec/integration/associations/many_to_many_spec.rb +76 -16
  29. data/spec/integration/associations/many_to_one_spec.rb +6 -1
  30. data/spec/integration/associations/one_to_many_spec.rb +69 -0
  31. data/spec/integration/collection_spec.rb +7 -0
  32. data/spec/integration/query_spec.rb +24 -7
  33. data/spec/integration/resource_spec.rb +59 -10
  34. data/spec/integration/sti_spec.rb +23 -0
  35. data/spec/models/zoo.rb +2 -3
  36. data/spec/spec_helper.rb +9 -1
  37. data/spec/unit/adapters/postgres_adapter_spec.rb +9 -1
  38. data/spec/unit/associations/many_to_one_spec.rb +6 -0
  39. data/spec/unit/auto_migrations_spec.rb +2 -1
  40. data/spec/unit/naming_conventions_spec.rb +26 -18
  41. data/spec/unit/property_spec.rb +3 -4
  42. data/spec/unit/resource_spec.rb +19 -22
  43. data/tasks/gemspec.rb +23 -0
  44. data/tasks/hoe.rb +9 -1
  45. metadata +6 -14
@@ -4,7 +4,6 @@ if ADAPTER
4
4
  describe 'through-associations' do
5
5
  before :all do
6
6
  repository(ADAPTER) do
7
-
8
7
  class Tag
9
8
  include DataMapper::Resource
10
9
  def self.default_repository_name
@@ -53,11 +52,11 @@ if ADAPTER
53
52
  :through => :relationships,
54
53
  :class_name => "Post"
55
54
 
56
- has n, :void_tags,
57
- :through => :taggings,
58
- :class_name => "Tag",
59
- :remote_relationship_name => :tag,
60
- Post.taggings.tag.voided => true
55
+ has n, :void_tags,
56
+ :through => :taggings,
57
+ :class_name => "Tag",
58
+ :remote_relationship_name => :tag,
59
+ Post.taggings.tag.voided => true
61
60
  end
62
61
 
63
62
  class Relationship
@@ -74,7 +73,11 @@ if ADAPTER
74
73
  [Post, Tag, Tagging, Relationship].each do |descendant|
75
74
  descendant.auto_migrate!(ADAPTER)
76
75
  end
76
+ end
77
+ end
77
78
 
79
+ describe '(sample data)' do
80
+ before(:each) do
78
81
  post = Post.create(:title => "Entry")
79
82
  another_post = Post.create(:title => "Another")
80
83
 
@@ -106,51 +109,93 @@ if ADAPTER
106
109
  post.relationships << relation
107
110
  post.save
108
111
  end
109
- end
110
112
 
111
- it 'should return the right children for has n => belongs_to relationships' do
112
- Post.first.tags.select do |tag|
113
- tag.title == 'crap'
114
- end.size.should == 1
115
- end
113
+ it 'should return the right children for has n => belongs_to relationships' do
114
+ Post.first.tags.select do |tag|
115
+ tag.title == 'crap'
116
+ end.size.should == 1
117
+ end
116
118
 
117
- it 'should return the right children for has n => belongs_to self-referential relationships' do
118
- Post.first.related_posts.select do |post|
119
- post.title == 'Another'
120
- end.size.should == 1
121
- end
119
+ it 'should return the right children for has n => belongs_to self-referential relationships' do
120
+ Post.first.related_posts.select do |post|
121
+ post.title == 'Another'
122
+ end.size.should == 1
123
+ end
122
124
 
123
- it 'should handle all()' do
124
- related_posts = Post.first.related_posts
125
- related_posts.all.object_id.should == related_posts.object_id
126
- related_posts.all(:id => 2).first.should == Post.get!(2)
127
- end
125
+ it 'should handle all()' do
126
+ related_posts = Post.first.related_posts
127
+ related_posts.all.object_id.should == related_posts.object_id
128
+ related_posts.all(:id => 2).first.should == Post.get!(2)
129
+ end
128
130
 
129
- it 'should handle first()' do
130
- post = Post.get!(2)
131
- related_posts = Post.first.related_posts
132
- related_posts.first.should == post
133
- related_posts.first(10).should == [ post ]
134
- related_posts.first(:id => 2).should == post
135
- related_posts.first(10, :id => 2).map { |r| r.id }.should == [ post.id ]
136
- end
131
+ it 'should handle first()' do
132
+ post = Post.get!(2)
133
+ related_posts = Post.first.related_posts
134
+ related_posts.first.should == post
135
+ related_posts.first(10).should == [ post ]
136
+ related_posts.first(:id => 2).should == post
137
+ related_posts.first(10, :id => 2).map { |r| r.id }.should == [post.id]
138
+ end
137
139
 
138
- it 'should handle get()' do
139
- post = Post.get!(2)
140
- related_posts = Post.first.related_posts
141
- related_posts.get(2).should == post
140
+ it 'should handle get()' do
141
+ post = Post.get!(2)
142
+ related_posts = Post.first.related_posts
143
+ related_posts.get(2).should == post
144
+ end
145
+
146
+ it 'should proxy object should be frozen' do
147
+ Post.first.related_posts.should be_frozen
148
+ end
149
+
150
+ it "should respect tagging with conditions" do
151
+ post = Post.get(1)
152
+ post.tags.size
153
+ post.tags.select{ |t| t.voided == true }.size.should == 1
154
+ post.void_tags.size.should == 1
155
+ post.void_tags.all?{ |t| t.voided == true }.should be_true
156
+ end
142
157
  end
143
158
 
144
- it 'should proxy object should be frozen' do
145
- Post.first.related_posts.should be_frozen
159
+ describe "Saved Tag, Post, Tagging" do
160
+ before(:each) do
161
+ @tag = Tag.create
162
+ @post = Post.create
163
+ @tagging = Tagging.create(
164
+ :tag => @tag,
165
+ :post => @post
166
+ )
167
+ end
168
+
169
+ it "should get posts of a tag" do
170
+ @tag.posts.should == [@post]
171
+ end
172
+
173
+ it "should get tags of a post" do
174
+ @post.tags.should == [@tag]
175
+ end
146
176
  end
147
177
 
148
- it "should respect tagging with conditions" do
149
- post = Post.get(1)
150
- post.tags.size
151
- post.tags.select{|t| t.voided == true}.size.should == 1
152
- post.void_tags.size.should == 1
153
- post.void_tags.all?{|t| t.voided == true}.should be_true
178
+ describe "In-memory Tag, Post, Tagging" do
179
+ before(:each) do
180
+ @tag = Tag.new
181
+ @post = Post.new
182
+ @tagging = Tagging.new(
183
+ :tag => @tag,
184
+ :post => @post
185
+ )
186
+ end
187
+
188
+ it "should get posts of a tag" do
189
+ pending("DataMapper does not yet support in-memory associations") do
190
+ @tag.posts.should == [@post]
191
+ end
192
+ end
193
+
194
+ it "should get tags of a post" do
195
+ pending("DataMapper does not yet support in-memory associations") do
196
+ @post.tags.should == [@tag]
197
+ end
198
+ end
154
199
  end
155
200
  end
156
201
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
2
2
 
3
3
  describe DataMapper::Associations::ManyToMany::Proxy do
4
4
  before :all do
@@ -48,36 +48,36 @@ describe DataMapper::Associations::ManyToMany::Proxy do
48
48
  end
49
49
  end
50
50
 
51
- it 'should provide #replace' do
51
+ it "should provide #replace" do
52
52
  @association.should respond_to(:replace)
53
53
  end
54
54
 
55
- describe '#replace' do
56
- it 'should remove the resource from the collection' do
55
+ describe "#replace" do
56
+ it "should remove the resource from the collection" do
57
57
  @association.should have(0).entries
58
58
  @association.replace(@other)
59
59
  @association.should == @other
60
60
  end
61
61
 
62
- it 'should not automatically save that the resource was removed from the association' do
62
+ it "should not automatically save that the resource was removed from the association" do
63
63
  @association.replace(@other)
64
64
  @parent.reload.should have(0).editors
65
65
  end
66
66
 
67
- it 'should return the association' do
67
+ it "should return the association" do
68
68
  @association.replace(@other).object_id.should == @association.object_id
69
69
  end
70
70
 
71
- it 'should add the new resources so they will be saved when saving the parent' do
71
+ it "should add the new resources so they will be saved when saving the parent" do
72
72
  @association.replace(@other)
73
73
  @association.should == @other
74
74
  @parent.save
75
75
  @association.reload.should == @other
76
76
  end
77
77
 
78
- it 'should instantiate the remote model if passed an array of hashes' do
79
- @association.replace([ { :name => 'Jim Smith' } ])
80
- other = [ Editor.first(:name => 'Jim Smith') ]
78
+ it "should instantiate the remote model if passed an array of hashes" do
79
+ @association.replace([ { :name => "Jim Smith" } ])
80
+ other = [ Editor.first(:name => "Jim Smith") ]
81
81
  other.first.should_not be_nil
82
82
  @association.should == other
83
83
  @parent.save
@@ -176,7 +176,7 @@ describe DataMapper::Associations::ManyToMany::Proxy do
176
176
  end
177
177
 
178
178
  it "should be destroyable" do
179
- pending 'cannot destroy a collection yet' do
179
+ pending "cannot destroy a collection yet" do
180
180
  book = Book.get(2)
181
181
  book.should have(1).editors
182
182
 
@@ -188,7 +188,7 @@ describe DataMapper::Associations::ManyToMany::Proxy do
188
188
  end
189
189
  end
190
190
 
191
- describe 'with natural keys' do
191
+ describe "with natural keys" do
192
192
  before :all do
193
193
  class Author
194
194
  include DataMapper::Resource
@@ -208,7 +208,7 @@ describe DataMapper::Associations::ManyToMany::Proxy do
208
208
  before do
209
209
  [ Author, AuthorBook ].each { |k| k.auto_migrate! }
210
210
 
211
- @author = Author.create(:name => 'James Joyce')
211
+ @author = Author.create(:name => "James Joyce")
212
212
 
213
213
  @book_1 = Book.get!(1)
214
214
  @book_2 = Book.get!(2)
@@ -219,19 +219,79 @@ describe DataMapper::Associations::ManyToMany::Proxy do
219
219
  AuthorBook.create(:book => @book_3, :author => @author)
220
220
  end
221
221
 
222
- it 'should have a join resource where the natural key is a property' do
222
+ it "should have a join resource where the natural key is a property" do
223
223
  AuthorBook.properties[:author_name].primitive.should == String
224
224
  end
225
225
 
226
- it 'should have a join resource where every property is part of the key' do
226
+ it "should have a join resource where every property is part of the key" do
227
227
  AuthorBook.key.should == AuthorBook.properties.to_a
228
228
  end
229
229
 
230
- it 'should correctly link records' do
230
+ it "should correctly link records" do
231
231
  @author.should have(3).books
232
232
  @book_1.should have(1).authors
233
233
  @book_2.should have(1).authors
234
234
  @book_3.should have(1).authors
235
235
  end
236
236
  end
237
+
238
+ describe "When join model has non-serial (integer) natural keys." do
239
+ before :all do
240
+ class Tag
241
+ include DataMapper::Resource
242
+
243
+ def self.default_repository_name; ADAPTER end
244
+
245
+ property :id, Serial
246
+ property :name, String, :size => 128
247
+
248
+ has n, :book_taggings
249
+ has n, :books, :through => :book_taggings
250
+ end
251
+
252
+ class BookTagging
253
+ include DataMapper::Resource
254
+
255
+ def self.default_repository_name; ADAPTER end
256
+
257
+ property :book_id, Integer, :key => true
258
+ property :tag_id, Integer, :key => true
259
+
260
+ belongs_to :book
261
+ belongs_to :tag
262
+ end
263
+
264
+ class Book
265
+ has n, :book_taggings
266
+ has n, :tags, :through => :book_taggings
267
+ end
268
+ end
269
+
270
+ before do
271
+ [ Tag, BookTagging ].each { |k| k.auto_migrate! }
272
+
273
+ @tag_1 = Tag.create(:name => "good")
274
+ @tag_2 = Tag.create(:name => "long")
275
+
276
+ @book_1 = Book.get!(1)
277
+ @book_2 = Book.get!(2)
278
+ @book_3 = Book.get!(3)
279
+
280
+ BookTagging.create(:book => @book_2, :tag => @tag_1)
281
+ BookTagging.create(:book => @book_2, :tag => @tag_2)
282
+ BookTagging.create(:book => @book_3, :tag => @tag_2)
283
+ end
284
+
285
+ it "should fetch all tags for a book" do
286
+ @book_1.tags.should have(0).tags
287
+ @book_2.tags.should have(2).tags
288
+ @book_3.tags.should have(1).tags
289
+ end
290
+
291
+ it "should allow for adding an association using the << operator" do
292
+ @book_1.book_taggings << @tag_1
293
+ @book_1.tags.should have(0).tags
294
+ end
295
+ end
296
+
237
297
  end
@@ -24,7 +24,7 @@ if ADAPTER
24
24
  property :name, String
25
25
  property :type, Discriminator
26
26
 
27
- belongs_to :parent, :class_name => 'ManyToOneSpec::Parent'
27
+ belongs_to :parent
28
28
  end
29
29
 
30
30
  class StepChild < Child
@@ -108,6 +108,7 @@ if ADAPTER
108
108
  describe 'when the parent is not a new record' do
109
109
  before do
110
110
  @parent.should_not be_new_record
111
+ @child.should_not be_new_record
111
112
  end
112
113
 
113
114
  it 'should not save the parent' do
@@ -118,6 +119,10 @@ if ADAPTER
118
119
  it 'should return true' do
119
120
  @association.save.should == true
120
121
  end
122
+
123
+ it "should return true to the child" do
124
+ @child.save.should == true
125
+ end
121
126
  end
122
127
 
123
128
  describe 'when the parent is a new record' do
@@ -34,6 +34,75 @@ describe "OneToMany" do
34
34
  BaseballTeam.create(:name => "Giants")
35
35
  end
36
36
 
37
+ describe "(saved parent, saved child)" do
38
+ before(:each) do
39
+ @dc_united = Team.create
40
+ @emilio = Player.create(:team => @dc_united)
41
+ end
42
+
43
+ it "child association should return parent" do
44
+ @emilio.team.should == @dc_united
45
+ end
46
+
47
+ it "parent association should return children" do
48
+ @dc_united.players.should == [@emilio]
49
+ end
50
+ end
51
+
52
+ describe "(saved parent, unsaved child)" do
53
+ before(:each) do
54
+ @dc_united = Team.create
55
+ @emilio = Player.new(:team => @dc_united)
56
+ end
57
+
58
+ it "child association should return parent" do
59
+ @emilio.team.should == @dc_united
60
+ end
61
+
62
+ it "parent association should return children" do
63
+ pending("DataMapper does not yet support in-memory associations") do
64
+ @dc_united.players.should == [@emilio]
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "(unsaved parent, saved child)" do
70
+ before(:each) do
71
+ @dc_united = Team.new
72
+ @emilio = Player.create(:team => @dc_united)
73
+ end
74
+
75
+ it "child association should return parent" do
76
+ @emilio.team.should == @dc_united
77
+ end
78
+
79
+ it "parent association should return children" do
80
+ @dc_united.players.should == [@emilio]
81
+ end
82
+
83
+ it "should return true to child.save" do
84
+ @emilio.should_not be_a_new_record
85
+ @emilio.save.should be_true
86
+ end
87
+ end
88
+
89
+ describe "(unsaved parent, unsaved child)" do
90
+ before(:each) do
91
+ @dc_united = Team.new
92
+ @emilio = Player.new(:team => @dc_united)
93
+ end
94
+
95
+ it "child association should return parent" do
96
+ @emilio.team.should == @dc_united
97
+ end
98
+
99
+ it "parent association should return children" do
100
+ pending("DataMapper does not yet support in-memory associations") do
101
+ @dc_united.players.should == [@emilio]
102
+ end
103
+ end
104
+ end
105
+
37
106
  it "unsaved parent model should accept array of hashes for association" do
38
107
  players = [{ :name => "Brett Favre" }, { :name => "Reggie White" }]
39
108
 
@@ -1055,6 +1055,13 @@ if ADAPTER
1055
1055
  collection.length.should == 2
1056
1056
  collection.should be_loaded
1057
1057
  end
1058
+
1059
+ it "should load lazy columns when using offset" do
1060
+ repository(ADAPTER) do
1061
+ zebras = Zebra.all(:offset => 1, :limit => 2)
1062
+ zebras.first.notes.should_not be_nil
1063
+ end
1064
+ end
1058
1065
  end
1059
1066
  end
1060
1067
  end
@@ -34,7 +34,7 @@ if ADAPTER
34
34
 
35
35
  property :id, Serial
36
36
  property :name, String
37
- property :type, String
37
+ property :type, String
38
38
 
39
39
  def self.default_repository_name
40
40
  ADAPTER
@@ -250,6 +250,23 @@ if ADAPTER
250
250
  end
251
251
  end
252
252
 
253
+ it "should find by conditions passed in as an array" do
254
+ repository(ADAPTER) do
255
+ find = QuerySpec::SailBoat.all(:id => [1,2])
256
+ find.should_not be_nil
257
+ find.should have(2).entries
258
+
259
+ find = QuerySpec::SailBoat.all(:id.not => [1,2])
260
+ find.should have(1).entries
261
+
262
+ find = QuerySpec::SailBoat.all(:id => [])
263
+ find.should have(0).entries
264
+
265
+ find = QuerySpec::SailBoat.all(:id.not => [])
266
+ find.should have(3).entries
267
+ end
268
+ end
269
+
253
270
  it "should order results" do
254
271
  repository(ADAPTER) do
255
272
  result = QuerySpec::SailBoat.all(:order => [
@@ -432,12 +449,12 @@ if ADAPTER
432
449
  vehicle.name.should == '10 ton delivery truck'
433
450
  end
434
451
 
435
- it "should accept 'id' and 'type' as endpoints on ah DM::QueryPath" do
436
- vehicle = QuerySpec::Vehicle.first( QuerySpec::Vehicle.factory.region.type => 'commercial' )
437
- vehicle.name.should == '10 ton delivery truck'
438
- vehicle = QuerySpec::Vehicle.first( QuerySpec::Vehicle.factory.region.id => 1 )
439
- vehicle.name.should == '10 ton delivery truck'
440
- end
452
+ it "should accept 'id' and 'type' as endpoints on ah DM::QueryPath" do
453
+ vehicle = QuerySpec::Vehicle.first( QuerySpec::Vehicle.factory.region.type => 'commercial' )
454
+ vehicle.name.should == '10 ton delivery truck'
455
+ vehicle = QuerySpec::Vehicle.first( QuerySpec::Vehicle.factory.region.id => 1 )
456
+ vehicle.name.should == '10 ton delivery truck'
457
+ end
441
458
 
442
459
  it 'should auto generate the link if a DM::Property from a different resource is in the :fields option'
443
460