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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +1 -1
  5. data/README.md +4 -4
  6. data/lib/mongoid.rb +3 -2
  7. data/lib/mongoid/association/many.rb +3 -2
  8. data/lib/mongoid/association/proxy.rb +5 -3
  9. data/lib/mongoid/association/referenced/has_many/enumerable.rb +2 -22
  10. data/lib/mongoid/association/referenced/has_many/proxy.rb +3 -2
  11. data/lib/mongoid/attributes.rb +28 -20
  12. data/lib/mongoid/config.rb +3 -3
  13. data/lib/mongoid/config/options.rb +5 -2
  14. data/lib/mongoid/contextual.rb +5 -4
  15. data/lib/mongoid/contextual/geo_near.rb +3 -2
  16. data/lib/mongoid/contextual/map_reduce.rb +3 -2
  17. data/lib/mongoid/contextual/mongo.rb +2 -1
  18. data/lib/mongoid/fields/standard.rb +2 -1
  19. data/lib/mongoid/findable.rb +5 -4
  20. data/lib/mongoid/interceptable.rb +5 -1
  21. data/lib/mongoid/railties/database.rake +7 -0
  22. data/lib/mongoid/serializable.rb +3 -1
  23. data/lib/mongoid/shardable.rb +56 -4
  24. data/lib/mongoid/tasks/database.rake +10 -5
  25. data/lib/mongoid/tasks/database.rb +48 -0
  26. data/lib/mongoid/timestamps/timeless.rb +3 -1
  27. data/lib/mongoid/version.rb +1 -1
  28. data/spec/integration/shardable_spec.rb +133 -0
  29. data/spec/lite_spec_helper.rb +3 -0
  30. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +41 -68
  31. data/spec/mongoid/attributes_spec.rb +19 -7
  32. data/spec/mongoid/changeable_spec.rb +23 -0
  33. data/spec/mongoid/document_fields_spec.rb +29 -0
  34. data/spec/mongoid/interceptable_spec.rb +62 -0
  35. data/spec/mongoid/interceptable_spec_models.rb +76 -0
  36. data/spec/mongoid/shardable_models.rb +61 -0
  37. data/spec/mongoid/shardable_spec.rb +69 -16
  38. data/spec/support/lite_constraints.rb +22 -0
  39. metadata +20 -12
  40. 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 try to set an invalid value" do
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
- }.to raise_error(Mongoid::Errors::InvalidValue)
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 try to set an invalid value" do
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
- }.to raise_error(Mongoid::Errors::InvalidValue)
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
- let(:klass) do
28
- Band
29
- end
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
- before do
32
- Band.shard_key(:name)
33
- end
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
- it "specifies a shard key on the collection" do
36
- expect(klass.shard_key_fields).to eq([:name])
37
- end
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
- context 'when a relation is used as the shard key' do
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
- let(:klass) do
42
- Game
61
+ it 'sets hashed to string' do
62
+ SmActor.shard_config[:key][:gender].should == 'hashed'
63
+ end
43
64
  end
44
65
 
45
- before do
46
- Game.shard_key(:person)
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
- it "converts the shard key to the foreign key field" do
50
- expect(klass.shard_key_fields).to eq([:person_id])
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