sam-dm-core 0.9.6
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.
- data/.autotest +26 -0
- data/CONTRIBUTING +51 -0
- data/FAQ +92 -0
- data/History.txt +145 -0
- data/MIT-LICENSE +22 -0
- data/Manifest.txt +125 -0
- data/QUICKLINKS +12 -0
- data/README.txt +143 -0
- data/Rakefile +30 -0
- data/SPECS +63 -0
- data/TODO +1 -0
- data/lib/dm-core.rb +224 -0
- data/lib/dm-core/adapters.rb +4 -0
- data/lib/dm-core/adapters/abstract_adapter.rb +202 -0
- data/lib/dm-core/adapters/data_objects_adapter.rb +707 -0
- data/lib/dm-core/adapters/mysql_adapter.rb +136 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +188 -0
- data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
- data/lib/dm-core/associations.rb +199 -0
- data/lib/dm-core/associations/many_to_many.rb +147 -0
- data/lib/dm-core/associations/many_to_one.rb +107 -0
- data/lib/dm-core/associations/one_to_many.rb +309 -0
- data/lib/dm-core/associations/one_to_one.rb +61 -0
- data/lib/dm-core/associations/relationship.rb +218 -0
- data/lib/dm-core/associations/relationship_chain.rb +81 -0
- data/lib/dm-core/auto_migrations.rb +113 -0
- data/lib/dm-core/collection.rb +638 -0
- data/lib/dm-core/dependency_queue.rb +31 -0
- data/lib/dm-core/hook.rb +11 -0
- data/lib/dm-core/identity_map.rb +45 -0
- data/lib/dm-core/is.rb +16 -0
- data/lib/dm-core/logger.rb +232 -0
- data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
- data/lib/dm-core/migrator.rb +29 -0
- data/lib/dm-core/model.rb +471 -0
- data/lib/dm-core/naming_conventions.rb +84 -0
- data/lib/dm-core/property.rb +673 -0
- data/lib/dm-core/property_set.rb +162 -0
- data/lib/dm-core/query.rb +625 -0
- data/lib/dm-core/repository.rb +159 -0
- data/lib/dm-core/resource.rb +637 -0
- data/lib/dm-core/scope.rb +58 -0
- data/lib/dm-core/support.rb +7 -0
- data/lib/dm-core/support/array.rb +13 -0
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/errors.rb +23 -0
- data/lib/dm-core/support/kernel.rb +7 -0
- data/lib/dm-core/support/symbol.rb +41 -0
- data/lib/dm-core/transaction.rb +267 -0
- data/lib/dm-core/type.rb +160 -0
- data/lib/dm-core/type_map.rb +80 -0
- data/lib/dm-core/types.rb +19 -0
- data/lib/dm-core/types/boolean.rb +7 -0
- data/lib/dm-core/types/discriminator.rb +34 -0
- data/lib/dm-core/types/object.rb +24 -0
- data/lib/dm-core/types/paranoid_boolean.rb +34 -0
- data/lib/dm-core/types/paranoid_datetime.rb +33 -0
- data/lib/dm-core/types/serial.rb +9 -0
- data/lib/dm-core/types/text.rb +10 -0
- data/lib/dm-core/version.rb +3 -0
- data/script/all +5 -0
- data/script/performance.rb +203 -0
- data/script/profile.rb +87 -0
- data/spec/integration/association_spec.rb +1371 -0
- data/spec/integration/association_through_spec.rb +203 -0
- data/spec/integration/associations/many_to_many_spec.rb +449 -0
- data/spec/integration/associations/many_to_one_spec.rb +163 -0
- data/spec/integration/associations/one_to_many_spec.rb +151 -0
- data/spec/integration/auto_migrations_spec.rb +398 -0
- data/spec/integration/collection_spec.rb +1069 -0
- data/spec/integration/data_objects_adapter_spec.rb +32 -0
- data/spec/integration/dependency_queue_spec.rb +58 -0
- data/spec/integration/model_spec.rb +127 -0
- data/spec/integration/mysql_adapter_spec.rb +85 -0
- data/spec/integration/postgres_adapter_spec.rb +731 -0
- data/spec/integration/property_spec.rb +233 -0
- data/spec/integration/query_spec.rb +506 -0
- data/spec/integration/repository_spec.rb +57 -0
- data/spec/integration/resource_spec.rb +475 -0
- data/spec/integration/sqlite3_adapter_spec.rb +352 -0
- data/spec/integration/sti_spec.rb +208 -0
- data/spec/integration/strategic_eager_loading_spec.rb +138 -0
- data/spec/integration/transaction_spec.rb +75 -0
- data/spec/integration/type_spec.rb +271 -0
- data/spec/lib/logging_helper.rb +18 -0
- data/spec/lib/mock_adapter.rb +27 -0
- data/spec/lib/model_loader.rb +91 -0
- data/spec/lib/publicize_methods.rb +28 -0
- data/spec/models/vehicles.rb +34 -0
- data/spec/models/zoo.rb +47 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +86 -0
- data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
- data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
- data/spec/unit/adapters/data_objects_adapter_spec.rb +628 -0
- data/spec/unit/adapters/postgres_adapter_spec.rb +133 -0
- data/spec/unit/associations/many_to_many_spec.rb +17 -0
- data/spec/unit/associations/many_to_one_spec.rb +152 -0
- data/spec/unit/associations/one_to_many_spec.rb +393 -0
- data/spec/unit/associations/one_to_one_spec.rb +7 -0
- data/spec/unit/associations/relationship_spec.rb +71 -0
- data/spec/unit/associations_spec.rb +242 -0
- data/spec/unit/auto_migrations_spec.rb +111 -0
- data/spec/unit/collection_spec.rb +182 -0
- data/spec/unit/data_mapper_spec.rb +35 -0
- data/spec/unit/identity_map_spec.rb +126 -0
- data/spec/unit/is_spec.rb +80 -0
- data/spec/unit/migrator_spec.rb +33 -0
- data/spec/unit/model_spec.rb +339 -0
- data/spec/unit/naming_conventions_spec.rb +36 -0
- data/spec/unit/property_set_spec.rb +83 -0
- data/spec/unit/property_spec.rb +753 -0
- data/spec/unit/query_spec.rb +530 -0
- data/spec/unit/repository_spec.rb +93 -0
- data/spec/unit/resource_spec.rb +626 -0
- data/spec/unit/scope_spec.rb +142 -0
- data/spec/unit/transaction_spec.rb +493 -0
- data/spec/unit/type_map_spec.rb +114 -0
- data/spec/unit/type_spec.rb +119 -0
- data/tasks/ci.rb +68 -0
- data/tasks/dm.rb +63 -0
- data/tasks/doc.rb +20 -0
- data/tasks/gemspec.rb +23 -0
- data/tasks/hoe.rb +46 -0
- data/tasks/install.rb +20 -0
- metadata +216 -0
@@ -0,0 +1,1069 @@
|
|
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
|
+
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
|
+
|
173
|
+
describe '.new' do
|
174
|
+
describe 'with non-index keys' do
|
175
|
+
it 'should instantiate read-only resources' do
|
176
|
+
@collection = DataMapper::Collection.new(DataMapper::Query.new(@repository, @model, :fields => [ :age ])) do |c|
|
177
|
+
c.load([ 1 ])
|
178
|
+
end
|
179
|
+
|
180
|
+
@collection.size.should == 1
|
181
|
+
|
182
|
+
resource = @collection.entries[0]
|
183
|
+
|
184
|
+
resource.should be_kind_of(@model)
|
185
|
+
resource.collection.object_id.should == @collection.object_id
|
186
|
+
resource.should_not be_new_record
|
187
|
+
resource.should be_readonly
|
188
|
+
resource.age.should == 1
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe 'with inheritance property' do
|
193
|
+
before do
|
194
|
+
CollectionSpecUser.auto_migrate!
|
195
|
+
CollectionSpecUser.create(:name => 'John')
|
196
|
+
|
197
|
+
properties = CollectionSpecParty.properties(:default)
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'should instantiate resources using the inheritance property class' do
|
201
|
+
query = DataMapper::Query.new(@repository, CollectionSpecParty)
|
202
|
+
collection = @repository.read_many(query)
|
203
|
+
collection.should have(1).entries
|
204
|
+
collection.first.model.should == CollectionSpecUser
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
[ true, false ].each do |loaded|
|
210
|
+
describe " (#{loaded ? '' : 'not '}loaded) " do
|
211
|
+
if loaded
|
212
|
+
before do
|
213
|
+
@collection.to_a
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe '#<<' do
|
218
|
+
it 'should relate each new resource to the collection' do
|
219
|
+
# resource is orphaned
|
220
|
+
@nancy.collection.object_id.should_not == @collection.object_id
|
221
|
+
|
222
|
+
@collection << @nancy
|
223
|
+
|
224
|
+
# resource is related
|
225
|
+
@nancy.collection.object_id.should == @collection.object_id
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'should return self' do
|
229
|
+
@collection.<<(@steve).object_id.should == @collection.object_id
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe '#all' do
|
234
|
+
describe 'with no arguments' do
|
235
|
+
it 'should return self' do
|
236
|
+
@collection.all.object_id.should == @collection.object_id
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe 'with query arguments' do
|
241
|
+
describe 'should return a Collection' do
|
242
|
+
before do
|
243
|
+
@query.update(:offset => 10, :limit => 10)
|
244
|
+
query = DataMapper::Query.new(@repository, @model)
|
245
|
+
@unlimited = DataMapper::Collection.new(query) {}
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'has an offset equal to 10' do
|
249
|
+
@collection.all.query.offset.should == 10
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'has a cumulative offset equal to 11 when passed an offset of 1' do
|
253
|
+
@collection.all(:offset => 1).query.offset.should == 11
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'has a cumulative offset equal to 19 when passed an offset of 9' do
|
257
|
+
@collection.all(:offset => 9).query.offset.should == 19
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'is empty when passed an offset that is out of range' do
|
261
|
+
pending do
|
262
|
+
empty_collection = @collection.all(:offset => 10)
|
263
|
+
empty_collection.should == []
|
264
|
+
empty_collection.should be_loaded
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'has an limit equal to 10' do
|
269
|
+
@collection.all.query.limit.should == 10
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'has a limit equal to 5' do
|
273
|
+
@collection.all(:limit => 5).query.limit.should == 5
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'has a limit equal to 10 if passed a limit greater than 10' do
|
277
|
+
@collection.all(:limit => 11).query.limit.should == 10
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'has no limit' do
|
281
|
+
@unlimited.all.query.limit.should be_nil
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'has a limit equal to 1000 when passed a limit of 1000' do
|
285
|
+
@unlimited.all(:limit => 1000).query.limit.should == 1000
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
describe '#at' do
|
292
|
+
it 'should return a Resource' do
|
293
|
+
resource_at = @collection.at(1)
|
294
|
+
resource_at.should be_kind_of(DataMapper::Resource)
|
295
|
+
resource_at.id.should == @bessie.id
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'should return a Resource when using a negative index' do
|
299
|
+
resource_at = @collection.at(-1)
|
300
|
+
resource_at.should be_kind_of(DataMapper::Resource)
|
301
|
+
resource_at.id.should == @steve.id
|
302
|
+
end
|
303
|
+
end
|
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
|
+
|
331
|
+
describe '#clear' do
|
332
|
+
it 'should orphan the resource from the collection' do
|
333
|
+
entries = @collection.entries
|
334
|
+
|
335
|
+
# resources are related
|
336
|
+
entries.each { |r| r.collection.object_id.should == @collection.object_id }
|
337
|
+
|
338
|
+
@collection.should have(3).entries
|
339
|
+
@collection.clear
|
340
|
+
@collection.should be_empty
|
341
|
+
|
342
|
+
# resources are orphaned
|
343
|
+
entries.each { |r| r.collection.object_id.should_not == @collection.object_id }
|
344
|
+
end
|
345
|
+
|
346
|
+
it 'should return self' do
|
347
|
+
@collection.clear.object_id.should == @collection.object_id
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
describe '#collect!' do
|
352
|
+
it 'should return self' do
|
353
|
+
@collection.collect! { |resource| resource }.object_id.should == @collection.object_id
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
describe '#concat' do
|
358
|
+
it 'should return self' do
|
359
|
+
@collection.concat(@other).object_id.should == @collection.object_id
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
describe '#create' do
|
364
|
+
it 'should create a new resource' do
|
365
|
+
resource = @collection.create(:name => 'John')
|
366
|
+
resource.should be_kind_of(@model)
|
367
|
+
resource.should_not be_new_record
|
368
|
+
end
|
369
|
+
|
370
|
+
it 'should append the new resource to the collection' do
|
371
|
+
resource = @collection.create(:name => 'John')
|
372
|
+
resource.should_not be_new_record
|
373
|
+
resource.collection.object_id.should == @collection.object_id
|
374
|
+
@collection.should include(resource)
|
375
|
+
end
|
376
|
+
|
377
|
+
it 'should not append the resource if it was not saved' do
|
378
|
+
@repository.should_receive(:create).and_return(false)
|
379
|
+
Zebra.should_receive(:repository).at_least(:once).and_return(@repository)
|
380
|
+
|
381
|
+
resource = @collection.create(:name => 'John')
|
382
|
+
resource.should be_new_record
|
383
|
+
|
384
|
+
resource.collection.object_id.should_not == @collection.object_id
|
385
|
+
@collection.should_not include(resource)
|
386
|
+
end
|
387
|
+
|
388
|
+
it 'should use the query conditions to set default values' do
|
389
|
+
resource = @collection.create
|
390
|
+
resource.should_not be_new_record
|
391
|
+
resource.name.should be_nil
|
392
|
+
|
393
|
+
@collection.query.update(:name => 'John')
|
394
|
+
|
395
|
+
resource = @collection.create
|
396
|
+
resource.name.should == 'John'
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
describe '#delete' do
|
401
|
+
it 'should orphan the resource from the collection' do
|
402
|
+
collection = @nancy.collection
|
403
|
+
|
404
|
+
# resource is related
|
405
|
+
@nancy.collection.object_id.should == collection.object_id
|
406
|
+
|
407
|
+
collection.should have(1).entries
|
408
|
+
collection.delete(@nancy)
|
409
|
+
collection.should be_empty
|
410
|
+
|
411
|
+
# resource is orphaned
|
412
|
+
@nancy.collection.object_id.should_not == collection.object_id
|
413
|
+
end
|
414
|
+
|
415
|
+
it 'should return a Resource' do
|
416
|
+
collection = @nancy.collection
|
417
|
+
|
418
|
+
resource = collection.delete(@nancy)
|
419
|
+
|
420
|
+
resource.should be_kind_of(DataMapper::Resource)
|
421
|
+
resource.object_id.should == @nancy.object_id
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
describe '#delete_at' do
|
426
|
+
it 'should orphan the resource from the collection' do
|
427
|
+
collection = @nancy.collection
|
428
|
+
|
429
|
+
# resource is related
|
430
|
+
@nancy.collection.object_id.should == collection.object_id
|
431
|
+
|
432
|
+
collection.should have(1).entries
|
433
|
+
collection.delete_at(0).object_id.should == @nancy.object_id
|
434
|
+
collection.should be_empty
|
435
|
+
|
436
|
+
# resource is orphaned
|
437
|
+
@nancy.collection.object_id.should_not == collection.object_id
|
438
|
+
end
|
439
|
+
|
440
|
+
it 'should return a Resource' do
|
441
|
+
collection = @nancy.collection
|
442
|
+
|
443
|
+
resource = collection.delete_at(0)
|
444
|
+
|
445
|
+
resource.should be_kind_of(DataMapper::Resource)
|
446
|
+
resource.object_id.should == @nancy.object_id
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
describe '#destroy!' do
|
451
|
+
before do
|
452
|
+
@ids = [ @nancy.id, @bessie.id, @steve.id ]
|
453
|
+
end
|
454
|
+
|
455
|
+
it 'should destroy the resources in the collection' do
|
456
|
+
@collection.map { |r| r.id }.should == @ids
|
457
|
+
@collection.destroy!.should == true
|
458
|
+
@model.all(:id => @ids).should == []
|
459
|
+
@collection.reload.should == []
|
460
|
+
end
|
461
|
+
|
462
|
+
it 'should clear the collection' do
|
463
|
+
@collection.map { |r| r.id }.should == @ids
|
464
|
+
@collection.destroy!.should == true
|
465
|
+
@collection.should == []
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
describe '#each' do
|
470
|
+
it 'should return self' do
|
471
|
+
@collection.each { |resource| }.object_id.should == @collection.object_id
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
describe '#each_index' do
|
476
|
+
it 'should return self' do
|
477
|
+
@collection.each_index { |resource| }.object_id.should == @collection.object_id
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
describe '#eql?' do
|
482
|
+
it 'should return true if for the same collection' do
|
483
|
+
@collection.object_id.should == @collection.object_id
|
484
|
+
@collection.should be_eql(@collection)
|
485
|
+
end
|
486
|
+
|
487
|
+
it 'should return true for duplicate collections' do
|
488
|
+
dup = @collection.dup
|
489
|
+
dup.should be_kind_of(DataMapper::Collection)
|
490
|
+
dup.object_id.should_not == @collection.object_id
|
491
|
+
dup.entries.should == @collection.entries
|
492
|
+
dup.should be_eql(@collection)
|
493
|
+
end
|
494
|
+
|
495
|
+
it 'should return false for different collections' do
|
496
|
+
@collection.should_not be_eql(@other)
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
describe '#fetch' do
|
501
|
+
it 'should return a Resource' do
|
502
|
+
@collection.fetch(0).should be_kind_of(DataMapper::Resource)
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
describe '#first' do
|
507
|
+
describe 'with no arguments' do
|
508
|
+
it 'should return a Resource' do
|
509
|
+
first = @collection.first
|
510
|
+
first.should_not be_nil
|
511
|
+
first.should be_kind_of(DataMapper::Resource)
|
512
|
+
first.id.should == @nancy.id
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
describe 'with limit specified' do
|
517
|
+
it 'should return a Collection' do
|
518
|
+
collection = @collection.first(2)
|
519
|
+
|
520
|
+
collection.should be_kind_of(DataMapper::Collection)
|
521
|
+
collection.object_id.should_not == @collection.object_id
|
522
|
+
|
523
|
+
collection.query.order.size.should == 1
|
524
|
+
collection.query.order.first.property.should == @model.properties[:id]
|
525
|
+
collection.query.order.first.direction.should == :asc
|
526
|
+
|
527
|
+
collection.query.offset.should == 0
|
528
|
+
collection.query.limit.should == 2
|
529
|
+
|
530
|
+
collection.length.should == 2
|
531
|
+
|
532
|
+
collection.entries.map { |r| r.id }.should == [ @nancy.id, @bessie.id ]
|
533
|
+
end
|
534
|
+
|
535
|
+
it 'should return a Collection if limit is 1' do
|
536
|
+
collection = @collection.first(1)
|
537
|
+
|
538
|
+
collection.should be_kind_of(DataMapper::Collection)
|
539
|
+
collection.object_id.should_not == @collection.object_id
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
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
|
+
|
552
|
+
describe '#get' do
|
553
|
+
it 'should find a resource in a collection by key' do
|
554
|
+
resource = @collection.get(*@nancy.key)
|
555
|
+
resource.should be_kind_of(DataMapper::Resource)
|
556
|
+
resource.id.should == @nancy.id
|
557
|
+
end
|
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
|
+
|
565
|
+
it 'should not find a resource not in the collection' do
|
566
|
+
@query.update(:offset => 0, :limit => 3)
|
567
|
+
@david = Zebra.create(:name => 'David', :age => 15, :notes => 'Albino')
|
568
|
+
@collection.get(@david.key).should be_nil
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
describe '#get!' do
|
573
|
+
it 'should find a resource in a collection by key' do
|
574
|
+
resource = @collection.get!(*@nancy.key)
|
575
|
+
resource.should be_kind_of(DataMapper::Resource)
|
576
|
+
resource.id.should == @nancy.id
|
577
|
+
end
|
578
|
+
|
579
|
+
it 'should raise an exception if the resource is not found' do
|
580
|
+
@query.update(:offset => 0, :limit => 3)
|
581
|
+
@david = Zebra.create(:name => 'David', :age => 15, :notes => 'Albino')
|
582
|
+
lambda {
|
583
|
+
@collection.get!(@david.key)
|
584
|
+
}.should raise_error(DataMapper::ObjectNotFoundError)
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
describe '#insert' do
|
589
|
+
it 'should return self' do
|
590
|
+
@collection.insert(1, @steve).object_id.should == @collection.object_id
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
describe '#last' do
|
595
|
+
describe 'with no arguments' do
|
596
|
+
it 'should return a Resource' do
|
597
|
+
last = @collection.last
|
598
|
+
last.should_not be_nil
|
599
|
+
last.should be_kind_of(DataMapper::Resource)
|
600
|
+
last.id.should == @steve.id
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
describe 'with limit specified' do
|
605
|
+
it 'should return a Collection' do
|
606
|
+
collection = @collection.last(2)
|
607
|
+
|
608
|
+
collection.should be_kind_of(DataMapper::Collection)
|
609
|
+
collection.object_id.should_not == @collection.object_id
|
610
|
+
|
611
|
+
collection.query.order.size.should == 1
|
612
|
+
collection.query.order.first.property.should == @model.properties[:id]
|
613
|
+
collection.query.order.first.direction.should == :desc
|
614
|
+
|
615
|
+
collection.query.offset.should == 0
|
616
|
+
collection.query.limit.should == 2
|
617
|
+
|
618
|
+
collection.length.should == 2
|
619
|
+
|
620
|
+
collection.entries.map { |r| r.id }.should == [ @bessie.id, @steve.id ]
|
621
|
+
end
|
622
|
+
|
623
|
+
it 'should return a Collection if limit is 1' do
|
624
|
+
collection = @collection.last(1)
|
625
|
+
|
626
|
+
collection.class.should == DataMapper::Collection # should be_kind_of(DataMapper::Collection)
|
627
|
+
collection.object_id.should_not == @collection.object_id
|
628
|
+
end
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
632
|
+
describe '#load' do
|
633
|
+
it 'should load resources from the identity map when possible' do
|
634
|
+
@steve.collection = nil
|
635
|
+
@repository.identity_map(@model).should_receive(:get).with([ @steve.id ]).and_return(@steve)
|
636
|
+
|
637
|
+
collection = @repository.read_many(@query.merge(:id => @steve.id))
|
638
|
+
|
639
|
+
collection.size.should == 1
|
640
|
+
collection.map { |r| r.object_id }.should == [ @steve.object_id ]
|
641
|
+
|
642
|
+
@steve.collection.object_id.should == collection.object_id
|
643
|
+
end
|
644
|
+
|
645
|
+
it 'should return a Resource' do
|
646
|
+
@collection.load([ @steve.id, @steve.name, @steve.age ]).should be_kind_of(DataMapper::Resource)
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
describe '#loaded?' do
|
651
|
+
if loaded
|
652
|
+
it 'should return true for an initialized collection' do
|
653
|
+
@collection.should be_loaded
|
654
|
+
end
|
655
|
+
else
|
656
|
+
it 'should return false for an uninitialized collection' do
|
657
|
+
@collection.should_not be_loaded
|
658
|
+
@collection.to_a # load collection
|
659
|
+
@collection.should be_loaded
|
660
|
+
end
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
664
|
+
describe '#pop' do
|
665
|
+
it 'should orphan the resource from the collection' do
|
666
|
+
collection = @steve.collection
|
667
|
+
|
668
|
+
# resource is related
|
669
|
+
@steve.collection.object_id.should == collection.object_id
|
670
|
+
|
671
|
+
collection.should have(1).entries
|
672
|
+
collection.pop.object_id.should == @steve.object_id
|
673
|
+
collection.should be_empty
|
674
|
+
|
675
|
+
# resource is orphaned
|
676
|
+
@steve.collection.object_id.should_not == collection.object_id
|
677
|
+
end
|
678
|
+
|
679
|
+
it 'should return a Resource' do
|
680
|
+
@collection.pop.key.should == @steve.key
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
describe '#properties' do
|
685
|
+
it 'should return a PropertySet' do
|
686
|
+
@collection.properties.should be_kind_of(DataMapper::PropertySet)
|
687
|
+
end
|
688
|
+
|
689
|
+
it 'should contain same properties as query.fields' do
|
690
|
+
properties = @collection.properties
|
691
|
+
properties.entries.should == @collection.query.fields
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
describe '#push' do
|
696
|
+
it 'should relate each new resource to the collection' do
|
697
|
+
# resource is orphaned
|
698
|
+
@nancy.collection.object_id.should_not == @collection.object_id
|
699
|
+
|
700
|
+
@collection.push(@nancy)
|
701
|
+
|
702
|
+
# resource is related
|
703
|
+
@nancy.collection.object_id.should == @collection.object_id
|
704
|
+
end
|
705
|
+
|
706
|
+
it 'should return self' do
|
707
|
+
@collection.push(@steve).object_id.should == @collection.object_id
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
describe '#relationships' do
|
712
|
+
it 'should return a Hash' do
|
713
|
+
@collection.relationships.should be_kind_of(Hash)
|
714
|
+
end
|
715
|
+
|
716
|
+
it 'should contain same properties as query.model.relationships' do
|
717
|
+
relationships = @collection.relationships
|
718
|
+
relationships.should == @collection.query.model.relationships
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
722
|
+
describe '#reject' do
|
723
|
+
it 'should return a Collection with resources that did not match the block' do
|
724
|
+
rejected = @collection.reject { |resource| false }
|
725
|
+
rejected.class.should == Array
|
726
|
+
rejected.should == [ @nancy, @bessie, @steve ]
|
727
|
+
end
|
728
|
+
|
729
|
+
it 'should return an empty Array if resources matched the block' do
|
730
|
+
rejected = @collection.reject { |resource| true }
|
731
|
+
rejected.class.should == Array
|
732
|
+
rejected.should == []
|
733
|
+
end
|
734
|
+
end
|
735
|
+
|
736
|
+
describe '#reject!' do
|
737
|
+
it 'should return self if resources matched the block' do
|
738
|
+
@collection.reject! { |resource| true }.object_id.should == @collection.object_id
|
739
|
+
end
|
740
|
+
|
741
|
+
it 'should return nil if no resources matched the block' do
|
742
|
+
@collection.reject! { |resource| false }.should be_nil
|
743
|
+
end
|
744
|
+
end
|
745
|
+
|
746
|
+
describe '#reload' do
|
747
|
+
it 'should return self' do
|
748
|
+
@collection.reload.object_id.should == @collection.object_id
|
749
|
+
end
|
750
|
+
|
751
|
+
it 'should replace the collection' do
|
752
|
+
original = @collection.dup
|
753
|
+
@collection.reload.should == @collection
|
754
|
+
@collection.should == original
|
755
|
+
end
|
756
|
+
|
757
|
+
it 'should reload lazily initialized fields' do
|
758
|
+
pending 'Move to unit specs'
|
759
|
+
|
760
|
+
@repository.should_receive(:all) do |model,query|
|
761
|
+
model.should == @model
|
762
|
+
|
763
|
+
query.should be_instance_of(DataMapper::Query)
|
764
|
+
query.reload.should == true
|
765
|
+
query.offset.should == 0
|
766
|
+
query.limit.should == 10
|
767
|
+
query.order.should == []
|
768
|
+
query.fields.should == @model.properties.defaults
|
769
|
+
query.links.should == []
|
770
|
+
query.includes.should == []
|
771
|
+
query.conditions.should == [ [ :eql, @model.properties[:id], [ 1, 2, 3 ] ] ]
|
772
|
+
|
773
|
+
@collection
|
774
|
+
end
|
775
|
+
|
776
|
+
@collection.reload
|
777
|
+
end
|
778
|
+
end
|
779
|
+
|
780
|
+
describe '#replace' do
|
781
|
+
it "should orphan each existing resource from the collection if loaded?" do
|
782
|
+
entries = @collection.entries
|
783
|
+
|
784
|
+
# resources are related
|
785
|
+
entries.each { |r| r.collection.object_id.should == @collection.object_id }
|
786
|
+
|
787
|
+
@collection.should have(3).entries
|
788
|
+
@collection.replace([]).object_id.should == @collection.object_id
|
789
|
+
@collection.should be_empty
|
790
|
+
|
791
|
+
# resources are orphaned
|
792
|
+
entries.each { |r| r.collection.object_id.should_not == @collection.object_id }
|
793
|
+
end
|
794
|
+
|
795
|
+
it 'should relate each new resource to the collection' do
|
796
|
+
# resource is orphaned
|
797
|
+
@nancy.collection.object_id.should_not == @collection.object_id
|
798
|
+
|
799
|
+
@collection.replace([ @nancy ])
|
800
|
+
|
801
|
+
# resource is related
|
802
|
+
@nancy.collection.object_id.should == @collection.object_id
|
803
|
+
end
|
804
|
+
|
805
|
+
it 'should replace the contents of the collection' do
|
806
|
+
other = [ @nancy ]
|
807
|
+
@collection.should_not == other
|
808
|
+
@collection.replace(other)
|
809
|
+
@collection.should == other
|
810
|
+
@collection.object_id.should_not == @other.object_id
|
811
|
+
end
|
812
|
+
end
|
813
|
+
|
814
|
+
describe '#reverse' do
|
815
|
+
[ true, false ].each do |loaded|
|
816
|
+
describe "on a collection where loaded? == #{loaded}" do
|
817
|
+
before do
|
818
|
+
@collection.to_a if loaded
|
819
|
+
end
|
820
|
+
|
821
|
+
it 'should return a Collection with reversed entries' do
|
822
|
+
reversed = @collection.reverse
|
823
|
+
reversed.should be_kind_of(DataMapper::Collection)
|
824
|
+
reversed.object_id.should_not == @collection.object_id
|
825
|
+
reversed.entries.should == @collection.entries.reverse
|
826
|
+
|
827
|
+
reversed.query.order.size.should == 1
|
828
|
+
reversed.query.order.first.property.should == @model.properties[:id]
|
829
|
+
reversed.query.order.first.direction.should == :desc
|
830
|
+
end
|
831
|
+
end
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
835
|
+
describe '#reverse!' do
|
836
|
+
it 'should return self' do
|
837
|
+
@collection.reverse!.object_id.should == @collection.object_id
|
838
|
+
end
|
839
|
+
end
|
840
|
+
|
841
|
+
describe '#reverse_each' do
|
842
|
+
it 'should return self' do
|
843
|
+
@collection.reverse_each { |resource| }.object_id.should == @collection.object_id
|
844
|
+
end
|
845
|
+
end
|
846
|
+
|
847
|
+
describe '#select' do
|
848
|
+
it 'should return an Array with resources that matched the block' do
|
849
|
+
selected = @collection.select { |resource| true }
|
850
|
+
selected.class.should == Array
|
851
|
+
selected.should == @collection
|
852
|
+
end
|
853
|
+
|
854
|
+
it 'should return an empty Array if no resources matched the block' do
|
855
|
+
selected = @collection.select { |resource| false }
|
856
|
+
selected.class.should == Array
|
857
|
+
selected.should == []
|
858
|
+
end
|
859
|
+
end
|
860
|
+
|
861
|
+
describe '#shift' do
|
862
|
+
it 'should orphan the resource from the collection' do
|
863
|
+
collection = @nancy.collection
|
864
|
+
|
865
|
+
# resource is related
|
866
|
+
@nancy.collection.object_id.should == collection.object_id
|
867
|
+
|
868
|
+
collection.should have(1).entries
|
869
|
+
collection.shift.object_id.should == @nancy.object_id
|
870
|
+
collection.should be_empty
|
871
|
+
|
872
|
+
# resource is orphaned
|
873
|
+
@nancy.collection.object_id.should_not == collection.object_id
|
874
|
+
end
|
875
|
+
|
876
|
+
it 'should return a Resource' do
|
877
|
+
@collection.shift.key.should == @nancy.key
|
878
|
+
end
|
879
|
+
end
|
880
|
+
|
881
|
+
[ :slice, :[] ].each do |method|
|
882
|
+
describe '#slice' do
|
883
|
+
describe 'with an index' do
|
884
|
+
it 'should return a Resource' do
|
885
|
+
resource = @collection.send(method, 0)
|
886
|
+
resource.should be_kind_of(DataMapper::Resource)
|
887
|
+
resource.id.should == @nancy.id
|
888
|
+
end
|
889
|
+
end
|
890
|
+
|
891
|
+
describe 'with a start and length' do
|
892
|
+
it 'should return a Collection' do
|
893
|
+
sliced = @collection.send(method, 0, 1)
|
894
|
+
sliced.should be_kind_of(DataMapper::Collection)
|
895
|
+
sliced.object_id.should_not == @collection.object_id
|
896
|
+
sliced.length.should == 1
|
897
|
+
sliced.map { |r| r.id }.should == [ @nancy.id ]
|
898
|
+
end
|
899
|
+
end
|
900
|
+
|
901
|
+
describe 'with a Range' do
|
902
|
+
it 'should return a Collection' do
|
903
|
+
sliced = @collection.send(method, 0..1)
|
904
|
+
sliced.should be_kind_of(DataMapper::Collection)
|
905
|
+
sliced.object_id.should_not == @collection.object_id
|
906
|
+
sliced.length.should == 2
|
907
|
+
sliced.map { |r| r.id }.should == [ @nancy.id, @bessie.id ]
|
908
|
+
end
|
909
|
+
end
|
910
|
+
end
|
911
|
+
end
|
912
|
+
|
913
|
+
describe '#slice!' do
|
914
|
+
describe 'with an index' do
|
915
|
+
it 'should return a Resource' do
|
916
|
+
resource = @collection.slice!(0)
|
917
|
+
resource.should be_kind_of(DataMapper::Resource)
|
918
|
+
end
|
919
|
+
end
|
920
|
+
|
921
|
+
describe 'with a start and length' do
|
922
|
+
it 'should return an Array' do
|
923
|
+
sliced = @collection.slice!(0, 1)
|
924
|
+
sliced.class.should == Array
|
925
|
+
sliced.map { |r| r.id }.should == [ @nancy.id ]
|
926
|
+
end
|
927
|
+
end
|
928
|
+
|
929
|
+
describe 'with a Range' do
|
930
|
+
it 'should return a Collection' do
|
931
|
+
sliced = @collection.slice(0..1)
|
932
|
+
sliced.should be_kind_of(DataMapper::Collection)
|
933
|
+
sliced.object_id.should_not == @collection.object_id
|
934
|
+
sliced.length.should == 2
|
935
|
+
sliced[0].id.should == @nancy.id
|
936
|
+
sliced[1].id.should == @bessie.id
|
937
|
+
end
|
938
|
+
end
|
939
|
+
end
|
940
|
+
|
941
|
+
describe '#sort' do
|
942
|
+
it 'should return an Array' do
|
943
|
+
sorted = @collection.sort { |a,b| a.age <=> b.age }
|
944
|
+
sorted.class.should == Array
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
describe '#sort!' do
|
949
|
+
it 'should return self' do
|
950
|
+
@collection.sort! { |a,b| 0 }.object_id.should == @collection.object_id
|
951
|
+
end
|
952
|
+
end
|
953
|
+
|
954
|
+
describe '#unshift' do
|
955
|
+
it 'should relate each new resource to the collection' do
|
956
|
+
# resource is orphaned
|
957
|
+
@nancy.collection.object_id.should_not == @collection.object_id
|
958
|
+
|
959
|
+
@collection.unshift(@nancy)
|
960
|
+
|
961
|
+
# resource is related
|
962
|
+
@nancy.collection.object_id.should == @collection.object_id
|
963
|
+
end
|
964
|
+
|
965
|
+
it 'should return self' do
|
966
|
+
@collection.unshift(@steve).object_id.should == @collection.object_id
|
967
|
+
end
|
968
|
+
end
|
969
|
+
|
970
|
+
describe '#update!' do
|
971
|
+
it 'should update the resources in the collection' do
|
972
|
+
pending do
|
973
|
+
# this will not pass with new update!
|
974
|
+
# update! should never loop through and set attributes
|
975
|
+
# even if it is loaded, and it will not reload the
|
976
|
+
# changed objects (even with reload=true, as objects
|
977
|
+
# are created is not in any identity map)
|
978
|
+
names = [ @nancy.name, @bessie.name, @steve.name ]
|
979
|
+
@collection.map { |r| r.name }.should == names
|
980
|
+
@collection.update!(:name => 'John')
|
981
|
+
@collection.map { |r| r.name }.should_not == names
|
982
|
+
@collection.map { |r| r.name }.should == %w[ John ] * 3
|
983
|
+
end
|
984
|
+
end
|
985
|
+
|
986
|
+
it 'should not update loaded resources unless forced' do
|
987
|
+
repository(ADAPTER) do
|
988
|
+
nancy = Zebra.first
|
989
|
+
nancy.name.should == "Nancy"
|
990
|
+
|
991
|
+
collection = Zebra.all(:name => ["Nancy","Bessie"])
|
992
|
+
collection.update!(:name => "Stevie")
|
993
|
+
|
994
|
+
nancy.name.should == "Nancy"
|
995
|
+
end
|
996
|
+
end
|
997
|
+
|
998
|
+
it 'should update loaded resources if forced' do
|
999
|
+
repository(ADAPTER) do
|
1000
|
+
nancy = Zebra.first
|
1001
|
+
nancy.name.should == "Nancy"
|
1002
|
+
|
1003
|
+
collection = Zebra.all(:name => ["Nancy","Bessie"])
|
1004
|
+
collection.update!({:name => "Stevie"},true)
|
1005
|
+
|
1006
|
+
nancy.name.should == "Stevie"
|
1007
|
+
end
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
it 'should update collection-query when updating' do
|
1011
|
+
repository(ADAPTER) do
|
1012
|
+
collection = Zebra.all(:name => ["Nancy","Bessie"])
|
1013
|
+
collection.query.conditions.first[2].should == ["Nancy","Bessie"]
|
1014
|
+
collection.length.should == 2
|
1015
|
+
collection.update!(:name => "Stevie")
|
1016
|
+
collection.length.should == 2
|
1017
|
+
collection.query.conditions.first[2].should == "Stevie"
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
describe '#keys' do
|
1023
|
+
it 'should return a hash of keys' do
|
1024
|
+
keys = @collection.send(:keys)
|
1025
|
+
keys.length.should == 1
|
1026
|
+
keys.each{|property,values| values.should == [1,2,3]}
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
it 'should return an empty hash if collection is empty' do
|
1030
|
+
keys = Zebra.all(:id.gt => 10000).send(:keys)
|
1031
|
+
keys.should == {}
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
describe '#values_at' do
|
1036
|
+
it 'should return an Array' do
|
1037
|
+
values = @collection.values_at(0)
|
1038
|
+
values.class.should == Array
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
it 'should return an Array of the resources at the index' do
|
1042
|
+
@collection.values_at(0).entries.map { |r| r.id }.should == [ @nancy.id ]
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
describe 'with lazy loading' do
|
1047
|
+
it "should take a materialization block" do
|
1048
|
+
collection = DataMapper::Collection.new(@query) do |c|
|
1049
|
+
c.should == []
|
1050
|
+
c.load([ 1, 'Bob', 10 ])
|
1051
|
+
c.load([ 2, 'Nancy', 11 ])
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
collection.should_not be_loaded
|
1055
|
+
collection.length.should == 2
|
1056
|
+
collection.should be_loaded
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
it "should load lazy columns when using offset" do
|
1060
|
+
repository(ADAPTER) do
|
1061
|
+
zebras = Zebra.all(:offset => 1, :limit => 2)
|
1062
|
+
zebras.first.notes.should_not be_nil
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
end
|
1066
|
+
end
|
1067
|
+
end
|
1068
|
+
end
|
1069
|
+
end
|