mongoid_monkey 0.2.5 → 0.3.0
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.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/lib/mongoid_monkey.rb +2 -0
- data/lib/patches/aggregate_cursor.rb +16 -0
- data/lib/patches/atomic.rb +42 -7
- data/lib/patches/write_concern.rb +10 -0
- data/lib/version.rb +1 -1
- data/spec/app/models/address.rb +1 -0
- data/spec/app/models/album.rb +14 -0
- data/spec/app/models/animal.rb +25 -0
- data/spec/app/models/appointment.rb +7 -0
- data/spec/app/models/artist.rb +66 -0
- data/spec/app/models/circus.rb +7 -0
- data/spec/app/models/country_code.rb +8 -0
- data/spec/app/models/label.rb +39 -0
- data/spec/app/models/location.rb +8 -0
- data/spec/app/models/page.rb +2 -1
- data/spec/app/models/page_question.rb +4 -0
- data/spec/app/models/person.rb +5 -0
- data/spec/app/models/phone.rb +11 -0
- data/spec/app/models/quiz.rb +10 -0
- data/spec/app/models/role.rb +7 -0
- data/spec/app/models/song.rb +8 -0
- data/spec/app/models/symptom.rb +6 -0
- data/spec/app/models/user.rb +1 -0
- data/spec/app/models/video.rb +17 -0
- data/spec/unit/aggregate_cursor_spec.rb +495 -0
- data/spec/unit/atomic/mongoid3_style/atomic/embedded_insert_spec.rb +1213 -0
- data/spec/unit/only_pluck_localized_spec.rb +2 -2
- data/spec/unit/write_concern_spec.rb +29 -0
- metadata +41 -3
@@ -0,0 +1,1213 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
if Mongoid::VERSION =~ /\A3\./
|
4
|
+
|
5
|
+
describe Mongoid::Relations::Embedded::Many do
|
6
|
+
|
7
|
+
[ :<<, :push ].each do |method|
|
8
|
+
|
9
|
+
describe "##{method}" do
|
10
|
+
|
11
|
+
context "when the parent is a new record" do
|
12
|
+
|
13
|
+
let(:person) do
|
14
|
+
Person.new
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:address) do
|
18
|
+
Address.new
|
19
|
+
end
|
20
|
+
|
21
|
+
let!(:added) do
|
22
|
+
person.addresses.send(method, address)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "appends to the target" do
|
26
|
+
person.addresses.should eq([ address ])
|
27
|
+
end
|
28
|
+
|
29
|
+
it "sets the base on the inverse relation" do
|
30
|
+
address.addressable.should eq(person)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "sets the same instance on the inverse relation" do
|
34
|
+
address.addressable.should eql(person)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "does not save the new document" do
|
38
|
+
address.should_not be_persisted
|
39
|
+
end
|
40
|
+
|
41
|
+
it "sets the parent on the child" do
|
42
|
+
address._parent.should eq(person)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "sets the metadata on the child" do
|
46
|
+
address.metadata.should_not be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
it "sets the index on the child" do
|
50
|
+
address._index.should eq(0)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns the relation" do
|
54
|
+
added.should eq(person.addresses)
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with a limiting default scope" do
|
58
|
+
|
59
|
+
context "when the document matches the scope" do
|
60
|
+
|
61
|
+
let(:active) do
|
62
|
+
Appointment.new
|
63
|
+
end
|
64
|
+
|
65
|
+
before do
|
66
|
+
person.appointments.send(method, active)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "appends to the target" do
|
70
|
+
person.appointments.target.should eq([ active ])
|
71
|
+
end
|
72
|
+
|
73
|
+
it "appends to the _unscoped" do
|
74
|
+
person.appointments.send(:_unscoped).should eq([ active ])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when the document does not match the scope" do
|
79
|
+
|
80
|
+
let(:inactive) do
|
81
|
+
Appointment.new(active: false)
|
82
|
+
end
|
83
|
+
|
84
|
+
before do
|
85
|
+
person.appointments.send(method, inactive)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "doesn't append to the target" do
|
89
|
+
person.appointments.target.should_not eq([ inactive ])
|
90
|
+
end
|
91
|
+
|
92
|
+
it "appends to the _unscoped" do
|
93
|
+
person.appointments.send(:_unscoped).should eq([ inactive ])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "when the parent is not a new record" do
|
100
|
+
|
101
|
+
let(:person) do
|
102
|
+
Person.create
|
103
|
+
end
|
104
|
+
|
105
|
+
let(:address) do
|
106
|
+
Address.new
|
107
|
+
end
|
108
|
+
|
109
|
+
before do
|
110
|
+
person.addresses.send(method, address)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "saves the new document" do
|
114
|
+
address.should be_persisted
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "when appending more than one document at once" do
|
119
|
+
|
120
|
+
let(:person) do
|
121
|
+
Person.create
|
122
|
+
end
|
123
|
+
|
124
|
+
let(:address_one) do
|
125
|
+
Address.new
|
126
|
+
end
|
127
|
+
|
128
|
+
let(:address_two) do
|
129
|
+
Address.new
|
130
|
+
end
|
131
|
+
|
132
|
+
let!(:added) do
|
133
|
+
person.addresses.send(method, [ address_one, address_two ])
|
134
|
+
end
|
135
|
+
|
136
|
+
it "saves the first document" do
|
137
|
+
address_one.should be_persisted
|
138
|
+
end
|
139
|
+
|
140
|
+
it "saves the second document" do
|
141
|
+
address_two.should be_persisted
|
142
|
+
end
|
143
|
+
|
144
|
+
it "returns the relation" do
|
145
|
+
added.should eq(person.addresses)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "when the parent and child have a cyclic relation" do
|
150
|
+
|
151
|
+
context "when the parent is a new record" do
|
152
|
+
|
153
|
+
let(:parent_role) do
|
154
|
+
Role.new
|
155
|
+
end
|
156
|
+
|
157
|
+
let(:child_role) do
|
158
|
+
Role.new
|
159
|
+
end
|
160
|
+
|
161
|
+
before do
|
162
|
+
parent_role.child_roles.send(method, child_role)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "appends to the target" do
|
166
|
+
parent_role.child_roles.should eq([ child_role ])
|
167
|
+
end
|
168
|
+
|
169
|
+
it "sets the base on the inverse relation" do
|
170
|
+
child_role.parent_role.should eq(parent_role)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "sets the same instance on the inverse relation" do
|
174
|
+
child_role.parent_role.should eql(parent_role)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "does not save the new document" do
|
178
|
+
child_role.should_not be_persisted
|
179
|
+
end
|
180
|
+
|
181
|
+
it "sets the parent on the child" do
|
182
|
+
child_role._parent.should eq(parent_role)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "sets the metadata on the child" do
|
186
|
+
child_role.metadata.should_not be_nil
|
187
|
+
end
|
188
|
+
|
189
|
+
it "sets the index on the child" do
|
190
|
+
child_role._index.should eq(0)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context "when the parent is not a new record" do
|
195
|
+
|
196
|
+
let(:parent_role) do
|
197
|
+
Role.create(name: "CEO")
|
198
|
+
end
|
199
|
+
|
200
|
+
let(:child_role) do
|
201
|
+
Role.new(name: "COO")
|
202
|
+
end
|
203
|
+
|
204
|
+
before do
|
205
|
+
parent_role.child_roles.send(method, child_role)
|
206
|
+
end
|
207
|
+
|
208
|
+
it "saves the new document" do
|
209
|
+
child_role.should be_persisted
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe "#concat" do
|
217
|
+
|
218
|
+
context "when the parent is a new record" do
|
219
|
+
|
220
|
+
let(:person) do
|
221
|
+
Person.new
|
222
|
+
end
|
223
|
+
|
224
|
+
let(:address) do
|
225
|
+
Address.new
|
226
|
+
end
|
227
|
+
|
228
|
+
before do
|
229
|
+
person.addresses.concat([ address ])
|
230
|
+
end
|
231
|
+
|
232
|
+
it "appends to the target" do
|
233
|
+
person.addresses.should eq([ address ])
|
234
|
+
end
|
235
|
+
|
236
|
+
it "appends to the unscoped" do
|
237
|
+
person.addresses.send(:_unscoped).should eq([ address ])
|
238
|
+
end
|
239
|
+
|
240
|
+
it "sets the base on the inverse relation" do
|
241
|
+
address.addressable.should eq(person)
|
242
|
+
end
|
243
|
+
|
244
|
+
it "sets the same instance on the inverse relation" do
|
245
|
+
address.addressable.should eql(person)
|
246
|
+
end
|
247
|
+
|
248
|
+
it "does not save the new document" do
|
249
|
+
address.should_not be_persisted
|
250
|
+
end
|
251
|
+
|
252
|
+
it "sets the parent on the child" do
|
253
|
+
address._parent.should eq(person)
|
254
|
+
end
|
255
|
+
|
256
|
+
it "sets the metadata on the child" do
|
257
|
+
address.metadata.should_not be_nil
|
258
|
+
end
|
259
|
+
|
260
|
+
it "sets the index on the child" do
|
261
|
+
address._index.should eq(0)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context "when the parent is not a new record" do
|
266
|
+
|
267
|
+
let(:person) do
|
268
|
+
Person.create
|
269
|
+
end
|
270
|
+
|
271
|
+
let(:address) do
|
272
|
+
Address.new
|
273
|
+
end
|
274
|
+
|
275
|
+
before do
|
276
|
+
person.addresses.concat([ address ])
|
277
|
+
end
|
278
|
+
|
279
|
+
it "saves the new document" do
|
280
|
+
address.should be_persisted
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
context "when concatenating an empty array" do
|
285
|
+
|
286
|
+
let(:person) do
|
287
|
+
Person.create
|
288
|
+
end
|
289
|
+
|
290
|
+
before do
|
291
|
+
person.addresses.should_not_receive(:batch_insert)
|
292
|
+
person.addresses.concat([])
|
293
|
+
end
|
294
|
+
|
295
|
+
it "doesn't update the target" do
|
296
|
+
person.addresses.should be_empty
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
context "when appending more than one document at once" do
|
301
|
+
|
302
|
+
let(:person) do
|
303
|
+
Person.create
|
304
|
+
end
|
305
|
+
|
306
|
+
let(:address_one) do
|
307
|
+
Address.new
|
308
|
+
end
|
309
|
+
|
310
|
+
let(:address_two) do
|
311
|
+
Address.new
|
312
|
+
end
|
313
|
+
|
314
|
+
before do
|
315
|
+
person.addresses.concat([ address_one, address_two ])
|
316
|
+
end
|
317
|
+
|
318
|
+
it "saves the first document" do
|
319
|
+
address_one.should be_persisted
|
320
|
+
end
|
321
|
+
|
322
|
+
it "saves the second document" do
|
323
|
+
address_two.should be_persisted
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
context "when the parent and child have a cyclic relation" do
|
328
|
+
|
329
|
+
context "when the parent is a new record" do
|
330
|
+
|
331
|
+
let(:parent_role) do
|
332
|
+
Role.new
|
333
|
+
end
|
334
|
+
|
335
|
+
let(:child_role) do
|
336
|
+
Role.new
|
337
|
+
end
|
338
|
+
|
339
|
+
before do
|
340
|
+
parent_role.child_roles.concat([ child_role ])
|
341
|
+
end
|
342
|
+
|
343
|
+
it "appends to the target" do
|
344
|
+
parent_role.child_roles.should eq([ child_role ])
|
345
|
+
end
|
346
|
+
|
347
|
+
it "sets the base on the inverse relation" do
|
348
|
+
child_role.parent_role.should eq(parent_role)
|
349
|
+
end
|
350
|
+
|
351
|
+
it "sets the same instance on the inverse relation" do
|
352
|
+
child_role.parent_role.should eql(parent_role)
|
353
|
+
end
|
354
|
+
|
355
|
+
it "does not save the new document" do
|
356
|
+
child_role.should_not be_persisted
|
357
|
+
end
|
358
|
+
|
359
|
+
it "sets the parent on the child" do
|
360
|
+
child_role._parent.should eq(parent_role)
|
361
|
+
end
|
362
|
+
|
363
|
+
it "sets the metadata on the child" do
|
364
|
+
child_role.metadata.should_not be_nil
|
365
|
+
end
|
366
|
+
|
367
|
+
it "sets the index on the child" do
|
368
|
+
child_role._index.should eq(0)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
context "when the parent is not a new record" do
|
373
|
+
|
374
|
+
let(:parent_role) do
|
375
|
+
Role.create(name: "CEO")
|
376
|
+
end
|
377
|
+
|
378
|
+
let(:child_role) do
|
379
|
+
Role.new(name: "COO")
|
380
|
+
end
|
381
|
+
|
382
|
+
before do
|
383
|
+
parent_role.child_roles.concat([ child_role ])
|
384
|
+
end
|
385
|
+
|
386
|
+
it "saves the new document" do
|
387
|
+
child_role.should be_persisted
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
describe "#count" do
|
394
|
+
|
395
|
+
let(:person) do
|
396
|
+
Person.create
|
397
|
+
end
|
398
|
+
|
399
|
+
before do
|
400
|
+
person.addresses.create(street: "Upper")
|
401
|
+
person.addresses.build(street: "Bond")
|
402
|
+
end
|
403
|
+
|
404
|
+
it "returns the number of persisted documents" do
|
405
|
+
person.addresses.count.should eq(1)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
describe "#max" do
|
410
|
+
|
411
|
+
let(:person) do
|
412
|
+
Person.new
|
413
|
+
end
|
414
|
+
|
415
|
+
let(:address_one) do
|
416
|
+
Address.new(number: 5)
|
417
|
+
end
|
418
|
+
|
419
|
+
let(:address_two) do
|
420
|
+
Address.new(number: 10)
|
421
|
+
end
|
422
|
+
|
423
|
+
before do
|
424
|
+
person.addresses.push(address_one, address_two)
|
425
|
+
end
|
426
|
+
|
427
|
+
let(:max) do
|
428
|
+
person.addresses.max do |a,b|
|
429
|
+
a.number <=> b.number
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
it "returns the document with the max value of the supplied field" do
|
434
|
+
max.should eq(address_two)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
describe "#max_by" do
|
439
|
+
|
440
|
+
let(:person) do
|
441
|
+
Person.new
|
442
|
+
end
|
443
|
+
|
444
|
+
let(:address_one) do
|
445
|
+
Address.new(number: 5)
|
446
|
+
end
|
447
|
+
|
448
|
+
let(:address_two) do
|
449
|
+
Address.new(number: 10)
|
450
|
+
end
|
451
|
+
|
452
|
+
before do
|
453
|
+
person.addresses.push(address_one, address_two)
|
454
|
+
end
|
455
|
+
|
456
|
+
let(:max) do
|
457
|
+
person.addresses.max_by(&:number)
|
458
|
+
end
|
459
|
+
|
460
|
+
it "returns the document with the max value of the supplied field" do
|
461
|
+
max.should eq(address_two)
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
describe "#min" do
|
466
|
+
|
467
|
+
let(:person) do
|
468
|
+
Person.new
|
469
|
+
end
|
470
|
+
|
471
|
+
let(:address_one) do
|
472
|
+
Address.new(number: 5)
|
473
|
+
end
|
474
|
+
|
475
|
+
let(:address_two) do
|
476
|
+
Address.new(number: 10)
|
477
|
+
end
|
478
|
+
|
479
|
+
before do
|
480
|
+
person.addresses.push(address_one, address_two)
|
481
|
+
end
|
482
|
+
|
483
|
+
let(:min) do
|
484
|
+
person.addresses.min do |a,b|
|
485
|
+
a.number <=> b.number
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
it "returns the min value of the supplied field" do
|
490
|
+
min.should eq(address_one)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
describe "#min_by" do
|
495
|
+
|
496
|
+
let(:person) do
|
497
|
+
Person.new
|
498
|
+
end
|
499
|
+
|
500
|
+
let(:address_one) do
|
501
|
+
Address.new(number: 5)
|
502
|
+
end
|
503
|
+
|
504
|
+
let(:address_two) do
|
505
|
+
Address.new(number: 10)
|
506
|
+
end
|
507
|
+
|
508
|
+
before do
|
509
|
+
person.addresses.push(address_one, address_two)
|
510
|
+
end
|
511
|
+
|
512
|
+
let(:min) do
|
513
|
+
person.addresses.min_by(&:number)
|
514
|
+
end
|
515
|
+
|
516
|
+
it "returns the min value of the supplied field" do
|
517
|
+
min.should eq(address_one)
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
context "when deeply embedding documents" do
|
522
|
+
|
523
|
+
context "when updating the bottom level" do
|
524
|
+
|
525
|
+
let!(:person) do
|
526
|
+
Person.create
|
527
|
+
end
|
528
|
+
|
529
|
+
let!(:address) do
|
530
|
+
person.addresses.create(street: "Joachimstr")
|
531
|
+
end
|
532
|
+
|
533
|
+
let!(:location) do
|
534
|
+
address.locations.create(name: "work")
|
535
|
+
end
|
536
|
+
|
537
|
+
context "when updating with a hash" do
|
538
|
+
|
539
|
+
before do
|
540
|
+
address.update_attributes(locations: [{ name: "home" }])
|
541
|
+
end
|
542
|
+
|
543
|
+
it "updates the attributes" do
|
544
|
+
address.locations.first.name.should eq("home")
|
545
|
+
end
|
546
|
+
|
547
|
+
it "overwrites the existing documents" do
|
548
|
+
address.locations.count.should eq(1)
|
549
|
+
end
|
550
|
+
|
551
|
+
it "persists the changes" do
|
552
|
+
address.reload.locations.count.should eq(1)
|
553
|
+
end
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
context "when building the tree through hashes" do
|
558
|
+
|
559
|
+
let(:circus) do
|
560
|
+
Circus.new(hash)
|
561
|
+
end
|
562
|
+
|
563
|
+
let(:animal) do
|
564
|
+
circus.animals.first
|
565
|
+
end
|
566
|
+
|
567
|
+
let(:animal_name) do
|
568
|
+
"Lion"
|
569
|
+
end
|
570
|
+
|
571
|
+
let(:tag_list) do
|
572
|
+
"tigers, bears, oh my"
|
573
|
+
end
|
574
|
+
|
575
|
+
context "when the hash uses stringified keys" do
|
576
|
+
|
577
|
+
let(:hash) do
|
578
|
+
{ 'animals' => [{ 'name' => animal_name, 'tag_list' => tag_list }] }
|
579
|
+
end
|
580
|
+
|
581
|
+
it "sets up the hierarchy" do
|
582
|
+
animal.circus.should eq(circus)
|
583
|
+
end
|
584
|
+
|
585
|
+
it "assigns the attributes" do
|
586
|
+
animal.name.should eq(animal_name)
|
587
|
+
end
|
588
|
+
|
589
|
+
it "uses custom writer methods" do
|
590
|
+
animal.tag_list.should eq(tag_list)
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
context "when the hash uses symbolized keys" do
|
595
|
+
|
596
|
+
let(:hash) do
|
597
|
+
{ animals: [{ name: animal_name, tag_list: tag_list }] }
|
598
|
+
end
|
599
|
+
|
600
|
+
it "sets up the hierarchy" do
|
601
|
+
animal.circus.should eq(circus)
|
602
|
+
end
|
603
|
+
|
604
|
+
it "assigns the attributes" do
|
605
|
+
animal.name.should eq(animal_name)
|
606
|
+
end
|
607
|
+
|
608
|
+
it "uses custom writer methods" do
|
609
|
+
animal.tag_list.should eq(tag_list)
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
context "when building the tree through pushes" do
|
615
|
+
|
616
|
+
let(:quiz) do
|
617
|
+
Quiz.new
|
618
|
+
end
|
619
|
+
|
620
|
+
let(:page) do
|
621
|
+
Page.new
|
622
|
+
end
|
623
|
+
|
624
|
+
let(:page_question) do
|
625
|
+
PageQuestion.new
|
626
|
+
end
|
627
|
+
|
628
|
+
before do
|
629
|
+
quiz.pages << page
|
630
|
+
page.page_questions << page_question
|
631
|
+
end
|
632
|
+
|
633
|
+
let(:question) do
|
634
|
+
quiz.pages.first.page_questions.first
|
635
|
+
end
|
636
|
+
|
637
|
+
it "sets up the hierarchy" do
|
638
|
+
question.should eq(page_question)
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
context "when building the tree through builds" do
|
643
|
+
|
644
|
+
let!(:quiz) do
|
645
|
+
Quiz.new
|
646
|
+
end
|
647
|
+
|
648
|
+
let!(:page) do
|
649
|
+
quiz.pages.build
|
650
|
+
end
|
651
|
+
|
652
|
+
let!(:page_question) do
|
653
|
+
page.page_questions.build
|
654
|
+
end
|
655
|
+
|
656
|
+
let(:question) do
|
657
|
+
quiz.pages.first.page_questions.first
|
658
|
+
end
|
659
|
+
|
660
|
+
it "sets up the hierarchy" do
|
661
|
+
question.should eq(page_question)
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
context "when creating a persisted tree" do
|
666
|
+
|
667
|
+
let(:quiz) do
|
668
|
+
Quiz.create
|
669
|
+
end
|
670
|
+
|
671
|
+
let(:page) do
|
672
|
+
Page.new
|
673
|
+
end
|
674
|
+
|
675
|
+
let(:page_question) do
|
676
|
+
PageQuestion.new
|
677
|
+
end
|
678
|
+
|
679
|
+
let(:question) do
|
680
|
+
quiz.pages.first.page_questions.first
|
681
|
+
end
|
682
|
+
|
683
|
+
before do
|
684
|
+
quiz.pages << page
|
685
|
+
page.page_questions << page_question
|
686
|
+
end
|
687
|
+
|
688
|
+
it "sets up the hierarchy" do
|
689
|
+
question.should eq(page_question)
|
690
|
+
end
|
691
|
+
|
692
|
+
context "when reloading" do
|
693
|
+
|
694
|
+
let(:from_db) do
|
695
|
+
quiz.reload
|
696
|
+
end
|
697
|
+
|
698
|
+
let(:reloaded_question) do
|
699
|
+
from_db.pages.first.page_questions.first
|
700
|
+
end
|
701
|
+
|
702
|
+
it "reloads the entire tree" do
|
703
|
+
reloaded_question.should eq(question)
|
704
|
+
end
|
705
|
+
end
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
709
|
+
context "when deeply nesting documents" do
|
710
|
+
|
711
|
+
context "when all documents are new" do
|
712
|
+
|
713
|
+
let(:person) do
|
714
|
+
Person.new
|
715
|
+
end
|
716
|
+
|
717
|
+
let(:address) do
|
718
|
+
Address.new
|
719
|
+
end
|
720
|
+
|
721
|
+
let(:location) do
|
722
|
+
Location.new
|
723
|
+
end
|
724
|
+
|
725
|
+
before do
|
726
|
+
address.locations << location
|
727
|
+
person.addresses << address
|
728
|
+
end
|
729
|
+
|
730
|
+
context "when saving the root" do
|
731
|
+
|
732
|
+
before do
|
733
|
+
person.save
|
734
|
+
end
|
735
|
+
|
736
|
+
it "persists the first level document" do
|
737
|
+
person.reload.addresses.first.should eq(address)
|
738
|
+
end
|
739
|
+
|
740
|
+
it "persists the second level document" do
|
741
|
+
person.reload.addresses[0].locations.should eq([ location ])
|
742
|
+
end
|
743
|
+
end
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
747
|
+
context "when attempting nil pushes and substitutes" do
|
748
|
+
|
749
|
+
let(:home_phone) do
|
750
|
+
Phone.new(number: "555-555-5555")
|
751
|
+
end
|
752
|
+
|
753
|
+
let(:office_phone) do
|
754
|
+
Phone.new(number: "666-666-6666")
|
755
|
+
end
|
756
|
+
|
757
|
+
describe "replacing the entire embedded list" do
|
758
|
+
|
759
|
+
context "when an embeds many relationship contains a nil as the first item" do
|
760
|
+
|
761
|
+
let(:person) do
|
762
|
+
Person.create!
|
763
|
+
end
|
764
|
+
|
765
|
+
let(:phone_list) do
|
766
|
+
[nil, home_phone, office_phone]
|
767
|
+
end
|
768
|
+
|
769
|
+
before do
|
770
|
+
person.phone_numbers = phone_list
|
771
|
+
person.save!
|
772
|
+
end
|
773
|
+
|
774
|
+
it "ignores the nil and persist the remaining items" do
|
775
|
+
reloaded = Person.find(person.id)
|
776
|
+
reloaded.phone_numbers.should eq([ home_phone, office_phone ])
|
777
|
+
end
|
778
|
+
end
|
779
|
+
|
780
|
+
context "when an embeds many relationship contains a nil in the middle of the list" do
|
781
|
+
|
782
|
+
let(:person) do
|
783
|
+
Person.create!
|
784
|
+
end
|
785
|
+
|
786
|
+
let(:phone_list) do
|
787
|
+
[home_phone, nil, office_phone]
|
788
|
+
end
|
789
|
+
|
790
|
+
before do
|
791
|
+
person.phone_numbers = phone_list
|
792
|
+
person.save!
|
793
|
+
end
|
794
|
+
|
795
|
+
it "ignores the nil and persist the remaining items" do
|
796
|
+
reloaded = Person.find(person.id)
|
797
|
+
reloaded.phone_numbers.should eq([ home_phone, office_phone ])
|
798
|
+
end
|
799
|
+
end
|
800
|
+
|
801
|
+
context "when an embeds many relationship contains a nil at the end of the list" do
|
802
|
+
|
803
|
+
let(:person) do
|
804
|
+
Person.create!
|
805
|
+
end
|
806
|
+
|
807
|
+
let(:phone_list) do
|
808
|
+
[home_phone, office_phone, nil]
|
809
|
+
end
|
810
|
+
|
811
|
+
before do
|
812
|
+
person.phone_numbers = phone_list
|
813
|
+
person.save!
|
814
|
+
end
|
815
|
+
|
816
|
+
it "ignores the nil and persist the remaining items" do
|
817
|
+
reloaded = Person.find(person.id)
|
818
|
+
reloaded.phone_numbers.should eq([ home_phone, office_phone ])
|
819
|
+
end
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
describe "appending to the embedded list" do
|
824
|
+
|
825
|
+
context "when appending a nil to the first position in an embedded list" do
|
826
|
+
|
827
|
+
let(:person) do
|
828
|
+
Person.create! phone_numbers: []
|
829
|
+
end
|
830
|
+
|
831
|
+
before do
|
832
|
+
person.phone_numbers << nil
|
833
|
+
person.phone_numbers << home_phone
|
834
|
+
person.phone_numbers << office_phone
|
835
|
+
person.save!
|
836
|
+
end
|
837
|
+
|
838
|
+
it "ignores the nil and persist the remaining items" do
|
839
|
+
reloaded = Person.find(person.id)
|
840
|
+
reloaded.phone_numbers.should eq(person.phone_numbers)
|
841
|
+
end
|
842
|
+
end
|
843
|
+
|
844
|
+
context "when appending a nil into the middle of an embedded list" do
|
845
|
+
|
846
|
+
let(:person) do
|
847
|
+
Person.create! phone_numbers: []
|
848
|
+
end
|
849
|
+
|
850
|
+
before do
|
851
|
+
person.phone_numbers << home_phone
|
852
|
+
person.phone_numbers << nil
|
853
|
+
person.phone_numbers << office_phone
|
854
|
+
person.save!
|
855
|
+
end
|
856
|
+
|
857
|
+
it "ignores the nil and persist the remaining items" do
|
858
|
+
reloaded = Person.find(person.id)
|
859
|
+
reloaded.phone_numbers.should eq(person.phone_numbers)
|
860
|
+
end
|
861
|
+
end
|
862
|
+
|
863
|
+
context "when appending a nil to the end of an embedded list" do
|
864
|
+
|
865
|
+
let(:person) do
|
866
|
+
Person.create! phone_numbers: []
|
867
|
+
end
|
868
|
+
|
869
|
+
before do
|
870
|
+
person.phone_numbers << home_phone
|
871
|
+
person.phone_numbers << office_phone
|
872
|
+
person.phone_numbers << nil
|
873
|
+
person.save!
|
874
|
+
end
|
875
|
+
|
876
|
+
it "ignores the nil and persist the remaining items" do
|
877
|
+
reloaded = Person.find(person.id)
|
878
|
+
reloaded.phone_numbers.should eq(person.phone_numbers)
|
879
|
+
end
|
880
|
+
end
|
881
|
+
end
|
882
|
+
end
|
883
|
+
|
884
|
+
context "when moving an embedded document from one parent to another" do
|
885
|
+
|
886
|
+
let!(:person_one) do
|
887
|
+
Person.create
|
888
|
+
end
|
889
|
+
|
890
|
+
let!(:person_two) do
|
891
|
+
Person.create
|
892
|
+
end
|
893
|
+
|
894
|
+
let!(:address) do
|
895
|
+
person_one.addresses.create(street: "Kudamm")
|
896
|
+
end
|
897
|
+
|
898
|
+
before do
|
899
|
+
person_two.addresses << address
|
900
|
+
end
|
901
|
+
|
902
|
+
it "adds the document to the new paarent" do
|
903
|
+
person_two.addresses.should eq([ address ])
|
904
|
+
end
|
905
|
+
|
906
|
+
it "sets the new parent on the document" do
|
907
|
+
address._parent.should eq(person_two)
|
908
|
+
end
|
909
|
+
|
910
|
+
context "when reloading the documents" do
|
911
|
+
|
912
|
+
before do
|
913
|
+
person_one.reload
|
914
|
+
person_two.reload
|
915
|
+
end
|
916
|
+
|
917
|
+
it "persists the change to the new parent" do
|
918
|
+
person_two.addresses.should eq([ address ])
|
919
|
+
end
|
920
|
+
|
921
|
+
it "keeps the address on the previous document" do
|
922
|
+
person_one.addresses.should eq([ address ])
|
923
|
+
end
|
924
|
+
end
|
925
|
+
end
|
926
|
+
|
927
|
+
context "when the relation has a default scope" do
|
928
|
+
|
929
|
+
let!(:person) do
|
930
|
+
Person.create
|
931
|
+
end
|
932
|
+
|
933
|
+
context "when the default scope is a sort" do
|
934
|
+
|
935
|
+
let(:cough) do
|
936
|
+
Symptom.new(name: "cough")
|
937
|
+
end
|
938
|
+
|
939
|
+
let(:headache) do
|
940
|
+
Symptom.new(name: "headache")
|
941
|
+
end
|
942
|
+
|
943
|
+
let(:nausea) do
|
944
|
+
Symptom.new(name: "nausea")
|
945
|
+
end
|
946
|
+
|
947
|
+
before do
|
948
|
+
person.symptoms.concat([ nausea, cough, headache ])
|
949
|
+
end
|
950
|
+
|
951
|
+
context "when accessing the relation" do
|
952
|
+
|
953
|
+
let(:symptoms) do
|
954
|
+
person.reload.symptoms
|
955
|
+
end
|
956
|
+
|
957
|
+
it "applies the default scope" do
|
958
|
+
symptoms.should eq([ cough, headache, nausea ])
|
959
|
+
end
|
960
|
+
end
|
961
|
+
|
962
|
+
context "when modifying the relation" do
|
963
|
+
|
964
|
+
let(:constipation) do
|
965
|
+
Symptom.new(name: "constipation")
|
966
|
+
end
|
967
|
+
|
968
|
+
before do
|
969
|
+
person.symptoms.push(constipation)
|
970
|
+
end
|
971
|
+
|
972
|
+
context "when reloading" do
|
973
|
+
|
974
|
+
let(:symptoms) do
|
975
|
+
person.reload.symptoms
|
976
|
+
end
|
977
|
+
|
978
|
+
it "applies the default scope" do
|
979
|
+
symptoms.should eq([ constipation, cough, headache, nausea ])
|
980
|
+
end
|
981
|
+
end
|
982
|
+
end
|
983
|
+
|
984
|
+
context "when unscoping the relation" do
|
985
|
+
|
986
|
+
let(:unscoped) do
|
987
|
+
person.reload.symptoms.unscoped
|
988
|
+
end
|
989
|
+
|
990
|
+
it "removes the default scope" do
|
991
|
+
unscoped.should eq([ nausea, cough, headache ])
|
992
|
+
end
|
993
|
+
end
|
994
|
+
end
|
995
|
+
end
|
996
|
+
|
997
|
+
context "when the embedded document has an array field" do
|
998
|
+
|
999
|
+
let!(:person) do
|
1000
|
+
Person.create
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
let!(:video) do
|
1004
|
+
person.videos.create
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
context "when saving the array on a persisted document" do
|
1008
|
+
|
1009
|
+
before do
|
1010
|
+
video.genres = [ "horror", "scifi" ]
|
1011
|
+
video.save
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
it "sets the value" do
|
1015
|
+
video.genres.should eq([ "horror", "scifi" ])
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
it "persists the value" do
|
1019
|
+
video.reload.genres.should eq([ "horror", "scifi" ])
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
context "when reloading the parent" do
|
1023
|
+
|
1024
|
+
let!(:loaded_person) do
|
1025
|
+
Person.find(person.id)
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
let!(:loaded_video) do
|
1029
|
+
loaded_person.videos.find(video.id)
|
1030
|
+
end
|
1031
|
+
|
1032
|
+
context "when writing a new array value" do
|
1033
|
+
|
1034
|
+
before do
|
1035
|
+
loaded_video.genres = [ "comedy" ]
|
1036
|
+
loaded_video.save
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
it "sets the new value" do
|
1040
|
+
loaded_video.genres.should eq([ "comedy" ])
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
it "persists the new value" do
|
1044
|
+
loaded_video.reload.genres.should eq([ "comedy" ])
|
1045
|
+
end
|
1046
|
+
end
|
1047
|
+
end
|
1048
|
+
end
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
context "when adding a document" do
|
1052
|
+
|
1053
|
+
let(:person) do
|
1054
|
+
Person.new
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
let(:address_one) do
|
1058
|
+
Address.new(street: "hobrecht")
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
let(:first_add) do
|
1062
|
+
person.addresses.push(address_one)
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
context "when chaining a second add" do
|
1066
|
+
|
1067
|
+
let(:address_two) do
|
1068
|
+
Address.new(street: "friedel")
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
let(:result) do
|
1072
|
+
first_add.push(address_two)
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
it "adds both documents" do
|
1076
|
+
result.should eq([ address_one, address_two ])
|
1077
|
+
end
|
1078
|
+
end
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
context "when using dot notation in a criteria" do
|
1082
|
+
|
1083
|
+
let(:person) do
|
1084
|
+
Person.new
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
let!(:address) do
|
1088
|
+
person.addresses.build(street: "hobrecht")
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
let!(:location) do
|
1092
|
+
address.locations.build(number: 5)
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
let(:criteria) do
|
1096
|
+
person.addresses.where("locations.number" => { "$gt" => 3 })
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
it "allows the dot notation criteria" do
|
1100
|
+
criteria.should eq([ address ])
|
1101
|
+
end
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
context "when updating multiple levels in one update" do
|
1105
|
+
|
1106
|
+
let!(:person) do
|
1107
|
+
Person.create(
|
1108
|
+
addresses: [
|
1109
|
+
{ locations: [{ name: "home" }]}
|
1110
|
+
]
|
1111
|
+
)
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
context "when updating with hashes" do
|
1115
|
+
|
1116
|
+
let(:from_db) do
|
1117
|
+
Person.find(person.id)
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
before do
|
1121
|
+
from_db.update_attributes(
|
1122
|
+
addresses: [
|
1123
|
+
{ locations: [{ name: "work" }]}
|
1124
|
+
]
|
1125
|
+
)
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
let(:updated) do
|
1129
|
+
person.reload.addresses.first.locations.first
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
it "updates the nested document" do
|
1133
|
+
updated.name.should eq("work")
|
1134
|
+
end
|
1135
|
+
end
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
context "when pushing with a before_add callback" do
|
1139
|
+
|
1140
|
+
let(:artist) do
|
1141
|
+
Artist.new
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
let(:song) do
|
1145
|
+
Song.new
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
context "when no errors are raised" do
|
1149
|
+
|
1150
|
+
before do
|
1151
|
+
artist.songs << song
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
it "executes the callback" do
|
1155
|
+
artist.before_add_called.should eq true
|
1156
|
+
end
|
1157
|
+
|
1158
|
+
it "executes the callback as proc" do
|
1159
|
+
song.before_add_called.should eq true
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
it "adds the document to the relation" do
|
1163
|
+
artist.songs.should eq([song])
|
1164
|
+
end
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
context "with errors" do
|
1168
|
+
|
1169
|
+
before do
|
1170
|
+
artist.should_receive(:before_add_song).and_raise
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
it "does not add the document to the relation" do
|
1174
|
+
expect {
|
1175
|
+
artist.songs << song
|
1176
|
+
}.to raise_error
|
1177
|
+
artist.songs.should be_empty
|
1178
|
+
end
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
context "when pushing with an after_add callback" do
|
1183
|
+
|
1184
|
+
let(:artist) do
|
1185
|
+
Artist.new
|
1186
|
+
end
|
1187
|
+
|
1188
|
+
let(:label) do
|
1189
|
+
Label.new
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
it "executes the callback" do
|
1193
|
+
artist.labels << label
|
1194
|
+
artist.after_add_called.should eq true
|
1195
|
+
end
|
1196
|
+
|
1197
|
+
context "when errors are raised" do
|
1198
|
+
|
1199
|
+
before do
|
1200
|
+
artist.should_receive(:after_add_label).and_raise
|
1201
|
+
end
|
1202
|
+
|
1203
|
+
it "adds the document to the relation" do
|
1204
|
+
expect {
|
1205
|
+
artist.labels << label
|
1206
|
+
}.to raise_error
|
1207
|
+
artist.labels.should eq([ label ])
|
1208
|
+
end
|
1209
|
+
end
|
1210
|
+
end
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
end
|