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
@@ -1,1073 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
-
3
- if ADAPTER
4
- class Zebra
5
- include DataMapper::Resource
6
-
7
- def self.default_repository_name
8
- ADAPTER
9
- end
10
-
11
- property :id, Serial
12
- property :name, String
13
- property :age, Integer
14
- property :notes, Text
15
-
16
- has n, :stripes
17
- end
18
-
19
- class Stripe
20
- include DataMapper::Resource
21
-
22
- def self.default_repository_name
23
- ADAPTER
24
- end
25
-
26
- property :id, Serial
27
- property :name, String
28
- property :age, Integer
29
- property :zebra_id, Integer
30
-
31
- belongs_to :zebra
32
-
33
- def self.sort_by_name
34
- all(:order => [ :name ])
35
- end
36
- end
37
-
38
- class CollectionSpecParty
39
- include DataMapper::Resource
40
-
41
- def self.default_repository_name
42
- ADAPTER
43
- end
44
-
45
- property :name, String, :key => true
46
- property :type, Discriminator
47
- end
48
-
49
- class CollectionSpecUser < CollectionSpecParty
50
- def self.default_repository_name
51
- ADAPTER
52
- end
53
-
54
- property :username, String
55
- property :password, String
56
- end
57
-
58
- module CollectionSpecHelper
59
- def setup
60
- Zebra.auto_migrate!(ADAPTER)
61
- Stripe.auto_migrate!(ADAPTER)
62
-
63
- repository(ADAPTER) do
64
- @nancy = Zebra.create(:name => 'Nancy', :age => 11, :notes => 'Spotted!')
65
- @bessie = Zebra.create(:name => 'Bessie', :age => 10, :notes => 'Striped!')
66
- @steve = Zebra.create(:name => 'Steve', :age => 8, :notes => 'Bald!')
67
-
68
- @babe = Stripe.create(:name => 'Babe')
69
- @snowball = Stripe.create(:name => 'snowball')
70
-
71
- @nancy.stripes << @babe
72
- @nancy.stripes << @snowball
73
- @nancy.save
74
- end
75
- end
76
- end
77
-
78
- describe DataMapper::Collection do
79
- include CollectionSpecHelper
80
-
81
- before do
82
- setup
83
- end
84
-
85
- before do
86
- @repository = repository(ADAPTER)
87
- @model = Zebra
88
- @query = DataMapper::Query.new(@repository, @model, :order => [ :id ])
89
- @collection = @repository.read_many(@query)
90
- @other = @repository.read_many(@query.merge(:limit => 2))
91
- end
92
-
93
- it "should return the correct repository" do
94
- repository = repository(:legacy)
95
- query = DataMapper::Query.new(repository, @model)
96
- DataMapper::Collection.new(query){}.repository.object_id.should == repository.object_id
97
- end
98
-
99
- it "should be able to add arbitrary objects" do
100
- properties = @model.properties(:default)
101
-
102
- collection = DataMapper::Collection.new(@query) do |c|
103
- c.load([ 4, 'Bob', 10 ])
104
- c.load([ 5, 'Nancy', 11 ])
105
- end
106
-
107
- collection.should respond_to(:reload)
108
-
109
- results = collection.entries
110
- results.should have(2).entries
111
-
112
- results.each do |cow|
113
- cow.attribute_loaded?(:name).should == true
114
- cow.attribute_loaded?(:age).should == true
115
- end
116
-
117
- bob, nancy = results[0], results[1]
118
-
119
- bob.name.should eql('Bob')
120
- bob.age.should eql(10)
121
- bob.should_not be_a_new_record
122
-
123
- nancy.name.should eql('Nancy')
124
- nancy.age.should eql(11)
125
- nancy.should_not be_a_new_record
126
-
127
- results.first.should == bob
128
- end
129
-
130
- it 'should be serializable with Marshal' do
131
- Marshal.load(Marshal.dump(Zebra.all)).should == Zebra.all
132
- end
133
-
134
- describe 'model proxying' do
135
- it 'should delegate to a model method' do
136
- stripes = @model.first.stripes
137
- stripes.should respond_to(:sort_by_name)
138
- stripes.sort_by_name.should == [ @babe, @snowball ]
139
- end
140
- end
141
-
142
- describe 'association proxying' do
143
- it "should provide a Query" do
144
- repository(ADAPTER) do
145
- zebras = Zebra.all(:order => [ :name ])
146
- zebras.query.order.should == [DataMapper::Query::Direction.new(Zebra.properties(ADAPTER)[:name])]
147
- end
148
- end
149
-
150
- it "should proxy the relationships of the model" do
151
- repository(ADAPTER) do
152
- zebras = Zebra.all
153
- zebras.should have(3).entries
154
- zebras.find { |zebra| zebra.name == 'Nancy' }.stripes.should have(2).entries
155
- zebras.should respond_to(:stripes)
156
- zebras.stripes.should == [@babe, @snowball]
157
- end
158
- end
159
-
160
- it "should preserve it's order on reload" do
161
- repository(ADAPTER) do |r|
162
- zebras = Zebra.all(:order => [ :name ])
163
-
164
- order = %w{ Bessie Nancy Steve }
165
-
166
- zebras.map { |z| z.name }.should == order
167
-
168
- # Force a lazy-load call:
169
- zebras.first.notes
170
-
171
- # The order should be unaffected.
172
- zebras.map { |z| z.name }.should == order
173
- end
174
- end
175
- end
176
-
177
- describe '.new' do
178
- describe 'with non-index keys' do
179
- it 'should instantiate read-only resources' do
180
- @collection = DataMapper::Collection.new(DataMapper::Query.new(@repository, @model, :fields => [ :age ])) do |c|
181
- c.load([ 1 ])
182
- end
183
-
184
- @collection.size.should == 1
185
-
186
- resource = @collection.entries[0]
187
-
188
- resource.should be_kind_of(@model)
189
- resource.collection.object_id.should == @collection.object_id
190
- resource.should_not be_new_record
191
- resource.should be_readonly
192
- resource.age.should == 1
193
- end
194
- end
195
-
196
- describe 'with inheritance property' do
197
- before do
198
- CollectionSpecUser.auto_migrate!
199
- CollectionSpecUser.create(:name => 'John')
200
-
201
- properties = CollectionSpecParty.properties(:default)
202
- end
203
-
204
- it 'should instantiate resources using the inheritance property class' do
205
- query = DataMapper::Query.new(@repository, CollectionSpecParty)
206
- collection = @repository.read_many(query)
207
- collection.should have(1).entries
208
- collection.first.model.should == CollectionSpecUser
209
- end
210
- end
211
- end
212
-
213
- [ true, false ].each do |loaded|
214
- describe " (#{loaded ? '' : 'not '}loaded) " do
215
- if loaded
216
- before do
217
- @collection.to_a
218
- end
219
- end
220
-
221
- describe '#<<' do
222
- it 'should relate each new resource to the collection' do
223
- # resource is orphaned
224
- @nancy.collection.object_id.should_not == @collection.object_id
225
-
226
- @collection << @nancy
227
-
228
- # resource is related
229
- @nancy.collection.object_id.should == @collection.object_id
230
- end
231
-
232
- it 'should return self' do
233
- @collection.<<(@steve).object_id.should == @collection.object_id
234
- end
235
- end
236
-
237
- describe '#all' do
238
- describe 'with no arguments' do
239
- it 'should return self' do
240
- @collection.all.object_id.should == @collection.object_id
241
- end
242
- end
243
-
244
- describe 'with query arguments' do
245
- describe 'should return a Collection' do
246
- before do
247
- @query.update(:offset => 10, :limit => 10)
248
- query = DataMapper::Query.new(@repository, @model)
249
- @unlimited = DataMapper::Collection.new(query) {}
250
- end
251
-
252
- it 'has an offset equal to 10' do
253
- @collection.all.query.offset.should == 10
254
- end
255
-
256
- it 'has a cumulative offset equal to 11 when passed an offset of 1' do
257
- @collection.all(:offset => 1).query.offset.should == 11
258
- end
259
-
260
- it 'has a cumulative offset equal to 19 when passed an offset of 9' do
261
- @collection.all(:offset => 9).query.offset.should == 19
262
- end
263
-
264
- it 'is empty when passed an offset that is out of range' do
265
- pending do
266
- empty_collection = @collection.all(:offset => 10)
267
- empty_collection.should == []
268
- empty_collection.should be_loaded
269
- end
270
- end
271
-
272
- it 'has an limit equal to 10' do
273
- @collection.all.query.limit.should == 10
274
- end
275
-
276
- it 'has a limit equal to 5' do
277
- @collection.all(:limit => 5).query.limit.should == 5
278
- end
279
-
280
- it 'has a limit equal to 10 if passed a limit greater than 10' do
281
- @collection.all(:limit => 11).query.limit.should == 10
282
- end
283
-
284
- it 'has no limit' do
285
- @unlimited.all.query.limit.should be_nil
286
- end
287
-
288
- it 'has a limit equal to 1000 when passed a limit of 1000' do
289
- @unlimited.all(:limit => 1000).query.limit.should == 1000
290
- end
291
- end
292
- end
293
- end
294
-
295
- describe '#at' do
296
- it 'should return a Resource' do
297
- resource_at = @collection.at(1)
298
- resource_at.should be_kind_of(DataMapper::Resource)
299
- resource_at.id.should == @bessie.id
300
- end
301
-
302
- it 'should return a Resource when using a negative index' do
303
- resource_at = @collection.at(-1)
304
- resource_at.should be_kind_of(DataMapper::Resource)
305
- resource_at.id.should == @steve.id
306
- end
307
- end
308
-
309
- describe '#build' do
310
- it 'should build a new resource' do
311
- resource = @collection.build(:name => 'John')
312
- resource.should be_kind_of(@model)
313
- resource.should be_new_record
314
- end
315
-
316
- it 'should append the new resource to the collection' do
317
- resource = @collection.build(:name => 'John')
318
- resource.should be_new_record
319
- resource.collection.object_id.should == @collection.object_id
320
- @collection.should include(resource)
321
- end
322
-
323
- it 'should use the query conditions to set default values' do
324
- resource = @collection.build
325
- resource.should be_new_record
326
- resource.name.should be_nil
327
-
328
- @collection.query.update(:name => 'John')
329
-
330
- resource = @collection.build
331
- resource.name.should == 'John'
332
- end
333
- end
334
-
335
- describe '#clear' do
336
- it 'should orphan the resource from the collection' do
337
- entries = @collection.entries
338
-
339
- # resources are related
340
- entries.each { |r| r.collection.object_id.should == @collection.object_id }
341
-
342
- @collection.should have(3).entries
343
- @collection.clear
344
- @collection.should be_empty
345
-
346
- # resources are orphaned
347
- entries.each { |r| r.collection.object_id.should_not == @collection.object_id }
348
- end
349
-
350
- it 'should return self' do
351
- @collection.clear.object_id.should == @collection.object_id
352
- end
353
- end
354
-
355
- describe '#collect!' do
356
- it 'should return self' do
357
- @collection.collect! { |resource| resource }.object_id.should == @collection.object_id
358
- end
359
- end
360
-
361
- describe '#concat' do
362
- it 'should return self' do
363
- @collection.concat(@other).object_id.should == @collection.object_id
364
- end
365
- end
366
-
367
- describe '#create' do
368
- it 'should create a new resource' do
369
- resource = @collection.create(:name => 'John')
370
- resource.should be_kind_of(@model)
371
- resource.should_not be_new_record
372
- end
373
-
374
- it 'should append the new resource to the collection' do
375
- resource = @collection.create(:name => 'John')
376
- resource.should_not be_new_record
377
- resource.collection.object_id.should == @collection.object_id
378
- @collection.should include(resource)
379
- end
380
-
381
- it 'should not append the resource if it was not saved' do
382
- @repository.should_receive(:create).and_return(false)
383
- Zebra.should_receive(:repository).at_least(:once).and_return(@repository)
384
-
385
- resource = @collection.create(:name => 'John')
386
- resource.should be_new_record
387
-
388
- resource.collection.object_id.should_not == @collection.object_id
389
- @collection.should_not include(resource)
390
- end
391
-
392
- it 'should use the query conditions to set default values' do
393
- resource = @collection.create
394
- resource.should_not be_new_record
395
- resource.name.should be_nil
396
-
397
- @collection.query.update(:name => 'John')
398
-
399
- resource = @collection.create
400
- resource.name.should == 'John'
401
- end
402
- end
403
-
404
- describe '#delete' do
405
- it 'should orphan the resource from the collection' do
406
- collection = @nancy.collection
407
-
408
- # resource is related
409
- @nancy.collection.object_id.should == collection.object_id
410
-
411
- collection.should have(1).entries
412
- collection.delete(@nancy)
413
- collection.should be_empty
414
-
415
- # resource is orphaned
416
- @nancy.collection.object_id.should_not == collection.object_id
417
- end
418
-
419
- it 'should return a Resource' do
420
- collection = @nancy.collection
421
-
422
- resource = collection.delete(@nancy)
423
-
424
- resource.should be_kind_of(DataMapper::Resource)
425
- resource.object_id.should == @nancy.object_id
426
- end
427
- end
428
-
429
- describe '#delete_at' do
430
- it 'should orphan the resource from the collection' do
431
- collection = @nancy.collection
432
-
433
- # resource is related
434
- @nancy.collection.object_id.should == collection.object_id
435
-
436
- collection.should have(1).entries
437
- collection.delete_at(0).object_id.should == @nancy.object_id
438
- collection.should be_empty
439
-
440
- # resource is orphaned
441
- @nancy.collection.object_id.should_not == collection.object_id
442
- end
443
-
444
- it 'should return a Resource' do
445
- collection = @nancy.collection
446
-
447
- resource = collection.delete_at(0)
448
-
449
- resource.should be_kind_of(DataMapper::Resource)
450
- resource.object_id.should == @nancy.object_id
451
- end
452
- end
453
-
454
- describe '#destroy!' do
455
- before do
456
- @ids = [ @nancy.id, @bessie.id, @steve.id ]
457
- end
458
-
459
- it 'should destroy the resources in the collection' do
460
- @collection.map { |r| r.id }.should == @ids
461
- @collection.destroy!.should == true
462
- @model.all(:id => @ids).should == []
463
- @collection.reload.should == []
464
- end
465
-
466
- it 'should clear the collection' do
467
- @collection.map { |r| r.id }.should == @ids
468
- @collection.destroy!.should == true
469
- @collection.should == []
470
- end
471
- end
472
-
473
- describe '#each' do
474
- it 'should return self' do
475
- @collection.each { |resource| }.object_id.should == @collection.object_id
476
- end
477
- end
478
-
479
- describe '#each_index' do
480
- it 'should return self' do
481
- @collection.each_index { |resource| }.object_id.should == @collection.object_id
482
- end
483
- end
484
-
485
- describe '#eql?' do
486
- it 'should return true if for the same collection' do
487
- @collection.object_id.should == @collection.object_id
488
- @collection.should be_eql(@collection)
489
- end
490
-
491
- it 'should return true for duplicate collections' do
492
- dup = @collection.dup
493
- dup.should be_kind_of(DataMapper::Collection)
494
- dup.object_id.should_not == @collection.object_id
495
- dup.entries.should == @collection.entries
496
- dup.should be_eql(@collection)
497
- end
498
-
499
- it 'should return false for different collections' do
500
- @collection.should_not be_eql(@other)
501
- end
502
- end
503
-
504
- describe '#fetch' do
505
- it 'should return a Resource' do
506
- @collection.fetch(0).should be_kind_of(DataMapper::Resource)
507
- end
508
- end
509
-
510
- describe '#first' do
511
- describe 'with no arguments' do
512
- it 'should return a Resource' do
513
- first = @collection.first
514
- first.should_not be_nil
515
- first.should be_kind_of(DataMapper::Resource)
516
- first.id.should == @nancy.id
517
- end
518
- end
519
-
520
- describe 'with limit specified' do
521
- it 'should return a Collection' do
522
- collection = @collection.first(2)
523
-
524
- collection.should be_kind_of(DataMapper::Collection)
525
- collection.object_id.should_not == @collection.object_id
526
-
527
- collection.query.order.size.should == 1
528
- collection.query.order.first.property.should == @model.properties[:id]
529
- collection.query.order.first.direction.should == :asc
530
-
531
- collection.query.offset.should == 0
532
- collection.query.limit.should == 2
533
-
534
- collection.length.should == 2
535
-
536
- collection.entries.map { |r| r.id }.should == [ @nancy.id, @bessie.id ]
537
- end
538
-
539
- it 'should return a Collection if limit is 1' do
540
- collection = @collection.first(1)
541
-
542
- collection.should be_kind_of(DataMapper::Collection)
543
- collection.object_id.should_not == @collection.object_id
544
- end
545
- end
546
- end
547
-
548
- describe '#freeze' do
549
- it 'should freeze the underlying array' do
550
- @collection.should_not be_frozen
551
- @collection.freeze
552
- @collection.should be_frozen
553
- end
554
- end
555
-
556
- describe '#get' do
557
- it 'should find a resource in a collection by key' do
558
- resource = @collection.get(*@nancy.key)
559
- resource.should be_kind_of(DataMapper::Resource)
560
- resource.id.should == @nancy.id
561
- end
562
-
563
- it "should find a resource in a collection by typecasting the key" do
564
- resource = @collection.get(*@nancy.key)
565
- resource.should be_kind_of(DataMapper::Resource)
566
- resource.id.should == @nancy.id
567
- end
568
-
569
- it 'should not find a resource not in the collection' do
570
- @query.update(:offset => 0, :limit => 3)
571
- @david = Zebra.create(:name => 'David', :age => 15, :notes => 'Albino')
572
- @collection.get(*@david.key).should be_nil
573
- end
574
- end
575
-
576
- describe '#get!' do
577
- it 'should find a resource in a collection by key' do
578
- resource = @collection.get!(*@nancy.key)
579
- resource.should be_kind_of(DataMapper::Resource)
580
- resource.id.should == @nancy.id
581
- end
582
-
583
- it 'should raise an exception if the resource is not found' do
584
- @query.update(:offset => 0, :limit => 3)
585
- @david = Zebra.create(:name => 'David', :age => 15, :notes => 'Albino')
586
- lambda {
587
- @collection.get!(@david.key)
588
- }.should raise_error(DataMapper::ObjectNotFoundError)
589
- end
590
- end
591
-
592
- describe '#insert' do
593
- it 'should return self' do
594
- @collection.insert(1, @steve).object_id.should == @collection.object_id
595
- end
596
- end
597
-
598
- describe '#last' do
599
- describe 'with no arguments' do
600
- it 'should return a Resource' do
601
- last = @collection.last
602
- last.should_not be_nil
603
- last.should be_kind_of(DataMapper::Resource)
604
- last.id.should == @steve.id
605
- end
606
- end
607
-
608
- describe 'with limit specified' do
609
- it 'should return a Collection' do
610
- collection = @collection.last(2)
611
-
612
- collection.should be_kind_of(DataMapper::Collection)
613
- collection.object_id.should_not == @collection.object_id
614
-
615
- collection.query.order.size.should == 1
616
- collection.query.order.first.property.should == @model.properties[:id]
617
- collection.query.order.first.direction.should == :desc
618
-
619
- collection.query.offset.should == 0
620
- collection.query.limit.should == 2
621
-
622
- collection.length.should == 2
623
-
624
- collection.entries.map { |r| r.id }.should == [ @bessie.id, @steve.id ]
625
- end
626
-
627
- it 'should return a Collection if limit is 1' do
628
- collection = @collection.last(1)
629
-
630
- collection.class.should == DataMapper::Collection # should be_kind_of(DataMapper::Collection)
631
- collection.object_id.should_not == @collection.object_id
632
- end
633
- end
634
- end
635
-
636
- describe '#load' do
637
- it 'should load resources from the identity map when possible' do
638
- @steve.collection = nil
639
- @repository.identity_map(@model).should_receive(:get).with([ @steve.id ]).and_return(@steve)
640
-
641
- collection = @repository.read_many(@query.merge(:id => @steve.id))
642
-
643
- collection.size.should == 1
644
- collection.map { |r| r.object_id }.should == [ @steve.object_id ]
645
-
646
- @steve.collection.object_id.should == collection.object_id
647
- end
648
-
649
- it 'should return a Resource' do
650
- @collection.load([ @steve.id, @steve.name, @steve.age ]).should be_kind_of(DataMapper::Resource)
651
- end
652
- end
653
-
654
- describe '#loaded?' do
655
- if loaded
656
- it 'should return true for an initialized collection' do
657
- @collection.should be_loaded
658
- end
659
- else
660
- it 'should return false for an uninitialized collection' do
661
- @collection.should_not be_loaded
662
- @collection.to_a # load collection
663
- @collection.should be_loaded
664
- end
665
- end
666
- end
667
-
668
- describe '#pop' do
669
- it 'should orphan the resource from the collection' do
670
- collection = @steve.collection
671
-
672
- # resource is related
673
- @steve.collection.object_id.should == collection.object_id
674
-
675
- collection.should have(1).entries
676
- collection.pop.object_id.should == @steve.object_id
677
- collection.should be_empty
678
-
679
- # resource is orphaned
680
- @steve.collection.object_id.should_not == collection.object_id
681
- end
682
-
683
- it 'should return a Resource' do
684
- @collection.pop.key.should == @steve.key
685
- end
686
- end
687
-
688
- describe '#properties' do
689
- it 'should return a PropertySet' do
690
- @collection.properties.should be_kind_of(DataMapper::PropertySet)
691
- end
692
-
693
- it 'should contain same properties as query.fields' do
694
- properties = @collection.properties
695
- properties.entries.should == @collection.query.fields
696
- end
697
- end
698
-
699
- describe '#push' do
700
- it 'should relate each new resource to the collection' do
701
- # resource is orphaned
702
- @nancy.collection.object_id.should_not == @collection.object_id
703
-
704
- @collection.push(@nancy)
705
-
706
- # resource is related
707
- @nancy.collection.object_id.should == @collection.object_id
708
- end
709
-
710
- it 'should return self' do
711
- @collection.push(@steve).object_id.should == @collection.object_id
712
- end
713
- end
714
-
715
- describe '#relationships' do
716
- it 'should return a Hash' do
717
- @collection.relationships.should be_kind_of(Hash)
718
- end
719
-
720
- it 'should contain same properties as query.model.relationships' do
721
- relationships = @collection.relationships
722
- relationships.should == @collection.query.model.relationships
723
- end
724
- end
725
-
726
- describe '#reject' do
727
- it 'should return a Collection with resources that did not match the block' do
728
- rejected = @collection.reject { |resource| false }
729
- rejected.class.should == Array
730
- rejected.should == [ @nancy, @bessie, @steve ]
731
- end
732
-
733
- it 'should return an empty Array if resources matched the block' do
734
- rejected = @collection.reject { |resource| true }
735
- rejected.class.should == Array
736
- rejected.should == []
737
- end
738
- end
739
-
740
- describe '#reject!' do
741
- it 'should return self if resources matched the block' do
742
- @collection.reject! { |resource| true }.object_id.should == @collection.object_id
743
- end
744
-
745
- it 'should return nil if no resources matched the block' do
746
- @collection.reject! { |resource| false }.should be_nil
747
- end
748
- end
749
-
750
- describe '#reload' do
751
- it 'should return self' do
752
- @collection.reload.object_id.should == @collection.object_id
753
- end
754
-
755
- it 'should replace the collection' do
756
- original = @collection.dup
757
- @collection.reload.should == @collection
758
- @collection.should == original
759
- end
760
-
761
- it 'should reload lazily initialized fields' do
762
- pending 'Move to unit specs'
763
-
764
- @repository.should_receive(:all) do |model,query|
765
- model.should == @model
766
-
767
- query.should be_instance_of(DataMapper::Query)
768
- query.reload.should == true
769
- query.offset.should == 0
770
- query.limit.should == 10
771
- query.order.should == []
772
- query.fields.should == @model.properties.defaults
773
- query.links.should == []
774
- query.includes.should == []
775
- query.conditions.should == [ [ :eql, @model.properties[:id], [ 1, 2, 3 ] ] ]
776
-
777
- @collection
778
- end
779
-
780
- @collection.reload
781
- end
782
- end
783
-
784
- describe '#replace' do
785
- it "should orphan each existing resource from the collection if loaded?" do
786
- entries = @collection.entries
787
-
788
- # resources are related
789
- entries.each { |r| r.collection.object_id.should == @collection.object_id }
790
-
791
- @collection.should have(3).entries
792
- @collection.replace([]).object_id.should == @collection.object_id
793
- @collection.should be_empty
794
-
795
- # resources are orphaned
796
- entries.each { |r| r.collection.object_id.should_not == @collection.object_id }
797
- end
798
-
799
- it 'should relate each new resource to the collection' do
800
- # resource is orphaned
801
- @nancy.collection.object_id.should_not == @collection.object_id
802
-
803
- @collection.replace([ @nancy ])
804
-
805
- # resource is related
806
- @nancy.collection.object_id.should == @collection.object_id
807
- end
808
-
809
- it 'should replace the contents of the collection' do
810
- other = [ @nancy ]
811
- @collection.should_not == other
812
- @collection.replace(other)
813
- @collection.should == other
814
- @collection.object_id.should_not == @other.object_id
815
- end
816
- end
817
-
818
- describe '#reverse' do
819
- [ true, false ].each do |loaded|
820
- describe "on a collection where loaded? == #{loaded}" do
821
- before do
822
- @collection.to_a if loaded
823
- end
824
-
825
- it 'should return a Collection with reversed entries' do
826
- reversed = @collection.reverse
827
- reversed.should be_kind_of(DataMapper::Collection)
828
- reversed.object_id.should_not == @collection.object_id
829
- reversed.entries.should == @collection.entries.reverse
830
-
831
- reversed.query.order.size.should == 1
832
- reversed.query.order.first.property.should == @model.properties[:id]
833
- reversed.query.order.first.direction.should == :desc
834
- end
835
- end
836
- end
837
- end
838
-
839
- describe '#reverse!' do
840
- it 'should return self' do
841
- @collection.reverse!.object_id.should == @collection.object_id
842
- end
843
- end
844
-
845
- describe '#reverse_each' do
846
- it 'should return self' do
847
- @collection.reverse_each { |resource| }.object_id.should == @collection.object_id
848
- end
849
- end
850
-
851
- describe '#select' do
852
- it 'should return an Array with resources that matched the block' do
853
- selected = @collection.select { |resource| true }
854
- selected.class.should == Array
855
- selected.should == @collection
856
- end
857
-
858
- it 'should return an empty Array if no resources matched the block' do
859
- selected = @collection.select { |resource| false }
860
- selected.class.should == Array
861
- selected.should == []
862
- end
863
- end
864
-
865
- describe '#shift' do
866
- it 'should orphan the resource from the collection' do
867
- collection = @nancy.collection
868
-
869
- # resource is related
870
- @nancy.collection.object_id.should == collection.object_id
871
-
872
- collection.should have(1).entries
873
- collection.shift.object_id.should == @nancy.object_id
874
- collection.should be_empty
875
-
876
- # resource is orphaned
877
- @nancy.collection.object_id.should_not == collection.object_id
878
- end
879
-
880
- it 'should return a Resource' do
881
- @collection.shift.key.should == @nancy.key
882
- end
883
- end
884
-
885
- [ :slice, :[] ].each do |method|
886
- describe '#slice' do
887
- describe 'with an index' do
888
- it 'should return a Resource' do
889
- resource = @collection.send(method, 0)
890
- resource.should be_kind_of(DataMapper::Resource)
891
- resource.id.should == @nancy.id
892
- end
893
- end
894
-
895
- describe 'with a start and length' do
896
- it 'should return a Collection' do
897
- sliced = @collection.send(method, 0, 1)
898
- sliced.should be_kind_of(DataMapper::Collection)
899
- sliced.object_id.should_not == @collection.object_id
900
- sliced.length.should == 1
901
- sliced.map { |r| r.id }.should == [ @nancy.id ]
902
- end
903
- end
904
-
905
- describe 'with a Range' do
906
- it 'should return a Collection' do
907
- sliced = @collection.send(method, 0..1)
908
- sliced.should be_kind_of(DataMapper::Collection)
909
- sliced.object_id.should_not == @collection.object_id
910
- sliced.length.should == 2
911
- sliced.map { |r| r.id }.should == [ @nancy.id, @bessie.id ]
912
- end
913
- end
914
- end
915
- end
916
-
917
- describe '#slice!' do
918
- describe 'with an index' do
919
- it 'should return a Resource' do
920
- resource = @collection.slice!(0)
921
- resource.should be_kind_of(DataMapper::Resource)
922
- end
923
- end
924
-
925
- describe 'with a start and length' do
926
- it 'should return an Array' do
927
- sliced = @collection.slice!(0, 1)
928
- sliced.class.should == Array
929
- sliced.map { |r| r.id }.should == [ @nancy.id ]
930
- end
931
- end
932
-
933
- describe 'with a Range' do
934
- it 'should return a Collection' do
935
- sliced = @collection.slice(0..1)
936
- sliced.should be_kind_of(DataMapper::Collection)
937
- sliced.object_id.should_not == @collection.object_id
938
- sliced.length.should == 2
939
- sliced[0].id.should == @nancy.id
940
- sliced[1].id.should == @bessie.id
941
- end
942
- end
943
- end
944
-
945
- describe '#sort' do
946
- it 'should return an Array' do
947
- sorted = @collection.sort { |a,b| a.age <=> b.age }
948
- sorted.class.should == Array
949
- end
950
- end
951
-
952
- describe '#sort!' do
953
- it 'should return self' do
954
- @collection.sort! { |a,b| 0 }.object_id.should == @collection.object_id
955
- end
956
- end
957
-
958
- describe '#unshift' do
959
- it 'should relate each new resource to the collection' do
960
- # resource is orphaned
961
- @nancy.collection.object_id.should_not == @collection.object_id
962
-
963
- @collection.unshift(@nancy)
964
-
965
- # resource is related
966
- @nancy.collection.object_id.should == @collection.object_id
967
- end
968
-
969
- it 'should return self' do
970
- @collection.unshift(@steve).object_id.should == @collection.object_id
971
- end
972
- end
973
-
974
- describe '#update!' do
975
- it 'should update the resources in the collection' do
976
- pending do
977
- # this will not pass with new update!
978
- # update! should never loop through and set attributes
979
- # even if it is loaded, and it will not reload the
980
- # changed objects (even with reload=true, as objects
981
- # are created is not in any identity map)
982
- names = [ @nancy.name, @bessie.name, @steve.name ]
983
- @collection.map { |r| r.name }.should == names
984
- @collection.update!(:name => 'John')
985
- @collection.map { |r| r.name }.should_not == names
986
- @collection.map { |r| r.name }.should == %w[ John ] * 3
987
- end
988
- end
989
-
990
- it 'should not update loaded resources unless forced' do
991
- repository(ADAPTER) do
992
- nancy = Zebra.first
993
- nancy.name.should == "Nancy"
994
-
995
- collection = Zebra.all(:name => ["Nancy","Bessie"])
996
- collection.update!(:name => "Stevie")
997
-
998
- nancy.name.should == "Nancy"
999
- end
1000
- end
1001
-
1002
- it 'should update loaded resources if forced' do
1003
- repository(ADAPTER) do
1004
- nancy = Zebra.first
1005
- nancy.name.should == "Nancy"
1006
-
1007
- collection = Zebra.all(:name => ["Nancy","Bessie"])
1008
- collection.update!({:name => "Stevie"},true)
1009
-
1010
- nancy.name.should == "Stevie"
1011
- end
1012
- end
1013
-
1014
- it 'should update collection-query when updating' do
1015
- repository(ADAPTER) do
1016
- collection = Zebra.all(:name => ["Nancy","Bessie"])
1017
- collection.query.conditions.first[2].should == ["Nancy","Bessie"]
1018
- collection.length.should == 2
1019
- collection.update!(:name => "Stevie")
1020
- collection.length.should == 2
1021
- collection.query.conditions.first[2].should == "Stevie"
1022
- end
1023
- end
1024
- end
1025
-
1026
- describe '#keys' do
1027
- it 'should return a hash of keys' do
1028
- keys = @collection.send(:keys)
1029
- keys.length.should == 1
1030
- keys.each{|property,values| values.should == [1,2,3]}
1031
- end
1032
-
1033
- it 'should return an empty hash if collection is empty' do
1034
- keys = Zebra.all(:id.gt => 10000).send(:keys)
1035
- keys.should == {}
1036
- end
1037
- end
1038
-
1039
- describe '#values_at' do
1040
- it 'should return an Array' do
1041
- values = @collection.values_at(0)
1042
- values.class.should == Array
1043
- end
1044
-
1045
- it 'should return an Array of the resources at the index' do
1046
- @collection.values_at(0).entries.map { |r| r.id }.should == [ @nancy.id ]
1047
- end
1048
- end
1049
-
1050
- describe 'with lazy loading' do
1051
- it "should take a materialization block" do
1052
- collection = DataMapper::Collection.new(@query) do |c|
1053
- c.should == []
1054
- c.load([ 1, 'Bob', 10 ])
1055
- c.load([ 2, 'Nancy', 11 ])
1056
- end
1057
-
1058
- collection.should_not be_loaded
1059
- collection.length.should == 2
1060
- collection.should be_loaded
1061
- end
1062
-
1063
- it "should load lazy columns when using offset" do
1064
- repository(ADAPTER) do
1065
- zebras = Zebra.all(:offset => 1, :limit => 2)
1066
- zebras.first.notes.should_not be_nil
1067
- end
1068
- end
1069
- end
1070
- end
1071
- end
1072
- end
1073
- end