dm-core 0.9.3 → 0.9.4

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