dm-core 0.9.2 → 0.9.3

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 (84) hide show
  1. data/.autotest +26 -0
  2. data/{CHANGELOG → History.txt} +78 -77
  3. data/Manifest.txt +123 -0
  4. data/{README → README.txt} +0 -0
  5. data/Rakefile +29 -0
  6. data/SPECS +63 -0
  7. data/TODO +1 -0
  8. data/lib/dm-core.rb +6 -1
  9. data/lib/dm-core/adapters/data_objects_adapter.rb +29 -32
  10. data/lib/dm-core/adapters/mysql_adapter.rb +1 -1
  11. data/lib/dm-core/adapters/postgres_adapter.rb +1 -1
  12. data/lib/dm-core/adapters/sqlite3_adapter.rb +2 -2
  13. data/lib/dm-core/associations.rb +26 -0
  14. data/lib/dm-core/associations/many_to_many.rb +34 -25
  15. data/lib/dm-core/associations/many_to_one.rb +4 -4
  16. data/lib/dm-core/associations/one_to_many.rb +48 -13
  17. data/lib/dm-core/associations/one_to_one.rb +4 -4
  18. data/lib/dm-core/associations/relationship.rb +144 -42
  19. data/lib/dm-core/associations/relationship_chain.rb +31 -24
  20. data/lib/dm-core/auto_migrations.rb +0 -4
  21. data/lib/dm-core/collection.rb +40 -7
  22. data/lib/dm-core/dependency_queue.rb +31 -0
  23. data/lib/dm-core/hook.rb +2 -2
  24. data/lib/dm-core/is.rb +2 -2
  25. data/lib/dm-core/logger.rb +10 -10
  26. data/lib/dm-core/model.rb +94 -41
  27. data/lib/dm-core/property.rb +72 -41
  28. data/lib/dm-core/property_set.rb +8 -14
  29. data/lib/dm-core/query.rb +34 -9
  30. data/lib/dm-core/repository.rb +0 -0
  31. data/lib/dm-core/resource.rb +13 -13
  32. data/lib/dm-core/scope.rb +25 -2
  33. data/lib/dm-core/type.rb +3 -3
  34. data/lib/dm-core/types/discriminator.rb +10 -8
  35. data/lib/dm-core/types/object.rb +4 -0
  36. data/lib/dm-core/types/paranoid_boolean.rb +15 -4
  37. data/lib/dm-core/types/paranoid_datetime.rb +15 -4
  38. data/lib/dm-core/version.rb +3 -0
  39. data/script/all +5 -0
  40. data/script/performance.rb +191 -0
  41. data/script/profile.rb +86 -0
  42. data/spec/integration/association_spec.rb +288 -204
  43. data/spec/integration/association_through_spec.rb +9 -3
  44. data/spec/integration/associations/many_to_many_spec.rb +97 -31
  45. data/spec/integration/associations/many_to_one_spec.rb +41 -6
  46. data/spec/integration/associations/one_to_many_spec.rb +18 -2
  47. data/spec/integration/auto_migrations_spec.rb +0 -0
  48. data/spec/integration/collection_spec.rb +89 -42
  49. data/spec/integration/dependency_queue_spec.rb +58 -0
  50. data/spec/integration/model_spec.rb +67 -8
  51. data/spec/integration/postgres_adapter_spec.rb +19 -20
  52. data/spec/integration/property_spec.rb +17 -8
  53. data/spec/integration/query_spec.rb +273 -191
  54. data/spec/integration/resource_spec.rb +108 -10
  55. data/spec/integration/strategic_eager_loading_spec.rb +138 -0
  56. data/spec/integration/transaction_spec.rb +3 -3
  57. data/spec/integration/type_spec.rb +121 -0
  58. data/spec/lib/logging_helper.rb +18 -0
  59. data/spec/lib/model_loader.rb +91 -0
  60. data/spec/lib/publicize_methods.rb +28 -0
  61. data/spec/models/vehicles.rb +34 -0
  62. data/spec/models/zoo.rb +48 -0
  63. data/spec/spec.opts +3 -0
  64. data/spec/spec_helper.rb +25 -62
  65. data/spec/unit/adapters/data_objects_adapter_spec.rb +1 -0
  66. data/spec/unit/associations/many_to_many_spec.rb +3 -0
  67. data/spec/unit/associations/many_to_one_spec.rb +9 -1
  68. data/spec/unit/associations/one_to_many_spec.rb +12 -4
  69. data/spec/unit/associations/relationship_spec.rb +19 -15
  70. data/spec/unit/associations_spec.rb +37 -0
  71. data/spec/unit/collection_spec.rb +8 -0
  72. data/spec/unit/data_mapper_spec.rb +14 -0
  73. data/spec/unit/model_spec.rb +2 -2
  74. data/spec/unit/property_set_spec.rb +0 -13
  75. data/spec/unit/property_spec.rb +92 -21
  76. data/spec/unit/query_spec.rb +49 -4
  77. data/spec/unit/resource_spec.rb +122 -60
  78. data/spec/unit/scope_spec.rb +11 -0
  79. data/tasks/ci.rb +68 -0
  80. data/tasks/dm.rb +63 -0
  81. data/tasks/doc.rb +20 -0
  82. data/tasks/hoe.rb +38 -0
  83. data/tasks/install.rb +20 -0
  84. metadata +63 -22
@@ -18,7 +18,7 @@ if ADAPTER
18
18
  has n, :taggings
19
19
 
20
20
  has n, :relationships
21
- has n, :related_posts, :through => :relationships, :class_name => 'Post'
21
+ has n, :related_posts, :through => :relationships, :class_name => 'Post', :child_key => [:post_id]
22
22
 
23
23
  has n, :posts, :through => :taggings
24
24
  end
@@ -68,7 +68,7 @@ if ADAPTER
68
68
 
69
69
  property :id, Serial
70
70
  belongs_to :post
71
- belongs_to :related_post, :class_name => "Post"
71
+ belongs_to :related_post, :class_name => "Post", :child_key => [:related_post_id]
72
72
  end
73
73
 
74
74
  [Post, Tag, Tagging, Relationship].each do |descendant|
@@ -102,7 +102,7 @@ if ADAPTER
102
102
  good.taggings << goody
103
103
  good.save
104
104
 
105
- relation = Relationship.new(:related_post => another_post)
105
+ relation = Relationship.new(:related_post_id => another_post.id)
106
106
  post.relationships << relation
107
107
  post.save
108
108
  end
@@ -135,6 +135,12 @@ if ADAPTER
135
135
  related_posts.first(10, :id => 2).map { |r| r.id }.should == [ post.id ]
136
136
  end
137
137
 
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
142
+ end
143
+
138
144
  it 'should proxy object should be frozen' do
139
145
  Post.first.related_posts.should be_frozen
140
146
  end
@@ -13,6 +13,8 @@ describe DataMapper::Associations::ManyToMany::Proxy do
13
13
  has n, :books, :through => Resource
14
14
  end
15
15
 
16
+ Object.send(:remove_const, :Book) if defined?(Book)
17
+
16
18
  class Book
17
19
  include DataMapper::Resource
18
20
 
@@ -23,7 +25,9 @@ describe DataMapper::Associations::ManyToMany::Proxy do
23
25
 
24
26
  has n, :editors, :through => Resource
25
27
  end
28
+ end
26
29
 
30
+ before do
27
31
  [ Book, Editor, BookEditor ].each { |k| k.auto_migrate! }
28
32
 
29
33
  repository(ADAPTER) do
@@ -37,90 +41,150 @@ describe DataMapper::Associations::ManyToMany::Proxy do
37
41
  BookEditor.create(:book => book_1, :editor => editor_1)
38
42
  BookEditor.create(:book => book_2, :editor => editor_1)
39
43
  BookEditor.create(:book => book_1, :editor => editor_2)
44
+
45
+ @parent = book_3
46
+ @association = @parent.editors
47
+ @other = [ editor_1 ]
48
+ end
49
+ end
50
+
51
+ it 'should provide #replace' do
52
+ @association.should respond_to(:replace)
53
+ end
54
+
55
+ describe '#replace' do
56
+ it 'should remove the resource from the collection' do
57
+ @association.should have(0).entries
58
+ @association.replace(@other)
59
+ @association.should == @other
60
+ end
61
+
62
+ it 'should not automatically save that the resource was removed from the association' do
63
+ @association.replace(@other)
64
+ @parent.reload.should have(0).editors
65
+ end
66
+
67
+ it 'should return the association' do
68
+ @association.replace(@other).object_id.should == @association.object_id
69
+ end
70
+
71
+ it 'should add the new resources so they will be saved when saving the parent' do
72
+ @association.replace(@other)
73
+ @association.should == @other
74
+ @parent.save
75
+ @association.reload.should == @other
76
+ end
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') ]
81
+ other.first.should_not be_nil
82
+ @association.should == other
83
+ @parent.save
84
+ @association.reload.should == other
40
85
  end
41
86
  end
42
87
 
43
88
  it "should correctly link records" do
44
- Editor.get(1).books.size.should == 2
45
- Editor.get(2).books.size.should == 1
46
- Book.get(1).editors.size.should == 2
47
- Book.get(2).editors.size.should == 1
89
+ Book.get(1).should have(2).editors
90
+ Book.get(2).should have(1).editors
91
+ Book.get(3).should have(0).editors
92
+ Editor.get(1).should have(2).books
93
+ Editor.get(2).should have(1).books
48
94
  end
49
95
 
50
96
  it "should be able to have associated objects manually added" do
51
97
  book = Book.get(3)
52
- # book.editors.size.should == 0
98
+ book.should have(0).editors
53
99
 
54
100
  be = BookEditor.new(:book_id => book.id, :editor_id => 2)
55
101
  book.book_editors << be
56
102
  book.save
57
103
 
58
- book.reload
59
- book.editors.size.should == 1
104
+ book.reload.should have(1).editors
60
105
  end
61
106
 
62
107
  it "should automatically added necessary through class" do
63
108
  book = Book.get(3)
109
+ book.should have(0).editors
110
+
64
111
  book.editors << Editor.get(1)
65
112
  book.editors << Editor.new(:name => "Jimmy John")
66
113
  book.save
67
- book.editors.size.should == 3
114
+
115
+ book.reload.should have(2).editors
68
116
  end
69
117
 
70
118
  it "should react correctly to a new record" do
71
119
  book = Book.new(:title => "Finnegan's Wake")
72
- book.editors << Editor.get(2)
120
+ editor = Editor.get(2)
121
+ book.should have(0).editors
122
+ editor.should have(1).books
123
+
124
+ book.editors << editor
73
125
  book.save
74
- book.editors.size.should == 1
75
- Editor.get(2).books.size.should == 3
126
+
127
+ book.reload.should have(1).editors
128
+ editor.reload.should have(2).books
76
129
  end
77
130
 
78
131
  it "should be able to delete intermediate model" do
79
- book = Book.get(3)
80
- be = BookEditor.get(3,1)
132
+ book = Book.get(1)
133
+ book.should have(2).book_editors
134
+ book.should have(2).editors
135
+
136
+ be = BookEditor.get(1,1)
81
137
  book.book_editors.delete(be)
82
138
  book.save
139
+
83
140
  book.reload
84
- book = Book.get(3)
85
- book.book_editors.size.should == 2
86
- book.editors.size.should == 2
141
+ book.should have(1).book_editors
142
+ book.should have(1).editors
87
143
  end
88
144
 
89
145
  it "should be clearable" do
90
146
  repository(ADAPTER) do
91
147
  book = Book.get(2)
92
- book.editors.size.should == 1
148
+ book.should have(1).book_editors
149
+ book.should have(1).editors
150
+
93
151
  book.editors.clear
94
152
  book.save
153
+
95
154
  book.reload
96
- book.book_editors.size.should == 0
97
- book.editors.size.should == 0
155
+ book.should have(0).book_editors
156
+ book.should have(0).editors
98
157
  end
99
158
  repository(ADAPTER) do
100
- Book.get(2).editors.size.should == 0
159
+ Book.get(2).should have(0).editors
101
160
  end
102
161
  end
103
162
 
104
163
  it "should be able to delete one object" do
105
164
  book = Book.get(1)
106
- editor = book.editors.first
165
+ book.should have(2).book_editors
166
+ book.should have(2).editors
107
167
 
108
- book.editors.size.should == 2
168
+ editor = book.editors.first
109
169
  book.editors.delete(editor)
110
- book.book_editors.size.should == 1
111
- book.editors.size.should == 1
112
170
  book.save
171
+
113
172
  book.reload
114
- Editor.get(1).books.should_not include(book)
173
+ book.should have(1).book_editors
174
+ book.should have(1).editors
175
+ editor.reload.books.should_not include(book)
115
176
  end
116
177
 
117
178
  it "should be destroyable" do
118
179
  pending 'cannot destroy a collection yet' do
119
- book = Book.get(3)
180
+ book = Book.get(2)
181
+ book.should have(1).editors
182
+
120
183
  book.editors.destroy
121
184
  book.save
185
+
122
186
  book.reload
123
- book.editors.size.should == 0
187
+ book.should have(0).editors
124
188
  end
125
189
  end
126
190
 
@@ -139,7 +203,9 @@ describe DataMapper::Associations::ManyToMany::Proxy do
139
203
  class Book
140
204
  has n, :authors, :through => Resource
141
205
  end
206
+ end
142
207
 
208
+ before do
143
209
  [ Author, AuthorBook ].each { |k| k.auto_migrate! }
144
210
 
145
211
  @author = Author.create(:name => 'James Joyce')
@@ -162,10 +228,10 @@ describe DataMapper::Associations::ManyToMany::Proxy do
162
228
  end
163
229
 
164
230
  it 'should correctly link records' do
165
- @author.books.should have(3).entries
166
- @book_1.authors.should have(1).entries
167
- @book_2.authors.should have(1).entries
168
- @book_3.authors.should have(1).entries
231
+ @author.should have(3).books
232
+ @book_1.should have(1).authors
233
+ @book_2.should have(1).authors
234
+ @book_3.should have(1).authors
169
235
  end
170
236
  end
171
237
  end
@@ -22,20 +22,55 @@ if ADAPTER
22
22
 
23
23
  property :id, Serial
24
24
  property :name, String
25
+ property :type, Discriminator
25
26
 
26
27
  belongs_to :parent, :class_name => 'ManyToOneSpec::Parent'
27
28
  end
29
+
30
+ class StepChild < Child
31
+ end
28
32
  end
29
33
 
30
34
  describe DataMapper::Associations::ManyToOne::Proxy do
31
35
  before do
32
- ManyToOneSpec::Parent.auto_migrate!
33
- ManyToOneSpec::Child.auto_migrate!
36
+ [ ManyToOneSpec::Parent, ManyToOneSpec::Child ].each { |model| model.auto_migrate! }
37
+
38
+ repository(ADAPTER) do
39
+ @parent = ManyToOneSpec::Parent.create(:name => 'parent')
40
+ @child = ManyToOneSpec::Child.create(:name => 'child', :parent => @parent)
41
+ @other = ManyToOneSpec::Parent.create(:name => 'other parent')
42
+ @step_child = ManyToOneSpec::StepChild.create(:name => 'step child', :parent => @other)
43
+ @association = @child.parent
44
+ end
45
+ end
46
+
47
+ describe "#association_accessor (STI)" do
48
+ include LoggingHelper
49
+
50
+ it "should set parent" do
51
+ ManyToOneSpec::StepChild.first(:id => @step_child.id).parent.should == @other
52
+ end
53
+
54
+ it "should use the identity map for STI" do
55
+ repository(ADAPTER) do |r|
56
+ parent = ManyToOneSpec::Parent.first(:id => @parent.id)
57
+ child = ManyToOneSpec::Child.first(:id => @child.id)
58
+ step_child = ManyToOneSpec::StepChild.first(:id => @step_child.id)
59
+ logger do |log|
60
+ # should retrieve from the IdentityMap
61
+ child.parent.object_id.should == parent.object_id
62
+
63
+ # should retrieve from the datasource
64
+ other = step_child.parent
34
65
 
35
- @parent = ManyToOneSpec::Parent.create(:name => 'parent')
36
- @child = ManyToOneSpec::Child.create(:name => 'child', :parent => @parent)
37
- @other = ManyToOneSpec::Parent.create(:name => 'other parent')
38
- @association = @child.parent
66
+ # should retrieve from the IdentityMap
67
+ step_child.parent.should == @other
68
+ step_child.parent.object_id.should == other.object_id
69
+
70
+ log.readlines.size.should == 1
71
+ end
72
+ end
73
+ end
39
74
  end
40
75
 
41
76
  describe '#replace' do
@@ -9,10 +9,14 @@ describe "OneToMany" do
9
9
 
10
10
  property :id, Serial
11
11
  property :name, String
12
+ property :class_type, Discriminator
12
13
 
13
14
  has n, :players
14
15
  end
15
16
 
17
+ class BaseballTeam < Team
18
+ end
19
+
16
20
  class Player
17
21
  include DataMapper::Resource
18
22
 
@@ -26,7 +30,8 @@ describe "OneToMany" do
26
30
 
27
31
  [Team, Player].each { |k| k.auto_migrate!(ADAPTER) }
28
32
 
29
- Team.create!(:name => "Cowboys")
33
+ Team.create(:name => "Cowboys")
34
+ BaseballTeam.create(:name => "Giants")
30
35
  end
31
36
 
32
37
  it "unsaved parent model should accept array of hashes for association" do
@@ -42,7 +47,7 @@ describe "OneToMany" do
42
47
  team.save
43
48
 
44
49
  repository(ADAPTER) do
45
- Team.get(2).players.should == players
50
+ Team.get(3).players.should == players
46
51
  end
47
52
  end
48
53
 
@@ -63,4 +68,15 @@ describe "OneToMany" do
63
68
  Team.get(1).players.should == players
64
69
  end
65
70
  end
71
+
72
+ describe "STI" do
73
+ it "should work" do
74
+ repository(ADAPTER) do
75
+ Player.create(:name => "Barry Bonds", :team => BaseballTeam.first)
76
+ end
77
+ repository(ADAPTER) do
78
+ Player.first.team.should == BaseballTeam.first
79
+ end
80
+ end
81
+ end
66
82
  end
File without changes
@@ -29,6 +29,10 @@ if ADAPTER
29
29
  property :zebra_id, Integer
30
30
 
31
31
  belongs_to :zebra
32
+
33
+ def self.sort_by_name
34
+ all(:order => [ :name ])
35
+ end
32
36
  end
33
37
 
34
38
  class CollectionSpecParty
@@ -71,46 +75,6 @@ if ADAPTER
71
75
  end
72
76
  end
73
77
 
74
- describe 'association proxying' do
75
- include CollectionSpecHelper
76
-
77
- before do
78
- setup
79
- end
80
-
81
- it "should provide a Query" do
82
- repository(ADAPTER) do
83
- zebras = Zebra.all(:order => [ :name ])
84
- zebras.query.order.should == [DataMapper::Query::Direction.new(Zebra.properties(ADAPTER)[:name])]
85
- end
86
- end
87
-
88
- it "should proxy the relationships of the model" do
89
- repository(ADAPTER) do
90
- zebras = Zebra.all
91
- zebras.should have(3).entries
92
- zebras.find { |zebra| zebra.name == 'Nancy' }.stripes.should have(2).entries
93
- zebras.stripes.should == [@babe, @snowball]
94
- end
95
- end
96
-
97
- it "should preserve it's order on reload" do
98
- repository(ADAPTER) do |r|
99
- zebras = Zebra.all(:order => [ :name ])
100
-
101
- order = %w{ Bessie Nancy Steve }
102
-
103
- zebras.map { |z| z.name }.should == order
104
-
105
- # Force a lazy-load call:
106
- zebras.first.notes
107
-
108
- # The order should be unaffected.
109
- zebras.map { |z| z.name }.should == order
110
- end
111
- end
112
- end
113
-
114
78
  describe DataMapper::Collection do
115
79
  include CollectionSpecHelper
116
80
 
@@ -163,6 +127,49 @@ if ADAPTER
163
127
  results.first.should == bob
164
128
  end
165
129
 
130
+ describe 'model proxying' do
131
+ it 'should delegate to a model method' do
132
+ stripes = @model.first.stripes
133
+ stripes.should respond_to(:sort_by_name)
134
+ stripes.sort_by_name.should == [ @babe, @snowball ]
135
+ end
136
+ end
137
+
138
+ describe 'association proxying' do
139
+ it "should provide a Query" do
140
+ repository(ADAPTER) do
141
+ zebras = Zebra.all(:order => [ :name ])
142
+ zebras.query.order.should == [DataMapper::Query::Direction.new(Zebra.properties(ADAPTER)[:name])]
143
+ end
144
+ end
145
+
146
+ it "should proxy the relationships of the model" do
147
+ repository(ADAPTER) do
148
+ zebras = Zebra.all
149
+ zebras.should have(3).entries
150
+ zebras.find { |zebra| zebra.name == 'Nancy' }.stripes.should have(2).entries
151
+ zebras.should respond_to(:stripes)
152
+ zebras.stripes.should == [@babe, @snowball]
153
+ end
154
+ end
155
+
156
+ it "should preserve it's order on reload" do
157
+ repository(ADAPTER) do |r|
158
+ zebras = Zebra.all(:order => [ :name ])
159
+
160
+ order = %w{ Bessie Nancy Steve }
161
+
162
+ zebras.map { |z| z.name }.should == order
163
+
164
+ # Force a lazy-load call:
165
+ zebras.first.notes
166
+
167
+ # The order should be unaffected.
168
+ zebras.map { |z| z.name }.should == order
169
+ end
170
+ end
171
+ end
172
+
166
173
  describe '.new' do
167
174
  describe 'with non-index keys' do
168
175
  it 'should instantiate read-only resources' do
@@ -295,6 +302,32 @@ if ADAPTER
295
302
  end
296
303
  end
297
304
 
305
+ describe '#build' do
306
+ it 'should build a new resource' do
307
+ resource = @collection.build(:name => 'John')
308
+ resource.should be_kind_of(@model)
309
+ resource.should be_new_record
310
+ end
311
+
312
+ it 'should append the new resource to the collection' do
313
+ resource = @collection.build(:name => 'John')
314
+ resource.should be_new_record
315
+ resource.collection.object_id.should == @collection.object_id
316
+ @collection.should include(resource)
317
+ end
318
+
319
+ it 'should use the query conditions to set default values' do
320
+ resource = @collection.build
321
+ resource.should be_new_record
322
+ resource.name.should be_nil
323
+
324
+ @collection.query.update(:name => 'John')
325
+
326
+ resource = @collection.build
327
+ resource.name.should == 'John'
328
+ end
329
+ end
330
+
298
331
  describe '#clear' do
299
332
  it 'should orphan the resource from the collection' do
300
333
  entries = @collection.entries
@@ -508,6 +541,14 @@ if ADAPTER
508
541
  end
509
542
  end
510
543
 
544
+ describe '#freeze' do
545
+ it 'should freeze the underlying array' do
546
+ @collection.should_not be_frozen
547
+ @collection.freeze
548
+ @collection.should be_frozen
549
+ end
550
+ end
551
+
511
552
  describe '#get' do
512
553
  it 'should find a resource in a collection by key' do
513
554
  resource = @collection.get(*@nancy.key)
@@ -515,9 +556,15 @@ if ADAPTER
515
556
  resource.id.should == @nancy.id
516
557
  end
517
558
 
559
+ it "should find a resource in a collection by typecasting the key" do
560
+ resource = @collection.get(@nancy.key.to_s)
561
+ resource.should be_kind_of(DataMapper::Resource)
562
+ resource.id.should == @nancy.id
563
+ end
564
+
518
565
  it 'should not find a resource not in the collection' do
519
566
  @query.update(:offset => 0, :limit => 3)
520
- @david = Zebra.create!(:name => 'David', :age => 15, :notes => 'Albino')
567
+ @david = Zebra.create(:name => 'David', :age => 15, :notes => 'Albino')
521
568
  @collection.get(@david.key).should be_nil
522
569
  end
523
570
  end
@@ -531,7 +578,7 @@ if ADAPTER
531
578
 
532
579
  it 'should raise an exception if the resource is not found' do
533
580
  @query.update(:offset => 0, :limit => 3)
534
- @david = Zebra.create!(:name => 'David', :age => 15, :notes => 'Albino')
581
+ @david = Zebra.create(:name => 'David', :age => 15, :notes => 'Albino')
535
582
  lambda {
536
583
  @collection.get!(@david.key)
537
584
  }.should raise_error(DataMapper::ObjectNotFoundError)