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
@@ -5,27 +5,32 @@ namespace :db do
|
|
5
5
|
task :load_models do
|
6
6
|
end
|
7
7
|
|
8
|
-
desc "Create
|
8
|
+
desc "Create indexes specified in Mongoid models"
|
9
9
|
task :create_indexes => [:environment, :load_models] do
|
10
10
|
::Mongoid::Tasks::Database.create_indexes
|
11
11
|
end
|
12
12
|
|
13
|
-
desc "Remove indexes that exist in the database but
|
13
|
+
desc "Remove indexes that exist in the database but are not specified in Mongoid models"
|
14
14
|
task :remove_undefined_indexes => [:environment, :load_models] do
|
15
15
|
::Mongoid::Tasks::Database.remove_undefined_indexes
|
16
16
|
end
|
17
17
|
|
18
|
-
desc "Remove
|
18
|
+
desc "Remove indexes specified in Mongoid models"
|
19
19
|
task :remove_indexes => [:environment, :load_models] do
|
20
20
|
::Mongoid::Tasks::Database.remove_indexes
|
21
21
|
end
|
22
22
|
|
23
|
-
desc "
|
23
|
+
desc "Shard collections with shard keys specified in Mongoid models"
|
24
|
+
task :shard_collections => [:environment, :load_models] do
|
25
|
+
::Mongoid::Tasks::Database.shard_collections
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Drop the database of the default Mongoid client"
|
24
29
|
task :drop => :environment do
|
25
30
|
::Mongoid::Clients.default.database.drop
|
26
31
|
end
|
27
32
|
|
28
|
-
desc "Drop all
|
33
|
+
desc "Drop all non-system collections"
|
29
34
|
task :purge => :environment do
|
30
35
|
::Mongoid.purge!
|
31
36
|
end
|
@@ -108,6 +108,54 @@ module Mongoid
|
|
108
108
|
end.compact
|
109
109
|
end
|
110
110
|
|
111
|
+
# Shard collections for models that declare shard keys.
|
112
|
+
#
|
113
|
+
# Returns the model classes that have had their collections sharded,
|
114
|
+
# including model classes whose collections had already been sharded
|
115
|
+
# prior to the invocation of this method.
|
116
|
+
#
|
117
|
+
# @example Shard all collections
|
118
|
+
# Mongoid::Tasks::Database.shard_collections
|
119
|
+
#
|
120
|
+
# @return [ Array<Class> ] The sharded models
|
121
|
+
def shard_collections(models = ::Mongoid.models)
|
122
|
+
models.map do |model|
|
123
|
+
next if model.shard_config.nil?
|
124
|
+
|
125
|
+
if model.embedded? && !model.cyclic?
|
126
|
+
logger.warn("MONGOID: #{model} has shard config but is emdedded")
|
127
|
+
next
|
128
|
+
end
|
129
|
+
|
130
|
+
unless model.collection.cluster.sharded?
|
131
|
+
logger.warn("MONGOID: #{model} has shard config but is not persisted in a sharded cluster: #{model.collection.cluster.summary}")
|
132
|
+
next
|
133
|
+
end
|
134
|
+
|
135
|
+
# Database must exist in order to run collStats
|
136
|
+
model.collection.create
|
137
|
+
|
138
|
+
stats = model.collection.database.command(collStats: model.collection.name).first
|
139
|
+
if stats[:sharded]
|
140
|
+
logger.info("MONGOID: #{model.collection.namespace} is already sharded for #{model}")
|
141
|
+
next model
|
142
|
+
end
|
143
|
+
|
144
|
+
admin_db = model.collection.client.use(:admin).database
|
145
|
+
admin_db.command(enableSharding: model.collection.database.name)
|
146
|
+
begin
|
147
|
+
admin_db.command(shardCollection: model.collection.namespace, **model.shard_config)
|
148
|
+
rescue Mongo::Error::OperationFailure => e
|
149
|
+
logger.error("MONGOID: Failed to shard collection #{model.collection.namespace} for #{model}: #{e.class}: #{e}")
|
150
|
+
next
|
151
|
+
end
|
152
|
+
|
153
|
+
logger.info("MONGOID: Sharded collection #{model.collection.namespace} for #{model}")
|
154
|
+
|
155
|
+
model
|
156
|
+
end.compact
|
157
|
+
end
|
158
|
+
|
111
159
|
private
|
112
160
|
|
113
161
|
def logger
|
@@ -44,11 +44,13 @@ module Mongoid
|
|
44
44
|
end
|
45
45
|
|
46
46
|
class << self
|
47
|
+
extend Forwardable
|
47
48
|
|
48
49
|
def timeless_table
|
49
50
|
Thread.current['[mongoid]:timeless'] ||= Hash.new
|
50
51
|
end
|
51
|
-
|
52
|
+
|
53
|
+
def_delegators :timeless_table, :[]=, :[]
|
52
54
|
end
|
53
55
|
|
54
56
|
private
|
data/lib/mongoid/version.rb
CHANGED
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
require_relative '../mongoid/shardable_models'
|
6
|
+
|
7
|
+
describe 'Sharding helpers' do
|
8
|
+
require_topology :sharded
|
9
|
+
|
10
|
+
describe 'shard_collection rake task' do
|
11
|
+
let(:shard_collections) do
|
12
|
+
Mongoid::Tasks::Database.shard_collections([model_cls])
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:create_indexes) do
|
16
|
+
Mongoid::Tasks::Database.create_indexes([model_cls])
|
17
|
+
end
|
18
|
+
|
19
|
+
shared_examples_for 'shards collection' do
|
20
|
+
it 'returns the model class' do
|
21
|
+
shard_collections.should == [model_cls]
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'shards collection' do
|
25
|
+
shard_collections
|
26
|
+
|
27
|
+
stats = model_cls.collection.database.command(collStats: model_cls.collection.name).first
|
28
|
+
stats[:sharded].should be true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'simple model' do
|
33
|
+
let(:model_cls) { SmMovie }
|
34
|
+
|
35
|
+
before do
|
36
|
+
SmMovie.collection.drop
|
37
|
+
end
|
38
|
+
|
39
|
+
it_behaves_like 'shards collection'
|
40
|
+
|
41
|
+
it 'makes inserts work' do
|
42
|
+
shard_collections
|
43
|
+
create_indexes
|
44
|
+
|
45
|
+
SmMovie.create!(year: 2020)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when database does not exist' do
|
50
|
+
let(:model_cls) { SmMovie }
|
51
|
+
|
52
|
+
before do
|
53
|
+
SmMovie.collection.database.drop
|
54
|
+
end
|
55
|
+
|
56
|
+
it_behaves_like 'shards collection'
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when database exists but collection does not exist' do
|
60
|
+
let(:model_cls) { SmMovie }
|
61
|
+
|
62
|
+
before do
|
63
|
+
SmMovie.collection.database.drop
|
64
|
+
SmMovie.collection.create
|
65
|
+
SmMovie.collection.drop
|
66
|
+
end
|
67
|
+
|
68
|
+
it_behaves_like 'shards collection'
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when collection is already sharded' do
|
72
|
+
let(:model_cls) { SmMovie }
|
73
|
+
|
74
|
+
before do
|
75
|
+
Mongoid::Tasks::Database.shard_collections([model_cls])
|
76
|
+
end
|
77
|
+
|
78
|
+
it_behaves_like 'shards collection'
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when hashed shard key is given' do
|
82
|
+
let(:model_cls) { SmAssistant }
|
83
|
+
|
84
|
+
before do
|
85
|
+
SmAssistant.collection.drop
|
86
|
+
end
|
87
|
+
|
88
|
+
it_behaves_like 'shards collection'
|
89
|
+
|
90
|
+
it 'makes inserts work' do
|
91
|
+
shard_collections
|
92
|
+
create_indexes
|
93
|
+
|
94
|
+
SmAssistant.create!(gender: 'm')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'when shard configuration is invalid' do
|
99
|
+
let(:model_cls) { SmActor }
|
100
|
+
|
101
|
+
it 'returns empty array' do
|
102
|
+
shard_collections.should == []
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'does not shards collection' do
|
106
|
+
shard_collections
|
107
|
+
|
108
|
+
stats = model_cls.collection.database.command(collStats: model_cls.collection.name).first
|
109
|
+
stats[:sharded].should be false
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'when models have no sharded configuration' do
|
115
|
+
let(:model_cls) { SmNotSharded }
|
116
|
+
|
117
|
+
before do
|
118
|
+
model_cls.shard_config.should be nil
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'returns empty array' do
|
122
|
+
shard_collections.should == []
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'does not shards collection' do
|
126
|
+
shard_collections
|
127
|
+
|
128
|
+
stats = model_cls.collection.database.command(collStats: model_cls.collection.name).first
|
129
|
+
stats[:sharded].should be false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/spec/lite_spec_helper.rb
CHANGED
@@ -15,6 +15,7 @@ require "mongo"
|
|
15
15
|
require 'pp'
|
16
16
|
|
17
17
|
require 'support/spec_config'
|
18
|
+
require 'support/lite_constraints'
|
18
19
|
|
19
20
|
unless SpecConfig.instance.ci?
|
20
21
|
begin
|
@@ -58,6 +59,8 @@ RSpec.configure do |config|
|
|
58
59
|
end
|
59
60
|
end
|
60
61
|
end
|
62
|
+
|
63
|
+
config.extend(LiteConstraints)
|
61
64
|
end
|
62
65
|
|
63
66
|
# require all shared examples
|
@@ -782,11 +782,7 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
782
782
|
end
|
783
783
|
end
|
784
784
|
|
785
|
-
|
786
|
-
|
787
|
-
subject do
|
788
|
-
enumerable.public_send(subject_method)
|
789
|
-
end
|
785
|
+
describe "#first" do
|
790
786
|
|
791
787
|
let(:person) do
|
792
788
|
Person.create
|
@@ -810,8 +806,12 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
810
806
|
Post.create(person_id: person.id)
|
811
807
|
end
|
812
808
|
|
809
|
+
let(:first) do
|
810
|
+
enumerable.first
|
811
|
+
end
|
812
|
+
|
813
813
|
it "returns the first unloaded doc" do
|
814
|
-
expect(
|
814
|
+
expect(first).to eq(post)
|
815
815
|
end
|
816
816
|
|
817
817
|
it "does not load the enumerable" do
|
@@ -820,7 +820,7 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
820
820
|
|
821
821
|
it "receives query only once" do
|
822
822
|
expect(criteria).to receive(:first).once
|
823
|
-
|
823
|
+
first
|
824
824
|
end
|
825
825
|
end
|
826
826
|
|
@@ -838,10 +838,14 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
838
838
|
enumerable << post_two
|
839
839
|
end
|
840
840
|
|
841
|
+
let(:first) do
|
842
|
+
enumerable.first
|
843
|
+
end
|
844
|
+
|
841
845
|
context "when a perviously persisted unloaded doc exists" do
|
842
846
|
|
843
847
|
it "returns the first added doc" do
|
844
|
-
expect(
|
848
|
+
expect(first).to eq(post)
|
845
849
|
end
|
846
850
|
|
847
851
|
it "does not load the enumerable" do
|
@@ -861,8 +865,12 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
861
865
|
enumerable << post
|
862
866
|
end
|
863
867
|
|
868
|
+
let(:first) do
|
869
|
+
enumerable.first
|
870
|
+
end
|
871
|
+
|
864
872
|
it "returns the first loaded doc" do
|
865
|
-
expect(
|
873
|
+
expect(first).to eq(post)
|
866
874
|
end
|
867
875
|
|
868
876
|
it "does not load the enumerable" do
|
@@ -872,8 +880,12 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
872
880
|
|
873
881
|
context "when unloaded and added are empty" do
|
874
882
|
|
883
|
+
let(:first) do
|
884
|
+
enumerable.first
|
885
|
+
end
|
886
|
+
|
875
887
|
it "returns nil" do
|
876
|
-
expect(
|
888
|
+
expect(first).to be_nil
|
877
889
|
end
|
878
890
|
|
879
891
|
it "does not load the enumerable" do
|
@@ -894,8 +906,12 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
894
906
|
described_class.new([ post ])
|
895
907
|
end
|
896
908
|
|
909
|
+
let(:first) do
|
910
|
+
enumerable.first
|
911
|
+
end
|
912
|
+
|
897
913
|
it "returns the first loaded doc" do
|
898
|
-
expect(
|
914
|
+
expect(first).to eq(post)
|
899
915
|
end
|
900
916
|
end
|
901
917
|
|
@@ -913,8 +929,12 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
913
929
|
enumerable << post
|
914
930
|
end
|
915
931
|
|
932
|
+
let(:first) do
|
933
|
+
enumerable.first
|
934
|
+
end
|
935
|
+
|
916
936
|
it "returns the first added doc" do
|
917
|
-
expect(
|
937
|
+
expect(first).to eq(post)
|
918
938
|
end
|
919
939
|
end
|
920
940
|
|
@@ -924,8 +944,12 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
924
944
|
described_class.new([])
|
925
945
|
end
|
926
946
|
|
947
|
+
let(:first) do
|
948
|
+
enumerable.first
|
949
|
+
end
|
950
|
+
|
927
951
|
it "returns nil" do
|
928
|
-
expect(
|
952
|
+
expect(first).to be_nil
|
929
953
|
end
|
930
954
|
end
|
931
955
|
end
|
@@ -953,21 +977,9 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
953
977
|
end
|
954
978
|
|
955
979
|
it 'does not use the sort on id' do
|
956
|
-
expect(enumerable.
|
980
|
+
expect(enumerable.first(id_sort: :none)).to eq(first_post)
|
957
981
|
end
|
958
982
|
end
|
959
|
-
end
|
960
|
-
|
961
|
-
describe "#first" do
|
962
|
-
let(:subject_method) do
|
963
|
-
:first
|
964
|
-
end
|
965
|
-
|
966
|
-
it_behaves_like 'first or one'
|
967
|
-
|
968
|
-
subject do
|
969
|
-
enumerable.public_send(subject_method)
|
970
|
-
end
|
971
983
|
|
972
984
|
context 'when the id_sort option is not provided' do
|
973
985
|
|
@@ -984,54 +996,15 @@ describe Mongoid::Association::Referenced::HasMany::Targets::Enumerable do
|
|
984
996
|
end
|
985
997
|
|
986
998
|
let!(:first_post) do
|
987
|
-
person.posts.create(
|
999
|
+
person.posts.create(title: "One")
|
988
1000
|
end
|
989
1001
|
|
990
1002
|
let!(:second_post) do
|
991
|
-
person.posts.create(
|
1003
|
+
person.posts.create(title: "Two")
|
992
1004
|
end
|
993
1005
|
|
994
1006
|
it 'uses the sort on id' do
|
995
|
-
expect(
|
996
|
-
end
|
997
|
-
end
|
998
|
-
end
|
999
|
-
|
1000
|
-
describe "#one" do
|
1001
|
-
let(:subject_method) do
|
1002
|
-
:one
|
1003
|
-
end
|
1004
|
-
|
1005
|
-
it_behaves_like 'first or one'
|
1006
|
-
|
1007
|
-
subject do
|
1008
|
-
enumerable.public_send(subject_method)
|
1009
|
-
end
|
1010
|
-
|
1011
|
-
context 'when the id_sort option is not provided' do
|
1012
|
-
|
1013
|
-
let(:person) do
|
1014
|
-
Person.create
|
1015
|
-
end
|
1016
|
-
|
1017
|
-
let(:criteria) do
|
1018
|
-
Post.where(person_id: person.id)
|
1019
|
-
end
|
1020
|
-
|
1021
|
-
let(:enumerable) do
|
1022
|
-
described_class.new(criteria)
|
1023
|
-
end
|
1024
|
-
|
1025
|
-
let!(:first_post) do
|
1026
|
-
person.posts.create(id: 'one', title: "One")
|
1027
|
-
end
|
1028
|
-
|
1029
|
-
let!(:second_post) do
|
1030
|
-
person.posts.create(id: 'atwo', title: "Two")
|
1031
|
-
end
|
1032
|
-
|
1033
|
-
it 'does not use the sort on id' do
|
1034
|
-
expect(subject).to eq(first_post)
|
1007
|
+
expect(enumerable.first).to eq(first_post)
|
1035
1008
|
end
|
1036
1009
|
end
|
1037
1010
|
end
|