mongoid 7.3.0 → 7.3.1

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: 3d1e8ba04808e5217cc1622623532caa8c519a412278bfe85d2ed6cfdeda62c7
4
- data.tar.gz: 38067c7a3a2a3347b8e564e2069938cbed1d1adb4668573465b088fc01bbe167
3
+ metadata.gz: 408fcc1f85dce0c9a16140dda363526896fe1fb37f627e33f15ef6d1a2628de0
4
+ data.tar.gz: '084168385d0912909c5292100334c8eb7edf162d72bcd1cd51673fd8140013ca'
5
5
  SHA512:
6
- metadata.gz: 067d6b81359b6c45c2c877ebeab3382425abe08f3ca5a75bf4dd880e7f082479a63823c38030fba356c061da8e9a7ea7393ca30f58c10c858b2f2d412a0aca0d
7
- data.tar.gz: 4cdc9196e41db201ec36ea7024eab9ce9d7f20bf45db005c5c5111bd73756e9c5cf1ff2fc2fbead7c702ac47fabaa44aead2ab6d4db6d008ffb387d2c0c0efdb
6
+ metadata.gz: 193c335677afc72c56eebc7d64a0167cb4c9112e7b0a81baa39d6433a7c8b04d1a456e451777823c5678219bd73ad46198c8bd650e0cfb89b1ee87e77d4b62d4
7
+ data.tar.gz: b994ad71c11e4c9f94074fc082c91ffc479146bb0a9af87b28a4c7fa1bc338f737cb902d4098d50241ffb62cf9e6ba1deb2cdd3ffb951e1afa09cf3c02450e2c
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -19,7 +19,7 @@ Compatibility
19
19
 
20
20
  Mongoid supports and is tested against:
21
21
 
22
- - MRI 2.3-2.7
22
+ - MRI 2.3-3.0
23
23
  - JRuby 9.2
24
24
  - MongoDB server 2.6-4.4
25
25
 
@@ -121,6 +121,9 @@ module Mongoid
121
121
  # (embedded) association with the given key, or nil if no projection
122
122
  # is to be performed.
123
123
  #
124
+ # Also returns nil if exclusionary projection was requested but it does
125
+ # not exclude the field of the association.
126
+ #
124
127
  # For example, if __selected_fields is {'a' => 1, 'b.c' => 2, 'b.c.f' => 3},
125
128
  # and assoc_key is 'b', return value would be {'c' => 2, 'c.f' => 3}.
126
129
  #
@@ -132,6 +135,15 @@ module Mongoid
132
135
  def _mongoid_filter_selected_fields(assoc_key)
133
136
  return nil unless __selected_fields
134
137
 
138
+ # If the list of fields was specified using #without instead of #only
139
+ # and the provided list does not include the association, any of its
140
+ # fields should be allowed.
141
+ if __selected_fields.values.all? { |v| v == 0 } &&
142
+ __selected_fields.keys.none? { |k| k.split('.', 2).first == assoc_key }
143
+ then
144
+ return nil
145
+ end
146
+
135
147
  projecting_assoc = false
136
148
 
137
149
  filtered = {}
@@ -48,7 +48,7 @@ module Mongoid
48
48
  #
49
49
  # @return [ String ] A localized error message string.
50
50
  def translate(key, options)
51
- ::I18n.translate("#{BASE_KEY}.#{key}", options)
51
+ ::I18n.translate("#{BASE_KEY}.#{key}", **options)
52
52
  end
53
53
 
54
54
  # Create the problem.
@@ -43,7 +43,7 @@ module Mongoid
43
43
  ensure
44
44
  document.exit_validate
45
45
  end
46
- document.errors.add(attribute, :invalid, options) unless valid
46
+ document.errors.add(attribute, :invalid, **options) unless valid
47
47
  end
48
48
  end
49
49
  end
@@ -34,15 +34,15 @@ module Mongoid
34
34
  document.errors.add(
35
35
  attribute,
36
36
  :blank_in_locale,
37
- options.merge(location: _locale)
37
+ **options.merge(location: _locale)
38
38
  ) if not_present?(_value)
39
39
  end
40
40
  elsif document.relations.has_key?(attribute.to_s)
41
41
  if relation_or_fk_missing?(document, attribute, value)
42
- document.errors.add(attribute, :blank, options)
42
+ document.errors.add(attribute, :blank, **options)
43
43
  end
44
44
  else
45
- document.errors.add(attribute, :blank, options) if not_present?(value)
45
+ document.errors.add(attribute, :blank, **options) if not_present?(value)
46
46
  end
47
47
  end
48
48
 
@@ -68,7 +68,7 @@ module Mongoid
68
68
  # @since 2.4.10
69
69
  def add_error(document, attribute, value)
70
70
  document.errors.add(
71
- attribute, :taken, options.except(:case_sensitive, :scope).merge(value: value)
71
+ attribute, :taken, **options.except(:case_sensitive, :scope).merge(value: value)
72
72
  )
73
73
  end
74
74
 
@@ -2,5 +2,5 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  module Mongoid
5
- VERSION = "7.3.0"
5
+ VERSION = "7.3.1"
6
6
  end
@@ -57,7 +57,7 @@ development:
57
57
  # connect: :direct
58
58
 
59
59
  # Changes the default time in seconds the server monitors refresh their status
60
- # via ismaster commands. (default: 10)
60
+ # via hello commands. (default: 10)
61
61
  # heartbeat_frequency: 10
62
62
 
63
63
  # The time in seconds for selecting servers for a near read preference. (default: 0.015)
@@ -297,6 +297,9 @@ describe 'Mongoid application tests' do
297
297
  end
298
298
 
299
299
  def remove_bundler_req
300
+ return unless File.file?('Gemfile.lock')
301
+ # TODO: Remove this method completely when we get rid of .lock files in
302
+ # mongoid-demo apps.
300
303
  lock_lines = IO.readlines('Gemfile.lock')
301
304
  # Get rid of the bundled with line so that whatever bundler is installed
302
305
  # on the system is usable with the application.
@@ -36,4 +36,55 @@ describe Mongoid::Document do
36
36
  expect(_person.age).to be 42
37
37
  end
38
38
  end
39
+
40
+ context 'when projecting with #without' do
41
+ before do
42
+ duck = Pet.new(name: 'Duck')
43
+ Person.create!(username: 'Dev', title: 'CEO', pet: duck)
44
+ end
45
+
46
+ let(:person) { Person.where(username: 'Dev').without(:title).first }
47
+
48
+ it 'allows access to attribute of embedded document' do
49
+ expect(person.pet.name).to eq 'Duck'
50
+ end
51
+
52
+ context 'when exclusion starts with association name but is not the association' do
53
+
54
+ let(:person) { Person.where(username: 'Dev').without(:pet_).first }
55
+
56
+ it 'allows access to attribute of embedded document' do
57
+ expect(person.pet.name).to eq 'Duck'
58
+ end
59
+ end
60
+
61
+ context 'when exclusion starts with prefix of association name' do
62
+
63
+ let(:person) { Person.where(username: 'Dev').without(:pe).first }
64
+
65
+ it 'allows access to attribute of embedded document' do
66
+ expect(person.pet.name).to eq 'Duck'
67
+ end
68
+ end
69
+
70
+ context 'when another attribute of the association is excluded' do
71
+
72
+ let(:person) { Person.where(username: 'Dev').without('pet.weight').first }
73
+
74
+ it 'allows access to non-excluded attribute of embedded document' do
75
+ expect(person.pet.name).to eq 'Duck'
76
+ end
77
+ end
78
+
79
+ context 'when the excluded attribute of the association is retrieved' do
80
+
81
+ let(:person) { Person.where(username: 'Dev').without('pet.name').first }
82
+
83
+ it 'prohibits the retrieval' do
84
+ lambda do
85
+ person.pet.name
86
+ end.should raise_error(ActiveModel::MissingAttributeError)
87
+ end
88
+ end
89
+ end
39
90
  end
@@ -10,14 +10,26 @@ describe Mongoid::Errors::MongoidError do
10
10
  let(:options) { {} }
11
11
 
12
12
  before do
13
- {"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
14
- expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", {}).and_return(name)
15
- end
16
-
17
- ["message", "summary", "resolution"].each do |name|
18
- expect(::I18n).to receive(:translate).
19
- with("mongoid.errors.messages.#{key}.#{name}", {}).
20
- and_return(name)
13
+ if RUBY_VERSION.start_with?('3.', '2.7')
14
+ {"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
15
+ expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", **{}).and_return(name)
16
+ end
17
+
18
+ ["message", "summary", "resolution"].each do |name|
19
+ expect(::I18n).to receive(:translate).
20
+ with("mongoid.errors.messages.#{key}.#{name}", **{}).
21
+ and_return(name)
22
+ end
23
+ else
24
+ {"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
25
+ expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", {}).and_return(name)
26
+ end
27
+
28
+ ["message", "summary", "resolution"].each do |name|
29
+ expect(::I18n).to receive(:translate).
30
+ with("mongoid.errors.messages.#{key}.#{name}", {}).
31
+ and_return(name)
32
+ end
21
33
  end
22
34
 
23
35
  error.compose_message(key, options)
@@ -178,8 +178,8 @@ describe Mongoid::Persistable do
178
178
 
179
179
  before do
180
180
  class Band
181
- def my_updates(*args)
182
- atomically(*args) do |d|
181
+ def my_updates(**args)
182
+ atomically(**args) do |d|
183
183
  d.set(name: "Placebo")
184
184
  d.unset(:origin)
185
185
  end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'aws-sdk-s3'
5
+
6
+ options = {}
7
+ OptionParser.new do |opts|
8
+ opts.banner = "Usage: s3-copy options"
9
+
10
+ opts.on("-r", "--region=REGION", "AWS region to use (default us-east-1)") do |v|
11
+ options[:region] = v
12
+ end
13
+
14
+ opts.on("-p", "--param=KEY=VALUE", "Specify parameter for new files") do |v|
15
+ options[:params] ||= {}
16
+ k, v = v.split('=', 2)
17
+ options[:params][k.to_sym] = v
18
+ end
19
+
20
+ opts.on("-f", "--from=BUCKET:PATH", "Bucket name and key (or path) to copy from") do |v|
21
+ options[:from] = v
22
+ end
23
+
24
+ opts.on("-t", "--to=BUCKET:PATH", "Bucket name and key (or path) to write to (may be specified more than once)") do |v|
25
+ options[:to] ||= []
26
+ options[:to] << v
27
+ end
28
+ end.parse!
29
+
30
+ ENV['AWS_REGION'] ||= options[:region] || 'us-east-1'
31
+
32
+ bucket, key = options.fetch(:from).split(':', 2)
33
+
34
+ s3 = Aws::S3::Client.new
35
+
36
+ options.fetch(:to).each do |dest|
37
+ STDERR.puts "Copying to #{dest}"
38
+ dbucket, dkey = dest.split(':', 2)
39
+ s3.copy_object(
40
+ bucket: dbucket,
41
+ key: dkey,
42
+ copy_source: "/#{bucket}/#{key}",
43
+ **options[:params] || {},
44
+ )
45
+ end
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'aws-sdk-s3'
5
+
6
+ options = {}
7
+ OptionParser.new do |opts|
8
+ opts.banner = "Usage: s3-upload options"
9
+
10
+ opts.on("-r", "--region=REGION", "AWS region to use (default us-east-1)") do |v|
11
+ options[:region] = v
12
+ end
13
+
14
+ opts.on("-p", "--param=KEY=VALUE", "Specify parameter for S3 upload") do |v|
15
+ options[:params] ||= {}
16
+ k, v = v.split('=', 2)
17
+ options[:params][k.to_sym] = v
18
+ end
19
+
20
+ opts.on("-f", "--file=PATH", "Path to the file to upload, - to upload standard input") do |v|
21
+ options[:file] = v
22
+ end
23
+
24
+ opts.on("-w", "--write=BUCKET:PATH", "Bucket name and key (or path) to upload to") do |v|
25
+ options[:write] = v
26
+ end
27
+
28
+ opts.on("-c", "--copy=BUCKET:PATH", "Bucket name and key (or path) to copy to (may be specified more than once)") do |v|
29
+ options[:copy] ||= []
30
+ options[:copy] << v
31
+ end
32
+ end.parse!
33
+
34
+ ENV['AWS_REGION'] ||= options[:region] || 'us-east-1'
35
+
36
+ def upload(f, options)
37
+ s3 = Aws::S3::Client.new
38
+ write = options.fetch(:write)
39
+ STDERR.puts "Writing #{write}"
40
+ bucket, key = write.split(':', 2)
41
+ s3.put_object(
42
+ body: f.read,
43
+ bucket: bucket,
44
+ key: key,
45
+ **options[:params] || {},
46
+ )
47
+ if copy = options[:copy]
48
+ copy.each do |dest|
49
+ STDERR.puts "Copying to #{dest}"
50
+ dbucket, dkey = dest.split(':', 2)
51
+ s3.copy_object(
52
+ bucket: dbucket,
53
+ key: dkey,
54
+ copy_source: "/#{bucket}/#{key}",
55
+ **options[:params] || {},
56
+ )
57
+ end
58
+ end
59
+ end
60
+
61
+ if options[:file] == '-'
62
+ upload(STDIN, options)
63
+ elsif options[:file]
64
+ File.open(options[:file]) do |f|
65
+ upload(f, options)
66
+ end
67
+ else
68
+ upload(STDIN, options)
69
+ end
@@ -15,6 +15,11 @@ module Mrss
15
15
  @single_server
16
16
  end
17
17
 
18
+ def sharded_ish?
19
+ determine_cluster_config
20
+ @topology == :sharded || @topology == :load_balanced
21
+ end
22
+
18
23
  def replica_set_name
19
24
  determine_cluster_config
20
25
  @replica_set_name
@@ -48,7 +53,7 @@ module Mrss
48
53
  raise "Deployment server version not known - check that connection to deployment succeeded"
49
54
  end
50
55
 
51
- if server_version >= '3.4' && topology != :sharded
56
+ if server_version >= '3.4' && !sharded_ish?
52
57
  fcv
53
58
  else
54
59
  if short_server_version == '4.1'
@@ -115,7 +120,7 @@ module Mrss
115
120
  :mmapv1
116
121
  else
117
122
  client = ClientRegistry.instance.global_client('root_authorized')
118
- if topology == :sharded
123
+ if sharded_ish?
119
124
  shards = client.use(:admin).command(listShards: 1).first
120
125
  if shards['shards'].empty?
121
126
  raise 'Shards are empty'
@@ -206,7 +211,7 @@ module Mrss
206
211
 
207
212
  @server_parameters = client.use(:admin).command(getParameter: '*').first
208
213
 
209
- if @topology != :sharded && short_server_version >= '3.4'
214
+ if !sharded_ish? && short_server_version >= '3.4'
210
215
  rv = @server_parameters['featureCompatibilityVersion']
211
216
  @fcv = rv['version'] || rv
212
217
  end
@@ -52,7 +52,7 @@ module Mrss
52
52
  end
53
53
 
54
54
  def require_topology(*topologies)
55
- invalid_topologies = topologies - [:single, :replica_set, :sharded]
55
+ invalid_topologies = topologies - [:single, :replica_set, :sharded, :load_balanced]
56
56
 
57
57
  unless invalid_topologies.empty?
58
58
  raise ArgumentError, "Invalid topologies requested: #{invalid_topologies.join(', ')}"
@@ -82,7 +82,7 @@ module Mrss
82
82
  unless ClusterConfig.instance.server_version >= '4.0'
83
83
  skip 'Transactions tests in a replica set topology require server 4.0+'
84
84
  end
85
- when :sharded
85
+ when :sharded, :load_balanced
86
86
  unless ClusterConfig.instance.server_version >= '4.2'
87
87
  skip 'Transactions tests in a sharded cluster topology require server 4.2+'
88
88
  end
@@ -249,7 +249,9 @@ module Mrss
249
249
  # (mongos 4.0+ overrides the write concern)
250
250
  def require_set_write_concern
251
251
  before(:all) do
252
- if ClusterConfig.instance.topology == :sharded && ClusterConfig.instance.short_server_version >= '4.0'
252
+ if %i(sharded load_balanced).include?(ClusterConfig.instance.topology) &&
253
+ ClusterConfig.instance.short_server_version >= '4.0'
254
+ then
253
255
  skip "mongos 4.0+ overrides write concern"
254
256
  end
255
257
  end
@@ -273,7 +275,9 @@ module Mrss
273
275
 
274
276
  def require_wired_tiger
275
277
  before(:all) do
276
- if ClusterConfig.instance.storage_engine != :wired_tiger
278
+ # Storage detection fails for serverless instances. However, it is safe to
279
+ # assume that a serverless instance uses WiredTiger Storage Engine.
280
+ if !SpecConfig.instance.serverless? && ClusterConfig.instance.storage_engine != :wired_tiger
277
281
  skip 'Test requires WiredTiger storage engine'
278
282
  end
279
283
  end
@@ -282,7 +286,9 @@ module Mrss
282
286
  def require_wired_tiger_on_36
283
287
  before(:all) do
284
288
  if ClusterConfig.instance.short_server_version >= '3.6'
285
- if ClusterConfig.instance.storage_engine != :wired_tiger
289
+ # Storage detection fails for serverless instances. However, it is safe to
290
+ # assume that a serverless instance uses WiredTiger Storage Engine.
291
+ if !SpecConfig.instance.serverless? && ClusterConfig.instance.storage_engine != :wired_tiger
286
292
  skip 'Test requires WiredTiger storage engine on 3.6+ servers'
287
293
  end
288
294
  end
@@ -291,7 +297,7 @@ module Mrss
291
297
 
292
298
  def require_mmapv1
293
299
  before(:all) do
294
- if ClusterConfig.instance.storage_engine != :mmapv1
300
+ if SpecConfig.instance.serverless? || ClusterConfig.instance.storage_engine != :mmapv1
295
301
  skip 'Test requires MMAPv1 storage engine'
296
302
  end
297
303
  end
@@ -350,5 +356,13 @@ module Mrss
350
356
  end
351
357
  end
352
358
  end
359
+
360
+ def require_unix_socket
361
+ before(:all) do
362
+ if ENV['TOPOLOGY'] == 'load-balanced'
363
+ skip 'Load balancer does not listen on Unix sockets'
364
+ end
365
+ end
366
+ end
353
367
  end
354
368
  end