mongoid 7.0.3 → 7.0.8
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
- checksums.yaml.gz.sig +2 -0
- data.tar.gz.sig +1 -0
- data/LICENSE +1 -0
- data/README.md +3 -2
- data/Rakefile +12 -0
- data/lib/mongoid.rb +2 -1
- data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
- data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
- data/lib/mongoid/association/proxy.rb +1 -1
- data/lib/mongoid/association/relatable.rb +23 -21
- data/lib/mongoid/atomic.rb +13 -3
- data/lib/mongoid/atomic/paths/embedded.rb +1 -1
- data/lib/mongoid/attributes.rb +28 -20
- data/lib/mongoid/attributes/dynamic.rb +15 -14
- data/lib/mongoid/config/environment.rb +21 -8
- data/lib/mongoid/copyable.rb +5 -1
- data/lib/mongoid/criteria.rb +7 -1
- data/lib/mongoid/criteria/modifiable.rb +13 -2
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
- data/lib/mongoid/criteria/queryable/key.rb +67 -8
- data/lib/mongoid/criteria/queryable/mergeable.rb +5 -4
- data/lib/mongoid/criteria/queryable/selectable.rb +3 -4
- data/lib/mongoid/criteria/queryable/selector.rb +9 -31
- data/lib/mongoid/extensions/hash.rb +4 -2
- data/lib/mongoid/extensions/regexp.rb +1 -1
- data/lib/mongoid/extensions/string.rb +5 -3
- data/lib/mongoid/fields.rb +2 -1
- data/lib/mongoid/matchable.rb +14 -15
- data/lib/mongoid/matchable/all.rb +4 -3
- data/lib/mongoid/matchable/default.rb +71 -24
- data/lib/mongoid/matchable/regexp.rb +2 -2
- data/lib/mongoid/persistable/pushable.rb +11 -2
- data/lib/mongoid/persistence_context.rb +6 -6
- data/lib/mongoid/positional.rb +1 -1
- data/lib/mongoid/query_cache.rb +3 -2
- data/lib/mongoid/validatable/macros.rb +1 -1
- data/lib/mongoid/validatable/uniqueness.rb +1 -1
- data/lib/mongoid/version.rb +2 -1
- data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
- data/spec/README.md +18 -0
- data/spec/app/models/delegating_patient.rb +16 -0
- data/spec/app/models/other_owner_object.rb +2 -0
- data/spec/integration/app_spec.rb +192 -0
- data/spec/integration/associations/embedded_spec.rb +62 -0
- data/spec/integration/criteria/time_with_zone_spec.rb +32 -0
- data/spec/integration/document_spec.rb +22 -0
- data/spec/integration/matchable_spec.rb +680 -0
- data/spec/lite_spec_helper.rb +15 -5
- data/spec/mongoid/association/embedded/embedded_in_spec.rb +58 -0
- data/spec/mongoid/association/embedded/embeds_many_models.rb +53 -0
- data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
- data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +6 -0
- data/spec/mongoid/association/embedded/embeds_one_models.rb +51 -0
- data/spec/mongoid/association/embedded/embeds_one_spec.rb +46 -0
- data/spec/mongoid/association/referenced/belongs_to_spec.rb +23 -6
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +2 -1
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
- data/spec/mongoid/association/referenced/has_one_spec.rb +12 -2
- data/spec/mongoid/attributes/dynamic_spec.rb +153 -0
- data/spec/mongoid/attributes_spec.rb +19 -7
- data/spec/mongoid/clients/factory_spec.rb +2 -2
- data/spec/mongoid/clients/options_spec.rb +4 -4
- data/spec/mongoid/clients/sessions_spec.rb +20 -7
- data/spec/mongoid/clients/transactions_spec.rb +36 -15
- data/spec/mongoid/clients_spec.rb +2 -2
- data/spec/mongoid/contextual/atomic_spec.rb +20 -10
- data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
- data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
- data/spec/mongoid/contextual/mongo_spec.rb +76 -53
- data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
- data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +54 -0
- data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/key_spec.rb +48 -6
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +762 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +5 -224
- data/spec/mongoid/criteria/queryable/selector_spec.rb +37 -0
- data/spec/mongoid/criteria_spec.rb +7 -2
- data/spec/mongoid/document_fields_spec.rb +88 -0
- data/spec/mongoid/document_persistence_context_spec.rb +33 -0
- data/spec/mongoid/extensions/string_spec.rb +35 -7
- data/spec/mongoid/indexable_spec.rb +6 -4
- data/spec/mongoid/matchable/default_spec.rb +10 -3
- data/spec/mongoid/matchable/regexp_spec.rb +2 -2
- data/spec/mongoid/matchable_spec.rb +2 -2
- data/spec/mongoid/persistable/pushable_spec.rb +55 -1
- data/spec/mongoid/query_cache_spec.rb +2 -1
- data/spec/mongoid/relations/proxy_spec.rb +1 -1
- data/spec/mongoid/scopable_spec.rb +2 -1
- data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
- data/spec/mongoid/tasks/database_spec.rb +1 -1
- data/spec/mongoid/validatable/uniqueness_spec.rb +33 -6
- data/spec/spec_helper.rb +4 -37
- data/spec/support/child_process_helper.rb +76 -0
- data/spec/support/cluster_config.rb +158 -0
- data/spec/support/constraints.rb +29 -19
- data/spec/support/expectations.rb +17 -3
- data/spec/support/spec_config.rb +12 -4
- metadata +525 -464
- metadata.gz.sig +2 -0
data/spec/lite_spec_helper.rb
CHANGED
|
@@ -4,7 +4,6 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
|
4
4
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
|
5
5
|
|
|
6
6
|
require "mongoid"
|
|
7
|
-
require "rspec"
|
|
8
7
|
|
|
9
8
|
# MRI 2.5 and JRuby 9.2 change visibility of Object#pp when 'pp' is required,
|
|
10
9
|
# which happens when RSpec reports anything. This creates an issue for tests
|
|
@@ -36,16 +35,27 @@ else
|
|
|
36
35
|
end
|
|
37
36
|
|
|
38
37
|
RSpec.configure do |config|
|
|
38
|
+
config.expect_with(:rspec) do |c|
|
|
39
|
+
c.syntax = [:should, :expect]
|
|
40
|
+
end
|
|
41
|
+
|
|
39
42
|
if SpecConfig.instance.ci?
|
|
40
43
|
config.add_formatter(RSpec::Core::Formatters::JsonFormatter, File.join(File.dirname(__FILE__), '../tmp/rspec.json'))
|
|
41
44
|
end
|
|
42
45
|
|
|
43
46
|
if SpecConfig.instance.ci?
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
timeout = if SpecConfig.instance.app_tests?
|
|
48
|
+
# Allow 5 minutes per test for the app tests, since they install
|
|
49
|
+
# gems for Rails applications which can take a long time.
|
|
50
|
+
300
|
|
51
|
+
else
|
|
52
|
+
# Allow a max of 30 seconds per test.
|
|
53
|
+
# Tests should take under 10 seconds ideally but it seems
|
|
54
|
+
# we have some that run for more than 10 seconds in CI.
|
|
55
|
+
30
|
|
56
|
+
end
|
|
47
57
|
config.around(:each) do |example|
|
|
48
|
-
TimeoutInterrupt.timeout(
|
|
58
|
+
TimeoutInterrupt.timeout(timeout) do
|
|
49
59
|
example.run
|
|
50
60
|
end
|
|
51
61
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
|
+
require_relative './embeds_one_models'
|
|
2
3
|
|
|
3
4
|
describe Mongoid::Association::Embedded::EmbeddedIn do
|
|
4
5
|
|
|
@@ -313,6 +314,42 @@ describe Mongoid::Association::Embedded::EmbeddedIn do
|
|
|
313
314
|
it 'returns nil' do
|
|
314
315
|
expect(association.inverses).to eq(nil)
|
|
315
316
|
end
|
|
317
|
+
|
|
318
|
+
context 'when class_name is given and is a plain string' do
|
|
319
|
+
let(:association) do
|
|
320
|
+
EomParent.relations['child']
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it 'returns the inverse in an array' do
|
|
324
|
+
inverses = association.inverses
|
|
325
|
+
expect(inverses).to eq([:parent])
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
context 'when class_name is given and is a :: prefixed string' do
|
|
330
|
+
let(:association) do
|
|
331
|
+
EomCcChild.relations['parent']
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
it 'returns the inverse in an array' do
|
|
335
|
+
pending 'MONGOID-4751'
|
|
336
|
+
|
|
337
|
+
inverses = association.inverses
|
|
338
|
+
expect(inverses).to eq([:child])
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
context 'when other associations referencing unloaded classes exist' do
|
|
342
|
+
let(:association) do
|
|
343
|
+
EomDnlChild.relations['parent']
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
it 'does not load other classes' do
|
|
347
|
+
inverses = association.inverses
|
|
348
|
+
expect(inverses).to eq([:child])
|
|
349
|
+
expect(Object.const_defined?(:EoDnlMarker)).to be false
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
end
|
|
316
353
|
end
|
|
317
354
|
end
|
|
318
355
|
end
|
|
@@ -549,6 +586,16 @@ describe Mongoid::Association::Embedded::EmbeddedIn do
|
|
|
549
586
|
it 'returns the class name option' do
|
|
550
587
|
expect(association.relation_class_name).to eq('OtherContainer')
|
|
551
588
|
end
|
|
589
|
+
|
|
590
|
+
context ':class_name is a :: prefixed string' do
|
|
591
|
+
let(:association) do
|
|
592
|
+
EomCcChild.relations['parent']
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
it 'returns the :: prefixed string' do
|
|
596
|
+
expect(association.relation_class_name).to eq('::EomCcParent')
|
|
597
|
+
end
|
|
598
|
+
end
|
|
552
599
|
end
|
|
553
600
|
|
|
554
601
|
context 'when the class_name option is not specified' do
|
|
@@ -557,6 +604,17 @@ describe Mongoid::Association::Embedded::EmbeddedIn do
|
|
|
557
604
|
expect(association.relation_class_name).to eq('Container')
|
|
558
605
|
end
|
|
559
606
|
end
|
|
607
|
+
|
|
608
|
+
context 'when another association in the model is referencing a third model class' do
|
|
609
|
+
let(:association) do
|
|
610
|
+
EomDnlChild.relations['parent']
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
it 'does not attempt to load the third class' do
|
|
614
|
+
expect(association.relation_class_name).to eq('EomDnlParent')
|
|
615
|
+
expect(Object.const_defined?(:EoDnlMarker)).to be false
|
|
616
|
+
end
|
|
617
|
+
end
|
|
560
618
|
end
|
|
561
619
|
|
|
562
620
|
describe '#klass' do
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
class EmmCongress
|
|
5
|
+
include Mongoid::Document
|
|
6
|
+
|
|
7
|
+
embeds_many :legislators, class_name: 'EmmLegislator'
|
|
8
|
+
|
|
9
|
+
field :name, type: String
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class EmmLegislator
|
|
13
|
+
include Mongoid::Document
|
|
14
|
+
|
|
15
|
+
embedded_in :congress, class_name: 'EmmCongress'
|
|
16
|
+
|
|
17
|
+
field :a, type: Integer, default: 0
|
|
18
|
+
field :b, type: Integer, default: 0
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Models with associations with :class_name as a :: prefixed string
|
|
22
|
+
|
|
23
|
+
class EmmCcCongress
|
|
24
|
+
include Mongoid::Document
|
|
25
|
+
|
|
26
|
+
embeds_many :legislators, class_name: '::EmmCcLegislator'
|
|
27
|
+
|
|
28
|
+
field :name, type: String
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class EmmCcLegislator
|
|
32
|
+
include Mongoid::Document
|
|
33
|
+
|
|
34
|
+
embedded_in :congress, class_name: '::EmmCcCongress'
|
|
35
|
+
|
|
36
|
+
field :a, type: Integer, default: 0
|
|
37
|
+
field :b, type: Integer, default: 0
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class EmmManufactory
|
|
41
|
+
include Mongoid::Document
|
|
42
|
+
|
|
43
|
+
embeds_many :products, order: :id.desc, class_name: 'EmmProduct'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class EmmProduct
|
|
48
|
+
include Mongoid::Document
|
|
49
|
+
|
|
50
|
+
embedded_in :manufactory, class_name: 'EmmManufactory'
|
|
51
|
+
|
|
52
|
+
field :name, type: String
|
|
53
|
+
end
|
|
@@ -646,6 +646,16 @@ describe Mongoid::Association::Embedded::EmbedsMany do
|
|
|
646
646
|
it 'returns the class name option' do
|
|
647
647
|
expect(association.klass).to eq(_class)
|
|
648
648
|
end
|
|
649
|
+
|
|
650
|
+
context 'when the class name is prefixed with ::' do
|
|
651
|
+
let(:options) do
|
|
652
|
+
{ class_name: '::OtherEmbeddedObject' }
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
it 'returns the class name option' do
|
|
656
|
+
expect(association.klass).to eq(_class)
|
|
657
|
+
end
|
|
658
|
+
end
|
|
649
659
|
end
|
|
650
660
|
|
|
651
661
|
context 'when the class_name option is not specified' do
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
class EomParent
|
|
2
|
+
include Mongoid::Document
|
|
3
|
+
|
|
4
|
+
embeds_one :child, class_name: 'EomChild'
|
|
5
|
+
|
|
6
|
+
field :name, type: String
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class EomChild
|
|
10
|
+
include Mongoid::Document
|
|
11
|
+
|
|
12
|
+
embedded_in :parent, class_name: 'EomParent'
|
|
13
|
+
|
|
14
|
+
field :a, type: Integer, default: 0
|
|
15
|
+
field :b, type: Integer, default: 0
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Models with associations with :class_name as a :: prefixed string
|
|
19
|
+
|
|
20
|
+
class EomCcParent
|
|
21
|
+
include Mongoid::Document
|
|
22
|
+
|
|
23
|
+
embeds_one :child, class_name: '::EomCcChild'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class EomCcChild
|
|
27
|
+
include Mongoid::Document
|
|
28
|
+
|
|
29
|
+
embedded_in :parent, class_name: '::EomCcParent'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Models referencing other models which should not be loaded unless the
|
|
33
|
+
# respective association is referenced
|
|
34
|
+
|
|
35
|
+
autoload :EomDnlMissingChild, 'mongoid/association/embedded/embeds_one_dnl_models'
|
|
36
|
+
|
|
37
|
+
class EomDnlParent
|
|
38
|
+
include Mongoid::Document
|
|
39
|
+
|
|
40
|
+
embeds_one :child, class_name: 'EomDnlChild'
|
|
41
|
+
embeds_one :missing_child, class_name: 'EomDnlMissingChild'
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
autoload :EomDnlMissingParent, 'mongoid/association/embedded/embeds_one_dnl_models'
|
|
45
|
+
|
|
46
|
+
class EomDnlChild
|
|
47
|
+
include Mongoid::Document
|
|
48
|
+
|
|
49
|
+
embedded_in :parent, class_name: 'EomDnlParent'
|
|
50
|
+
embedded_in :missing_parent, class_name: 'EomDnlMissingParent'
|
|
51
|
+
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
|
+
require_relative './embeds_one_models'
|
|
2
3
|
|
|
3
4
|
describe Mongoid::Association::Embedded::EmbedsOne do
|
|
4
5
|
|
|
@@ -444,6 +445,30 @@ describe Mongoid::Association::Embedded::EmbedsOne do
|
|
|
444
445
|
it 'returns the :as attribute' do
|
|
445
446
|
expect(association.inverses).to eq([ :containable ])
|
|
446
447
|
end
|
|
448
|
+
|
|
449
|
+
context 'when class_name is given and is a :: prefixed string' do
|
|
450
|
+
|
|
451
|
+
let(:association) do
|
|
452
|
+
EomCcParent.relations['child']
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
it 'returns the inverse in an array' do
|
|
456
|
+
inverses = association.inverses
|
|
457
|
+
expect(inverses).to eq([:parent])
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
context 'when other associations referencing unloaded classes exist' do
|
|
461
|
+
let(:association) do
|
|
462
|
+
EomDnlParent.relations['child']
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
it 'does not load other classes' do
|
|
466
|
+
inverses = association.inverses
|
|
467
|
+
expect(inverses).to eq([:parent])
|
|
468
|
+
expect(Object.const_defined?(:EoDnlMarker)).to be false
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
end
|
|
447
472
|
end
|
|
448
473
|
end
|
|
449
474
|
end
|
|
@@ -604,6 +629,16 @@ describe Mongoid::Association::Embedded::EmbedsOne do
|
|
|
604
629
|
it 'returns the class name option' do
|
|
605
630
|
expect(association.relation_class_name).to eq('OtherEmbeddedObject')
|
|
606
631
|
end
|
|
632
|
+
|
|
633
|
+
context ':class_name is a :: prefixed string' do
|
|
634
|
+
let(:association) do
|
|
635
|
+
EomCcParent.relations['child']
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
it 'returns the :: prefixed string' do
|
|
639
|
+
expect(association.relation_class_name).to eq('::EomCcChild')
|
|
640
|
+
end
|
|
641
|
+
end
|
|
607
642
|
end
|
|
608
643
|
|
|
609
644
|
context 'when the class_name option is not specified' do
|
|
@@ -612,6 +647,17 @@ describe Mongoid::Association::Embedded::EmbedsOne do
|
|
|
612
647
|
expect(association.relation_class_name).to eq('EmbeddedObject')
|
|
613
648
|
end
|
|
614
649
|
end
|
|
650
|
+
|
|
651
|
+
context 'when another association in the model is referencing a third model class' do
|
|
652
|
+
let(:association) do
|
|
653
|
+
EomDnlParent.relations['child']
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
it 'does not attempt to load the third class' do
|
|
657
|
+
expect(association.relation_class_name).to eq('EomDnlChild')
|
|
658
|
+
expect(Object.const_defined?(:EoDnlMarker)).to be false
|
|
659
|
+
end
|
|
660
|
+
end
|
|
615
661
|
end
|
|
616
662
|
|
|
617
663
|
describe '#klass' do
|
|
@@ -1622,6 +1622,17 @@ describe Mongoid::Association::Referenced::BelongsTo do
|
|
|
1622
1622
|
end
|
|
1623
1623
|
end
|
|
1624
1624
|
|
|
1625
|
+
context 'when the :class_name option is scoped with ::' do
|
|
1626
|
+
|
|
1627
|
+
let(:options) do
|
|
1628
|
+
{ class_name: '::OtherOwnerObject' }
|
|
1629
|
+
end
|
|
1630
|
+
|
|
1631
|
+
it 'returns the class name option' do
|
|
1632
|
+
expect(association.relation_class_name).to eq('::OtherOwnerObject')
|
|
1633
|
+
end
|
|
1634
|
+
end
|
|
1635
|
+
|
|
1625
1636
|
context 'when the class_name option is not specified' do
|
|
1626
1637
|
|
|
1627
1638
|
it 'uses the name of the relation to deduce the class name' do
|
|
@@ -1644,17 +1655,23 @@ describe Mongoid::Association::Referenced::BelongsTo do
|
|
|
1644
1655
|
|
|
1645
1656
|
context 'when the :class_name option is specified' do
|
|
1646
1657
|
|
|
1647
|
-
let
|
|
1648
|
-
|
|
1649
|
-
|
|
1658
|
+
let(:options) do
|
|
1659
|
+
{ class_name: 'OtherOwnerObject' }
|
|
1660
|
+
end
|
|
1661
|
+
|
|
1662
|
+
it 'returns the named class' do
|
|
1663
|
+
expect(association.relation_class).to eq(OtherOwnerObject)
|
|
1650
1664
|
end
|
|
1665
|
+
end
|
|
1666
|
+
|
|
1667
|
+
context 'when the :class_name option is scoped with ::' do
|
|
1651
1668
|
|
|
1652
1669
|
let(:options) do
|
|
1653
|
-
{ class_name: 'OtherOwnerObject' }
|
|
1670
|
+
{ class_name: '::OtherOwnerObject' }
|
|
1654
1671
|
end
|
|
1655
1672
|
|
|
1656
|
-
it 'returns the class
|
|
1657
|
-
expect(association.relation_class).to eq(
|
|
1673
|
+
it 'returns the named class' do
|
|
1674
|
+
expect(association.relation_class).to eq(OtherOwnerObject)
|
|
1658
1675
|
end
|
|
1659
1676
|
end
|
|
1660
1677
|
|
|
@@ -2686,7 +2686,8 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
|
|
|
2686
2686
|
expect(preferences).to eq([ preference_one ])
|
|
2687
2687
|
end
|
|
2688
2688
|
|
|
2689
|
-
context 'when providing a collation'
|
|
2689
|
+
context 'when providing a collation' do
|
|
2690
|
+
min_server_version '3.4'
|
|
2690
2691
|
|
|
2691
2692
|
let(:preferences) do
|
|
2692
2693
|
person.preferences.where(name: "FIRST").collation(locale: 'en_US', strength: 2).to_a
|
|
@@ -2904,7 +2904,8 @@ describe Mongoid::Association::Referenced::HasMany::Proxy do
|
|
|
2904
2904
|
expect(posts).to eq([ post_one ])
|
|
2905
2905
|
end
|
|
2906
2906
|
|
|
2907
|
-
context 'when providing a collation'
|
|
2907
|
+
context 'when providing a collation' do
|
|
2908
|
+
min_server_version '3.4'
|
|
2908
2909
|
|
|
2909
2910
|
let(:posts) do
|
|
2910
2911
|
person.posts.where(title: "FIRST").collation(locale: 'en_US', strength: 2)
|
|
@@ -909,12 +909,12 @@ describe Mongoid::Association::Referenced::HasOne do
|
|
|
909
909
|
end
|
|
910
910
|
end
|
|
911
911
|
|
|
912
|
-
it 'returns the
|
|
912
|
+
it 'returns the inferred unqualified class name' do
|
|
913
913
|
define_classes
|
|
914
914
|
|
|
915
915
|
expect(
|
|
916
916
|
HasOneAssociationClassName::OwnedClass.relations['owner_class'].relation_class_name
|
|
917
|
-
).to eq('
|
|
917
|
+
).to eq('OwnerClass')
|
|
918
918
|
end
|
|
919
919
|
end
|
|
920
920
|
|
|
@@ -945,6 +945,16 @@ describe Mongoid::Association::Referenced::HasOne do
|
|
|
945
945
|
expect(association.relation_class_name).to eq('BelongingObject')
|
|
946
946
|
end
|
|
947
947
|
end
|
|
948
|
+
|
|
949
|
+
context "when the class is not defined" do
|
|
950
|
+
let(:name) do
|
|
951
|
+
:undefined_class
|
|
952
|
+
end
|
|
953
|
+
|
|
954
|
+
it 'does not trigger autoloading' do
|
|
955
|
+
expect(association.relation_class_name).to eq('UndefinedClass')
|
|
956
|
+
end
|
|
957
|
+
end
|
|
948
958
|
end
|
|
949
959
|
|
|
950
960
|
describe '#relation_class' do
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
require "spec_helper"
|
|
5
|
+
|
|
6
|
+
describe Mongoid::Attributes::Dynamic do
|
|
7
|
+
shared_examples_for 'dynamic field' do
|
|
8
|
+
let(:raw_attributes) do
|
|
9
|
+
{attr_name => 'foo bar'}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
context 'when reading attributes' do
|
|
13
|
+
context 'an unsaved model' do
|
|
14
|
+
it 'can be read' do
|
|
15
|
+
bar = Bar.new(raw_attributes)
|
|
16
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'saved model' do
|
|
21
|
+
it 'can be read' do
|
|
22
|
+
bar = Bar.new(raw_attributes)
|
|
23
|
+
bar.save!
|
|
24
|
+
|
|
25
|
+
bar = Bar.find(bar.id)
|
|
26
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context 'when attribute is not set' do
|
|
31
|
+
it 'cannot be read' do
|
|
32
|
+
bar = Bar.new
|
|
33
|
+
expect do
|
|
34
|
+
bar.send(attr_name)
|
|
35
|
+
end.to raise_error(NoMethodError)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context 'reading via read_attribute' do
|
|
39
|
+
it 'returns nil' do
|
|
40
|
+
bar = Bar.new
|
|
41
|
+
expect(bar.read_attribute(:foo)).to be nil
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context 'reading via []' do
|
|
46
|
+
it 'returns nil' do
|
|
47
|
+
bar = Bar.new
|
|
48
|
+
expect(bar[:foo]).to be nil
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context 'when writing attributes via constructor' do
|
|
55
|
+
it 'can be written' do
|
|
56
|
+
bar = Bar.new(raw_attributes)
|
|
57
|
+
bar.save!
|
|
58
|
+
|
|
59
|
+
bar = Bar.find(bar.id)
|
|
60
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context 'when writing attributes via attributes=' do
|
|
65
|
+
it 'can be written' do
|
|
66
|
+
bar = Bar.new
|
|
67
|
+
bar.attributes = raw_attributes
|
|
68
|
+
bar.save!
|
|
69
|
+
|
|
70
|
+
bar = Bar.find(bar.id)
|
|
71
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context 'when writing attributes via write_attribute' do
|
|
76
|
+
it 'can be written' do
|
|
77
|
+
bar = Bar.new
|
|
78
|
+
bar.write_attribute(attr_name, 'foo bar')
|
|
79
|
+
bar.save!
|
|
80
|
+
|
|
81
|
+
bar = Bar.find(bar.id)
|
|
82
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context 'when writing attributes via []=' do
|
|
87
|
+
context 'string key' do
|
|
88
|
+
it 'can be written' do
|
|
89
|
+
bar = Bar.new
|
|
90
|
+
bar[attr_name.to_s] = 'foo bar'
|
|
91
|
+
bar.save!
|
|
92
|
+
|
|
93
|
+
bar = Bar.find(bar.id)
|
|
94
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
context 'symbol key' do
|
|
99
|
+
it 'can be written' do
|
|
100
|
+
bar = Bar.new
|
|
101
|
+
bar[attr_name.to_sym] = 'foo bar'
|
|
102
|
+
bar.save!
|
|
103
|
+
|
|
104
|
+
bar = Bar.find(bar.id)
|
|
105
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
context 'when writing attributes via #{attribute}=' do
|
|
111
|
+
context 'when attribute is not already set' do
|
|
112
|
+
let(:bar) { Bar.new }
|
|
113
|
+
|
|
114
|
+
it 'cannot be written' do
|
|
115
|
+
expect do
|
|
116
|
+
bar.send("#{attr_name}=", 'foo bar')
|
|
117
|
+
bar.save!
|
|
118
|
+
end.to raise_error(NoMethodError)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
context 'when attribute is already set' do
|
|
123
|
+
let(:bar) { Bar.new(attr_name => 'foo bar') }
|
|
124
|
+
|
|
125
|
+
it 'can be written' do
|
|
126
|
+
bar.send("#{attr_name}=", 'new foo bar')
|
|
127
|
+
bar.save!
|
|
128
|
+
|
|
129
|
+
_bar = Bar.find(bar.id)
|
|
130
|
+
expect(_bar.send(attr_name)).to eq('new foo bar')
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
context 'when attribute name is alphanumeric' do
|
|
137
|
+
let(:attr_name) { 'foo' }
|
|
138
|
+
|
|
139
|
+
it_behaves_like 'dynamic field'
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
context 'when attribute name contains spaces' do
|
|
143
|
+
let(:attr_name) { 'hello world' }
|
|
144
|
+
|
|
145
|
+
it_behaves_like 'dynamic field'
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
context 'when attribute name contains special characters' do
|
|
149
|
+
let(:attr_name) { 'hello%world' }
|
|
150
|
+
|
|
151
|
+
it_behaves_like 'dynamic field'
|
|
152
|
+
end
|
|
153
|
+
end
|