mongoid 7.1.0.rc0 → 7.1.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
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/LICENSE +1 -1
- data/README.md +4 -4
- data/lib/mongoid.rb +3 -2
- data/lib/mongoid/association/many.rb +3 -2
- data/lib/mongoid/association/proxy.rb +5 -3
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +2 -22
- data/lib/mongoid/association/referenced/has_many/proxy.rb +3 -2
- data/lib/mongoid/attributes.rb +28 -20
- data/lib/mongoid/config.rb +3 -3
- data/lib/mongoid/config/options.rb +5 -2
- data/lib/mongoid/contextual.rb +5 -4
- data/lib/mongoid/contextual/geo_near.rb +3 -2
- data/lib/mongoid/contextual/map_reduce.rb +3 -2
- data/lib/mongoid/contextual/mongo.rb +2 -1
- data/lib/mongoid/fields/standard.rb +2 -1
- data/lib/mongoid/findable.rb +5 -4
- data/lib/mongoid/interceptable.rb +5 -1
- data/lib/mongoid/railties/database.rake +7 -0
- data/lib/mongoid/serializable.rb +3 -1
- data/lib/mongoid/shardable.rb +56 -4
- data/lib/mongoid/tasks/database.rake +10 -5
- data/lib/mongoid/tasks/database.rb +48 -0
- data/lib/mongoid/timestamps/timeless.rb +3 -1
- data/lib/mongoid/version.rb +1 -1
- data/spec/integration/shardable_spec.rb +133 -0
- data/spec/lite_spec_helper.rb +3 -0
- data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +41 -68
- data/spec/mongoid/attributes_spec.rb +19 -7
- data/spec/mongoid/changeable_spec.rb +23 -0
- data/spec/mongoid/document_fields_spec.rb +29 -0
- data/spec/mongoid/interceptable_spec.rb +62 -0
- data/spec/mongoid/interceptable_spec_models.rb +76 -0
- data/spec/mongoid/shardable_models.rb +61 -0
- data/spec/mongoid/shardable_spec.rb +69 -16
- data/spec/support/lite_constraints.rb +22 -0
- metadata +20 -12
- metadata.gz.sig +0 -0
@@ -1349,10 +1349,16 @@ describe Mongoid::Attributes do
|
|
1349
1349
|
context "when attribute is a Hash" do
|
1350
1350
|
let(:person) { Person.new map: { somekey: "somevalue" } }
|
1351
1351
|
|
1352
|
-
it "raises an error when
|
1353
|
-
expect
|
1352
|
+
it "raises an error when trying to set a value of invalid type - array" do
|
1353
|
+
expect do
|
1354
1354
|
person.map = []
|
1355
|
-
|
1355
|
+
end.to raise_error(Mongoid::Errors::InvalidValue, /Value of type Array cannot be written to a field of type Hash/)
|
1356
|
+
end
|
1357
|
+
|
1358
|
+
it "raises an error when trying to set a value of invalid type - boolean" do
|
1359
|
+
expect do
|
1360
|
+
person.map = false
|
1361
|
+
end.to raise_error(Mongoid::Errors::InvalidValue, /Value of type FalseClass cannot be written to a field of type Hash/)
|
1356
1362
|
end
|
1357
1363
|
|
1358
1364
|
it "can set a Hash value" do
|
@@ -1367,10 +1373,16 @@ describe Mongoid::Attributes do
|
|
1367
1373
|
expect(person.aliases).to eq([ :alias_1 ])
|
1368
1374
|
end
|
1369
1375
|
|
1370
|
-
it "raises an error when
|
1371
|
-
expect
|
1376
|
+
it "raises an error when trying to set a value of invalid type - hash" do
|
1377
|
+
expect do
|
1372
1378
|
person.aliases = {}
|
1373
|
-
|
1379
|
+
end.to raise_error(Mongoid::Errors::InvalidValue, /Value of type Hash cannot be written to a field of type Array/)
|
1380
|
+
end
|
1381
|
+
|
1382
|
+
it "raises an error when trying to set a value of invalid type - boolean" do
|
1383
|
+
expect do
|
1384
|
+
person.aliases = false
|
1385
|
+
end.to raise_error(Mongoid::Errors::InvalidValue, /Value of type FalseClass cannot be written to a field of type Array/)
|
1374
1386
|
end
|
1375
1387
|
end
|
1376
1388
|
|
@@ -1425,7 +1437,7 @@ describe Mongoid::Attributes do
|
|
1425
1437
|
end
|
1426
1438
|
|
1427
1439
|
describe "#typed_attributes" do
|
1428
|
-
|
1440
|
+
|
1429
1441
|
let(:date_time) do
|
1430
1442
|
DateTime.current
|
1431
1443
|
end
|
@@ -949,6 +949,29 @@ describe Mongoid::Changeable do
|
|
949
949
|
end
|
950
950
|
end
|
951
951
|
|
952
|
+
context 'when habtm association changes' do
|
953
|
+
|
954
|
+
let(:person) do
|
955
|
+
Person.create!(title: "Grand Poobah")
|
956
|
+
end
|
957
|
+
|
958
|
+
let(:user_account) do
|
959
|
+
UserAccount.create!
|
960
|
+
end
|
961
|
+
|
962
|
+
before do
|
963
|
+
person.user_accounts << user_account
|
964
|
+
end
|
965
|
+
|
966
|
+
it 'returns a hash of changes' do
|
967
|
+
pending 'https://jira.mongodb.org/browse/MONGOID-4843'
|
968
|
+
|
969
|
+
person.changes.should == {
|
970
|
+
user_account_ids: [[], [user_account.id]]
|
971
|
+
}
|
972
|
+
end
|
973
|
+
end
|
974
|
+
|
952
975
|
context "when the document has not changed" do
|
953
976
|
|
954
977
|
let(:acolyte) do
|
@@ -56,4 +56,33 @@ describe Mongoid::Document do
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
59
|
+
|
60
|
+
describe 'Hash field' do
|
61
|
+
context 'with symbol key and value' do
|
62
|
+
let(:church) do
|
63
|
+
Church.create!(location: {state: :ny})
|
64
|
+
end
|
65
|
+
|
66
|
+
let(:found_church) do
|
67
|
+
Church.find(church.id)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'round-trips the value' do
|
71
|
+
found_church.location[:state].should == :ny
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'stringifies the key' do
|
75
|
+
found_church.location.keys.should == %w(state)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'retrieves value as symbol via driver' do
|
79
|
+
Church.delete_all
|
80
|
+
|
81
|
+
church
|
82
|
+
|
83
|
+
v = Church.collection.find.first
|
84
|
+
v['location'].should == {'state' => :ny}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
59
88
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
4
|
require "spec_helper"
|
5
|
+
require_relative './interceptable_spec_models'
|
5
6
|
|
6
7
|
describe Mongoid::Interceptable do
|
7
8
|
|
@@ -1722,4 +1723,65 @@ describe Mongoid::Interceptable do
|
|
1722
1723
|
end
|
1723
1724
|
end
|
1724
1725
|
end
|
1726
|
+
|
1727
|
+
context 'when creating a parent and embedded child' do
|
1728
|
+
let(:registry) { InterceptableSpec::CallbackRegistry.new }
|
1729
|
+
let(:parent) do
|
1730
|
+
InterceptableSpec::CbParent.new(registry).tap do |parent|
|
1731
|
+
parent.cb_children << InterceptableSpec::CbChild.new(registry, cb_parent: parent)
|
1732
|
+
end
|
1733
|
+
end
|
1734
|
+
|
1735
|
+
let(:expected) do
|
1736
|
+
[
|
1737
|
+
[InterceptableSpec::CbParent, :before_validation],
|
1738
|
+
[InterceptableSpec::CbChild, :before_validation],
|
1739
|
+
[InterceptableSpec::CbChild, :after_validation],
|
1740
|
+
[InterceptableSpec::CbParent, :after_validation],
|
1741
|
+
[InterceptableSpec::CbParent, :before_save],
|
1742
|
+
[InterceptableSpec::CbParent, :before_create],
|
1743
|
+
[InterceptableSpec::CbParent, :after_create],
|
1744
|
+
[InterceptableSpec::CbParent, :after_save],
|
1745
|
+
]
|
1746
|
+
end
|
1747
|
+
|
1748
|
+
it 'calls callbacks in the right order' do
|
1749
|
+
parent.save!
|
1750
|
+
expect(registry.calls).to eq expected
|
1751
|
+
end
|
1752
|
+
end
|
1753
|
+
|
1754
|
+
context 'when creating a parent and embedded child with cascading callbacks' do
|
1755
|
+
let(:registry) { InterceptableSpec::CallbackRegistry.new }
|
1756
|
+
let(:parent) do
|
1757
|
+
InterceptableSpec::CbParent.new(registry).tap do |parent|
|
1758
|
+
parent.cb_cascaded_children <<
|
1759
|
+
InterceptableSpec::CbCascadedChild.new(registry, cb_parent: parent)
|
1760
|
+
end
|
1761
|
+
end
|
1762
|
+
|
1763
|
+
let(:expected) do
|
1764
|
+
[
|
1765
|
+
[InterceptableSpec::CbParent, :before_validation],
|
1766
|
+
[InterceptableSpec::CbCascadedChild, :before_validation],
|
1767
|
+
[InterceptableSpec::CbCascadedChild, :after_validation],
|
1768
|
+
[InterceptableSpec::CbParent, :after_validation],
|
1769
|
+
[InterceptableSpec::CbParent, :before_save],
|
1770
|
+
[InterceptableSpec::CbCascadedChild, :before_save],
|
1771
|
+
[InterceptableSpec::CbParent, :before_create],
|
1772
|
+
[InterceptableSpec::CbCascadedChild, :before_create],
|
1773
|
+
[InterceptableSpec::CbParent, :after_create],
|
1774
|
+
[InterceptableSpec::CbCascadedChild, :after_create],
|
1775
|
+
[InterceptableSpec::CbParent, :after_save],
|
1776
|
+
[InterceptableSpec::CbCascadedChild, :after_save],
|
1777
|
+
]
|
1778
|
+
end
|
1779
|
+
|
1780
|
+
it 'calls callbacks in the right order' do
|
1781
|
+
pending 'MONGOID-3795'
|
1782
|
+
|
1783
|
+
parent.save!
|
1784
|
+
expect(registry.calls).to eq expected
|
1785
|
+
end
|
1786
|
+
end
|
1725
1787
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module InterceptableSpec
|
2
|
+
class CallbackRegistry
|
3
|
+
def initialize
|
4
|
+
@calls = []
|
5
|
+
end
|
6
|
+
|
7
|
+
def record_call(cls, cb)
|
8
|
+
@calls << [cls, cb]
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :calls
|
12
|
+
end
|
13
|
+
|
14
|
+
module CallbackTracking
|
15
|
+
extend ActiveSupport::Concern
|
16
|
+
|
17
|
+
included do
|
18
|
+
%i(
|
19
|
+
validation save create update
|
20
|
+
).each do |what|
|
21
|
+
%i(before after).each do |whn|
|
22
|
+
send("#{whn}_#{what}", "#{whn}_#{what}_stub".to_sym)
|
23
|
+
define_method("#{whn}_#{what}_stub") do
|
24
|
+
callback_registry.record_call(self.class, "#{whn}_#{what}".to_sym)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class CbParent
|
32
|
+
include Mongoid::Document
|
33
|
+
|
34
|
+
def initialize(callback_registry)
|
35
|
+
@callback_registry = callback_registry
|
36
|
+
super()
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :callback_registry
|
40
|
+
|
41
|
+
embeds_many :cb_children
|
42
|
+
embeds_many :cb_cascaded_children, cascade_callbacks: true
|
43
|
+
|
44
|
+
include CallbackTracking
|
45
|
+
end
|
46
|
+
|
47
|
+
class CbChild
|
48
|
+
include Mongoid::Document
|
49
|
+
|
50
|
+
embedded_in :cb_parent
|
51
|
+
|
52
|
+
def initialize(callback_registry, options)
|
53
|
+
@callback_registry = callback_registry
|
54
|
+
super(options)
|
55
|
+
end
|
56
|
+
|
57
|
+
attr_reader :callback_registry
|
58
|
+
|
59
|
+
include CallbackTracking
|
60
|
+
end
|
61
|
+
|
62
|
+
class CbCascadedChild
|
63
|
+
include Mongoid::Document
|
64
|
+
|
65
|
+
embedded_in :cb_parent
|
66
|
+
|
67
|
+
def initialize(callback_registry, options)
|
68
|
+
@callback_registry = callback_registry
|
69
|
+
super(options)
|
70
|
+
end
|
71
|
+
|
72
|
+
attr_reader :callback_registry
|
73
|
+
|
74
|
+
include CallbackTracking
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class SmMovie
|
2
|
+
include Mongoid::Document
|
3
|
+
|
4
|
+
field :year, type: Integer
|
5
|
+
|
6
|
+
index year: 1
|
7
|
+
shard_key :year
|
8
|
+
end
|
9
|
+
|
10
|
+
class SmTrailer
|
11
|
+
include Mongoid::Document
|
12
|
+
|
13
|
+
index year: 1
|
14
|
+
shard_key 'year'
|
15
|
+
end
|
16
|
+
|
17
|
+
class SmActor
|
18
|
+
include Mongoid::Document
|
19
|
+
|
20
|
+
# This is not a usable shard configuration for the server.
|
21
|
+
# We just have it for unit tests.
|
22
|
+
shard_key age: 1, 'gender' => :hashed
|
23
|
+
end
|
24
|
+
|
25
|
+
class SmAssistant
|
26
|
+
include Mongoid::Document
|
27
|
+
|
28
|
+
field :gender, type: String
|
29
|
+
|
30
|
+
index gender: 1
|
31
|
+
shard_key 'gender' => :hashed
|
32
|
+
end
|
33
|
+
|
34
|
+
class SmProducer
|
35
|
+
include Mongoid::Document
|
36
|
+
|
37
|
+
index age: 1, gender: 1
|
38
|
+
shard_key({age: 1, gender: 'hashed'}, unique: true, numInitialChunks: 2)
|
39
|
+
end
|
40
|
+
|
41
|
+
class SmDirector
|
42
|
+
include Mongoid::Document
|
43
|
+
|
44
|
+
belongs_to :agency
|
45
|
+
|
46
|
+
index age: 1
|
47
|
+
shard_key :agency
|
48
|
+
end
|
49
|
+
|
50
|
+
class SmDriver
|
51
|
+
include Mongoid::Document
|
52
|
+
|
53
|
+
belongs_to :agency
|
54
|
+
|
55
|
+
index age: 1, agency: 1
|
56
|
+
shard_key age: 1, agency: :hashed
|
57
|
+
end
|
58
|
+
|
59
|
+
class SmNotSharded
|
60
|
+
include Mongoid::Document
|
61
|
+
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
4
|
require "spec_helper"
|
5
|
+
require_relative './shardable_models'
|
5
6
|
|
6
7
|
describe Mongoid::Shardable do
|
7
8
|
|
@@ -24,30 +25,82 @@ describe Mongoid::Shardable do
|
|
24
25
|
|
25
26
|
describe ".shard_key" do
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
context 'when full syntax is used' do
|
29
|
+
context 'with symbol value' do
|
30
|
+
it 'sets shard key fields to symbol value' do
|
31
|
+
SmProducer.shard_key_fields.should == %i(age gender)
|
32
|
+
end
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
+
it 'sets shard config' do
|
35
|
+
SmProducer.shard_config.should == {
|
36
|
+
key: {age: 1, gender: 'hashed'},
|
37
|
+
options: {
|
38
|
+
unique: true,
|
39
|
+
numInitialChunks: 2,
|
40
|
+
},
|
41
|
+
}
|
42
|
+
end
|
34
43
|
|
35
|
-
|
36
|
-
|
37
|
-
|
44
|
+
it 'keeps hashed as string' do
|
45
|
+
SmProducer.shard_config[:key][:gender].should == 'hashed'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with string value' do
|
50
|
+
it 'sets shard key fields to symbol value' do
|
51
|
+
SmActor.shard_key_fields.should == %i(age gender)
|
52
|
+
end
|
38
53
|
|
39
|
-
|
54
|
+
it 'sets shard config' do
|
55
|
+
SmActor.shard_config.should == {
|
56
|
+
key: {age: 1, gender: 'hashed'},
|
57
|
+
options: {},
|
58
|
+
}
|
59
|
+
end
|
40
60
|
|
41
|
-
|
42
|
-
|
61
|
+
it 'sets hashed to string' do
|
62
|
+
SmActor.shard_config[:key][:gender].should == 'hashed'
|
63
|
+
end
|
43
64
|
end
|
44
65
|
|
45
|
-
|
46
|
-
|
66
|
+
context 'when passed association name' do
|
67
|
+
it 'uses foreign key as shard key in shard config' do
|
68
|
+
SmDriver.shard_config.should == {
|
69
|
+
key: {age: 1, agency_id: 'hashed'},
|
70
|
+
options: {},
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'uses foreign key as shard key in shard key fields' do
|
75
|
+
SmDriver.shard_key_fields.should == %i(age agency_id)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when shorthand syntax is used' do
|
81
|
+
context 'with symbol value' do
|
82
|
+
it 'sets shard key fields to symbol value' do
|
83
|
+
SmMovie.shard_key_fields.should == %i(year)
|
84
|
+
end
|
47
85
|
end
|
48
86
|
|
49
|
-
|
50
|
-
|
87
|
+
context 'with string value' do
|
88
|
+
it 'sets shard key fields to symbol value' do
|
89
|
+
SmTrailer.shard_key_fields.should == %i(year)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when passed association name' do
|
94
|
+
it 'uses foreign key as shard key in shard config' do
|
95
|
+
SmDirector.shard_config.should == {
|
96
|
+
key: {agency_id: 1},
|
97
|
+
options: {},
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'uses foreign key as shard key in shard key fields' do
|
102
|
+
SmDirector.shard_key_fields.should == %i(agency_id)
|
103
|
+
end
|
51
104
|
end
|
52
105
|
end
|
53
106
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module LiteConstraints
|
2
|
+
# Constrain tests that use TimeoutInterrupt to MRI (and Unix)
|
3
|
+
def only_mri
|
4
|
+
before do
|
5
|
+
unless SpecConfig.instance.mri?
|
6
|
+
skip "MRI required, we have #{SpecConfig.instance.platform}"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# This is for marking tests that fail on jruby that should
|
12
|
+
# in principle work (as opposed to being fundamentally incompatible
|
13
|
+
# with jruby).
|
14
|
+
# Often times these failures happen only in Evergreen.
|
15
|
+
def fails_on_jruby
|
16
|
+
before do
|
17
|
+
unless SpecConfig.instance.mri?
|
18
|
+
skip "Fails on jruby"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|