mongoid 8.1.3 → 8.1.11
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/Rakefile +43 -45
- data/lib/mongoid/association/accessors.rb +5 -1
- data/lib/mongoid/association/eager_loadable.rb +3 -0
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +18 -3
- data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +21 -4
- data/lib/mongoid/association/referenced/has_many/proxy.rb +11 -2
- data/lib/mongoid/atomic.rb +9 -7
- data/lib/mongoid/attributes/readonly.rb +8 -3
- data/lib/mongoid/contextual/mongo.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -1
- data/lib/mongoid/criteria/queryable/selectable.rb +1 -1
- data/lib/mongoid/document.rb +8 -1
- data/lib/mongoid/equality.rb +1 -0
- data/lib/mongoid/extensions/hash.rb +4 -4
- data/lib/mongoid/fields.rb +13 -8
- data/lib/mongoid/interceptable.rb +6 -7
- data/lib/mongoid/matcher.rb +15 -1
- data/lib/mongoid/serializable.rb +7 -7
- data/lib/mongoid/timestamps/created.rb +8 -1
- data/lib/mongoid/touchable.rb +1 -1
- data/lib/mongoid/traversable.rb +36 -1
- data/lib/mongoid/validatable/associated.rb +98 -17
- data/lib/mongoid/validatable/macros.rb +15 -0
- data/lib/mongoid/validatable/numericality.rb +19 -0
- data/lib/mongoid/validatable.rb +9 -0
- data/lib/mongoid/version.rb +5 -1
- data/spec/integration/app_spec.rb +24 -5
- data/spec/integration/associations/embeds_one_spec.rb +25 -5
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +40 -0
- data/spec/mongoid/association/eager_spec.rb +24 -2
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +35 -0
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +4 -0
- data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +4 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +28 -37
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +42 -0
- data/spec/mongoid/attributes/readonly_spec.rb +19 -0
- data/spec/mongoid/attributes_spec.rb +16 -0
- data/spec/mongoid/contextual/mongo_spec.rb +78 -3
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +29 -0
- data/spec/mongoid/document_spec.rb +27 -0
- data/spec/mongoid/equality_spec.rb +6 -0
- data/spec/mongoid/fields_spec.rb +3 -3
- data/spec/mongoid/interceptable_spec.rb +80 -0
- data/spec/mongoid/interceptable_spec_models.rb +47 -111
- data/spec/mongoid/serializable_spec.rb +16 -9
- data/spec/mongoid/timestamps/created_spec.rb +23 -0
- data/spec/mongoid/validatable/associated_spec.rb +27 -34
- data/spec/mongoid/validatable/numericality_spec.rb +16 -0
- data/spec/shared/lib/mrss/docker_runner.rb +1 -2
- data/spec/shared/lib/mrss/release/candidate.rb +281 -0
- data/spec/shared/lib/mrss/release/product_data.rb +144 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +1 -1
- data/spec/shared/lib/tasks/candidate.rake +64 -0
- data/spec/shared/share/Dockerfile.erb +15 -85
- data/spec/shared/shlib/distro.sh +10 -0
- data/spec/shared/shlib/server.sh +33 -26
- data/spec/shared/shlib/set_env.sh +9 -68
- data/spec/support/expectations.rb +20 -17
- data/spec/support/models/band.rb +1 -0
- data/spec/support/models/lat_lng.rb +6 -0
- data/spec/support/models/name.rb +10 -0
- metadata +15 -38
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
|
@@ -265,7 +265,26 @@ describe Mongoid::Attributes::Readonly do
|
|
|
265
265
|
expect(child.mother).to be_nil
|
|
266
266
|
end
|
|
267
267
|
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
context "when a subclass inherits readonly fields" do
|
|
271
|
+
let(:attributes) do
|
|
272
|
+
[:title, :terms]
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
before do
|
|
276
|
+
class OldPerson < Person
|
|
277
|
+
attr_readonly :age
|
|
278
|
+
end
|
|
279
|
+
end
|
|
268
280
|
|
|
281
|
+
it "ensures subclass inherits the readonly attributes from parent" do
|
|
282
|
+
expect(OldPerson.readonly_attributes.to_a).to include("title","terms")
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it "ensures subclass does not modify parent's readonly attributes" do
|
|
286
|
+
expect(Person.readonly_attributes.to_a).not_to include("age")
|
|
287
|
+
end
|
|
269
288
|
end
|
|
270
289
|
end
|
|
271
290
|
end
|
|
@@ -288,6 +288,22 @@ describe Mongoid::Attributes do
|
|
|
288
288
|
end
|
|
289
289
|
end
|
|
290
290
|
|
|
291
|
+
context "when given nil" do
|
|
292
|
+
|
|
293
|
+
it "returns nil" do
|
|
294
|
+
expect(person[nil]).to be nil
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
context "when given an empty string" do
|
|
300
|
+
|
|
301
|
+
it "returns nil" do
|
|
302
|
+
expect(person[""]).to be nil
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
end
|
|
306
|
+
|
|
291
307
|
context "when the field was not explicitly defined" do
|
|
292
308
|
|
|
293
309
|
context "when excluding with only and the field was not excluded" do
|
|
@@ -3387,6 +3387,12 @@ describe Mongoid::Contextual::Mongo do
|
|
|
3387
3387
|
it "limits the results" do
|
|
3388
3388
|
expect(context.skip(1).entries).to eq([ new_order ])
|
|
3389
3389
|
end
|
|
3390
|
+
|
|
3391
|
+
context "with #last" do
|
|
3392
|
+
it "returns the nth from last element" do
|
|
3393
|
+
expect(context.skip(1).last).to eq(depeche_mode)
|
|
3394
|
+
end
|
|
3395
|
+
end
|
|
3390
3396
|
end
|
|
3391
3397
|
|
|
3392
3398
|
describe "#sort" do
|
|
@@ -3746,6 +3752,75 @@ describe Mongoid::Contextual::Mongo do
|
|
|
3746
3752
|
expect(new_order.reload.genres).to eq(["electronic"])
|
|
3747
3753
|
end
|
|
3748
3754
|
end
|
|
3755
|
+
|
|
3756
|
+
context "when operation is $pull" do
|
|
3757
|
+
context "when pulling single element" do
|
|
3758
|
+
|
|
3759
|
+
before do
|
|
3760
|
+
depeche_mode.update_attribute(:genres, ["electronic", "pop"])
|
|
3761
|
+
new_order.update_attribute(:genres, ["electronic", "pop"])
|
|
3762
|
+
context.update_all("$pull" => { genres: "electronic" })
|
|
3763
|
+
end
|
|
3764
|
+
|
|
3765
|
+
it "updates the first matching document" do
|
|
3766
|
+
expect(depeche_mode.reload.genres).to eq(["pop"])
|
|
3767
|
+
end
|
|
3768
|
+
|
|
3769
|
+
it "updates the last matching document" do
|
|
3770
|
+
expect(new_order.reload.genres).to eq(["pop"])
|
|
3771
|
+
end
|
|
3772
|
+
end
|
|
3773
|
+
|
|
3774
|
+
context "when pulling based on condition" do
|
|
3775
|
+
before do
|
|
3776
|
+
depeche_mode.update_attribute(:genres, ["electronic", "pop", "dance"])
|
|
3777
|
+
new_order.update_attribute(:genres, ["electronic", "pop", "dance"])
|
|
3778
|
+
context.update_all("$pull" => { genres: { '$in' => ["electronic", "pop"] } })
|
|
3779
|
+
end
|
|
3780
|
+
|
|
3781
|
+
it "updates the first matching document" do
|
|
3782
|
+
expect(depeche_mode.reload.genres).to eq(["dance"])
|
|
3783
|
+
end
|
|
3784
|
+
|
|
3785
|
+
it "updates the last matching document" do
|
|
3786
|
+
expect(new_order.reload.genres).to eq(["dance"])
|
|
3787
|
+
end
|
|
3788
|
+
end
|
|
3789
|
+
end
|
|
3790
|
+
|
|
3791
|
+
context "when operation is $pop" do
|
|
3792
|
+
|
|
3793
|
+
before do
|
|
3794
|
+
depeche_mode.update_attribute(:genres, ["pop", "electronic"])
|
|
3795
|
+
end
|
|
3796
|
+
|
|
3797
|
+
it "removes first element in array" do
|
|
3798
|
+
context.update_all("$pop" => { genres: -1 })
|
|
3799
|
+
expect(depeche_mode.reload.genres).to eq(["electronic"])
|
|
3800
|
+
end
|
|
3801
|
+
|
|
3802
|
+
it "removes last element in array" do
|
|
3803
|
+
context.update_all("$pop" => { genres: 1 })
|
|
3804
|
+
expect(depeche_mode.reload.genres).to eq(["pop"])
|
|
3805
|
+
end
|
|
3806
|
+
end
|
|
3807
|
+
|
|
3808
|
+
context "when operation is $pullAll" do
|
|
3809
|
+
|
|
3810
|
+
before do
|
|
3811
|
+
depeche_mode.update_attribute(:genres, ["pop", "electronic", "dance", "pop" ])
|
|
3812
|
+
new_order.update_attribute(:genres, ["electronic", "pop", "electronic", "dance"])
|
|
3813
|
+
context.update_all("$pullAll" => { genres: ["pop", "electronic"] })
|
|
3814
|
+
end
|
|
3815
|
+
|
|
3816
|
+
it "updates the first matching document" do
|
|
3817
|
+
expect(depeche_mode.reload.genres).to eq(["dance"])
|
|
3818
|
+
end
|
|
3819
|
+
|
|
3820
|
+
it "updates the last matching document" do
|
|
3821
|
+
expect(new_order.reload.genres).to eq(["dance"])
|
|
3822
|
+
end
|
|
3823
|
+
end
|
|
3749
3824
|
end
|
|
3750
3825
|
|
|
3751
3826
|
context 'when using aliased field names' do
|
|
@@ -3765,15 +3840,15 @@ describe Mongoid::Contextual::Mongo do
|
|
|
3765
3840
|
context "when the attributes must be mongoized" do
|
|
3766
3841
|
|
|
3767
3842
|
before do
|
|
3768
|
-
context.update_all("$set" => {
|
|
3843
|
+
context.update_all("$set" => { location: LatLng.new(52.30, 13.25) })
|
|
3769
3844
|
end
|
|
3770
3845
|
|
|
3771
3846
|
it "updates the first matching document" do
|
|
3772
|
-
expect(depeche_mode.reload.
|
|
3847
|
+
expect(depeche_mode.reload.location).to eq(LatLng.new(52.30, 13.25))
|
|
3773
3848
|
end
|
|
3774
3849
|
|
|
3775
3850
|
it "updates the last matching document" do
|
|
3776
|
-
expect(new_order.reload.
|
|
3851
|
+
expect(new_order.reload.location).to eq(LatLng.new(52.30, 13.25))
|
|
3777
3852
|
end
|
|
3778
3853
|
end
|
|
3779
3854
|
end
|
|
@@ -2059,6 +2059,35 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
|
2059
2059
|
end
|
|
2060
2060
|
end
|
|
2061
2061
|
|
|
2062
|
+
describe "#not" do
|
|
2063
|
+
context "when negating a criterion" do
|
|
2064
|
+
let(:selection) do
|
|
2065
|
+
query.not(field: /value/)
|
|
2066
|
+
end
|
|
2067
|
+
|
|
2068
|
+
it "adds the $not selector" do
|
|
2069
|
+
expect(selection.selector).to eq({
|
|
2070
|
+
"field" => { "$not" => /value/ }
|
|
2071
|
+
})
|
|
2072
|
+
end
|
|
2073
|
+
|
|
2074
|
+
it "returns a cloned query" do
|
|
2075
|
+
expect(selection).to_not equal(query)
|
|
2076
|
+
end
|
|
2077
|
+
|
|
2078
|
+
context "when toggling negation state" do
|
|
2079
|
+
it "negates the negating value" do
|
|
2080
|
+
expect(query.negating).to be_nil
|
|
2081
|
+
negated_query = query.not
|
|
2082
|
+
expect(negated_query.negating).to be true
|
|
2083
|
+
double_negated_query = negated_query.not
|
|
2084
|
+
expect(double_negated_query.negating).to be false
|
|
2085
|
+
end
|
|
2086
|
+
end
|
|
2087
|
+
end
|
|
2088
|
+
end
|
|
2089
|
+
|
|
2090
|
+
|
|
2062
2091
|
describe Symbol do
|
|
2063
2092
|
|
|
2064
2093
|
describe "#all" do
|
|
@@ -591,6 +591,33 @@ describe Mongoid::Document do
|
|
|
591
591
|
expect(person.as_document["addresses"].first).to have_key(:locations)
|
|
592
592
|
end
|
|
593
593
|
|
|
594
|
+
context 'when modifying the returned object' do
|
|
595
|
+
let(:record) do
|
|
596
|
+
RootCategory.create(categories: [{ name: 'tests' }]).reload
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
shared_examples_for 'an object with protected internal state' do
|
|
600
|
+
it 'does not expose internal state' do
|
|
601
|
+
before_change = record.as_document.dup
|
|
602
|
+
record.categories.first.name = 'things'
|
|
603
|
+
after_change = record.as_document
|
|
604
|
+
expect(before_change['categories'].first['name']).not_to eq('things')
|
|
605
|
+
end
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
context 'when legacy_attributes is true' do
|
|
609
|
+
config_override :legacy_attributes, true
|
|
610
|
+
|
|
611
|
+
it_behaves_like 'an object with protected internal state'
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
context 'when legacy_attributes is false' do
|
|
615
|
+
config_override :legacy_attributes, false
|
|
616
|
+
|
|
617
|
+
it_behaves_like 'an object with protected internal state'
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
|
|
594
621
|
context "with relation define store_as option in embeded_many" do
|
|
595
622
|
|
|
596
623
|
let!(:phone) do
|
|
@@ -291,6 +291,12 @@ describe Mongoid::Equality do
|
|
|
291
291
|
it "compares based on the document id" do
|
|
292
292
|
expect(first <=> second).to eq(-1)
|
|
293
293
|
end
|
|
294
|
+
|
|
295
|
+
it "doesn't break if one isn't a document" do
|
|
296
|
+
expect do
|
|
297
|
+
first <=> "Foo"
|
|
298
|
+
end.to_not raise_error
|
|
299
|
+
end
|
|
294
300
|
end
|
|
295
301
|
|
|
296
302
|
describe "#eql?" do
|
data/spec/mongoid/fields_spec.rb
CHANGED
|
@@ -1845,12 +1845,12 @@ describe Mongoid::Fields do
|
|
|
1845
1845
|
|
|
1846
1846
|
context 'given nil' do
|
|
1847
1847
|
subject { Person.database_field_name(nil) }
|
|
1848
|
-
it { is_expected.to eq
|
|
1848
|
+
it { is_expected.to eq '' }
|
|
1849
1849
|
end
|
|
1850
1850
|
|
|
1851
1851
|
context 'given an empty String' do
|
|
1852
1852
|
subject { Person.database_field_name('') }
|
|
1853
|
-
it { is_expected.to eq
|
|
1853
|
+
it { is_expected.to eq '' }
|
|
1854
1854
|
end
|
|
1855
1855
|
|
|
1856
1856
|
context 'given a String' do
|
|
@@ -1869,7 +1869,7 @@ describe Mongoid::Fields do
|
|
|
1869
1869
|
|
|
1870
1870
|
context 'given nil' do
|
|
1871
1871
|
subject { Person.database_field_name(nil) }
|
|
1872
|
-
it { is_expected.to eq
|
|
1872
|
+
it { is_expected.to eq '' }
|
|
1873
1873
|
end
|
|
1874
1874
|
|
|
1875
1875
|
context 'given an empty String' do
|
|
@@ -388,6 +388,86 @@ describe Mongoid::Interceptable do
|
|
|
388
388
|
end
|
|
389
389
|
end
|
|
390
390
|
end
|
|
391
|
+
|
|
392
|
+
context 'with embedded grandchildren' do
|
|
393
|
+
IS = InterceptableSpec
|
|
394
|
+
|
|
395
|
+
config_override :prevent_multiple_calls_of_embedded_callbacks, true
|
|
396
|
+
|
|
397
|
+
context 'when creating' do
|
|
398
|
+
let(:registry) { IS::CallbackRegistry.new(only: %i[ before_save ]) }
|
|
399
|
+
|
|
400
|
+
let(:expected_calls) do
|
|
401
|
+
[
|
|
402
|
+
# the parent
|
|
403
|
+
[ IS::CbParent, :before_save ],
|
|
404
|
+
|
|
405
|
+
# the immediate child of the parent
|
|
406
|
+
[ IS::CbCascadedNode, :before_save ],
|
|
407
|
+
|
|
408
|
+
# the grandchild of the parent
|
|
409
|
+
[ IS::CbCascadedNode, :before_save ],
|
|
410
|
+
]
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
let!(:parent) do
|
|
414
|
+
parent = IS::CbParent.new(registry)
|
|
415
|
+
child = IS::CbCascadedNode.new(registry)
|
|
416
|
+
grandchild = IS::CbCascadedNode.new(registry)
|
|
417
|
+
|
|
418
|
+
child.cb_cascaded_nodes = [ grandchild ]
|
|
419
|
+
parent.cb_cascaded_nodes = [ child ]
|
|
420
|
+
|
|
421
|
+
parent.tap(&:save)
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
it 'should cascade callbacks to grandchildren' do
|
|
425
|
+
expect(registry.calls).to be == expected_calls
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
context 'when updating' do
|
|
430
|
+
let(:registry) { IS::CallbackRegistry.new(only: %i[ before_update ]) }
|
|
431
|
+
|
|
432
|
+
let(:expected_calls) do
|
|
433
|
+
[
|
|
434
|
+
# the parent
|
|
435
|
+
[ IS::CbParent, :before_update ],
|
|
436
|
+
|
|
437
|
+
# the immediate child of the parent
|
|
438
|
+
[ IS::CbCascadedNode, :before_update ],
|
|
439
|
+
|
|
440
|
+
# the grandchild of the parent
|
|
441
|
+
[ IS::CbCascadedNode, :before_update ],
|
|
442
|
+
]
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
let!(:parent) do
|
|
446
|
+
parent = IS::CbParent.new(nil)
|
|
447
|
+
child = IS::CbCascadedNode.new(nil)
|
|
448
|
+
grandchild = IS::CbCascadedNode.new(nil)
|
|
449
|
+
|
|
450
|
+
child.cb_cascaded_nodes = [ grandchild ]
|
|
451
|
+
parent.cb_cascaded_nodes = [ child ]
|
|
452
|
+
|
|
453
|
+
parent.save
|
|
454
|
+
|
|
455
|
+
parent.callback_registry = registry
|
|
456
|
+
child.callback_registry = registry
|
|
457
|
+
grandchild.callback_registry = registry
|
|
458
|
+
|
|
459
|
+
parent.name = 'updated'
|
|
460
|
+
child.name = 'updated'
|
|
461
|
+
grandchild.name = 'updated'
|
|
462
|
+
|
|
463
|
+
parent.tap(&:save)
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
it 'should cascade callbacks to grandchildren' do
|
|
467
|
+
expect(registry.calls).to be == expected_calls
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
end
|
|
391
471
|
end
|
|
392
472
|
|
|
393
473
|
describe ".before_destroy" do
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
module InterceptableSpec
|
|
2
2
|
class CallbackRegistry
|
|
3
|
-
def initialize
|
|
3
|
+
def initialize(only: [])
|
|
4
4
|
@calls = []
|
|
5
|
+
@only = only
|
|
5
6
|
end
|
|
6
7
|
|
|
7
8
|
def record_call(cls, cb)
|
|
9
|
+
return unless @only.empty? || @only.any? { |pat| pat == cb }
|
|
8
10
|
@calls << [cls, cb]
|
|
9
11
|
end
|
|
10
12
|
|
|
@@ -15,6 +17,8 @@ module InterceptableSpec
|
|
|
15
17
|
extend ActiveSupport::Concern
|
|
16
18
|
|
|
17
19
|
included do
|
|
20
|
+
field :name, type: String
|
|
21
|
+
|
|
18
22
|
%i(
|
|
19
23
|
validation save create update
|
|
20
24
|
).each do |what|
|
|
@@ -34,196 +38,128 @@ module InterceptableSpec
|
|
|
34
38
|
end
|
|
35
39
|
end
|
|
36
40
|
end
|
|
37
|
-
end
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
include Mongoid::Document
|
|
41
|
-
|
|
42
|
-
has_one :child, autosave: true, class_name: "CbHasOneChild", inverse_of: :parent
|
|
42
|
+
attr_accessor :callback_registry
|
|
43
43
|
|
|
44
|
-
def initialize(callback_registry)
|
|
44
|
+
def initialize(callback_registry, *args, **kwargs)
|
|
45
45
|
@callback_registry = callback_registry
|
|
46
|
-
super()
|
|
46
|
+
super(*args, **kwargs)
|
|
47
47
|
end
|
|
48
|
+
end
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
module RootInsertable
|
|
51
51
|
def insert_as_root
|
|
52
52
|
@callback_registry&.record_call(self.class, :insert_into_database)
|
|
53
53
|
super
|
|
54
54
|
end
|
|
55
|
+
end
|
|
55
56
|
|
|
57
|
+
class CbHasOneParent
|
|
58
|
+
include Mongoid::Document
|
|
56
59
|
include CallbackTracking
|
|
60
|
+
include RootInsertable
|
|
61
|
+
|
|
62
|
+
has_one :child, autosave: true, class_name: "CbHasOneChild", inverse_of: :parent
|
|
57
63
|
end
|
|
58
64
|
|
|
59
65
|
class CbHasOneChild
|
|
60
66
|
include Mongoid::Document
|
|
67
|
+
include CallbackTracking
|
|
61
68
|
|
|
62
69
|
belongs_to :parent, class_name: "CbHasOneParent", inverse_of: :child
|
|
63
|
-
|
|
64
|
-
def initialize(callback_registry)
|
|
65
|
-
@callback_registry = callback_registry
|
|
66
|
-
super()
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
attr_accessor :callback_registry
|
|
70
|
-
|
|
71
|
-
include CallbackTracking
|
|
72
70
|
end
|
|
73
71
|
|
|
74
72
|
class CbHasManyParent
|
|
75
73
|
include Mongoid::Document
|
|
74
|
+
include CallbackTracking
|
|
75
|
+
include RootInsertable
|
|
76
76
|
|
|
77
77
|
has_many :children, autosave: true, class_name: "CbHasManyChild", inverse_of: :parent
|
|
78
|
-
|
|
79
|
-
def initialize(callback_registry)
|
|
80
|
-
@callback_registry = callback_registry
|
|
81
|
-
super()
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
attr_accessor :callback_registry
|
|
85
|
-
|
|
86
|
-
def insert_as_root
|
|
87
|
-
@callback_registry&.record_call(self.class, :insert_into_database)
|
|
88
|
-
super
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
include CallbackTracking
|
|
92
78
|
end
|
|
93
79
|
|
|
94
80
|
class CbHasManyChild
|
|
95
81
|
include Mongoid::Document
|
|
82
|
+
include CallbackTracking
|
|
96
83
|
|
|
97
84
|
belongs_to :parent, class_name: "CbHasManyParent", inverse_of: :children
|
|
98
|
-
|
|
99
|
-
def initialize(callback_registry)
|
|
100
|
-
@callback_registry = callback_registry
|
|
101
|
-
super()
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
attr_accessor :callback_registry
|
|
105
|
-
|
|
106
|
-
include CallbackTracking
|
|
107
85
|
end
|
|
108
86
|
|
|
109
87
|
class CbEmbedsOneParent
|
|
110
88
|
include Mongoid::Document
|
|
89
|
+
include CallbackTracking
|
|
90
|
+
include RootInsertable
|
|
111
91
|
|
|
112
92
|
field :name
|
|
113
93
|
|
|
114
94
|
embeds_one :child, cascade_callbacks: true, class_name: "CbEmbedsOneChild", inverse_of: :parent
|
|
115
|
-
|
|
116
|
-
def initialize(callback_registry)
|
|
117
|
-
@callback_registry = callback_registry
|
|
118
|
-
super()
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
attr_accessor :callback_registry
|
|
122
|
-
|
|
123
|
-
def insert_as_root
|
|
124
|
-
@callback_registry&.record_call(self.class, :insert_into_database)
|
|
125
|
-
super
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
include CallbackTracking
|
|
129
95
|
end
|
|
130
96
|
|
|
131
97
|
class CbEmbedsOneChild
|
|
132
98
|
include Mongoid::Document
|
|
99
|
+
include CallbackTracking
|
|
133
100
|
|
|
134
101
|
field :age
|
|
135
102
|
|
|
136
103
|
embedded_in :parent, class_name: "CbEmbedsOneParent", inverse_of: :child
|
|
137
|
-
|
|
138
|
-
def initialize(callback_registry)
|
|
139
|
-
@callback_registry = callback_registry
|
|
140
|
-
super()
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
attr_accessor :callback_registry
|
|
144
|
-
|
|
145
|
-
include CallbackTracking
|
|
146
104
|
end
|
|
147
105
|
|
|
148
106
|
class CbEmbedsManyParent
|
|
149
107
|
include Mongoid::Document
|
|
108
|
+
include CallbackTracking
|
|
109
|
+
include RootInsertable
|
|
150
110
|
|
|
151
111
|
embeds_many :children, cascade_callbacks: true, class_name: "CbEmbedsManyChild", inverse_of: :parent
|
|
152
|
-
|
|
153
|
-
def initialize(callback_registry)
|
|
154
|
-
@callback_registry = callback_registry
|
|
155
|
-
super()
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
attr_accessor :callback_registry
|
|
159
|
-
|
|
160
|
-
def insert_as_root
|
|
161
|
-
@callback_registry&.record_call(self.class, :insert_into_database)
|
|
162
|
-
super
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
include CallbackTracking
|
|
166
112
|
end
|
|
167
113
|
|
|
168
114
|
class CbEmbedsManyChild
|
|
169
115
|
include Mongoid::Document
|
|
116
|
+
include CallbackTracking
|
|
170
117
|
|
|
171
118
|
embedded_in :parent, class_name: "CbEmbedsManyParent", inverse_of: :children
|
|
172
|
-
|
|
173
|
-
def initialize(callback_registry)
|
|
174
|
-
@callback_registry = callback_registry
|
|
175
|
-
super()
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
attr_accessor :callback_registry
|
|
179
|
-
|
|
180
|
-
include CallbackTracking
|
|
181
119
|
end
|
|
182
120
|
|
|
183
121
|
class CbParent
|
|
184
122
|
include Mongoid::Document
|
|
185
|
-
|
|
186
|
-
def initialize(callback_registry)
|
|
187
|
-
@callback_registry = callback_registry
|
|
188
|
-
super()
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
attr_accessor :callback_registry
|
|
123
|
+
include CallbackTracking
|
|
192
124
|
|
|
193
125
|
embeds_many :cb_children
|
|
194
126
|
embeds_many :cb_cascaded_children, cascade_callbacks: true
|
|
195
|
-
|
|
196
|
-
include CallbackTracking
|
|
127
|
+
embeds_many :cb_cascaded_nodes, cascade_callbacks: true, as: :parent
|
|
197
128
|
end
|
|
198
129
|
|
|
199
130
|
class CbChild
|
|
200
131
|
include Mongoid::Document
|
|
132
|
+
include CallbackTracking
|
|
201
133
|
|
|
202
134
|
embedded_in :cb_parent
|
|
203
|
-
|
|
204
|
-
def initialize(callback_registry, options)
|
|
205
|
-
@callback_registry = callback_registry
|
|
206
|
-
super(options)
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
attr_accessor :callback_registry
|
|
210
|
-
|
|
211
|
-
include CallbackTracking
|
|
212
135
|
end
|
|
213
136
|
|
|
214
137
|
class CbCascadedChild
|
|
215
138
|
include Mongoid::Document
|
|
139
|
+
include CallbackTracking
|
|
216
140
|
|
|
217
141
|
embedded_in :cb_parent
|
|
218
142
|
|
|
219
|
-
|
|
220
|
-
@callback_registry = callback_registry
|
|
221
|
-
super(options)
|
|
222
|
-
end
|
|
143
|
+
before_save :test_mongoid_state
|
|
223
144
|
|
|
224
|
-
|
|
145
|
+
private
|
|
146
|
+
|
|
147
|
+
# Helps test that cascading child callbacks have access to the Mongoid
|
|
148
|
+
# state objects; if the implementation uses fiber-local (instead of truly
|
|
149
|
+
# thread-local) variables, the related tests will fail because the
|
|
150
|
+
# cascading child callbacks use fibers to linearize the recursion.
|
|
151
|
+
def test_mongoid_state
|
|
152
|
+
Mongoid::Threaded.stack('interceptable').push(self)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
225
155
|
|
|
156
|
+
class CbCascadedNode
|
|
157
|
+
include Mongoid::Document
|
|
226
158
|
include CallbackTracking
|
|
159
|
+
|
|
160
|
+
embedded_in :parent, polymorphic: true
|
|
161
|
+
|
|
162
|
+
embeds_many :cb_cascaded_nodes, cascade_callbacks: true, as: :parent
|
|
227
163
|
end
|
|
228
164
|
end
|
|
229
165
|
|
|
@@ -510,13 +510,15 @@ describe Mongoid::Serializable do
|
|
|
510
510
|
end
|
|
511
511
|
|
|
512
512
|
it "includes the first relation" do
|
|
513
|
-
expect(relation_hash[0]).to include
|
|
513
|
+
expect(relation_hash[0]).to include(
|
|
514
514
|
{ "_id" => "kudamm", "street" => "Kudamm" }
|
|
515
|
+
)
|
|
515
516
|
end
|
|
516
517
|
|
|
517
518
|
it "includes the second relation" do
|
|
518
|
-
expect(relation_hash[1]).to include
|
|
519
|
+
expect(relation_hash[1]).to include(
|
|
519
520
|
{ "_id" => "tauentzienstr", "street" => "Tauentzienstr" }
|
|
521
|
+
)
|
|
520
522
|
end
|
|
521
523
|
end
|
|
522
524
|
|
|
@@ -527,13 +529,15 @@ describe Mongoid::Serializable do
|
|
|
527
529
|
end
|
|
528
530
|
|
|
529
531
|
it "includes the first relation" do
|
|
530
|
-
expect(relation_hash[0]).to include
|
|
532
|
+
expect(relation_hash[0]).to include(
|
|
531
533
|
{ "_id" => "kudamm", "street" => "Kudamm" }
|
|
534
|
+
)
|
|
532
535
|
end
|
|
533
536
|
|
|
534
537
|
it "includes the second relation" do
|
|
535
|
-
expect(relation_hash[1]).to include
|
|
538
|
+
expect(relation_hash[1]).to include(
|
|
536
539
|
{ "_id" => "tauentzienstr", "street" => "Tauentzienstr" }
|
|
540
|
+
)
|
|
537
541
|
end
|
|
538
542
|
end
|
|
539
543
|
|
|
@@ -652,8 +656,9 @@ describe Mongoid::Serializable do
|
|
|
652
656
|
end
|
|
653
657
|
|
|
654
658
|
it "includes the specified relation" do
|
|
655
|
-
expect(relation_hash).to include
|
|
656
|
-
{ "_id" => "
|
|
659
|
+
expect(relation_hash).to include(
|
|
660
|
+
{ "_id" => "Leo-Marvin", "first_name" => "Leo", "last_name" => "Marvin" }
|
|
661
|
+
)
|
|
657
662
|
end
|
|
658
663
|
end
|
|
659
664
|
|
|
@@ -664,8 +669,9 @@ describe Mongoid::Serializable do
|
|
|
664
669
|
end
|
|
665
670
|
|
|
666
671
|
it "includes the specified relation" do
|
|
667
|
-
expect(relation_hash).to include
|
|
668
|
-
{ "_id" => "
|
|
672
|
+
expect(relation_hash).to include(
|
|
673
|
+
{ "_id" => "Leo-Marvin", "first_name" => "Leo", "last_name" => "Marvin" }
|
|
674
|
+
)
|
|
669
675
|
end
|
|
670
676
|
end
|
|
671
677
|
|
|
@@ -676,8 +682,9 @@ describe Mongoid::Serializable do
|
|
|
676
682
|
end
|
|
677
683
|
|
|
678
684
|
it "includes the specified relation sans exceptions" do
|
|
679
|
-
expect(relation_hash).to include
|
|
685
|
+
expect(relation_hash).to include(
|
|
680
686
|
{ "first_name" => "Leo", "last_name" => "Marvin" }
|
|
687
|
+
)
|
|
681
688
|
end
|
|
682
689
|
end
|
|
683
690
|
end
|