mongoid 4.0.2 → 5.0.0

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -1
  3. data/README.md +11 -19
  4. data/lib/config/locales/en.yml +33 -30
  5. data/lib/mongoid/atomic.rb +2 -4
  6. data/lib/mongoid/attributes/processing.rb +4 -1
  7. data/lib/mongoid/attributes/readonly.rb +2 -2
  8. data/lib/mongoid/attributes.rb +7 -7
  9. data/lib/mongoid/changeable.rb +4 -6
  10. data/lib/mongoid/clients/factory.rb +78 -0
  11. data/lib/mongoid/{sessions → clients}/options.rb +30 -19
  12. data/lib/mongoid/{sessions → clients}/storage_options.rb +27 -13
  13. data/lib/mongoid/{sessions → clients}/thread_options.rb +6 -3
  14. data/lib/mongoid/{sessions → clients}/validators/storage.rb +5 -2
  15. data/lib/mongoid/clients/validators.rb +2 -0
  16. data/lib/mongoid/clients.rb +141 -0
  17. data/lib/mongoid/composable.rb +3 -3
  18. data/lib/mongoid/config/environment.rb +1 -1
  19. data/lib/mongoid/config/options.rb +1 -1
  20. data/lib/mongoid/config/validators/{session.rb → client.rb} +31 -28
  21. data/lib/mongoid/config/validators/option.rb +1 -1
  22. data/lib/mongoid/config/validators.rb +1 -1
  23. data/lib/mongoid/config.rb +39 -41
  24. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  25. data/lib/mongoid/contextual/atomic.rb +11 -11
  26. data/lib/mongoid/contextual/command.rb +9 -6
  27. data/lib/mongoid/contextual/geo_near.rb +17 -1
  28. data/lib/mongoid/contextual/map_reduce.rb +12 -11
  29. data/lib/mongoid/contextual/memory.rb +2 -5
  30. data/lib/mongoid/contextual/mongo.rb +92 -82
  31. data/lib/mongoid/contextual/none.rb +13 -0
  32. data/lib/mongoid/copyable.rb +6 -1
  33. data/lib/mongoid/criteria.rb +37 -4
  34. data/lib/mongoid/document.rb +3 -4
  35. data/lib/mongoid/errors/{mixed_session_configuration.rb → mixed_client_configuration.rb} +5 -5
  36. data/lib/mongoid/errors/mongoid_error.rb +15 -9
  37. data/lib/mongoid/errors/no_client_config.rb +22 -0
  38. data/lib/mongoid/errors/{no_session_database.rb → no_client_database.rb} +4 -4
  39. data/lib/mongoid/errors/{no_session_hosts.rb → no_client_hosts.rb} +4 -4
  40. data/lib/mongoid/errors/{no_sessions_config.rb → no_clients_config.rb} +4 -4
  41. data/lib/mongoid/errors/no_default_client.rb +23 -0
  42. data/lib/mongoid/errors.rb +6 -6
  43. data/lib/mongoid/extensions/hash.rb +5 -1
  44. data/lib/mongoid/extensions/object.rb +3 -2
  45. data/lib/mongoid/extensions/set.rb +5 -5
  46. data/lib/mongoid/factory.rb +4 -2
  47. data/lib/mongoid/fields.rb +7 -2
  48. data/lib/mongoid/findable.rb +4 -1
  49. data/lib/mongoid/indexable.rb +15 -9
  50. data/lib/mongoid/persistable/creatable.rb +2 -2
  51. data/lib/mongoid/persistable/deletable.rb +3 -3
  52. data/lib/mongoid/persistable/incrementable.rb +1 -1
  53. data/lib/mongoid/persistable/logical.rb +1 -1
  54. data/lib/mongoid/persistable/poppable.rb +1 -1
  55. data/lib/mongoid/persistable/pullable.rb +2 -2
  56. data/lib/mongoid/persistable/pushable.rb +2 -2
  57. data/lib/mongoid/persistable/renamable.rb +1 -1
  58. data/lib/mongoid/persistable/settable.rb +1 -1
  59. data/lib/mongoid/persistable/unsettable.rb +1 -1
  60. data/lib/mongoid/persistable/updatable.rb +2 -2
  61. data/lib/mongoid/persistable/upsertable.rb +1 -1
  62. data/lib/mongoid/persistable.rb +1 -2
  63. data/lib/mongoid/query_cache.rb +98 -104
  64. data/lib/mongoid/railtie.rb +4 -25
  65. data/lib/mongoid/railties/database.rake +1 -1
  66. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +3 -2
  67. data/lib/mongoid/relations/builders.rb +3 -1
  68. data/lib/mongoid/relations/counter_cache.rb +1 -1
  69. data/lib/mongoid/relations/embedded/batchable.rb +3 -10
  70. data/lib/mongoid/relations/embedded/many.rb +4 -2
  71. data/lib/mongoid/relations/embedded/one.rb +1 -0
  72. data/lib/mongoid/relations/many.rb +1 -0
  73. data/lib/mongoid/relations/metadata.rb +14 -0
  74. data/lib/mongoid/relations/proxy.rb +6 -6
  75. data/lib/mongoid/relations/referenced/many.rb +2 -1
  76. data/lib/mongoid/relations/targets/enumerable.rb +11 -11
  77. data/lib/mongoid/relations/touchable.rb +1 -1
  78. data/lib/mongoid/reloadable.rb +2 -2
  79. data/lib/mongoid/scopable.rb +6 -17
  80. data/lib/mongoid/selectable.rb +1 -36
  81. data/lib/mongoid/serializable.rb +2 -2
  82. data/lib/mongoid/stateful.rb +0 -1
  83. data/lib/mongoid/tasks/database.rake +2 -2
  84. data/lib/mongoid/tasks/database.rb +24 -17
  85. data/lib/mongoid/threaded/lifecycle.rb +21 -16
  86. data/lib/mongoid/threaded.rb +54 -33
  87. data/lib/mongoid/traversable.rb +17 -1
  88. data/lib/mongoid/validatable/queryable.rb +1 -1
  89. data/lib/mongoid/validatable/uniqueness.rb +3 -20
  90. data/lib/mongoid/validatable.rb +1 -1
  91. data/lib/mongoid/version.rb +1 -1
  92. data/lib/mongoid.rb +28 -21
  93. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +91 -57
  94. data/lib/rails/mongoid.rb +2 -2
  95. data/spec/app/models/audio.rb +1 -1
  96. data/spec/app/models/band.rb +1 -0
  97. data/spec/app/models/code.rb +6 -0
  98. data/spec/app/models/company.rb +5 -0
  99. data/spec/app/models/label.rb +7 -0
  100. data/spec/app/models/pub.rb +6 -0
  101. data/spec/app/models/staff.rb +7 -0
  102. data/spec/app/models/store_as_dup_test1.rb +5 -0
  103. data/spec/app/models/store_as_dup_test2.rb +5 -0
  104. data/spec/config/mongoid.yml +7 -25
  105. data/spec/mongoid/atomic/paths_spec.rb +3 -11
  106. data/spec/mongoid/attributes/nested_spec.rb +16 -16
  107. data/spec/mongoid/attributes/readonly_spec.rb +80 -18
  108. data/spec/mongoid/attributes_spec.rb +3 -3
  109. data/spec/mongoid/changeable_spec.rb +156 -0
  110. data/spec/mongoid/clients/factory_spec.rb +284 -0
  111. data/spec/mongoid/{sessions → clients}/options_spec.rb +4 -6
  112. data/spec/mongoid/clients_spec.rb +754 -0
  113. data/spec/mongoid/config/environment_spec.rb +14 -11
  114. data/spec/mongoid/config_spec.rb +33 -48
  115. data/spec/mongoid/contextual/atomic_spec.rb +1 -17
  116. data/spec/mongoid/contextual/geo_near_spec.rb +35 -0
  117. data/spec/mongoid/contextual/mongo_spec.rb +26 -83
  118. data/spec/mongoid/contextual/none_spec.rb +15 -0
  119. data/spec/mongoid/copyable_spec.rb +35 -1
  120. data/spec/mongoid/criteria/findable_spec.rb +197 -0
  121. data/spec/mongoid/criteria/modifiable_spec.rb +7 -29
  122. data/spec/mongoid/criteria_spec.rb +74 -91
  123. data/spec/mongoid/document_spec.rb +1 -1
  124. data/spec/mongoid/errors/{mixed_session_configuration_spec.rb → mixed_client_configuration_spec.rb} +1 -1
  125. data/spec/mongoid/errors/mongoid_error_spec.rb +19 -3
  126. data/spec/mongoid/errors/{no_session_config_spec.rb → no_client_config_spec.rb} +4 -4
  127. data/spec/mongoid/errors/{no_session_database_spec.rb → no_client_database_spec.rb} +4 -4
  128. data/spec/mongoid/errors/{no_session_hosts_spec.rb → no_client_hosts_spec.rb} +3 -3
  129. data/spec/mongoid/errors/{no_sessions_config_spec.rb → no_clients_config_spec.rb} +2 -2
  130. data/spec/mongoid/fields/localized_spec.rb +1 -0
  131. data/spec/mongoid/fields_spec.rb +1 -0
  132. data/spec/mongoid/findable_spec.rb +2 -23
  133. data/spec/mongoid/indexable_spec.rb +12 -8
  134. data/spec/mongoid/interceptable_spec.rb +15 -0
  135. data/spec/mongoid/persistable/settable_spec.rb +16 -0
  136. data/spec/mongoid/persistable/updatable_spec.rb +3 -2
  137. data/spec/mongoid/persistable_spec.rb +4 -4
  138. data/spec/mongoid/query_cache_spec.rb +13 -8
  139. data/spec/mongoid/relations/auto_save_spec.rb +1 -1
  140. data/spec/mongoid/relations/counter_cache_spec.rb +34 -0
  141. data/spec/mongoid/relations/eager/belongs_to_spec.rb +9 -0
  142. data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +3 -3
  143. data/spec/mongoid/relations/embedded/many_spec.rb +123 -1
  144. data/spec/mongoid/relations/embedded/one_spec.rb +3 -3
  145. data/spec/mongoid/relations/proxy_spec.rb +28 -0
  146. data/spec/mongoid/relations/referenced/in_spec.rb +1 -1
  147. data/spec/mongoid/relations/referenced/many_spec.rb +47 -23
  148. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +1 -1
  149. data/spec/mongoid/relations/referenced/one_spec.rb +1 -1
  150. data/spec/mongoid/relations/targets/enumerable_spec.rb +9 -2
  151. data/spec/mongoid/reloadable_spec.rb +6 -6
  152. data/spec/mongoid/scopable_spec.rb +41 -28
  153. data/spec/mongoid/selectable_spec.rb +6 -16
  154. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  155. data/spec/mongoid/tasks/database_spec.rb +2 -2
  156. data/spec/mongoid/threaded_spec.rb +0 -7
  157. data/spec/mongoid/traversable_spec.rb +2 -2
  158. data/spec/mongoid/validatable/uniqueness_spec.rb +30 -1
  159. data/spec/mongoid_spec.rb +13 -15
  160. data/spec/rails/mongoid_spec.rb +13 -4
  161. data/spec/spec_helper.rb +44 -27
  162. data/spec/support/authorization.rb +12 -0
  163. data/spec/support/expectations.rb +14 -0
  164. metadata +50 -57
  165. data/lib/mongoid/contextual/find_and_modify.rb +0 -69
  166. data/lib/mongoid/contextual/text_search.rb +0 -178
  167. data/lib/mongoid/criteria/#findable.rb# +0 -141
  168. data/lib/mongoid/errors/no_default_session.rb +0 -23
  169. data/lib/mongoid/errors/no_session_config.rb +0 -22
  170. data/lib/mongoid/log_subscriber.rb +0 -55
  171. data/lib/mongoid/positional.rb +0 -71
  172. data/lib/mongoid/sessions/factory.rb +0 -131
  173. data/lib/mongoid/sessions/mongo_uri.rb +0 -93
  174. data/lib/mongoid/sessions/validators.rb +0 -2
  175. data/lib/mongoid/sessions.rb +0 -125
  176. data/lib/mongoid/support/query_counter.rb +0 -23
  177. data/spec/helpers.rb +0 -18
  178. data/spec/mongoid/#atomic_spec.rb# +0 -365
  179. data/spec/mongoid/contextual/find_and_modify_spec.rb +0 -220
  180. data/spec/mongoid/contextual/text_search_spec.rb +0 -209
  181. data/spec/mongoid/log_subscriber_spec.rb +0 -75
  182. data/spec/mongoid/positional_spec.rb +0 -222
  183. data/spec/mongoid/sessions/factory_spec.rb +0 -333
  184. data/spec/mongoid/sessions/mongo_uri_spec.rb +0 -103
  185. data/spec/mongoid/sessions_spec.rb +0 -1252
@@ -17,7 +17,7 @@ module Mongoid
17
17
  # @param [ Array<String, Symbol> ] fields The names of the fields to
18
18
  # unset.
19
19
  #
20
- # @return [ true ] If the operation succeeded.
20
+ # @return [ Document ] The document.
21
21
  #
22
22
  # @since 4.0.0
23
23
  def unset(*fields)
@@ -141,9 +141,9 @@ module Mongoid
141
141
  unless updates.empty?
142
142
  coll = _root.collection
143
143
  selector = atomic_selector
144
- coll.find(selector).update(positionally(selector, updates))
144
+ coll.find(selector).update_one(updates)
145
145
  conflicts.each_pair do |key, value|
146
- coll.find(selector).update(positionally(selector, { key => value }))
146
+ coll.find(selector).update_one({ key => value })
147
147
  end
148
148
  end
149
149
  end
@@ -21,7 +21,7 @@ module Mongoid
21
21
  # @since 3.0.0
22
22
  def upsert(options = {})
23
23
  prepare_upsert(options) do
24
- collection.find(atomic_selector).update(as_document, [ :upsert ])
24
+ collection.find(atomic_selector).update_one(as_document, upsert: true)
25
25
  end
26
26
  end
27
27
 
@@ -27,7 +27,6 @@ module Mongoid
27
27
  include Incrementable
28
28
  include Logical
29
29
  include Poppable
30
- include Positional
31
30
  include Pullable
32
31
  include Pushable
33
32
  include Renamable
@@ -209,7 +208,7 @@ module Mongoid
209
208
  def persist_atomic_operations(operations)
210
209
  if persisted?
211
210
  selector = atomic_selector
212
- _root.collection.find(selector).update(positionally(selector, operations))
211
+ _root.collection.find(selector).update_one(operations)
213
212
  end
214
213
  end
215
214
  end
@@ -107,149 +107,143 @@ module Mongoid
107
107
  end
108
108
  end
109
109
 
110
- module Base # :nodoc:
111
-
112
- def alias_query_cache_clear(*method_names)
113
- method_names.each do |method_name|
114
- class_eval <<-CODE, __FILE__, __LINE__ + 1
115
- def #{method_name}_with_clear_cache(*args) # def upsert_with_clear_cache(*args)
116
- QueryCache.clear_cache # QueryCache.clear_cache
117
- #{method_name}_without_clear_cache(*args) # upsert_without_clear_cache(*args)
118
- end # end
119
- CODE
110
+ # A Cursor that attempts to load documents from memory first before hitting
111
+ # the database if the same query has already been executed.
112
+ #
113
+ # @since 5.0.0
114
+ class CachedCursor < Mongo::Cursor
120
115
 
121
- alias_method_chain method_name, :clear_cache
116
+ # We iterate over the cached documents if they exist already in the
117
+ # cursor otherwise proceed as normal.
118
+ #
119
+ # @example Iterate over the documents.
120
+ # cursor.each do |doc|
121
+ # # ...
122
+ # end
123
+ #
124
+ # @since 5.0.0
125
+ def each
126
+ if @cached_documents
127
+ @cached_documents.each{ |doc| yield doc }
128
+ else
129
+ super
122
130
  end
123
131
  end
132
+
133
+ # Get a human-readable string representation of +Cursor+.
134
+ #
135
+ # @example Inspect the cursor.
136
+ # cursor.inspect
137
+ #
138
+ # @return [ String ] A string representation of a +Cursor+ instance.
139
+ #
140
+ # @since 2.0.0
141
+ def inspect
142
+ "#<Mongoid::QueryCache::CachedCursor:0x#{object_id} @view=#{@view.inspect}>"
143
+ end
144
+
145
+ private
146
+
147
+ def process(result)
148
+ @remaining -= result.returned_count if limited?
149
+ @cursor_id = result.cursor_id
150
+ @coll_name ||= result.namespace.sub("#{database.name}.", '') if result.namespace
151
+ documents = result.documents
152
+ (@cached_documents ||= []).concat(documents)
153
+ documents
154
+ end
124
155
  end
125
156
 
126
- # Module to include in objects which need to wrap caching behaviour around
127
- # them.
157
+ # Included to add behaviour for clearing out the query cache on certain
158
+ # operations.
128
159
  #
129
160
  # @since 4.0.0
130
- module Cacheable
161
+ module Base
131
162
 
132
- private
163
+ def alias_query_cache_clear(*method_names)
164
+ method_names.each do |method_name|
165
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
166
+ def #{method_name}_with_clear_cache(*args)
167
+ QueryCache.clear_cache
168
+ #{method_name}_without_clear_cache(*args)
169
+ end
170
+ CODE
133
171
 
134
- def with_cache(context = :cursor, more = false, &block)
135
- return yield unless QueryCache.enabled?
136
- return yield if system_collection?
137
- key = cache_key.push(context)
138
-
139
- if more
140
- docs = yield
141
- QueryCache.cache_table[key].push(*docs)
142
- docs
143
- elsif QueryCache.cache_table.has_key?(key)
144
- instrument(key) { QueryCache.cache_table[key] }
145
- else
146
- QueryCache.cache_table[key] = yield
172
+ alias_method_chain method_name, :clear_cache
147
173
  end
148
174
  end
149
-
150
- def instrument(key, &block)
151
- ActiveSupport::Notifications.instrument("query_cache.mongoid", key: key, &block)
152
- end
153
175
  end
154
176
 
155
- # Adds behaviour around caching to a Moped Query object.
177
+ # Contains enhancements to the Mongo::Collection::View in order to get a
178
+ # cached cursor or a regular cursor on iteration.
156
179
  #
157
- # @since 4.0.0
158
- module Query
180
+ # @since 5.0.0
181
+ module View
159
182
  extend ActiveSupport::Concern
160
- include Cacheable
161
183
 
162
184
  included do
163
185
  extend QueryCache::Base
164
- alias_method_chain :cursor, :cache
165
- alias_method_chain :first, :cache
166
- alias_query_cache_clear :remove, :remove_all, :update, :update_all, :upsert
167
- end
168
-
169
- # Provide a wrapped query cache cursor.
170
- #
171
- # @example Get the wrapped caching cursor.
172
- # query.cursor_with_cache
173
- #
174
- # @return [ CachedCursor ] The cached cursor.
175
- #
176
- # @since 4.0.0
177
- def cursor_with_cache
178
- CachedCursor.new(session, operation)
179
- end
180
-
181
- # Override first with caching.
182
- #
183
- # @example Get the first with a cache.
184
- # query.first_with_cache
185
- #
186
- # @return [ Hash ] The first document.
187
- #
188
- # @since 4.0.0
189
- def first_with_cache
190
- with_cache(:first) do
191
- first_without_cache
186
+ alias_query_cache_clear :delete_one,
187
+ :delete_many,
188
+ :update_one,
189
+ :update_many,
190
+ :replace_one,
191
+ :find_one_and_delete,
192
+ :find_one_and_replace,
193
+ :find_one_and_update
194
+ end
195
+
196
+ # Override the default enumeration to handle if the cursor can be cached
197
+ # or not.
198
+ #
199
+ # @example Iterate over the view.
200
+ # view.each do |doc|
201
+ # # ...
202
+ # end
203
+ #
204
+ # @since 5.0.0
205
+ def each
206
+ if system_collection? || !QueryCache.enabled?
207
+ super
208
+ else
209
+ key = cache_key
210
+ cursor = QueryCache.cache_table[key]
211
+ unless cursor
212
+ server = read.select_server(cluster)
213
+ cursor = CachedCursor.new(view, send_initial_query(server), server)
214
+ QueryCache.cache_table[key] = cursor
215
+ end
216
+ cursor.each do |doc|
217
+ yield doc
218
+ end if block_given?
219
+ cursor
192
220
  end
193
221
  end
194
222
 
195
223
  private
196
224
 
197
225
  def cache_key
198
- [ operation.database, operation.collection, operation.selector, operation.limit, operation.skip, operation.fields ]
226
+ [ collection.namespace, selector, limit, skip, projection ]
199
227
  end
200
228
 
201
229
  def system_collection?
202
- operation.collection =~ /^system./
230
+ collection.namespace =~ /^system./
203
231
  end
204
232
  end
205
233
 
206
234
  # Adds behaviour to the query cache for collections.
207
235
  #
208
- # @since 4.0.0
236
+ # @since 5.0.0
209
237
  module Collection
210
238
  extend ActiveSupport::Concern
211
239
 
212
240
  included do
213
241
  extend QueryCache::Base
214
- alias_query_cache_clear :insert
215
- end
216
- end
217
-
218
- # A Cursor that attempts to load documents from memory first before hitting
219
- # the database if the same query has already been executed.
220
- #
221
- # @since 4.0.0
222
- class CachedCursor < Moped::Cursor
223
- include Cacheable
224
-
225
- # Override the loading of docs to attempt to fetch from the cache.
226
- #
227
- # @example Load the documents.
228
- # cursor.load_docs
229
- #
230
- # @return [ Array<Hash> ] The documents.
231
- #
232
- # @since 4.0.0
233
- def load_docs
234
- with_cache { super }
235
- end
236
-
237
- def get_more
238
- with_cache(:cursor, true) { super }
239
- end
240
-
241
- private
242
-
243
- def cache_key
244
- [ @database, @collection, @selector, @options[:limit], @options[:skip], @options[:fields] ]
245
- end
246
-
247
- def system_collection?
248
- @collection =~ /^system./
242
+ alias_query_cache_clear :insert_one, :insert_many
249
243
  end
250
244
  end
251
245
  end
252
246
  end
253
247
 
254
- Moped::Query.__send__(:include, Mongoid::QueryCache::Query)
255
- Moped::Collection.__send__(:include, Mongoid::QueryCache::Collection)
248
+ Mongo::Collection.__send__(:include, Mongoid::QueryCache::Collection)
249
+ Mongo::Collection::View.__send__(:include, Mongoid::QueryCache::View)
@@ -1,6 +1,4 @@
1
1
  # encoding: utf-8
2
- require "mongoid"
3
- require "mongoid/config"
4
2
  require "mongoid/railties/document"
5
3
  require "rails"
6
4
  require "rails/mongoid"
@@ -44,7 +42,6 @@ module Rails
44
42
  # module MyApplication
45
43
  # class Application < Rails::Application
46
44
  # config.mongoid.logger = Logger.new($stdout, :warn)
47
- # config.mongoid.persist_in_safe_mode = true
48
45
  # end
49
46
  # end
50
47
  #
@@ -60,13 +57,13 @@ module Rails
60
57
  if config_file.file?
61
58
  begin
62
59
  ::Mongoid.load!(config_file)
63
- rescue ::Mongoid::Errors::NoSessionsConfig => e
60
+ rescue ::Mongoid::Errors::NoClientsConfig => e
64
61
  handle_configuration_error(e)
65
- rescue ::Mongoid::Errors::NoDefaultSession => e
62
+ rescue ::Mongoid::Errors::NoDefaultClient => e
66
63
  handle_configuration_error(e)
67
- rescue ::Mongoid::Errors::NoSessionDatabase => e
64
+ rescue ::Mongoid::Errors::NoClientDatabase => e
68
65
  handle_configuration_error(e)
69
- rescue ::Mongoid::Errors::NoSessionHosts => e
66
+ rescue ::Mongoid::Errors::NoClientHosts => e
70
67
  handle_configuration_error(e)
71
68
  end
72
69
  end
@@ -95,24 +92,6 @@ module Rails
95
92
  end
96
93
  end
97
94
 
98
- config.after_initialize do
99
- # Unicorn clears the START_CTX when a worker is forked, so if we have
100
- # data in START_CTX then we know we're being preloaded. Unicorn does
101
- # not provide application-level hooks for executing code after the
102
- # process has forked, so we reconnect lazily.
103
- if defined?(Unicorn) && !Unicorn::HttpServer::START_CTX.empty?
104
- ::Mongoid.default_session.disconnect if ::Mongoid.configured?
105
- end
106
-
107
- # Passenger provides the :starting_worker_process event for executing
108
- # code after it has forked, so we use that and reconnect immediately.
109
- if ::Mongoid::Config.running_with_passenger?
110
- PhusionPassenger.on_event(:starting_worker_process) do |forked|
111
- ::Mongoid.default_session.disconnect if forked
112
- end
113
- end
114
- end
115
-
116
95
  # Rails runs all initializers first before getting into any generator
117
96
  # code, so we have no way in the intitializer to know if we are
118
97
  # generating a mongoid.yml. So instead of failing, we catch all the
@@ -67,7 +67,7 @@ namespace :db do
67
67
 
68
68
  namespace :mongoid do
69
69
  task :load_models do
70
- ::Rails.application.eager_load! if defined?(Rails)
70
+ ::Rails.application.eager_load! if defined?(::Rails)
71
71
  end
72
72
  end
73
73
  end
@@ -20,8 +20,9 @@ module Mongoid
20
20
  binding do
21
21
  inverse_keys = doc.you_must(metadata.inverse_foreign_key)
22
22
  if inverse_keys
23
- unless inverse_keys.include?(inverse_record_id(doc))
24
- inverse_keys.push(inverse_record_id(doc))
23
+ record_id = inverse_record_id(doc)
24
+ unless inverse_keys.include?(record_id)
25
+ doc.you_must(metadata.inverse_foreign_key_setter, inverse_keys.push(record_id))
25
26
  end
26
27
  doc.reset_relation_criteria(metadata.inverse)
27
28
  end
@@ -91,7 +91,9 @@ module Mongoid
91
91
  re_define_method("create_#{name}") do |*args|
92
92
  attributes, options = parse_args(*args)
93
93
  document = Factory.build(metadata.klass, attributes)
94
- doc = send("#{name}=", document)
94
+ doc = _assigning do
95
+ send("#{name}=", document)
96
+ end
95
97
  doc.save
96
98
  save if new_record? && metadata.stores_foreign_key?
97
99
  doc
@@ -116,7 +116,7 @@ module Mongoid
116
116
 
117
117
  before_destroy do
118
118
  if record = __send__(name)
119
- record[cache_column] = (record[cache_column] || 0) - 1
119
+ record[cache_column] = (record[cache_column] || 0) - 1 unless record.frozen?
120
120
 
121
121
  if record.persisted?
122
122
  record.class.decrement_counter(cache_column, record._id)
@@ -6,7 +6,6 @@ module Mongoid
6
6
  # Contains behaviour for executing operations in batch on embedded
7
7
  # documents.
8
8
  module Batchable
9
- include Positional
10
9
 
11
10
  # Insert new documents as a batch push ($pushAll). This ensures that
12
11
  # all callbacks are run at the appropriate time and only 1 request is
@@ -37,9 +36,7 @@ module Mongoid
37
36
  def batch_clear(docs)
38
37
  pre_process_batch_remove(docs, :delete)
39
38
  unless docs.empty?
40
- collection.find(selector).update(
41
- positionally(selector, "$unset" => { path => true })
42
- )
39
+ collection.find(selector).update_one("$unset" => { path => true })
43
40
  post_process_batch_remove(docs, :delete)
44
41
  end
45
42
  _unscoped.clear
@@ -57,9 +54,7 @@ module Mongoid
57
54
  def batch_remove(docs, method = :delete)
58
55
  removals = pre_process_batch_remove(docs, method)
59
56
  if !docs.empty?
60
- collection.find(selector).update(
61
- positionally(selector, "$pullAll" => { path => removals })
62
- )
57
+ collection.find(selector).update_one("$pullAll" => { path => removals })
63
58
  post_process_batch_remove(docs, method)
64
59
  end
65
60
  reindex
@@ -130,9 +125,7 @@ module Mongoid
130
125
  self.inserts_valid = true
131
126
  inserts = pre_process_batch_insert(docs)
132
127
  if insertable?
133
- collection.find(selector).update(
134
- positionally(selector, operation => { path => inserts })
135
- )
128
+ collection.find(selector).update_one(operation => { path => inserts })
136
129
  post_process_batch_insert(docs)
137
130
  end
138
131
  inserts
@@ -84,6 +84,7 @@ module Mongoid
84
84
  doc.apply_post_processed_defaults
85
85
  yield(doc) if block_given?
86
86
  doc.run_callbacks(:build) { doc }
87
+ base._reset_memoized_children!
87
88
  doc
88
89
  end
89
90
  alias :new :build
@@ -161,7 +162,7 @@ module Mongoid
161
162
  #
162
163
  # @example Delete the matching documents.
163
164
  # person.addresses.delete_if do |doc|
164
- # doc.state = "GA"
165
+ # doc.state == "GA"
165
166
  # end
166
167
  #
167
168
  # @return [ Many, Enumerator ] The relation or an enumerator if no
@@ -170,7 +171,8 @@ module Mongoid
170
171
  # @since 3.1.0
171
172
  def delete_if
172
173
  if block_given?
173
- target.each do |doc|
174
+ dup_target = target.dup
175
+ dup_target.each do |doc|
174
176
  delete(doc) if yield(doc)
175
177
  end
176
178
  self
@@ -20,6 +20,7 @@ module Mongoid
20
20
  characterize_one(target)
21
21
  bind_one
22
22
  characterize_one(target)
23
+ base._reset_memoized_children!
23
24
  target.save if persistable?
24
25
  end
25
26
  end
@@ -5,6 +5,7 @@ module Mongoid
5
5
  # This is the superclass for all many to one and many to many relation
6
6
  # proxies.
7
7
  class Many < Proxy
8
+ include ::Enumerable
8
9
 
9
10
  delegate :avg, :max, :min, :sum, to: :criteria
10
11
  delegate :length, :size, to: :target
@@ -459,6 +459,20 @@ module Mongoid
459
459
  @inverse_foreign_key ||= determine_inverse_foreign_key
460
460
  end
461
461
 
462
+ # Used for relational many to many only. This determines the name of the
463
+ # foreign key field setter on the inverse side of the relation, since in this
464
+ # case there are keys on both sides.
465
+ #
466
+ # @example Find the inverse foreign key setter.
467
+ # metadata.inverse_foreign_key_setter
468
+ #
469
+ # @return [ String ] The foreign key setter on the inverse.
470
+ #
471
+ # @since 2.0.0.rc.1
472
+ def inverse_foreign_key_setter
473
+ @inverse_foreign_key_setter ||= "#{inverse_foreign_key}="
474
+ end
475
+
462
476
  # Returns the inverse class of the proxied relation.
463
477
  #
464
478
  # @example Get the inverse class.
@@ -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|^respond_to|^tap|extend_proxy|extend_proxies)/
15
+ method =~ /(^__|^send|^object_id|^respond_to|^tap|^public_send|extend_proxy|extend_proxies)/
16
16
  end
17
17
 
18
18
  include Threaded::Lifecycle
@@ -85,7 +85,7 @@ module Mongoid
85
85
  end
86
86
 
87
87
  # Tell the next persistance operation to store in a specific collection,
88
- # database or session.
88
+ # database or client.
89
89
  #
90
90
  # @example Save the current document to a different collection.
91
91
  # model.with(collection: "secondary").save
@@ -93,17 +93,17 @@ module Mongoid
93
93
  # @example Save the current document to a different database.
94
94
  # model.with(database: "secondary").save
95
95
  #
96
- # @example Save the current document to a different session.
97
- # model.with(session: "replica_set").save
96
+ # @example Save the current document to a different client.
97
+ # model.with(client: "replica_set").save
98
98
  #
99
99
  # @example Save with a combination of options.
100
- # model.with(session: "sharded", database: "secondary").save
100
+ # model.with(client: "sharded", database: "secondary").save
101
101
  #
102
102
  # @param [ Hash ] options The storage options.
103
103
  #
104
104
  # @option options [ String, Symbol ] :collection The collection name.
105
105
  # @option options [ String, Symbol ] :database The database name.
106
- # @option options [ String, Symbol ] :session The session name.
106
+ # @option options [ String, Symbol ] :client The client name.
107
107
  #
108
108
  # @return [ Document ] The current document.
109
109
  #
@@ -320,6 +320,7 @@ module Mongoid
320
320
  #
321
321
  # @since 2.0.0.rc.1
322
322
  def append(document)
323
+ # @todo: remove?
323
324
  document.with(@persistence_options) if @persistence_options
324
325
 
325
326
  execute_callback :before_add, document
@@ -428,7 +429,7 @@ module Mongoid
428
429
  # @since 3.0.0
429
430
  def persist_delayed(docs, inserts)
430
431
  unless docs.empty?
431
- collection.insert(inserts)
432
+ collection.insert_many(inserts)
432
433
  docs.each do |doc|
433
434
  doc.new_record = false
434
435
  doc.run_after_callbacks(:create, :save)
@@ -45,7 +45,7 @@ module Mongoid
45
45
  #
46
46
  # @since 3.1.4
47
47
  def ===(other)
48
- other.class == Class ? Array == other : self == other
48
+ other.class == Class ? (Array == other || Enumerable == other) : self == other
49
49
  end
50
50
 
51
51
  # Append a document to the enumerable.
@@ -175,7 +175,8 @@ module Mongoid
175
175
  end
176
176
  if _loaded?
177
177
  _loaded.each_pair do |id, doc|
178
- yield(doc)
178
+ document = _added.delete(doc._id) || doc
179
+ yield(document)
179
180
  end
180
181
  else
181
182
  unloaded_documents.each do |doc|
@@ -217,7 +218,10 @@ module Mongoid
217
218
  #
218
219
  # @since 2.1.0
219
220
  def first
220
- matching_document(:first)
221
+ _loaded.try(:values).try(:first) ||
222
+ _added[(ul = _unloaded.try(:first)).try(:id)] ||
223
+ ul ||
224
+ _added.values.try(:first)
221
225
  end
222
226
 
223
227
  # Initialize the new enumerable either with a criteria or an array.
@@ -298,7 +302,10 @@ module Mongoid
298
302
  #
299
303
  # @since 2.1.0
300
304
  def last
301
- matching_document(:last)
305
+ _added.values.try(:last) ||
306
+ _loaded.try(:values).try(:last) ||
307
+ _added[(ul = _unloaded.try(:last)).try(:id)] ||
308
+ ul
302
309
  end
303
310
 
304
311
  # Loads all the documents in the enumerable from the database.
@@ -457,13 +464,6 @@ module Mongoid
457
464
  entries.send(name, *args, &block)
458
465
  end
459
466
 
460
- def matching_document(location)
461
- _loaded.try(:values).try(location) ||
462
- _added[(ul = _unloaded.try(location)).try(:id)] ||
463
- ul ||
464
- _added.values.try(location)
465
- end
466
-
467
467
  def unloaded_documents
468
468
  _unloaded.selector.values.any?(&:blank_criteria?) ? [] : _unloaded
469
469
  end
@@ -31,7 +31,7 @@ module Mongoid
31
31
  touches = touch_atomic_updates(field)
32
32
  unless touches.empty?
33
33
  selector = atomic_selector
34
- _root.collection.where(selector).update(positionally(selector, touches))
34
+ _root.collection.find(selector).update_one(touches)
35
35
  end
36
36
  run_callbacks(:touch)
37
37
  true
@@ -57,7 +57,7 @@ module Mongoid
57
57
  #
58
58
  # @since 2.3.2
59
59
  def reload_root_document
60
- {}.merge(with(read: :primary).collection.find(_id: _id).one || {})
60
+ {}.merge(collection.find(_id: _id).read(mode: :primary).first || {})
61
61
  end
62
62
 
63
63
  # Reload the embedded document.
@@ -70,7 +70,7 @@ module Mongoid
70
70
  # @since 2.3.2
71
71
  def reload_embedded_document
72
72
  extract_embedded_attributes({}.merge(
73
- _root.with(read: :primary).collection.find(_id: _root._id).one
73
+ _root.collection.find(_id: _root._id).read(mode: :primary).first
74
74
  ))
75
75
  end
76
76