mongoid 7.2.2 → 7.2.6

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 (71) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +1 -1
  4. data/lib/config/locales/en.yml +13 -0
  5. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +1 -1
  6. data/lib/mongoid/association/proxy.rb +1 -1
  7. data/lib/mongoid/association/referenced/has_many/enumerable.rb +1 -1
  8. data/lib/mongoid/association/referenced/has_many/proxy.rb +1 -1
  9. data/lib/mongoid/association/relatable.rb +2 -0
  10. data/lib/mongoid/config/environment.rb +9 -1
  11. data/lib/mongoid/contextual/atomic.rb +7 -2
  12. data/lib/mongoid/contextual/none.rb +3 -0
  13. data/lib/mongoid/criteria/queryable/selectable.rb +2 -2
  14. data/lib/mongoid/criteria/queryable/storable.rb +4 -4
  15. data/lib/mongoid/criteria.rb +1 -1
  16. data/lib/mongoid/document.rb +3 -2
  17. data/lib/mongoid/errors/empty_config_file.rb +26 -0
  18. data/lib/mongoid/errors/invalid_config_file.rb +26 -0
  19. data/lib/mongoid/errors/mongoid_error.rb +1 -1
  20. data/lib/mongoid/errors.rb +2 -0
  21. data/lib/mongoid/interceptable.rb +1 -1
  22. data/lib/mongoid/persistence_context.rb +3 -1
  23. data/lib/mongoid/query_cache.rb +11 -1
  24. data/lib/mongoid/tasks/database.rb +1 -1
  25. data/lib/mongoid/validatable/associated.rb +1 -1
  26. data/lib/mongoid/validatable/presence.rb +3 -3
  27. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  28. data/lib/mongoid/version.rb +1 -1
  29. data/lib/mongoid.rb +1 -0
  30. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +1 -1
  31. data/spec/integration/app_spec.rb +3 -0
  32. data/spec/integration/contextual/empty_spec.rb +142 -0
  33. data/spec/integration/stringified_symbol_field_spec.rb +2 -2
  34. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +17 -4
  35. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +17 -0
  36. data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +20 -0
  37. data/spec/mongoid/association/referenced/has_many_models.rb +17 -0
  38. data/spec/mongoid/clients/factory_spec.rb +9 -3
  39. data/spec/mongoid/clients/options_spec.rb +11 -3
  40. data/spec/mongoid/config/environment_spec.rb +86 -8
  41. data/spec/mongoid/contextual/atomic_spec.rb +64 -25
  42. data/spec/mongoid/contextual/geo_near_spec.rb +1 -1
  43. data/spec/mongoid/criteria_spec.rb +4 -0
  44. data/spec/mongoid/document_fields_spec.rb +26 -0
  45. data/spec/mongoid/document_query_spec.rb +51 -0
  46. data/spec/mongoid/document_spec.rb +21 -1
  47. data/spec/mongoid/errors/invalid_config_file_spec.rb +32 -0
  48. data/spec/mongoid/errors/mongoid_error_spec.rb +20 -8
  49. data/spec/mongoid/persistable/updatable_spec.rb +2 -0
  50. data/spec/mongoid/persistable_spec.rb +2 -2
  51. data/spec/mongoid/query_cache_spec.rb +24 -0
  52. data/spec/shared/bin/s3-copy +45 -0
  53. data/spec/shared/bin/s3-upload +69 -0
  54. data/spec/shared/lib/mrss/cluster_config.rb +8 -3
  55. data/spec/shared/lib/mrss/constraints.rb +49 -10
  56. data/spec/shared/lib/mrss/docker_runner.rb +7 -1
  57. data/spec/shared/lib/mrss/event_subscriber.rb +200 -0
  58. data/spec/shared/lib/mrss/server_version_registry.rb +17 -12
  59. data/spec/shared/lib/mrss/spec_organizer.rb +29 -2
  60. data/spec/shared/share/Dockerfile.erb +127 -35
  61. data/spec/shared/share/haproxy-1.conf +16 -0
  62. data/spec/shared/share/haproxy-2.conf +17 -0
  63. data/spec/shared/shlib/server.sh +100 -23
  64. data/spec/shared/shlib/set_env.sh +4 -1
  65. data/spec/spec_helper.rb +1 -1
  66. data/spec/support/models/address.rb +4 -0
  67. data/spec/support/models/mop.rb +10 -0
  68. data/spec/support/models/person.rb +9 -0
  69. data.tar.gz.sig +0 -0
  70. metadata +549 -519
  71. metadata.gz.sig +0 -0
@@ -59,7 +59,7 @@ describe Mongoid::Contextual::GeoNear do
59
59
  end
60
60
 
61
61
  it "is nil except for 4.0 sharded when it is 0" do
62
- expect(geo_near.average_distance).to be expected_value
62
+ expect(geo_near.average_distance).to eq expected_value
63
63
  end
64
64
  end
65
65
  end
@@ -3769,10 +3769,14 @@ describe Mongoid::Criteria do
3769
3769
 
3770
3770
  before do
3771
3771
  expect(Person).to receive(:minor).and_call_original
3772
+ expect(Person).to receive(:older_than).and_call_original
3772
3773
  end
3773
3774
 
3774
3775
  it "calls the method on the class" do
3775
3776
  expect(criteria.minor).to be_empty
3777
+ expect do
3778
+ criteria.older_than(age: 25)
3779
+ end.not_to raise_error
3776
3780
  end
3777
3781
  end
3778
3782
 
@@ -85,4 +85,30 @@ describe Mongoid::Document do
85
85
  end
86
86
  end
87
87
  end
88
+
89
+ context 'Regexp field' do
90
+ shared_examples "persists strings as regexp" do |type|
91
+ it 'persists strings as regexp' do
92
+ mop = Mop.create!(regexp_field: 'foo')
93
+ expect(mop.regexp_field).to be_a Regexp
94
+ expect(Mop.find(mop.id).regexp_field).to be_a BSON::Regexp::Raw
95
+ expect(
96
+ Mop.collection.find(
97
+ "_id" => mop.id,
98
+ "regexp_field" => { "$type" => type }
99
+ ).count
100
+ ).to be == 1
101
+ end
102
+ end
103
+
104
+ context "< 3.2" do
105
+ max_server_version("3.1")
106
+ include_examples "persists strings as regexp", 11
107
+ end
108
+
109
+ context ">= 3.2" do
110
+ min_server_version("3.2")
111
+ it_behaves_like "persists strings as regexp", "regex"
112
+ end
113
+ end
88
114
  end
@@ -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
@@ -501,7 +501,7 @@ describe Mongoid::Document do
501
501
  end
502
502
  end
503
503
 
504
- context ':compact option' do
504
+ context 'deprecated :compact option' do
505
505
  # Since rails 6 differs in how it treats id fields,
506
506
  # run this test on one version of rails. Currently rails 6 is in beta,
507
507
  # when it is released this version should be changed to 6.
@@ -513,6 +513,26 @@ describe Mongoid::Document do
513
513
  expect(church.as_json.keys.sort).to eq(%w(_id location name))
514
514
  end
515
515
 
516
+ context 'deprecation' do
517
+ let(:church) do
518
+ Church.create!(name: 'St. Basil')
519
+ end
520
+
521
+ let(:message) do
522
+ '#as_json :compact option is deprecated. Please call #compact on the returned Hash object instead.'
523
+ end
524
+
525
+ it 'logs a deprecation warning when :compact is given' do
526
+ expect_any_instance_of(Logger).to receive(:warn).with(message)
527
+ church.as_json(compact: true)
528
+ end
529
+
530
+ it 'does not log a deprecation warning when :compact is not given' do
531
+ expect_any_instance_of(Logger).to_not receive(:warn).with(message)
532
+ church.as_json
533
+ end
534
+ end
535
+
516
536
  context 'there is a nil valued attribute' do
517
537
  let(:church) do
518
538
  Church.create!(name: 'St. Basil')
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require "spec_helper"
5
+
6
+ describe Mongoid::Errors::InvalidConfigFile do
7
+
8
+ describe "#message" do
9
+
10
+ let(:error) do
11
+ described_class.new('/my/path')
12
+ end
13
+
14
+ it "contains the problem in the message" do
15
+ expect(error.message).to include(
16
+ "Invalid configuration file: /my/path."
17
+ )
18
+ end
19
+
20
+ it "contains the summary in the message" do
21
+ expect(error.message).to include(
22
+ "Your mongoid.yml configuration file does not contain the"
23
+ )
24
+ end
25
+
26
+ it "contains the resolution in the message" do
27
+ expect(error.message).to include(
28
+ "Ensure your configuration file contains the correct contents."
29
+ )
30
+ end
31
+ end
32
+ 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)
@@ -458,6 +458,7 @@ describe Mongoid::Persistable::Updatable do
458
458
  describe "##{method}" do
459
459
 
460
460
  context "when saving with a hash field with invalid keys" do
461
+ max_server_version '4.9'
461
462
 
462
463
  let(:person) do
463
464
  Person.create
@@ -494,6 +495,7 @@ describe Mongoid::Persistable::Updatable do
494
495
  end
495
496
 
496
497
  context "when the document has been destroyed" do
498
+ max_server_version '4.9'
497
499
 
498
500
  let(:person) do
499
501
  Person.create
@@ -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
@@ -24,10 +24,27 @@ describe Mongoid::QueryCache do
24
24
  SessionRegistry.instance.verify_sessions_ended!
25
25
  end
26
26
 
27
+ let(:reset_legacy_qc_warning) do
28
+ begin
29
+ Mongoid::QueryCache.remove_instance_variable('@legacy_query_cache_warned')
30
+ rescue NameError
31
+ # raised if the instance variable wasn't set
32
+ end
33
+ end
34
+
27
35
  describe '#cache' do
28
36
  context 'with driver query cache' do
29
37
  min_driver_version '2.14'
30
38
 
39
+ it 'does not log a deprecation warning' do
40
+ reset_legacy_qc_warning
41
+
42
+ expect_any_instance_of(Logger).to_not receive(:warn).with(
43
+ described_class::LEGACY_WARNING
44
+ )
45
+ described_class.cache { }
46
+ end
47
+
31
48
  context 'when query cache is not enabled' do
32
49
  before do
33
50
  Mongoid::QueryCache.enabled = false
@@ -180,6 +197,13 @@ describe Mongoid::QueryCache do
180
197
  context 'with mongoid query cache' do
181
198
  max_driver_version '2.13'
182
199
 
200
+ it 'logs a deprecation warning' do
201
+ reset_legacy_qc_warning
202
+
203
+ expect_any_instance_of(Logger).to receive(:warn).with(described_class::LEGACY_WARNING)
204
+ described_class.cache { }
205
+ end
206
+
183
207
  context 'when query cache is not enabled' do
184
208
  before do
185
209
  Mongoid::QueryCache.enabled = false
@@ -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