mongoid 7.0.12 → 7.0.13

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08107532375c756a9a063a167169b570fa9d5f195e753a4f19a70ee7778eff1c'
4
- data.tar.gz: addbf1ebd6dc0edc11a2604b4e3c1bf7297d67ad12739dcd44e981d2a8949cac
3
+ metadata.gz: c687add0cd3bcd3001781fcb3011966fb5617848c1b1096c9ecf08a6a8d3e123
4
+ data.tar.gz: 242b9126fc96c4719aa23e96a25f9ff590c063020b8d8806315cbd887316fd24
5
5
  SHA512:
6
- metadata.gz: 77dbc0a24838853d496fd5957770ef250c952cf57a126b36845540e6421888aa3abc9465ecb64d0a55940324c02a7e22a37935729deec400b6d2f0510138930a
7
- data.tar.gz: 0b78a7bbe3049aff86657a02e88f61ef4b8281f5cd198567bbe153d44f7f56d74eca7b0119a40d9b8188ffb0b78f73847abbba82b39b601220f177ef7ac80a61
6
+ metadata.gz: 13f8de150ffbc721206b56d8b532525bd66d380454d3ae53e202159da26d39db48a0c70f15ae0f10278adaa97ec3380c6565c2c97993f7953920b1ab89ea02a4
7
+ data.tar.gz: 2e5a35a8935add506b7a514ca392ce1f9f9e3d6440b0152a154d56bce2b9f5e12dabf7ce1ca9c99f6f424d7efcdeb1ddd3e05dad17849b91b7b76fd3b5cb543d
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/Rakefile CHANGED
@@ -2,8 +2,13 @@ require "bundler"
2
2
  require "bundler/gem_tasks"
3
3
  Bundler.setup
4
4
 
5
+ ROOT = File.expand_path(File.join(File.dirname(__FILE__)))
6
+
7
+ $: << File.join(ROOT, 'spec/shared/lib')
8
+
5
9
  require "rake"
6
10
  require "rspec/core/rake_task"
11
+ require 'mrss/spec_organizer'
7
12
 
8
13
  $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
9
14
  require "mongoid/version"
@@ -33,6 +38,32 @@ RSpec::Core::RakeTask.new('spec:progress') do |spec|
33
38
  spec.pattern = "spec/**/*_spec.rb"
34
39
  end
35
40
 
41
+ CLASSIFIERS = [
42
+ [%r,^mongoid/attribute,, :attributes],
43
+ [%r,^mongoid/association/[or],, :associations_referenced],
44
+ [%r,^mongoid/association,, :associations],
45
+ [%r,^mongoid,, :unit],
46
+ [%r,^integration,, :integration],
47
+ [%r,^rails,, :rails],
48
+ ]
49
+
50
+ RUN_PRIORITY = %i(
51
+ unit attributes associations_referenced associations
52
+ integration rails
53
+ )
54
+
55
+ def spec_organizer
56
+ Mrss::SpecOrganizer.new(
57
+ root: ROOT,
58
+ classifiers: CLASSIFIERS,
59
+ priority_order: RUN_PRIORITY,
60
+ )
61
+ end
62
+
63
+ task :ci do
64
+ spec_organizer.run
65
+ end
66
+
36
67
  task :default => :spec
37
68
 
38
69
  desc "Generate all documentation"
@@ -364,15 +364,12 @@ module Mongoid
364
364
  Binding.new(_base, _target, _association)
365
365
  end
366
366
 
367
- # Returns the "#{criteria}"# object for the target class with its documents set
368
- # to target.
369
- #
370
- # @example Get a criteria for the relation.
371
- # relation.criteria
367
+ # Returns the +Criteria+ object for the target class with its
368
+ # documents set to the list of target documents in the association.
372
369
  #
373
370
  # @return [ Criteria ] A new criteria.
374
371
  def criteria
375
- @criteria ||= _association.criteria(_base, _target)
372
+ _association.criteria(_base, _target)
376
373
  end
377
374
 
378
375
  # Deletes one document from the target and unscoped.
@@ -448,8 +445,8 @@ module Mongoid
448
445
  end
449
446
  end
450
447
 
451
- # Apply the association ordering or the default scoping to the provided
452
- # documents.
448
+ # Apply the association ordering and default scoping (defined on
449
+ # association's target class) to the provided documents.
453
450
  #
454
451
  # @example Apply scoping.
455
452
  # person.addresses.scope(target)
@@ -460,7 +457,10 @@ module Mongoid
460
457
  #
461
458
  # @since 2.4.0
462
459
  def scope(docs)
463
- return docs unless _association.order || _association.klass.default_scoping?
460
+ unless _association.order || _association.klass.default_scoping?
461
+ return docs
462
+ end
463
+
464
464
  crit = _association.klass.order_by(_association.order)
465
465
  crit.embedded = true
466
466
  crit.documents = docs
@@ -18,7 +18,20 @@ module Mongoid
18
18
  include Threaded::Lifecycle
19
19
  include Marshalable
20
20
 
21
- attr_accessor :_base, :_association, :_target
21
+ # Model instance for the base of the association.
22
+ #
23
+ # For example, if a Post embeds_many Comments, _base is a particular
24
+ # instance of the Post model.
25
+ attr_accessor :_base
26
+
27
+ attr_accessor :_association
28
+
29
+ # Model instance for one to one associations, or array of model instances
30
+ # for one to many associations, for the target of the association.
31
+ #
32
+ # For example, if a Post embeds_many Comments, _target is an array of
33
+ # Comment models embedded in a particular Post.
34
+ attr_accessor :_target
22
35
 
23
36
  # Backwards compatibility with Mongoid beta releases.
24
37
  delegate :foreign_key, :inverse_foreign_key, to: :_association
@@ -158,6 +158,11 @@ module Mongoid
158
158
  # @since 1.0.0
159
159
  def write_attribute(name, value)
160
160
  field_name = database_field_name(name)
161
+
162
+ if attribute_missing?(field_name)
163
+ raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'"
164
+ end
165
+
161
166
  if attribute_writable?(field_name)
162
167
  _assigning do
163
168
  validate_attribute_value(field_name, value)
@@ -175,6 +180,8 @@ module Mongoid
175
180
  end
176
181
  typed_value
177
182
  end
183
+ else
184
+ # TODO: MONGOID-5072
178
185
  end
179
186
  end
180
187
  alias :[]= :write_attribute
@@ -292,7 +299,7 @@ module Mongoid
292
299
  def read_raw_attribute(name)
293
300
  normalized = database_field_name(name.to_s)
294
301
  if attribute_missing?(normalized)
295
- raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'."
302
+ raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'"
296
303
  end
297
304
  if hash_dot_syntax?(normalized)
298
305
  attributes.__nested__(normalized)
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Mongoid
4
- VERSION = "7.0.12"
4
+ VERSION = "7.0.13"
5
5
  end
@@ -13,7 +13,14 @@ module Mongoid
13
13
  end
14
14
 
15
15
  def app_name
16
- Rails::Application.subclasses.first.parent.to_s.underscore
16
+ app_cls = Rails.application.class
17
+ parent = begin
18
+ # Rails 6.1+
19
+ app_cls.module_parent_name
20
+ rescue NoMethodError
21
+ app_cls.parent.to_s
22
+ end
23
+ parent.underscore
17
24
  end
18
25
 
19
26
  def create_config_file
@@ -13,102 +13,173 @@ describe 'Mongoid application tests' do
13
13
  end
14
14
 
15
15
  require 'fileutils'
16
- require 'support/child_process_helper'
16
+ require 'mrss/child_process_helper'
17
17
  require 'open-uri'
18
18
 
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
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
28
29
 
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
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
- ChildProcessHelper.check_call(%w(gem uni rails -a))
95
- 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
- ChildProcessHelper.check_call(%w(rails new mongoid-test --skip-spring), env: clean_env)
100
-
101
- Dir.chdir('mongoid-test') do
102
- adjust_app_gemfile
103
- ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
104
-
105
- ChildProcessHelper.check_call(%w(rails g model post), env: clean_env)
106
- 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/
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/
128
+ end
129
+ end
130
+ end
131
+ end
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
+
141
+ context 'local test applications' do
142
+ let(:client) { Mongoid.default_client }
143
+
144
+ describe 'create_indexes rake task' do
145
+
146
+ APP_PATH = File.join(File.dirname(__FILE__), '../../test-apps/rails-api')
147
+
148
+ %w(development production).each do |rails_env|
149
+ context "in #{rails_env}" do
150
+
151
+ %w(classic zeitwerk).each do |autoloader|
152
+ context "with #{autoloader} autoloader" do
153
+
154
+ let(:env) do
155
+ clean_env.merge(RAILS_ENV: rails_env, AUTOLOADER: autoloader)
156
+ end
157
+
158
+ before do
159
+ Dir.chdir(APP_PATH) do
160
+ remove_bundler_req
161
+ Mrss::ChildProcessHelper.check_call(%w(bundle install), env: env)
162
+ write_mongoid_yml
163
+ end
164
+
165
+ client['posts'].drop
166
+ client['posts'].create
167
+ end
168
+
169
+ it 'creates an index' do
170
+ index = client['posts'].indexes.detect do |index|
171
+ index['key'] == {'subject' => 1}
172
+ end
173
+ index.should be nil
174
+
175
+ Mrss::ChildProcessHelper.check_call(%w(bundle exec rake db:mongoid:create_indexes),
176
+ cwd: APP_PATH, env: env)
177
+
178
+ index = client['posts'].indexes.detect do |index|
179
+ index['key'] == {'subject' => 1}
180
+ end
181
+ index.should be_a(Hash)
182
+ end
112
183
  end
113
184
  end
114
185
  end
@@ -116,35 +187,70 @@ describe 'Mongoid application tests' do
116
187
  end
117
188
  end
118
189
 
119
- def clone_application(repo_url, subdir: nil, rails_version: nil)
190
+ def clone_application(repo_url, subdir: nil)
120
191
  Dir.chdir(TMP_BASE) do
121
192
  FileUtils.rm_rf(File.basename(repo_url))
122
- ChildProcessHelper.check_call(%w(git clone) + [repo_url])
193
+ Mrss::ChildProcessHelper.check_call(%w(git clone) + [repo_url])
123
194
  Dir.chdir(File.join(*[File.basename(repo_url), subdir].compact)) do
124
- adjust_app_gemfile(rails_version: rails_version)
125
- ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
195
+ adjust_app_gemfile
196
+ adjust_rails_defaults
197
+ Mrss::ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
126
198
  puts `git diff`
127
199
 
128
- config = {'development' => {'clients' => {'default' => {'uri' => SpecConfig.instance.uri_str}}}}
129
- File.open('config/mongoid.yml', 'w') do |f|
130
- f << YAML.dump(config)
131
- end
200
+ write_mongoid_yml
132
201
 
133
202
  yield
134
203
  end
135
204
  end
136
205
  end
137
206
 
138
- def adjust_app_gemfile(rails_version: nil)
139
- lock_lines = IO.readlines('Gemfile.lock')
140
- # Get rid of the bundled with line so that whatever bundler is installed
141
- # on the system is usable with the application.
142
- if i = lock_lines.index("BUNDLED WITH\n")
143
- lock_lines.slice!(i, 2)
144
- File.open('Gemfile.lock', 'w') do |f|
145
- f << lock_lines.join
207
+ def parse_mongodb_uri(uri)
208
+ pre, query = uri.split('?', 2)
209
+ if pre =~ %r,\A(mongodb(?:.*?))://([^/]+)(?:/(.*))?\z,
210
+ protocol = $1
211
+ hosts = $2
212
+ database = $3
213
+ if database == ''
214
+ database = nil
146
215
  end
216
+ else
217
+ raise ArgumentError, "Invalid MongoDB URI: #{uri}"
218
+ end
219
+ if query == ''
220
+ query = nil
221
+ end
222
+ {
223
+ protocol: protocol,
224
+ hosts: hosts,
225
+ database: database,
226
+ query: query,
227
+ }
228
+ end
229
+
230
+ def build_mongodb_uri(parts)
231
+ "#{parts.fetch(:protocol)}://#{parts.fetch(:hosts)}/#{parts[:database]}?#{parts[:query]}"
232
+ end
233
+
234
+ def write_mongoid_yml
235
+ # HACK: the driver does not provide a MongoDB URI parser and assembler,
236
+ # and the Ruby standard library URI module doesn't handle multiple hosts.
237
+ parts = parse_mongodb_uri(SpecConfig.instance.uri_str)
238
+ parts[:database] = 'mongoid_test'
239
+ uri = build_mongodb_uri(parts)
240
+ p uri
241
+ env_config = {'clients' => {'default' => {
242
+ # TODO massive hack, will fail if uri specifies a database name or
243
+ # any uri options
244
+ 'uri' => uri,
245
+ }}}
246
+ config = {'development' => env_config, 'production' => env_config}
247
+ File.open('config/mongoid.yml', 'w') do |f|
248
+ f << YAML.dump(config)
147
249
  end
250
+ end
251
+
252
+ def adjust_app_gemfile(rails_version: SpecConfig.instance.rails_version)
253
+ remove_bundler_req
148
254
 
149
255
  gemfile_lines = IO.readlines('Gemfile')
150
256
  gemfile_lines.delete_if do |line|
@@ -155,27 +261,67 @@ describe 'Mongoid application tests' do
155
261
  gemfile_lines.delete_if do |line|
156
262
  line =~ /rails/
157
263
  end
158
- 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
159
269
  end
160
270
  File.open('Gemfile', 'w') do |f|
161
271
  f << gemfile_lines.join
162
272
  end
163
273
  end
164
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
+
299
+ def remove_bundler_req
300
+ lock_lines = IO.readlines('Gemfile.lock')
301
+ # Get rid of the bundled with line so that whatever bundler is installed
302
+ # on the system is usable with the application.
303
+ if i = lock_lines.index("BUNDLED WITH\n")
304
+ lock_lines.slice!(i, 2)
305
+ File.open('Gemfile.lock', 'w') do |f|
306
+ f << lock_lines.join
307
+ end
308
+ end
309
+ end
310
+
165
311
  def remove_spring
166
312
  # Spring produces this error in Evergreen:
167
313
  # /data/mci/280eb2ecf4fd69208e2106cd3af526f1/src/rubies/ruby-2.7.0/lib/ruby/gems/2.7.0/gems/spring-2.1.0/lib/spring/client/run.rb:26:
168
314
  # in `initialize': too long unix socket path (126bytes given but 108bytes max) (ArgumentError)
169
315
  # Is it trying to create unix sockets in current directory?
170
316
  # https://stackoverflow.com/questions/30302021/rails-runner-without-spring
171
- ChildProcessHelper.check_call(%w(bin/spring binstub --remove --all), env: clean_env)
317
+ Mrss::ChildProcessHelper.check_call(%w(bin/spring binstub --remove --all), env: clean_env)
172
318
  end
173
319
 
174
320
  def clean_env
175
321
  @clean_env ||= Hash[ENV.keys.grep(/BUNDLE|RUBYOPT/).map { |k| [k, nil ] }]
176
322
  end
177
323
 
178
- def wait_for_port(port, timeout)
324
+ def wait_for_port(port, timeout, process)
179
325
  deadline = Time.now + timeout
180
326
  loop do
181
327
  begin
@@ -183,6 +329,9 @@ describe 'Mongoid application tests' do
183
329
  return
184
330
  end
185
331
  rescue IOError, SystemCallError
332
+ unless process.alive?
333
+ raise "Process #{process} died while waiting for port #{port}"
334
+ end
186
335
  if Time.now > deadline
187
336
  raise
188
337
  end