mongoid 7.2.1 → 7.2.2

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 (35) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongoid/attributes.rb +8 -1
  5. data/lib/mongoid/matcher.rb +19 -43
  6. data/lib/mongoid/matcher/elem_match.rb +2 -1
  7. data/lib/mongoid/matcher/expression.rb +5 -14
  8. data/lib/mongoid/matcher/field_expression.rb +4 -5
  9. data/lib/mongoid/reloadable.rb +5 -0
  10. data/lib/mongoid/version.rb +1 -1
  11. data/lib/rails/generators/mongoid/config/config_generator.rb +8 -1
  12. data/spec/integration/app_spec.rb +136 -82
  13. data/spec/integration/document_spec.rb +21 -0
  14. data/spec/integration/matcher_operator_data/elem_match.yml +46 -0
  15. data/spec/integration/matcher_operator_data/implicit_traversal.yml +96 -0
  16. data/spec/lite_spec_helper.rb +2 -3
  17. data/spec/mongoid/attributes_spec.rb +241 -0
  18. data/spec/mongoid/contextual/atomic_spec.rb +17 -4
  19. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  20. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +68 -88
  21. data/spec/mongoid/matcher/extract_attribute_spec.rb +3 -13
  22. data/spec/mongoid/persistable/settable_spec.rb +30 -0
  23. data/spec/shared/bin/get-mongodb-download-url +17 -0
  24. data/spec/shared/lib/mrss/cluster_config.rb +11 -1
  25. data/spec/shared/lib/mrss/constraints.rb +18 -2
  26. data/spec/shared/lib/mrss/docker_runner.rb +3 -0
  27. data/spec/shared/lib/mrss/lite_constraints.rb +16 -0
  28. data/spec/shared/lib/mrss/server_version_registry.rb +79 -33
  29. data/spec/shared/lib/mrss/spec_organizer.rb +3 -0
  30. data/spec/shared/lib/mrss/utils.rb +15 -0
  31. data/spec/shared/share/Dockerfile.erb +13 -11
  32. data/spec/shared/shlib/server.sh +29 -9
  33. data/spec/support/spec_config.rb +8 -0
  34. metadata +8 -2
  35. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb2c430462ea474d889d41fa20a7011b5ddfeeac215cddc762c2e2a4324e8ef9
4
- data.tar.gz: 002a48e7013981c8c12f45edca4f5c9a5c75c9b99ac5f2fd46422532871ae775
3
+ metadata.gz: 9ad177a2fa24df66fa961debfa6cf72d704197aac40c03ef6159754df707133f
4
+ data.tar.gz: c3a391dd0d98167417b6823e6741e48a65894815c96446ffeca071d836c07239
5
5
  SHA512:
6
- metadata.gz: 6985ec8a658d859e3a8f863eca20326d11aba2249488f10cff0bb6c01c8a4de759ab6726b1573e7e6a845ccf5b72213b8fe0374d699761e13608121216bafe98
7
- data.tar.gz: fb681e64b86e56203d0029452b71f197bcadfb86b56ccadd514edc6bac416c68490ed708db5a09bc84cf638a43fb359d6ec977f31ca226429c0ca99de0af3120
6
+ metadata.gz: 337fdd906646d343a8e1c675d094d48a66f23109b8b024fb1114e09021f6f705cf67b47f2846255802fb67cd2fb4a0201c9772abbbbdad1df908a2f94ba5c43a
7
+ data.tar.gz: 8809e783b1c54d140498fd59580a19400368642175da05827c7f3dbd76fee0cdb77177bd29bd896594b02fc64f199e52c10faaaed012424c49226ddc0f054645
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -160,6 +160,11 @@ module Mongoid
160
160
  # @since 1.0.0
161
161
  def write_attribute(name, value)
162
162
  field_name = database_field_name(name)
163
+
164
+ if attribute_missing?(field_name)
165
+ raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'"
166
+ end
167
+
163
168
  if attribute_writable?(field_name)
164
169
  _assigning do
165
170
  validate_attribute_value(field_name, value)
@@ -177,6 +182,8 @@ module Mongoid
177
182
  end
178
183
  typed_value
179
184
  end
185
+ else
186
+ # TODO: MONGOID-5072
180
187
  end
181
188
  end
182
189
  alias :[]= :write_attribute
@@ -294,7 +301,7 @@ module Mongoid
294
301
  def read_raw_attribute(name)
295
302
  normalized = database_field_name(name.to_s)
296
303
  if attribute_missing?(normalized)
297
- raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'."
304
+ raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'"
298
305
  end
299
306
  if hash_dot_syntax?(normalized)
300
307
  attributes.__nested__(normalized)
@@ -43,60 +43,36 @@ module Mongoid
43
43
  document = BSON::Document.new(document.send(:as_attributes))
44
44
  end
45
45
 
46
- src = document
47
- expanded = false
48
- exists = true
46
+ current = [document]
49
47
 
50
48
  key.to_s.split('.').each do |field|
51
- if (index = field.to_i).to_s == field
52
- # Array indexing
53
- if Array === src
54
- exists = index < src.length
55
- src = src[index]
56
- else
57
- # Trying to index something that is not an array
58
- exists = false
59
- src = nil
60
- end
61
- else
62
- case src
63
- when nil
64
- exists = false
49
+ new = []
50
+ current.each do |doc|
51
+ case doc
65
52
  when Hash
66
- exists = src.key?(field)
67
- src = src[field]
53
+ if doc.key?(field)
54
+ new << doc[field]
55
+ end
68
56
  when Array
69
- expanded = true
70
- exists = false
71
- new = []
72
- src.each do |doc|
73
- case doc
74
- when Hash
75
- if doc.key?(field)
76
- v = doc[field]
77
- case v
78
- when Array
79
- new += v
80
- else
81
- new += [v]
82
- end
83
- exists = true
57
+ if (index = field.to_i).to_s == field
58
+ if doc.length > index
59
+ new << doc[index]
60
+ end
61
+ end
62
+ doc.each do |subdoc|
63
+ if Hash === subdoc
64
+ if subdoc.key?(field)
65
+ new << subdoc[field]
84
66
  end
85
- else
86
- # Trying to hash index into a value that is not a hash
87
67
  end
88
68
  end
89
- src = new
90
- else
91
- # Trying to descend into a field that is not a hash using
92
- # dot notation.
93
- exists = false
94
- src = nil
95
69
  end
96
70
  end
71
+ current = new
72
+ break if current.empty?
97
73
  end
98
74
 
99
- [exists, src, expanded]
75
+ current
100
76
  end
101
77
  end
102
78
  end
@@ -15,7 +15,8 @@ module Mongoid
15
15
  # Validate the condition is valid, even though we will never attempt
16
16
  # matching it.
17
17
  condition.each do |k, v|
18
- if k.to_s.start_with?('$')
18
+ k = k.to_s
19
+ if k.start_with?('$')
19
20
  begin
20
21
  ExpressionOperator.get(k)
21
22
  rescue Mongoid::Errors::InvalidExpressionOperator
@@ -15,22 +15,13 @@ module Mongoid
15
15
  if k.start_with?('$')
16
16
  ExpressionOperator.get(k).matches?(document, expr_v)
17
17
  else
18
- exists, value, expanded = Matcher.extract_attribute(document, k)
19
- # The value may have been expanded into an array, but then
20
- # array may have been shrunk back to a scalar (or hash) when
21
- # path contained a numeric position.
22
- # Do not treat a hash as an array here (both are iterable).
23
- if expanded && Array === value
24
- if value == []
25
- # Empty array is technically equivalent to exists: false.
26
- FieldExpression.matches?(false, nil, expr_v)
27
- else
28
- value.any? do |v|
29
- FieldExpression.matches?(true, v, expr_v)
30
- end
18
+ values = Matcher.extract_attribute(document, k)
19
+ if values.length > 0
20
+ values.any? do |v|
21
+ FieldExpression.matches?(true, v, expr_v)
31
22
  end
32
23
  else
33
- FieldExpression.matches?(exists, value, expr_v)
24
+ FieldExpression.matches?(false, nil, expr_v)
34
25
  end
35
26
  end
36
27
  end
@@ -36,14 +36,13 @@ module Mongoid
36
36
  FieldOperator.get(k).matches?(exists, value, cond_v)
37
37
  end
38
38
  elsif Hash === value
39
- sub_exists, sub_value, expanded =
40
- Matcher.extract_attribute(value, k)
41
- if expanded
42
- sub_value.any? do |sub_v|
39
+ sub_values = Matcher.extract_attribute(value, k)
40
+ if sub_values.length > 0
41
+ sub_values.any? do |sub_v|
43
42
  Eq.matches?(true, sub_v, cond_v)
44
43
  end
45
44
  else
46
- Eq.matches?(sub_exists, sub_value, cond_v)
45
+ Eq.matches?(false, nil, cond_v)
47
46
  end
48
47
  else
49
48
  false
@@ -21,6 +21,11 @@ module Mongoid
21
21
  #
22
22
  # @since 1.0.0
23
23
  def reload
24
+ if @atomic_selector
25
+ # Clear atomic_selector cache for sharded clusters. MONGOID-5076
26
+ remove_instance_variable('@atomic_selector')
27
+ end
28
+
24
29
  reloaded = _reload
25
30
  if Mongoid.raise_not_found_error && reloaded.empty?
26
31
  raise Errors::DocumentNotFound.new(self.class, _id, _id)
@@ -2,5 +2,5 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  module Mongoid
5
- VERSION = "7.2.1"
5
+ VERSION = "7.2.2"
6
6
  end
@@ -15,7 +15,14 @@ module Mongoid
15
15
  end
16
16
 
17
17
  def app_name
18
- Rails::Application.subclasses.first.parent.to_s.underscore
18
+ app_cls = Rails.application.class
19
+ parent = begin
20
+ # Rails 6.1+
21
+ app_cls.module_parent_name
22
+ rescue NoMethodError
23
+ app_cls.parent.to_s
24
+ end
25
+ parent.underscore
19
26
  end
20
27
 
21
28
  def create_config_file
@@ -19,103 +19,125 @@ describe 'Mongoid application tests' do
19
19
  FileUtils.mkdir_p(TMP_BASE)
20
20
  end
21
21
 
22
- context 'demo application - sinatra' do
23
- it 'runs' do
24
- clone_application(
25
- 'https://github.com/mongoid/mongoid-demo',
26
- subdir: 'sinatra-minimal',
27
- ) do
28
-
29
- process = ChildProcess.build(*%w(bundle exec ruby app.rb))
30
- process.environment.update(clean_env)
31
- process.io.inherit!
32
- process.start
33
-
34
- begin
22
+ context 'demo application' do
23
+ context 'sinatra' do
24
+ it 'runs' do
25
+ clone_application(
26
+ 'https://github.com/mongoid/mongoid-demo',
27
+ subdir: 'sinatra-minimal',
28
+ ) do
29
+
35
30
  # JRuby needs a long timeout
36
- wait_for_port(4567, 20)
37
- sleep 1
38
-
39
- uri = URI.parse('http://localhost:4567/posts')
40
- resp = JSON.parse(uri.open.read)
41
- ensure
42
- Process.kill('TERM', process.pid)
43
- status = process.wait
44
- end
31
+ start_app(%w(bundle exec ruby app.rb), 4567, 40) do |port|
32
+ uri = URI.parse('http://localhost:4567/posts')
33
+ resp = JSON.parse(uri.open.read)
45
34
 
46
- resp.should == []
35
+ resp.should == []
47
36
 
48
- status.should == 0
37
+ end
38
+ end
49
39
  end
50
40
  end
51
- end
52
41
 
53
- context 'demo application - rails-api' do
54
- ['~> 6.0.0'].each do |rails_version|
55
- context "with rails #{rails_version}" do
56
- it 'runs' do
57
- clone_application(
58
- 'https://github.com/mongoid/mongoid-demo',
59
- subdir: 'rails-api',
60
- rails_version: rails_version,
61
- ) do
62
-
63
- process = ChildProcess.build(*%w(bundle exec rails s))
64
- process.environment.update(clean_env)
65
- process.io.inherit!
66
- process.start
67
-
68
- begin
69
- # JRuby needs a long timeout
70
- wait_for_port(3000, 30)
71
- sleep 1
72
-
73
- uri = URI.parse('http://localhost:3000/posts')
74
- resp = JSON.parse(uri.open.read)
75
- ensure
76
- Process.kill('TERM', process.pid)
77
- status = process.wait
78
- end
42
+ context 'rails-api' do
43
+ it 'runs' do
44
+ clone_application(
45
+ 'https://github.com/mongoid/mongoid-demo',
46
+ subdir: 'rails-api',
47
+ ) do
79
48
 
80
- resp.should == []
49
+ # JRuby needs a long timeout
50
+ start_app(%w(bundle exec rails s), 3000, 50) do |port|
51
+ uri = URI.parse('http://localhost:3000/posts')
52
+ resp = JSON.parse(uri.open.read)
81
53
 
82
- # 143 = 128 + 15
83
- [0, 15, 143].should include(status)
54
+ resp.should == []
84
55
  end
85
56
  end
86
57
  end
87
58
  end
88
59
  end
89
60
 
61
+ def start_app(cmd, port, timeout)
62
+ process = ChildProcess.build(*cmd)
63
+ process.environment.update(clean_env)
64
+ process.io.inherit!
65
+ process.start
66
+
67
+ begin
68
+ wait_for_port(port, timeout, process)
69
+ sleep 1
70
+
71
+ rv = yield port
72
+ ensure
73
+ # The process may have already died (due to an error exit) -
74
+ # in this case killing it will raise an exception.
75
+ Process.kill('TERM', process.pid) rescue nil
76
+ status = process.wait
77
+ end
78
+
79
+ # Exit should be either success or SIGTERM
80
+ [0, 15, 128 + 15].should include(status)
81
+
82
+ rv
83
+ end
84
+
90
85
  context 'new application - rails' do
91
- ['~> 5.1.0', '~> 5.2.0', '~> 6.0.0'].each do |rails_version|
92
- context "with rails #{rails_version}" do
93
- it 'creates' do
94
- Mrss::ChildProcessHelper.check_call(%w(gem uni rails -a))
95
- Mrss::ChildProcessHelper.check_call(%w(gem install rails --no-document -v) + [rails_version])
96
-
97
- Dir.chdir(TMP_BASE) do
98
- FileUtils.rm_rf('mongoid-test')
99
- Mrss::ChildProcessHelper.check_call(%w(rails new mongoid-test --skip-spring --skip-active-record), env: clean_env)
100
-
101
- Dir.chdir('mongoid-test') do
102
- adjust_app_gemfile
103
- Mrss::ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
104
-
105
- Mrss::ChildProcessHelper.check_call(%w(rails g model post), env: clean_env)
106
- Mrss::ChildProcessHelper.check_call(%w(rails g model comment post:belongs_to), env: clean_env)
107
-
108
- # https://jira.mongodb.org/browse/MONGOID-4885
109
- comment_text = File.read('app/models/comment.rb')
110
- comment_text.should =~ /belongs_to :post/
111
- comment_text.should_not =~ /embedded_in :post/
112
- end
113
- end
86
+ it 'creates' do
87
+ install_rails
88
+
89
+ Dir.chdir(TMP_BASE) do
90
+ FileUtils.rm_rf('mongoid-test')
91
+ Mrss::ChildProcessHelper.check_call(%w(rails new mongoid-test --skip-spring --skip-active-record), env: clean_env)
92
+
93
+ Dir.chdir('mongoid-test') do
94
+ adjust_app_gemfile
95
+ Mrss::ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
96
+
97
+ Mrss::ChildProcessHelper.check_call(%w(rails g model post), env: clean_env)
98
+ Mrss::ChildProcessHelper.check_call(%w(rails g model comment post:belongs_to), env: clean_env)
99
+
100
+ # https://jira.mongodb.org/browse/MONGOID-4885
101
+ comment_text = File.read('app/models/comment.rb')
102
+ comment_text.should =~ /belongs_to :post/
103
+ comment_text.should_not =~ /embedded_in :post/
104
+ end
105
+ end
106
+ end
107
+
108
+ it 'generates Mongoid config' do
109
+ install_rails
110
+
111
+ Dir.chdir(TMP_BASE) do
112
+ FileUtils.rm_rf('mongoid-test-config')
113
+ Mrss::ChildProcessHelper.check_call(%w(rails new mongoid-test-config --skip-spring --skip-active-record), env: clean_env)
114
+
115
+ Dir.chdir('mongoid-test-config') do
116
+ adjust_app_gemfile
117
+ Mrss::ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
118
+
119
+ mongoid_config_file = File.join(TMP_BASE,'mongoid-test-config/config/mongoid.yml')
120
+
121
+ File.exist?(mongoid_config_file).should be false
122
+ Mrss::ChildProcessHelper.check_call(%w(rails g mongoid:config), env: clean_env)
123
+ File.exist?(mongoid_config_file).should be true
124
+
125
+ config_text = File.read(mongoid_config_file)
126
+ config_text.should =~ /mongoid_test_config_development/
127
+ config_text.should =~ /mongoid_test_config_test/
114
128
  end
115
129
  end
116
130
  end
117
131
  end
118
132
 
133
+ def install_rails
134
+ Mrss::ChildProcessHelper.check_call(%w(gem uni rails -a))
135
+ if (rails_version = SpecConfig.instance.rails_version) == 'master'
136
+ else
137
+ Mrss::ChildProcessHelper.check_call(%w(gem install rails --no-document -v) + [rails_version])
138
+ end
139
+ end
140
+
119
141
  context 'local test applications' do
120
142
  let(:client) { Mongoid.default_client }
121
143
 
@@ -165,12 +187,13 @@ describe 'Mongoid application tests' do
165
187
  end
166
188
  end
167
189
 
168
- def clone_application(repo_url, subdir: nil, rails_version: nil)
190
+ def clone_application(repo_url, subdir: nil)
169
191
  Dir.chdir(TMP_BASE) do
170
192
  FileUtils.rm_rf(File.basename(repo_url))
171
193
  Mrss::ChildProcessHelper.check_call(%w(git clone) + [repo_url])
172
194
  Dir.chdir(File.join(*[File.basename(repo_url), subdir].compact)) do
173
- adjust_app_gemfile(rails_version: rails_version)
195
+ adjust_app_gemfile
196
+ adjust_rails_defaults
174
197
  Mrss::ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
175
198
  puts `git diff`
176
199
 
@@ -226,7 +249,7 @@ describe 'Mongoid application tests' do
226
249
  end
227
250
  end
228
251
 
229
- def adjust_app_gemfile(rails_version: nil)
252
+ def adjust_app_gemfile(rails_version: SpecConfig.instance.rails_version)
230
253
  remove_bundler_req
231
254
 
232
255
  gemfile_lines = IO.readlines('Gemfile')
@@ -238,13 +261,41 @@ describe 'Mongoid application tests' do
238
261
  gemfile_lines.delete_if do |line|
239
262
  line =~ /rails/
240
263
  end
241
- gemfile_lines << "gem 'rails', '#{rails_version}'\n"
264
+ if rails_version == 'master'
265
+ gemfile_lines << "gem 'rails', git: 'https://github.com/rails/rails'\n"
266
+ else
267
+ gemfile_lines << "gem 'rails', '~> #{rails_version}.0'\n"
268
+ end
242
269
  end
243
270
  File.open('Gemfile', 'w') do |f|
244
271
  f << gemfile_lines.join
245
272
  end
246
273
  end
247
274
 
275
+ def adjust_rails_defaults(rails_version: SpecConfig.instance.rails_version)
276
+ if File.exist?('config/application.rb')
277
+ lines = IO.readlines('config/application.rb')
278
+ lines.each do |line|
279
+ line.gsub!(/config.load_defaults \d\.\d/, "config.load_defaults #{rails_version}")
280
+ end
281
+ File.open('config/application.rb', 'w') do |f|
282
+ f << lines.join
283
+ end
284
+ end
285
+
286
+ if rails_version == '5.1'
287
+ secrets = {
288
+ 'development' => {
289
+ 'secret_key_base' => 'abracadabra',
290
+ 'my_secret_token' => 'very_secret',
291
+ },
292
+ }
293
+ File.open('config/secrets.yml', 'w') do |f|
294
+ f << YAML.dump(secrets)
295
+ end
296
+ end
297
+ end
298
+
248
299
  def remove_bundler_req
249
300
  lock_lines = IO.readlines('Gemfile.lock')
250
301
  # Get rid of the bundled with line so that whatever bundler is installed
@@ -270,7 +321,7 @@ describe 'Mongoid application tests' do
270
321
  @clean_env ||= Hash[ENV.keys.grep(/BUNDLE|RUBYOPT/).map { |k| [k, nil ] }]
271
322
  end
272
323
 
273
- def wait_for_port(port, timeout)
324
+ def wait_for_port(port, timeout, process)
274
325
  deadline = Time.now + timeout
275
326
  loop do
276
327
  begin
@@ -278,6 +329,9 @@ describe 'Mongoid application tests' do
278
329
  return
279
330
  end
280
331
  rescue IOError, SystemCallError
332
+ unless process.alive?
333
+ raise "Process #{process} died while waiting for port #{port}"
334
+ end
281
335
  if Time.now > deadline
282
336
  raise
283
337
  end