mongoid 7.0.7 → 7.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) 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.rb +1 -1
  5. data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
  6. data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
  7. data/lib/mongoid/association/proxy.rb +1 -1
  8. data/lib/mongoid/atomic.rb +13 -3
  9. data/lib/mongoid/criteria.rb +7 -1
  10. data/lib/mongoid/criteria/modifiable.rb +2 -1
  11. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  12. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  13. data/lib/mongoid/extensions/hash.rb +4 -2
  14. data/lib/mongoid/extensions/regexp.rb +1 -1
  15. data/lib/mongoid/fields.rb +2 -1
  16. data/lib/mongoid/matchable/regexp.rb +2 -2
  17. data/lib/mongoid/persistable/pushable.rb +4 -1
  18. data/lib/mongoid/persistence_context.rb +6 -6
  19. data/lib/mongoid/query_cache.rb +2 -1
  20. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  21. data/lib/mongoid/version.rb +1 -1
  22. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  23. data/spec/app/models/delegating_patient.rb +16 -0
  24. data/spec/integration/app_spec.rb +192 -0
  25. data/spec/integration/associations/embedded_spec.rb +62 -0
  26. data/spec/integration/document_spec.rb +22 -0
  27. data/spec/lite_spec_helper.rb +11 -4
  28. data/spec/mongoid/association/embedded/embeds_many_models.rb +53 -0
  29. data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
  30. data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
  31. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +2 -1
  32. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
  33. data/spec/mongoid/clients/options_spec.rb +4 -4
  34. data/spec/mongoid/clients/sessions_spec.rb +8 -4
  35. data/spec/mongoid/clients/transactions_spec.rb +20 -8
  36. data/spec/mongoid/clients_spec.rb +2 -2
  37. data/spec/mongoid/contextual/atomic_spec.rb +20 -10
  38. data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
  39. data/spec/mongoid/contextual/mongo_spec.rb +76 -53
  40. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
  41. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
  42. data/spec/mongoid/criteria_spec.rb +4 -2
  43. data/spec/mongoid/document_persistence_context_spec.rb +33 -0
  44. data/spec/mongoid/indexable_spec.rb +6 -4
  45. data/spec/mongoid/matchable/default_spec.rb +1 -1
  46. data/spec/mongoid/matchable/regexp_spec.rb +2 -2
  47. data/spec/mongoid/matchable_spec.rb +2 -2
  48. data/spec/mongoid/query_cache_spec.rb +2 -1
  49. data/spec/mongoid/relations/proxy_spec.rb +1 -1
  50. data/spec/mongoid/scopable_spec.rb +2 -1
  51. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  52. data/spec/mongoid/tasks/database_spec.rb +1 -1
  53. data/spec/spec_helper.rb +0 -31
  54. data/spec/support/child_process_helper.rb +76 -0
  55. data/spec/support/cluster_config.rb +3 -3
  56. data/spec/support/constraints.rb +29 -19
  57. data/spec/support/spec_config.rb +12 -4
  58. metadata +16 -2
  59. metadata.gz.sig +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 82df1754cb3984ed07b2a5c83b17d489d4d5c3b00d5613d0294406fa818408a4
4
- data.tar.gz: 6d9b8693eecd837d139340eebcc08b340296da68bc7ffd5af84428e61ab83e08
3
+ metadata.gz: ef78cc81c2ff0304744dfd71a941ccb445860abea33dc7b2afd99058a0949bf2
4
+ data.tar.gz: 99cd2f0255d3ccb8a5487f35a39cd54a01e482602191f117cde26780ecd02037
5
5
  SHA512:
6
- metadata.gz: 2dba026ded69def250670ef96bdbbc9363237a3885002760918fe4aaed1d2e06755793383220b94fbdf57268770964f91ac30d62641b4ec74394ac98c0b332e5
7
- data.tar.gz: 227afb604eb0da1c058aa4f22d69bcaeccaf920c389dd3d5001776d688a2a1b72b030aa4a238c8d4ad0dc33e2394679e51a8560204ad9da041430c4d6f5becc9
6
+ metadata.gz: 57c42d28d64c7cb07cd6f67b4428bdb9565119df4428075d2c93502b270bb42f4446fa41aaf1e698ab5b47b5d6623389a1c13b2e67d6a30330699fed19958d69
7
+ data.tar.gz: 1f510169b514e67dd7c4c1692e829af73848c8997d03752dda28a8edc054f79a9679298004776a0b9fb059d7e35debaae51b1981b71f47dc7a0d89edacec8ac9
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -102,5 +102,5 @@ module Mongoid
102
102
  # Mongoid.database = Mongo::Connection.new.db("test")
103
103
  #
104
104
  # @since 1.0.0
105
- delegate(*(Config.public_instance_methods(false) - [ :logger=, :logger ] << { to: Config }))
105
+ delegate(*(Config.public_instance_methods(false) - [ :logger=, :logger ]), to: Config)
106
106
  end
@@ -197,7 +197,8 @@ module Mongoid
197
197
  def determine_inverses(other)
198
198
  matches = relation_class.relations.values.select do |rel|
199
199
  relation_complements.include?(rel.class) &&
200
- rel.relation_class_name == inverse_class_name
200
+ # https://jira.mongodb.org/browse/MONGOID-4882
201
+ rel.relation_class_name.sub(/\A::/, '') == inverse_class_name
201
202
  end
202
203
  if matches.size > 1
203
204
  raise Errors::AmbiguousRelationship.new(relation_class, @owner_class, name, matches)
@@ -159,7 +159,8 @@ module Mongoid
159
159
  def determine_inverses(other)
160
160
  matches = relation_class.relations.values.select do |rel|
161
161
  relation_complements.include?(rel.class) &&
162
- rel.relation_class_name == inverse_class_name
162
+ # https://jira.mongodb.org/browse/MONGOID-4882
163
+ rel.relation_class_name.sub(/\A::/, '') == inverse_class_name
163
164
 
164
165
  end
165
166
  if matches.size > 1
@@ -12,7 +12,7 @@ module Mongoid
12
12
  # We undefine most methods to get them sent through to the target.
13
13
  instance_methods.each do |method|
14
14
  undef_method(method) unless
15
- method =~ /^(__.*|send|object_id|equal\?|respond_to\?|tap|public_send|extend_proxy|extend_proxies)$/
15
+ method =~ /\A(__.*|send|object_id|equal\?|respond_to\?|tap|public_send|extend_proxy|extend_proxies)\z/
16
16
  end
17
17
 
18
18
  include Threaded::Lifecycle
@@ -36,7 +36,9 @@ module Mongoid
36
36
  # @since 2.2.0
37
37
  def add_atomic_pull(document)
38
38
  document.flagged_for_destroy = true
39
- (delayed_atomic_pulls[document.association_name.to_s] ||= []).push(document)
39
+ key = document.association_name.to_s
40
+ delayed_atomic_pulls[key] ||= []
41
+ delayed_atomic_pulls[key] << document
40
42
  end
41
43
 
42
44
  # Add an atomic unset for the document.
@@ -51,7 +53,9 @@ module Mongoid
51
53
  # @since 3.0.0
52
54
  def add_atomic_unset(document)
53
55
  document.flagged_for_destroy = true
54
- (delayed_atomic_unsets[document.association_name.to_s] ||= []).push(document)
56
+ key = document.association_name.to_s
57
+ delayed_atomic_unsets[key] ||= []
58
+ delayed_atomic_unsets[key] << document
55
59
  end
56
60
 
57
61
  # Returns path of the attribute for modification
@@ -189,7 +193,13 @@ module Mongoid
189
193
  #
190
194
  # @since 2.1.0
191
195
  def atomic_paths
192
- @atomic_paths ||= _association ? _association.path(self) : Atomic::Paths::Root.new(self)
196
+ @atomic_paths ||= begin
197
+ if _association
198
+ _association.path(self)
199
+ else
200
+ Atomic::Paths::Root.new(self)
201
+ end
202
+ end
193
203
  end
194
204
 
195
205
  # Get all the attributes that need to be pulled.
@@ -435,7 +435,13 @@ module Mongoid
435
435
  #
436
436
  # @since 3.1.0
437
437
  def for_js(javascript, scope = {})
438
- js_query(BSON::CodeWithScope.new(javascript, scope))
438
+ code = if scope.empty?
439
+ # CodeWithScope is not supported for $where as of MongoDB 4.4
440
+ BSON::Code.new(javascript)
441
+ else
442
+ BSON::CodeWithScope.new(javascript, scope)
443
+ end
444
+ js_query(code)
439
445
  end
440
446
 
441
447
  private
@@ -72,7 +72,8 @@ module Mongoid
72
72
  # @since 5.1.0
73
73
  def create_with(attrs = {})
74
74
  tap do
75
- (@create_attrs ||= {}).merge!(attrs)
75
+ @create_attrs ||= {}
76
+ @create_attrs.update(attrs)
76
77
  end
77
78
  end
78
79
 
@@ -58,7 +58,7 @@ module Mongoid
58
58
  #
59
59
  # @since 1.0.0
60
60
  def __numeric__(object)
61
- object.to_s =~ /(^[-+]?[0-9]+$)|(\.0+$)|(\.$)/ ? object.to_i : Float(object)
61
+ object.to_s =~ /(\A[-+]?[0-9]+\z)|(\.0+\z)|(\.\z)/ ? object.to_i : Float(object)
62
62
  end
63
63
 
64
64
  # Evolve the object to an integer.
@@ -10,7 +10,7 @@ module Mongoid
10
10
  # Is the object a regexp?
11
11
  #
12
12
  # @example Is the object a regex?
13
- # /^[123]/.regexp?
13
+ # /\A[123]/.regexp?
14
14
  #
15
15
  # @return [ true ] Always true.
16
16
  #
@@ -22,7 +22,7 @@ module Mongoid
22
22
  # Evolve the object into a regex.
23
23
  #
24
24
  # @example Evolve the object to a regex.
25
- # Regexp.evolve("^[123]")
25
+ # Regexp.evolve("\A[123]")
26
26
  #
27
27
  # @param [ Regexp, String ] object The object to evolve.
28
28
  #
@@ -53,7 +53,7 @@ module Mongoid
53
53
  # Evolve the object into a raw bson regex.
54
54
  #
55
55
  # @example Evolve the object to a regex.
56
- # BSON::Regexp::Raw.evolve("^[123]")
56
+ # BSON::Regexp::Raw.evolve("\\A[123]")
57
57
  #
58
58
  # @param [ BSON::Regexp::Raw, String ] object The object to evolve.
59
59
  #
@@ -46,9 +46,11 @@ module Mongoid
46
46
  value.each_pair do |_key, _value|
47
47
  value[_key] = (key == "$rename") ? _value.to_s : mongoize_for(key, klass, _key, _value)
48
48
  end
49
- (consolidated[key] ||= {}).merge!(value)
49
+ consolidated[key] ||= {}
50
+ consolidated[key].update(value)
50
51
  else
51
- (consolidated["$set"] ||= {}).merge!(key => mongoize_for(key, klass, key, value))
52
+ consolidated["$set"] ||= {}
53
+ consolidated["$set"].update(key => mongoize_for(key, klass, key, value))
52
54
  end
53
55
  end
54
56
  consolidated
@@ -9,7 +9,7 @@ module Mongoid
9
9
  # type.
10
10
  #
11
11
  # @example Mongoize the object.
12
- # Regexp.mongoize(/^[abc]/)
12
+ # Regexp.mongoize(/\A[abc]/)
13
13
  #
14
14
  # @param [ Regexp, String ] object The object to mongoize.
15
15
  #
@@ -498,7 +498,8 @@ module Mongoid
498
498
  def create_translations_getter(name, meth)
499
499
  generated_methods.module_eval do
500
500
  re_define_method("#{meth}_translations") do
501
- (attributes[name] ||= {}).with_indifferent_access
501
+ attributes[name] ||= {}
502
+ attributes[name].with_indifferent_access
502
503
  end
503
504
  alias_method :"#{meth}_t", :"#{meth}_translations"
504
505
  end
@@ -7,8 +7,8 @@ module Mongoid
7
7
  # Does the supplied query match the attribute?
8
8
  #
9
9
  # @example Does this match?
10
- # matcher._matches?(/^Em/)
11
- # matcher._matches?(BSON::Regex::Raw.new("^Em"))
10
+ # matcher._matches?(/\AEm/)
11
+ # matcher._matches?(BSON::Regex::Raw.new("\\AEm"))
12
12
  #
13
13
  # @param [ BSON::Regexp::Raw, Regexp ] regexp The regular expression object.
14
14
  #
@@ -55,7 +55,10 @@ module Mongoid
55
55
  def push(pushes)
56
56
  prepare_atomic_operation do |ops|
57
57
  process_atomic_operations(pushes) do |field, value|
58
- existing = send(field) || (attributes[field] ||= [])
58
+ existing = send(field) || begin
59
+ attributes[field] ||= []
60
+ attributes[field]
61
+ end
59
62
  values = [ value ].flatten(1)
60
63
  values.each{ |val| existing.push(val) }
61
64
  ops[atomic_attribute_name(field)] = { "$each" => values }
@@ -116,6 +116,12 @@ module Mongoid
116
116
  client.with(client_options))
117
117
  end
118
118
 
119
+ def client_name
120
+ @client_name ||= options[:client] ||
121
+ Threaded.client_override ||
122
+ storage_options && __evaluate__(storage_options[:client])
123
+ end
124
+
119
125
  # Determine if this persistence context is equal to another.
120
126
  #
121
127
  # @example Compare two persistence contexts.
@@ -133,12 +139,6 @@ module Mongoid
133
139
 
134
140
  private
135
141
 
136
- def client_name
137
- @client_name ||= options[:client] ||
138
- Threaded.client_override ||
139
- storage_options && __evaluate__(storage_options[:client])
140
- end
141
-
142
142
  def set_options!(opts)
143
143
  @options ||= opts.each.reduce({}) do |_options, (key, value)|
144
144
  unless VALID_OPTIONS.include?(key.to_sym)
@@ -166,7 +166,8 @@ module Mongoid
166
166
  @coll_name ||= result.namespace.sub("#{database.name}.", '') if result.namespace
167
167
  documents = result.documents
168
168
  if @cursor_id.zero? && !@after_first_batch
169
- (@cached_documents ||= []).concat(documents)
169
+ @cached_documents ||= []
170
+ @cached_documents.concat(documents)
170
171
  end
171
172
  @after_first_batch = true
172
173
  documents
@@ -148,7 +148,7 @@ module Mongoid
148
148
  #
149
149
  # @since 2.3.0
150
150
  def filter(value)
151
- !case_sensitive? && value ? /\A#{Regexp.escape(value.to_s)}$/i : value
151
+ !case_sensitive? && value ? /\A#{Regexp.escape(value.to_s)}\z/i : value
152
152
  end
153
153
 
154
154
  # Scope the criteria to the scope options provided.
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Mongoid
4
- VERSION = "7.0.7"
4
+ VERSION = "7.0.8"
5
5
  end
@@ -13,7 +13,7 @@ class <%= class_name %><%= " < #{options[:parent].classify}" if options[:parent]
13
13
  field :<%= attribute.name %>, type: <%= attribute.type_class %>
14
14
  <% end -%>
15
15
  <% attributes.select{|attr| attr.reference? }.each do |attribute| -%>
16
- embedded_in :<%= attribute.name%>
16
+ belongs_to :<%= attribute.name%>
17
17
  <% end -%>
18
18
  end
19
19
  <% end -%>
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ class DelegatingPatient
5
+ include Mongoid::Document
6
+
7
+ embeds_one :email
8
+
9
+ # Instance level delegation
10
+ delegate :address, to: :email
11
+
12
+ class << self
13
+ # Class level delegation
14
+ delegate :default_client, to: ::Mongoid
15
+ end
16
+ end
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require 'spec_helper'
5
+
6
+ BASE = File.join(File.dirname(__FILE__), '../..')
7
+ TMP_BASE = File.join(BASE, 'tmp')
8
+
9
+ describe 'Mongoid application tests' do
10
+ before(:all) do
11
+ unless SpecConfig.instance.app_tests?
12
+ skip 'Set APP_TESTS=1 in environment to run application tests'
13
+ end
14
+
15
+ require 'fileutils'
16
+ require 'support/child_process_helper'
17
+ require 'open-uri'
18
+
19
+ FileUtils.mkdir_p(TMP_BASE)
20
+ end
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
35
+ # 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
45
+
46
+ resp.should == []
47
+
48
+ status.should == 0
49
+ end
50
+ end
51
+ end
52
+
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
79
+
80
+ resp.should == []
81
+
82
+ # 143 = 128 + 15
83
+ [0, 15, 143].should include(status)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ 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/
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ def clone_application(repo_url, subdir: nil, rails_version: nil)
120
+ Dir.chdir(TMP_BASE) do
121
+ FileUtils.rm_rf(File.basename(repo_url))
122
+ ChildProcessHelper.check_call(%w(git clone) + [repo_url])
123
+ 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)
126
+ puts `git diff`
127
+
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
132
+
133
+ yield
134
+ end
135
+ end
136
+ end
137
+
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
146
+ end
147
+ end
148
+
149
+ gemfile_lines = IO.readlines('Gemfile')
150
+ gemfile_lines.delete_if do |line|
151
+ line =~ /mongoid/
152
+ end
153
+ gemfile_lines << "gem 'mongoid', path: '#{File.expand_path(BASE)}'\n"
154
+ if rails_version
155
+ gemfile_lines.delete_if do |line|
156
+ line =~ /rails/
157
+ end
158
+ gemfile_lines << "gem 'rails', '#{rails_version}'\n"
159
+ end
160
+ File.open('Gemfile', 'w') do |f|
161
+ f << gemfile_lines.join
162
+ end
163
+ end
164
+
165
+ def remove_spring
166
+ # Spring produces this error in Evergreen:
167
+ # /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
+ # in `initialize': too long unix socket path (126bytes given but 108bytes max) (ArgumentError)
169
+ # Is it trying to create unix sockets in current directory?
170
+ # https://stackoverflow.com/questions/30302021/rails-runner-without-spring
171
+ ChildProcessHelper.check_call(%w(bin/spring binstub --remove --all), env: clean_env)
172
+ end
173
+
174
+ def clean_env
175
+ @clean_env ||= Hash[ENV.keys.grep(/BUNDLE|RUBYOPT/).map { |k| [k, nil ] }]
176
+ end
177
+
178
+ def wait_for_port(port, timeout)
179
+ deadline = Time.now + timeout
180
+ loop do
181
+ begin
182
+ Socket.tcp('localhost', port, nil, nil, connect_timeout: 0.5) do |socket|
183
+ return
184
+ end
185
+ rescue IOError, SystemCallError
186
+ if Time.now > deadline
187
+ raise
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end