dm-core 0.9.11 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (194) hide show
  1. data/.autotest +17 -14
  2. data/.gitignore +3 -1
  3. data/FAQ +6 -5
  4. data/History.txt +5 -50
  5. data/Manifest.txt +66 -76
  6. data/QUICKLINKS +1 -1
  7. data/README.txt +21 -15
  8. data/Rakefile +6 -7
  9. data/SPECS +2 -29
  10. data/TODO +1 -1
  11. data/deps.rip +2 -0
  12. data/dm-core.gemspec +11 -15
  13. data/lib/dm-core.rb +105 -110
  14. data/lib/dm-core/adapters.rb +135 -16
  15. data/lib/dm-core/adapters/abstract_adapter.rb +251 -181
  16. data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
  17. data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
  18. data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
  19. data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
  20. data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
  21. data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
  22. data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
  23. data/lib/dm-core/associations/many_to_many.rb +372 -90
  24. data/lib/dm-core/associations/many_to_one.rb +220 -73
  25. data/lib/dm-core/associations/one_to_many.rb +319 -255
  26. data/lib/dm-core/associations/one_to_one.rb +66 -53
  27. data/lib/dm-core/associations/relationship.rb +561 -156
  28. data/lib/dm-core/collection.rb +1101 -379
  29. data/lib/dm-core/core_ext/kernel.rb +12 -0
  30. data/lib/dm-core/core_ext/symbol.rb +10 -0
  31. data/lib/dm-core/identity_map.rb +4 -34
  32. data/lib/dm-core/migrations.rb +1283 -0
  33. data/lib/dm-core/model.rb +570 -369
  34. data/lib/dm-core/model/descendant_set.rb +81 -0
  35. data/lib/dm-core/model/hook.rb +45 -0
  36. data/lib/dm-core/model/is.rb +32 -0
  37. data/lib/dm-core/model/property.rb +247 -0
  38. data/lib/dm-core/model/relationship.rb +335 -0
  39. data/lib/dm-core/model/scope.rb +90 -0
  40. data/lib/dm-core/property.rb +808 -273
  41. data/lib/dm-core/property_set.rb +141 -98
  42. data/lib/dm-core/query.rb +1037 -483
  43. data/lib/dm-core/query/conditions/comparison.rb +872 -0
  44. data/lib/dm-core/query/conditions/operation.rb +221 -0
  45. data/lib/dm-core/query/direction.rb +43 -0
  46. data/lib/dm-core/query/operator.rb +84 -0
  47. data/lib/dm-core/query/path.rb +138 -0
  48. data/lib/dm-core/query/sort.rb +45 -0
  49. data/lib/dm-core/repository.rb +210 -94
  50. data/lib/dm-core/resource.rb +641 -421
  51. data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
  52. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
  53. data/lib/dm-core/support/chainable.rb +22 -0
  54. data/lib/dm-core/support/deprecate.rb +12 -0
  55. data/lib/dm-core/support/logger.rb +13 -0
  56. data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
  57. data/lib/dm-core/transaction.rb +333 -92
  58. data/lib/dm-core/type.rb +98 -60
  59. data/lib/dm-core/types/boolean.rb +1 -1
  60. data/lib/dm-core/types/discriminator.rb +34 -20
  61. data/lib/dm-core/types/object.rb +7 -4
  62. data/lib/dm-core/types/paranoid_boolean.rb +11 -9
  63. data/lib/dm-core/types/paranoid_datetime.rb +11 -9
  64. data/lib/dm-core/types/serial.rb +3 -3
  65. data/lib/dm-core/types/text.rb +3 -4
  66. data/lib/dm-core/version.rb +1 -1
  67. data/script/performance.rb +102 -109
  68. data/script/profile.rb +169 -38
  69. data/spec/lib/adapter_helpers.rb +105 -0
  70. data/spec/lib/collection_helpers.rb +18 -0
  71. data/spec/lib/counter_adapter.rb +34 -0
  72. data/spec/lib/pending_helpers.rb +27 -0
  73. data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
  74. data/spec/public/associations/many_to_many_spec.rb +193 -0
  75. data/spec/public/associations/many_to_one_spec.rb +73 -0
  76. data/spec/public/associations/one_to_many_spec.rb +77 -0
  77. data/spec/public/associations/one_to_one_spec.rb +156 -0
  78. data/spec/public/collection_spec.rb +65 -0
  79. data/spec/public/migrations_spec.rb +359 -0
  80. data/spec/public/model/relationship_spec.rb +924 -0
  81. data/spec/public/model_spec.rb +159 -0
  82. data/spec/public/property_spec.rb +829 -0
  83. data/spec/public/resource_spec.rb +71 -0
  84. data/spec/public/sel_spec.rb +44 -0
  85. data/spec/public/setup_spec.rb +145 -0
  86. data/spec/public/shared/association_collection_shared_spec.rb +317 -0
  87. data/spec/public/shared/collection_shared_spec.rb +1670 -0
  88. data/spec/public/shared/finder_shared_spec.rb +1619 -0
  89. data/spec/public/shared/resource_shared_spec.rb +924 -0
  90. data/spec/public/shared/sel_shared_spec.rb +112 -0
  91. data/spec/public/transaction_spec.rb +129 -0
  92. data/spec/public/types/discriminator_spec.rb +130 -0
  93. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  94. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
  95. data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
  96. data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
  97. data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
  98. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
  99. data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
  100. data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
  101. data/spec/semipublic/associations/relationship_spec.rb +194 -0
  102. data/spec/semipublic/associations_spec.rb +177 -0
  103. data/spec/semipublic/collection_spec.rb +142 -0
  104. data/spec/semipublic/property_spec.rb +61 -0
  105. data/spec/semipublic/query/conditions_spec.rb +528 -0
  106. data/spec/semipublic/query/path_spec.rb +443 -0
  107. data/spec/semipublic/query_spec.rb +2626 -0
  108. data/spec/semipublic/resource_spec.rb +47 -0
  109. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  110. data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
  111. data/spec/spec.opts +3 -1
  112. data/spec/spec_helper.rb +80 -57
  113. data/tasks/ci.rb +19 -31
  114. data/tasks/dm.rb +43 -48
  115. data/tasks/doc.rb +8 -11
  116. data/tasks/gemspec.rb +5 -5
  117. data/tasks/hoe.rb +15 -16
  118. data/tasks/install.rb +8 -10
  119. metadata +74 -111
  120. data/lib/dm-core/associations.rb +0 -207
  121. data/lib/dm-core/associations/relationship_chain.rb +0 -81
  122. data/lib/dm-core/auto_migrations.rb +0 -105
  123. data/lib/dm-core/dependency_queue.rb +0 -32
  124. data/lib/dm-core/hook.rb +0 -11
  125. data/lib/dm-core/is.rb +0 -16
  126. data/lib/dm-core/logger.rb +0 -232
  127. data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
  128. data/lib/dm-core/migrator.rb +0 -29
  129. data/lib/dm-core/scope.rb +0 -58
  130. data/lib/dm-core/support.rb +0 -7
  131. data/lib/dm-core/support/array.rb +0 -13
  132. data/lib/dm-core/support/assertions.rb +0 -8
  133. data/lib/dm-core/support/errors.rb +0 -23
  134. data/lib/dm-core/support/kernel.rb +0 -11
  135. data/lib/dm-core/support/symbol.rb +0 -41
  136. data/lib/dm-core/type_map.rb +0 -80
  137. data/lib/dm-core/types.rb +0 -19
  138. data/script/all +0 -4
  139. data/spec/integration/association_spec.rb +0 -1382
  140. data/spec/integration/association_through_spec.rb +0 -203
  141. data/spec/integration/associations/many_to_many_spec.rb +0 -449
  142. data/spec/integration/associations/many_to_one_spec.rb +0 -163
  143. data/spec/integration/associations/one_to_many_spec.rb +0 -188
  144. data/spec/integration/auto_migrations_spec.rb +0 -413
  145. data/spec/integration/collection_spec.rb +0 -1073
  146. data/spec/integration/data_objects_adapter_spec.rb +0 -32
  147. data/spec/integration/dependency_queue_spec.rb +0 -46
  148. data/spec/integration/model_spec.rb +0 -197
  149. data/spec/integration/mysql_adapter_spec.rb +0 -85
  150. data/spec/integration/postgres_adapter_spec.rb +0 -731
  151. data/spec/integration/property_spec.rb +0 -253
  152. data/spec/integration/query_spec.rb +0 -514
  153. data/spec/integration/repository_spec.rb +0 -61
  154. data/spec/integration/resource_spec.rb +0 -513
  155. data/spec/integration/sqlite3_adapter_spec.rb +0 -352
  156. data/spec/integration/sti_spec.rb +0 -273
  157. data/spec/integration/strategic_eager_loading_spec.rb +0 -156
  158. data/spec/integration/transaction_spec.rb +0 -75
  159. data/spec/integration/type_spec.rb +0 -275
  160. data/spec/lib/logging_helper.rb +0 -18
  161. data/spec/lib/mock_adapter.rb +0 -27
  162. data/spec/lib/model_loader.rb +0 -100
  163. data/spec/lib/publicize_methods.rb +0 -28
  164. data/spec/models/content.rb +0 -16
  165. data/spec/models/vehicles.rb +0 -34
  166. data/spec/models/zoo.rb +0 -48
  167. data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
  168. data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
  169. data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
  170. data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
  171. data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
  172. data/spec/unit/associations/many_to_many_spec.rb +0 -32
  173. data/spec/unit/associations/many_to_one_spec.rb +0 -159
  174. data/spec/unit/associations/one_to_many_spec.rb +0 -393
  175. data/spec/unit/associations/one_to_one_spec.rb +0 -7
  176. data/spec/unit/associations/relationship_spec.rb +0 -71
  177. data/spec/unit/associations_spec.rb +0 -242
  178. data/spec/unit/auto_migrations_spec.rb +0 -111
  179. data/spec/unit/collection_spec.rb +0 -182
  180. data/spec/unit/data_mapper_spec.rb +0 -35
  181. data/spec/unit/identity_map_spec.rb +0 -126
  182. data/spec/unit/is_spec.rb +0 -80
  183. data/spec/unit/migrator_spec.rb +0 -33
  184. data/spec/unit/model_spec.rb +0 -321
  185. data/spec/unit/naming_conventions_spec.rb +0 -36
  186. data/spec/unit/property_set_spec.rb +0 -90
  187. data/spec/unit/property_spec.rb +0 -753
  188. data/spec/unit/query_spec.rb +0 -571
  189. data/spec/unit/repository_spec.rb +0 -93
  190. data/spec/unit/resource_spec.rb +0 -649
  191. data/spec/unit/scope_spec.rb +0 -142
  192. data/spec/unit/transaction_spec.rb +0 -493
  193. data/spec/unit/type_map_spec.rb +0 -114
  194. data/spec/unit/type_spec.rb +0 -119
@@ -0,0 +1,924 @@
1
+ share_examples_for 'A public Resource' do
2
+ before :all do
3
+ @no_join = defined?(DataMapper::Adapters::InMemoryAdapter) && @adapter.kind_of?(DataMapper::Adapters::InMemoryAdapter) ||
4
+ defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
5
+
6
+ relationship = @user_model.relationships[:referrer]
7
+ @one_to_one_through = relationship.kind_of?(DataMapper::Associations::OneToOne::Relationship) && relationship.respond_to?(:through)
8
+
9
+ @skip = @no_join && @one_to_one_through
10
+ end
11
+
12
+ before :all do
13
+ unless @skip
14
+ %w[ @user_model @user @comment_model ].each do |ivar|
15
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_get(ivar)
16
+ end
17
+ end
18
+ end
19
+
20
+ before do
21
+ pending if @skip
22
+ end
23
+
24
+ [ :==, :=== ].each do |method|
25
+ it { @user.should respond_to(method) }
26
+
27
+ describe "##{method}" do
28
+ describe 'when comparing to the same object' do
29
+ before :all do
30
+ @other = @user
31
+ @return = @user.send(method, @other)
32
+ end
33
+
34
+ it 'should return true' do
35
+ @return.should be_true
36
+ end
37
+ end
38
+
39
+ describe 'when comparing to an object that does not respond to model' do
40
+ before :all do
41
+ @other = Object.new
42
+ @return = @user.send(method, @other)
43
+ end
44
+
45
+ it 'should return false' do
46
+ @return.should be_false
47
+ end
48
+ end
49
+
50
+ describe 'when comparing to a resource with the same properties, but the model is a subclass' do
51
+ before :all do
52
+ rescue_if 'TODO', @skip do
53
+ @other = @author_model.new(@user.attributes)
54
+ @return = @user.send(method, @other)
55
+ end
56
+ end
57
+
58
+ it 'should return true' do
59
+ @return.should be_true
60
+ end
61
+ end
62
+
63
+ describe 'when comparing to a resource with the same repository, key and neither self or the other resource is dirty' do
64
+ before :all do
65
+ rescue_if 'TODO', @skip do
66
+ @other = @user_model.get(*@user.key)
67
+ @return = @user.send(method, @other)
68
+ end
69
+ end
70
+
71
+ it 'should return true' do
72
+ @return.should be_true
73
+ end
74
+ end
75
+
76
+ describe 'when comparing to a resource with the same repository, key but either self or the other resource is dirty' do
77
+ before :all do
78
+ rescue_if 'TODO', @skip do
79
+ @user.age = 20
80
+ @other = @user_model.get(*@user.key)
81
+ @return = @user.send(method, @other)
82
+ end
83
+ end
84
+
85
+ it 'should return false' do
86
+ @return.should be_false
87
+ end
88
+ end
89
+
90
+ describe 'when comparing to a resource with the same properties' do
91
+ before :all do
92
+ rescue_if 'TODO', @skip do
93
+ @other = @user_model.new(@user.attributes)
94
+ @return = @user.send(method, @other)
95
+ end
96
+ end
97
+
98
+ it 'should return true' do
99
+ @return.should be_true
100
+ end
101
+ end
102
+
103
+ with_alternate_adapter do
104
+ describe 'when comparing to a resource with a different repository, but the same properties' do
105
+ before :all do
106
+ rescue_if 'TODO', @skip do
107
+ @other = @alternate_repository.scope { @user_model.create(@user.attributes) }
108
+ @return = @user.send(method, @other)
109
+ end
110
+ end
111
+
112
+ it 'should return true' do
113
+ @return.should be_true
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ it { @user.should respond_to(:<=>) }
121
+
122
+ describe '#<=>' do
123
+ describe 'when the default order properties are equal with another resource' do
124
+ before :all do
125
+ rescue_if 'TODO', @skip do
126
+ @other = @user_model.new(:name => 'dbussink')
127
+ @return = @user <=> @other
128
+ end
129
+ end
130
+
131
+ it 'should return 0' do
132
+ @return.should == 0
133
+ end
134
+ end
135
+
136
+ describe 'when the default order property values are sorted before another resource' do
137
+ before :all do
138
+ rescue_if 'TODO', @skip do
139
+ @other = @user_model.new(:name => 'c')
140
+ @return = @user <=> @other
141
+ end
142
+ end
143
+
144
+ it 'should return 1' do
145
+ @return.should == 1
146
+ end
147
+ end
148
+
149
+ describe 'when the default order property values are sorted after another resource' do
150
+ before :all do
151
+ rescue_if 'TODO', @skip do
152
+ @other = @user_model.new(:name => 'e')
153
+ @return = @user <=> @other
154
+ end
155
+ end
156
+
157
+ it 'should return -1' do
158
+ @return.should == -1
159
+ end
160
+ end
161
+
162
+ describe 'when comparing an unrelated type of Object' do
163
+ it 'should raise an exception' do
164
+ lambda { @user <=> @comment_model.new }.should raise_error(ArgumentError, "Cannot compare a #{@comment_model} instance with a #{@user_model} instance")
165
+ end
166
+ end
167
+ end
168
+
169
+ it { @user.should respond_to(:attribute_get) }
170
+
171
+ describe '#attribute_get' do
172
+
173
+ it { @user.attribute_get(:name).should == 'dbussink' }
174
+
175
+ end
176
+
177
+ it { @user.should respond_to(:attribute_set) }
178
+
179
+ describe '#attribute_set' do
180
+
181
+ before { @user.attribute_set(:name, 'dkubb') }
182
+
183
+ it { @user.name.should == 'dkubb' }
184
+
185
+ end
186
+
187
+ it { @user.should respond_to(:attributes) }
188
+
189
+ describe '#attributes' do
190
+
191
+ it 'should return the expected values' do
192
+ @user.attributes.only(:name, :description, :age).should == { :name => 'dbussink', :description => 'Test', :age => 25 }
193
+ end
194
+
195
+ end
196
+
197
+ it { @user.should respond_to(:attributes=) }
198
+
199
+ describe '#attributes=' do
200
+ describe 'when a public mutator is specified' do
201
+ before :all do
202
+ rescue_if 'TODO', @skip do
203
+ @user.attributes = { :name => 'dkubb' }
204
+ end
205
+ end
206
+
207
+ it 'should set the value' do
208
+ @user.name.should eql('dkubb')
209
+ end
210
+ end
211
+
212
+ describe 'when a non-public mutator is specified' do
213
+ it 'should raise an exception' do
214
+ lambda {
215
+ @user.attributes = { :admin => true }
216
+ }.should raise_error(ArgumentError, "The attribute \'admin\' is not accessible in #{@user_model}")
217
+ end
218
+ end
219
+ end
220
+
221
+ [ :destroy, :destroy! ].each do |method|
222
+ it { @user.should respond_to(:destroy) }
223
+
224
+ describe "##{method}" do
225
+ describe 'on a single object' do
226
+ before :all do
227
+ @resource = @user_model.create(:name => 'hacker', :age => 20, :comment => @comment)
228
+
229
+ @return = @resource.send(method)
230
+ end
231
+
232
+ it 'should successfully remove a resource' do
233
+ @return.should be_true
234
+ end
235
+
236
+ it 'should freeze the destroyed resource' do
237
+ @resource.should be_frozen
238
+ end
239
+
240
+ it 'should not be able to remove an already removed resource' do
241
+ @resource.destroy.should be_false
242
+ end
243
+
244
+ it 'should remove object from persistent storage' do
245
+ @user_model.get(*@resource.key).should be_nil
246
+ end
247
+ end
248
+
249
+ describe 'with has relationship resources' do
250
+ it 'should raise an exception'
251
+ end
252
+ end
253
+ end
254
+
255
+ it { @user.should respond_to(:eql?) }
256
+
257
+ describe '#eql?' do
258
+ describe 'when comparing to the same object' do
259
+ before :all do
260
+ @other = @user
261
+ @return = @user.eql?(@other)
262
+ end
263
+
264
+ it 'should return true' do
265
+ @return.should be_true
266
+ end
267
+ end
268
+
269
+ describe 'when comparing to an object that does not respond to model' do
270
+ before :all do
271
+ @other = Object.new
272
+ @return = @user.eql?(@other)
273
+ end
274
+
275
+ it 'should return false' do
276
+ @return.should be_false
277
+ end
278
+ end
279
+
280
+ describe 'when comparing to a resource with the same properties, but the model is a subclass' do
281
+ before :all do
282
+ rescue_if 'TODO', @skip do
283
+ @other = @author_model.new(@user.attributes)
284
+ @return = @user.eql?(@other)
285
+ end
286
+ end
287
+
288
+ it 'should return false' do
289
+ @return.should be_false
290
+ end
291
+ end
292
+
293
+ describe 'when comparing to a resource with a different key' do
294
+ before :all do
295
+ @other = @user_model.create(:name => 'dkubb', :age => 33, :comment => @comment)
296
+ @return = @user.eql?(@other)
297
+ end
298
+
299
+ it 'should return false' do
300
+ @return.should be_false
301
+ end
302
+ end
303
+
304
+ describe 'when comparing to a resource with the same repository, key and neither self or the other resource is dirty' do
305
+ before :all do
306
+ rescue_if 'TODO', @skip do
307
+ @other = @user_model.get(*@user.key)
308
+ @return = @user.eql?(@other)
309
+ end
310
+ end
311
+
312
+ it 'should return true' do
313
+ @return.should be_true
314
+ end
315
+ end
316
+
317
+ describe 'when comparing to a resource with the same repository, key but either self or the other resource is dirty' do
318
+ before :all do
319
+ rescue_if 'TODO', @skip do
320
+ @user.age = 20
321
+ @other = @user_model.get(*@user.key)
322
+ @return = @user.eql?(@other)
323
+ end
324
+ end
325
+
326
+ it 'should return false' do
327
+ @return.should be_false
328
+ end
329
+ end
330
+
331
+ describe 'when comparing to a resource with the same properties' do
332
+ before :all do
333
+ rescue_if 'TODO', @skip do
334
+ @other = @user_model.new(@user.attributes)
335
+ @return = @user.eql?(@other)
336
+ end
337
+ end
338
+
339
+ it 'should return true' do
340
+ @return.should be_true
341
+ end
342
+ end
343
+
344
+ with_alternate_adapter do
345
+ describe 'when comparing to a resource with a different repository, but the same properties' do
346
+ before :all do
347
+ rescue_if 'TODO', @skip do
348
+ @other = @alternate_repository.scope { @user_model.create(@user.attributes) }
349
+ @return = @user.eql?(@other)
350
+ end
351
+ end
352
+
353
+ it 'should return true' do
354
+ @return.should be_true
355
+ end
356
+ end
357
+ end
358
+ end
359
+
360
+ it { @user.should respond_to(:inspect) }
361
+
362
+ describe '#inspect' do
363
+
364
+ before :all do
365
+ rescue_if 'TODO', @skip do
366
+ @user = @user_model.get(*@user.key)
367
+ @inspected = @user.inspect
368
+ end
369
+ end
370
+
371
+ it { @inspected.should match(/^#<#{@user_model}/) }
372
+
373
+ it { @inspected.should match(/name="dbussink"/) }
374
+
375
+ it { @inspected.should match(/age=25/) }
376
+
377
+ it { @inspected.should match(/description=<not loaded>/) }
378
+
379
+ end
380
+
381
+ it { @user.should respond_to(:key) }
382
+
383
+ describe '#key' do
384
+
385
+ before :all do
386
+ rescue_if 'TODO', @skip do
387
+ @key = @user.key
388
+ @user.name = 'dkubb'
389
+ end
390
+ end
391
+
392
+ it { @key.should be_kind_of(Array) }
393
+
394
+ it 'should always return the key value persisted in the back end' do
395
+ @key.first.should eql("dbussink")
396
+ end
397
+
398
+ it { @user.key.should eql(@key) }
399
+
400
+ end
401
+
402
+ it { @user.should respond_to(:new?) }
403
+
404
+ describe '#new?' do
405
+
406
+ describe 'on an existing record' do
407
+
408
+ it { @user.should_not be_new }
409
+
410
+ end
411
+
412
+ describe 'on a new record' do
413
+
414
+ before { @user = @user_model.new }
415
+
416
+ it { @user.should be_new }
417
+
418
+ end
419
+
420
+ end
421
+
422
+ it { @user.should respond_to(:reload) }
423
+
424
+ describe '#reload' do
425
+
426
+ describe 'for a single object' do
427
+
428
+ before :all do
429
+ rescue_if 'TODO', @skip do
430
+ @user.name = 'dkubb'
431
+ @user.description = 'test'
432
+ @user.reload
433
+ end
434
+ end
435
+
436
+ it { @user.name.should eql('dbussink') }
437
+
438
+ it 'should also reload previously loaded attributes' do
439
+ @user.attribute_loaded?(:description).should be_true
440
+ end
441
+ end
442
+
443
+ describe 'for when the object is changed outside another object' do
444
+
445
+ before :all do
446
+ rescue_if 'TODO', @skip do
447
+ @user2 = @user.dup
448
+ @user2.description = 'Changed'
449
+ @user2.save
450
+ @user.reload
451
+ end
452
+ end
453
+
454
+ it 'should reload the object from the data store' do
455
+ @user.description.should eql('Changed')
456
+ end
457
+
458
+ end
459
+
460
+ end
461
+
462
+ it { @user.should respond_to(:save) }
463
+
464
+ describe '#save' do
465
+
466
+ describe 'on a new, not dirty object' do
467
+
468
+ before :all do
469
+ @user = @user_model.new
470
+ @return = @user.save
471
+ end
472
+
473
+ it 'should return false' do
474
+ @return.should be_false
475
+ end
476
+
477
+ end
478
+
479
+ describe 'on a not new, not dirty object' do
480
+
481
+ it 'should return true even when resource is not dirty' do
482
+ @user.save.should be_true
483
+ end
484
+
485
+ end
486
+
487
+ describe 'on a not new, dirty object' do
488
+
489
+ before :all do
490
+ rescue_if 'TODO', @skip do
491
+ @user.age = 26
492
+ @return = @user.save
493
+ end
494
+ end
495
+
496
+ it 'should save a resource succesfully when dirty' do
497
+ @return.should be_true
498
+ end
499
+
500
+ it 'should actually store the changes to persistent storage' do
501
+ @user.attributes.should == @user.reload.attributes
502
+ end
503
+ end
504
+
505
+ describe 'on a dirty invalid object' do
506
+ before :all do
507
+ rescue_if 'TODO', @skip do
508
+ @user.name = nil
509
+ end
510
+ end
511
+
512
+ it 'should not save an invalid resource' do
513
+ @user.save.should be_false
514
+ end
515
+ end
516
+
517
+ describe 'with new resources in a has relationship' do
518
+ before do
519
+ rescue_if 'TODO: fix for one to one association', !@user.respond_to?(:comments) do
520
+ @initial_comments = @user.comments.size
521
+ @first_comment = @user.comments.new(:body => "DM is great!")
522
+ @second_comment = @comment_model.new(:user => @user, :body => "is it really?")
523
+ @return = @user.save
524
+ end
525
+ end
526
+
527
+ it 'should save resource' do
528
+ pending_if 'TODO', !@user.respond_to?(:comments) do
529
+ @return.should be_true
530
+ end
531
+ end
532
+
533
+ it 'should save the first resource created through new' do
534
+ pending_if 'TODO', !@user.respond_to?(:comments) do
535
+ @first_comment.new?.should be_false
536
+ end
537
+ end
538
+
539
+ it 'should save the correct foreign key for the first resource' do
540
+ pending_if 'TODO', !@user.respond_to?(:comments) do
541
+ @first_comment.user.should eql(@user)
542
+ end
543
+ end
544
+
545
+ it 'should save the second resource created through the constructor' do
546
+ pending "Changing a belongs_to parent should add the object to the correct association" do
547
+ @second_comment.new?.should be_false
548
+ end
549
+ end
550
+
551
+ it 'should save the correct foreign key for the second resource' do
552
+ pending_if 'TODO', !@user.respond_to?(:comments) do
553
+ @second_comment.user.should eql(@user)
554
+ end
555
+ end
556
+
557
+ it 'should create 2 extra resources in persistent storage' do
558
+ pending "Changing a belongs_to parent should add the object to the correct association" do
559
+ @user.comments.size.should == @initial_comments + 2
560
+ end
561
+ end
562
+
563
+ end
564
+
565
+ describe 'with dirty resources in a has relationship' do
566
+ before :all do
567
+ rescue_if 'TODO: fix for one to one association', !@user.respond_to?(:comments) do
568
+ @initial_comments = @user.comments.size
569
+ @first_comment = @user.comments.create(:body => "DM is great!")
570
+ @second_comment = @comment_model.create(:user => @user, :body => "is it really?")
571
+
572
+ @first_comment.body = "It still has rough edges"
573
+ @second_comment.body = "But these cool specs help fixing that"
574
+ @second_comment.user = @user_model.create(:name => 'dkubb')
575
+ @return = @user.save
576
+ end
577
+ end
578
+
579
+ it 'should save the dirty resources' do
580
+ pending_if 'TODO', !@user.respond_to?(:comments) do
581
+ @return.should be_true
582
+ end
583
+ end
584
+
585
+ it 'should have saved the first child resource' do
586
+ pending_if 'TODO', !@user.respond_to?(:comments) do
587
+ @first_comment.should_not be_dirty
588
+ end
589
+ end
590
+
591
+ it 'should not have saved the second child resource' do
592
+ pending_if 'TODO', !@user.respond_to?(:comments) do
593
+ @second_comment.should be_dirty
594
+ end
595
+ end
596
+
597
+ end
598
+
599
+ describe 'with a new dependency' do
600
+
601
+ before :all do
602
+ @first_comment = @comment_model.new(:body => "DM is great!")
603
+ @first_comment.user = @user_model.new(:name => 'dkubb')
604
+ end
605
+
606
+ it 'should not raise an exception when saving the resource' do
607
+ pending do
608
+ lambda { @first_comment.save.should be_false }.should_not raise_error
609
+ end
610
+ end
611
+
612
+ end
613
+
614
+ describe 'with a dirty dependency' do
615
+ before :all do
616
+ rescue_if 'TODO', @skip do
617
+ @user.name = 'dbussink-the-second'
618
+
619
+ @first_comment = @comment_model.new(:body => 'DM is great!')
620
+ @first_comment.user = @user
621
+
622
+ @return = @first_comment.save
623
+ end
624
+ end
625
+
626
+ it 'should succesfully save the object' do
627
+ @return.should be_true
628
+ end
629
+
630
+ it 'should not have a dirty dependency' do
631
+ @user.should_not be_dirty
632
+ end
633
+
634
+ it 'should succesfully save the dependency' do
635
+ @user.attributes.should == @user_model.get(*@user.key).attributes
636
+ end
637
+
638
+ end
639
+
640
+ describe 'with a new object and new relations' do
641
+ before :all do
642
+ @article = @article_model.new(:body => "Main")
643
+ rescue_if 'TODO: fix for one to one association', (!@article.respond_to?(:paragraphs)) do
644
+ @paragraph = @article.paragraphs.new(:text => 'Content')
645
+
646
+ @article.save
647
+ end
648
+ end
649
+
650
+ it 'should not be dirty' do
651
+ pending_if 'TODO', !@article.respond_to?(:paragraphs) do
652
+ @article.should_not be_dirty
653
+ end
654
+ end
655
+
656
+ it 'should not be dirty' do
657
+ pending_if 'TODO', !@article.respond_to?(:paragraphs) do
658
+ @paragraph.should_not be_dirty
659
+ end
660
+ end
661
+
662
+ it 'should set the related object' do
663
+ pending_if 'TODO', !@article.respond_to?(:paragraphs) do
664
+ @paragraph.article.should == @article
665
+ end
666
+ end
667
+
668
+ it 'should set the foreign key properly' do
669
+ pending_if 'TODO', !@article.respond_to?(:paragraphs) do
670
+ @paragraph.article_id.should == @article.id
671
+ end
672
+ end
673
+ end
674
+
675
+ describe 'with a dirty object with a changed key' do
676
+
677
+ before :all do
678
+ rescue_if 'TODO', @skip do
679
+ @original_key = @user.key
680
+ @user.name = 'dkubb'
681
+ @return = @user.save
682
+ end
683
+ end
684
+
685
+ it 'should save a resource succesfully when dirty' do
686
+ @return.should be_true
687
+ end
688
+
689
+ it 'should actually store the changes to persistent storage' do
690
+ @user.name.should == @user.reload.name
691
+ end
692
+
693
+ it 'should update the identity map' do
694
+ @user.repository.identity_map(@user_model).should have_key(%w[ dkubb ])
695
+ end
696
+
697
+ it 'should remove the old entry from the identity map' do
698
+ @user.repository.identity_map(@user_model).should_not have_key(@original_key)
699
+ end
700
+
701
+ end
702
+
703
+ describe 'on a new object with unsaved parent and grandparent' do
704
+ before :all do
705
+ @grandparent = @user_model.new(:name => 'dkubb', :comment => @comment)
706
+ @parent = @user_model.new(:name => 'ashleymoran', :comment => @comment, :referrer => @grandparent)
707
+ @child = @user_model.new(:name => 'mrship', :comment => @comment, :referrer => @parent)
708
+
709
+ @response = @child.save
710
+ end
711
+
712
+ it 'should return true' do
713
+ @response.should be_true
714
+ end
715
+
716
+ it 'should save the child' do
717
+ @child.should be_saved
718
+ end
719
+
720
+ it 'should save the parent' do
721
+ @parent.should be_saved
722
+ end
723
+
724
+ it 'should save the grandparent' do
725
+ @grandparent.should be_saved
726
+ end
727
+
728
+ it 'should relate the child to the parent' do
729
+ pending_if 'TODO', @one_to_one_through do
730
+ @child.model.get(*@child.key).referrer.should == @parent
731
+ end
732
+ end
733
+
734
+ it 'should relate the parent to the grandparent' do
735
+ pending_if 'TODO', @one_to_one_through do
736
+ @parent.model.get(*@parent.key).referrer.should == @grandparent
737
+ end
738
+ end
739
+
740
+ it 'should relate the grandparent to nothing' do
741
+ pending_if 'TODO', @one_to_one_through do
742
+ @grandparent.model.get(*@grandparent.key).referrer.should be_nil
743
+ end
744
+ end
745
+ end
746
+
747
+ end
748
+
749
+ it { @user.should respond_to(:saved?) }
750
+
751
+ describe '#saved?' do
752
+
753
+ describe 'on an existing record' do
754
+
755
+ it { @user.should be_saved }
756
+
757
+ end
758
+
759
+ describe 'on a new record' do
760
+
761
+ before { @user = @user_model.new }
762
+
763
+ it { @user.should_not be_saved }
764
+
765
+ end
766
+
767
+ end
768
+
769
+ [ :update, :update! ].each do |method|
770
+ it { @user.should respond_to(method) }
771
+
772
+ describe "##{method}" do
773
+ describe 'with no arguments' do
774
+ before :all do
775
+ rescue_if 'TODO', @skip do
776
+ @return = @user.send(method)
777
+ end
778
+ end
779
+
780
+ it 'should return true' do
781
+ @return.should be_true
782
+ end
783
+ end
784
+
785
+ describe 'with attributes' do
786
+ before :all do
787
+ rescue_if 'TODO', @skip do
788
+ @attributes = { :description => 'Changed' }
789
+ @return = @user.send(method, @attributes)
790
+ end
791
+ end
792
+
793
+ it 'should return true' do
794
+ @return.should be_true
795
+ end
796
+
797
+ it 'should update attributes of Resource' do
798
+ @attributes.each { |key, value| @user.send(key).should == value }
799
+ end
800
+
801
+ it 'should persist the changes' do
802
+ resource = @user_model.get(*@user.key)
803
+ @attributes.each { |key, value| resource.send(key).should == value }
804
+ end
805
+ end
806
+
807
+ describe 'with attributes where one is a parent association' do
808
+ before :all do
809
+ rescue_if 'Use table aliases to avoid ambiguous named in query', @one_to_one_through do
810
+ @attributes = { :referrer => @user_model.create(:name => 'dkubb', :age => 33, :comment => @comment) }
811
+ @return = @user.send(method, @attributes)
812
+ end
813
+ end
814
+
815
+ it 'should return true' do
816
+ pending_if 'TODO', @one_to_one_through do
817
+ @return.should be_true
818
+ end
819
+ end
820
+
821
+ it 'should update attributes of Resource' do
822
+ pending_if 'TODO', @one_to_one_through do
823
+ @attributes.each { |key, value| @user.send(key).should == value }
824
+ end
825
+ end
826
+
827
+ it 'should persist the changes' do
828
+ pending_if 'TODO', @one_to_one_through do
829
+ resource = @user_model.get(*@user.key)
830
+ @attributes.each { |key, value| resource.send(key).should == value }
831
+ end
832
+ end
833
+ end
834
+
835
+ describe 'with attributes where a value is nil for a property that does not allow nil' do
836
+ before :all do
837
+ rescue_if 'TODO', @skip do
838
+ @return = @user.send(method, :name => nil)
839
+ end
840
+ end
841
+
842
+ it 'should return false' do
843
+ @return.should be_false
844
+ end
845
+
846
+ it 'should not persist the changes' do
847
+ @user.reload.name.should_not be_nil
848
+ end
849
+ end
850
+
851
+ describe 'on a dirty resource' do
852
+ before :all do
853
+ rescue_if 'TODO', @skip do
854
+ @user.age = 99
855
+ end
856
+ end
857
+
858
+ it 'should raise an exception' do
859
+ lambda {
860
+ @user.send(method, :admin => true)
861
+ }.should raise_error(DataMapper::UpdateConflictError, "#{@user.model}##{method} cannot be called on a dirty resource")
862
+ end
863
+ end
864
+ end
865
+ end
866
+
867
+ describe 'invalid resources' do
868
+ before do
869
+ class ::EmptyObject
870
+ include DataMapper::Resource
871
+ end
872
+
873
+ class ::KeylessObject
874
+ include DataMapper::Resource
875
+ property :name, String
876
+ end
877
+ end
878
+
879
+ it 'should raise an error for a resource without attributes' do
880
+ lambda { EmptyObject.new }.should raise_error
881
+ end
882
+
883
+ it 'should raise an error for a resource without a key' do
884
+ lambda { KeylessObject.new }.should raise_error
885
+ end
886
+
887
+ after do
888
+ # clean out invalid models so that global model cleanup
889
+ # does not throw an exception when working with models
890
+ # in an invalid state
891
+ [ EmptyObject, KeylessObject ].each do |model|
892
+ Object.send(:remove_const, model.name.to_sym)
893
+ DataMapper::Model.descendants.delete(model)
894
+ end
895
+ end
896
+ end
897
+
898
+ describe 'lazy loading' do
899
+ before :all do
900
+ rescue_if 'TODO', @skip do
901
+ @user.name = 'dkubb'
902
+ @user.age = 33
903
+ @user.summary = 'Programmer'
904
+
905
+ # lazy load the description
906
+ @user.description
907
+ end
908
+ end
909
+
910
+ it 'should not overwrite dirty attribute' do
911
+ @user.age.should == 33
912
+ end
913
+
914
+ it 'should not overwrite dirty lazy attribute' do
915
+ @user.summary.should == 'Programmer'
916
+ end
917
+
918
+ it 'should not overwrite dirty key' do
919
+ pending do
920
+ @user.name.should == 'dkubb'
921
+ end
922
+ end
923
+ end
924
+ end