mongoid 2.0.2 → 2.1.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 (240) hide show
  1. data/README.rdoc +3 -1
  2. data/Rakefile +3 -2
  3. data/lib/config/locales/bg.yml +6 -0
  4. data/lib/config/locales/de.yml +6 -0
  5. data/lib/config/locales/en-GB.yml +48 -0
  6. data/lib/config/locales/en.yml +6 -3
  7. data/lib/config/locales/es.yml +6 -0
  8. data/lib/config/locales/fr.yml +6 -0
  9. data/lib/config/locales/hi.yml +39 -0
  10. data/lib/config/locales/hu.yml +13 -7
  11. data/lib/config/locales/id.yml +3 -0
  12. data/lib/config/locales/it.yml +7 -1
  13. data/lib/config/locales/ja.yml +4 -1
  14. data/lib/config/locales/kr.yml +9 -34
  15. data/lib/config/locales/nl.yml +6 -0
  16. data/lib/config/locales/pl.yml +6 -0
  17. data/lib/config/locales/pt-BR.yml +6 -0
  18. data/lib/config/locales/pt.yml +6 -0
  19. data/lib/config/locales/ro.yml +6 -0
  20. data/lib/config/locales/ru.yml +6 -0
  21. data/lib/config/locales/sv.yml +6 -0
  22. data/lib/config/locales/vi.yml +3 -0
  23. data/lib/config/locales/zh-CN.yml +6 -0
  24. data/lib/mongoid.rb +51 -45
  25. data/lib/mongoid/atomic.rb +145 -0
  26. data/lib/mongoid/atomic/modifiers.rb +109 -0
  27. data/lib/mongoid/atomic/paths.rb +3 -0
  28. data/lib/mongoid/atomic/paths/embedded.rb +43 -0
  29. data/lib/mongoid/atomic/paths/embedded/many.rb +44 -0
  30. data/lib/mongoid/atomic/paths/embedded/one.rb +43 -0
  31. data/lib/mongoid/atomic/paths/root.rb +40 -0
  32. data/lib/mongoid/attributes.rb +12 -23
  33. data/lib/mongoid/attributes/processing.rb +5 -5
  34. data/lib/mongoid/callbacks.rb +2 -0
  35. data/lib/mongoid/collection.rb +12 -59
  36. data/lib/mongoid/collections.rb +23 -20
  37. data/lib/mongoid/collections/master.rb +6 -4
  38. data/lib/mongoid/collections/operations.rb +1 -0
  39. data/lib/mongoid/collections/retry.rb +7 -0
  40. data/lib/mongoid/components.rb +2 -2
  41. data/lib/mongoid/config.rb +42 -55
  42. data/lib/mongoid/config/database.rb +6 -2
  43. data/lib/mongoid/config/replset_database.rb +7 -3
  44. data/lib/mongoid/contexts.rb +9 -3
  45. data/lib/mongoid/contexts/enumerable.rb +7 -3
  46. data/lib/mongoid/contexts/mongo.rb +139 -101
  47. data/lib/mongoid/criteria.rb +86 -69
  48. data/lib/mongoid/criterion/complex.rb +32 -5
  49. data/lib/mongoid/criterion/inclusion.rb +4 -2
  50. data/lib/mongoid/criterion/optional.rb +111 -86
  51. data/lib/mongoid/criterion/selector.rb +8 -4
  52. data/lib/mongoid/cursor.rb +27 -27
  53. data/lib/mongoid/dirty.rb +54 -214
  54. data/lib/mongoid/document.rb +37 -39
  55. data/lib/mongoid/errors/document_not_found.rb +3 -4
  56. data/lib/mongoid/errors/invalid_collection.rb +2 -3
  57. data/lib/mongoid/errors/invalid_database.rb +2 -3
  58. data/lib/mongoid/errors/invalid_field.rb +2 -3
  59. data/lib/mongoid/errors/invalid_options.rb +19 -7
  60. data/lib/mongoid/errors/invalid_type.rb +2 -3
  61. data/lib/mongoid/errors/mongoid_error.rb +5 -6
  62. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +2 -3
  63. data/lib/mongoid/errors/unsupported_version.rb +2 -3
  64. data/lib/mongoid/errors/validations.rb +2 -3
  65. data/lib/mongoid/extensions.rb +8 -62
  66. data/lib/mongoid/extensions/array/deletion.rb +29 -0
  67. data/lib/mongoid/extensions/false_class/equality.rb +14 -1
  68. data/lib/mongoid/extensions/hash/criteria_helpers.rb +21 -10
  69. data/lib/mongoid/extensions/hash/scoping.rb +14 -1
  70. data/lib/mongoid/extensions/nil/collectionization.rb +12 -1
  71. data/lib/mongoid/extensions/object/reflections.rb +33 -2
  72. data/lib/mongoid/extensions/object_id/conversions.rb +2 -36
  73. data/lib/mongoid/extensions/proc/scoping.rb +14 -1
  74. data/lib/mongoid/extensions/string/conversions.rb +4 -16
  75. data/lib/mongoid/extensions/string/inflections.rb +35 -14
  76. data/lib/mongoid/extensions/symbol/inflections.rb +38 -12
  77. data/lib/mongoid/extensions/true_class/equality.rb +14 -1
  78. data/lib/mongoid/extras.rb +11 -30
  79. data/lib/mongoid/factory.rb +1 -1
  80. data/lib/mongoid/fields.rb +121 -29
  81. data/lib/mongoid/fields/mappings.rb +36 -0
  82. data/lib/mongoid/fields/serializable.rb +131 -0
  83. data/lib/mongoid/fields/serializable/array.rb +64 -0
  84. data/lib/mongoid/fields/serializable/big_decimal.rb +42 -0
  85. data/lib/mongoid/fields/serializable/bignum.rb +10 -0
  86. data/lib/mongoid/fields/serializable/binary.rb +11 -0
  87. data/lib/mongoid/fields/serializable/boolean.rb +44 -0
  88. data/lib/mongoid/fields/serializable/date.rb +51 -0
  89. data/lib/mongoid/fields/serializable/date_time.rb +28 -0
  90. data/lib/mongoid/fields/serializable/fixnum.rb +10 -0
  91. data/lib/mongoid/fields/serializable/float.rb +33 -0
  92. data/lib/mongoid/fields/serializable/foreign_keys/array.rb +56 -0
  93. data/lib/mongoid/fields/serializable/foreign_keys/object.rb +43 -0
  94. data/lib/mongoid/fields/serializable/hash.rb +25 -0
  95. data/lib/mongoid/fields/serializable/integer.rb +33 -0
  96. data/lib/mongoid/fields/serializable/object.rb +11 -0
  97. data/lib/mongoid/fields/serializable/object_id.rb +32 -0
  98. data/lib/mongoid/fields/serializable/range.rb +42 -0
  99. data/lib/mongoid/fields/serializable/set.rb +42 -0
  100. data/lib/mongoid/fields/serializable/string.rb +28 -0
  101. data/lib/mongoid/fields/serializable/symbol.rb +28 -0
  102. data/lib/mongoid/fields/serializable/time.rb +12 -0
  103. data/lib/mongoid/fields/serializable/time_with_zone.rb +12 -0
  104. data/lib/mongoid/fields/serializable/timekeeping.rb +102 -0
  105. data/lib/mongoid/finders.rb +61 -37
  106. data/lib/mongoid/hierarchy.rb +43 -8
  107. data/lib/mongoid/identity_map.rb +106 -0
  108. data/lib/mongoid/indexes.rb +17 -1
  109. data/lib/mongoid/javascript.rb +2 -3
  110. data/lib/mongoid/keys.rb +10 -21
  111. data/lib/mongoid/logger.rb +22 -1
  112. data/lib/mongoid/matchers/all.rb +10 -0
  113. data/lib/mongoid/matchers/default.rb +1 -1
  114. data/lib/mongoid/matchers/exists.rb +10 -0
  115. data/lib/mongoid/matchers/gt.rb +10 -0
  116. data/lib/mongoid/matchers/gte.rb +10 -0
  117. data/lib/mongoid/matchers/in.rb +10 -0
  118. data/lib/mongoid/matchers/lt.rb +10 -0
  119. data/lib/mongoid/matchers/lte.rb +10 -0
  120. data/lib/mongoid/matchers/ne.rb +10 -0
  121. data/lib/mongoid/matchers/nin.rb +10 -0
  122. data/lib/mongoid/matchers/or.rb +7 -4
  123. data/lib/mongoid/matchers/size.rb +10 -0
  124. data/lib/mongoid/multi_database.rb +26 -6
  125. data/lib/mongoid/multi_parameter_attributes.rb +40 -17
  126. data/lib/mongoid/named_scope.rb +1 -2
  127. data/lib/mongoid/nested_attributes.rb +4 -1
  128. data/lib/mongoid/observer.rb +108 -5
  129. data/lib/mongoid/paranoia.rb +26 -26
  130. data/lib/mongoid/persistence.rb +15 -21
  131. data/lib/mongoid/persistence/atomic.rb +135 -0
  132. data/lib/mongoid/persistence/atomic/add_to_set.rb +11 -8
  133. data/lib/mongoid/persistence/atomic/bit.rb +37 -0
  134. data/lib/mongoid/persistence/atomic/inc.rb +9 -6
  135. data/lib/mongoid/persistence/atomic/operation.rb +48 -7
  136. data/lib/mongoid/persistence/atomic/pop.rb +34 -0
  137. data/lib/mongoid/persistence/atomic/pull.rb +34 -0
  138. data/lib/mongoid/persistence/atomic/pull_all.rb +10 -9
  139. data/lib/mongoid/persistence/atomic/push.rb +8 -5
  140. data/lib/mongoid/persistence/atomic/push_all.rb +31 -0
  141. data/lib/mongoid/persistence/atomic/rename.rb +31 -0
  142. data/lib/mongoid/persistence/atomic/set.rb +30 -0
  143. data/lib/mongoid/persistence/atomic/unset.rb +28 -0
  144. data/lib/mongoid/persistence/deletion.rb +32 -0
  145. data/lib/mongoid/persistence/insertion.rb +41 -0
  146. data/lib/mongoid/persistence/modification.rb +37 -0
  147. data/lib/mongoid/persistence/operations.rb +214 -0
  148. data/lib/mongoid/persistence/operations/embedded/insert.rb +42 -0
  149. data/lib/mongoid/persistence/operations/embedded/remove.rb +40 -0
  150. data/lib/mongoid/persistence/operations/insert.rb +34 -0
  151. data/lib/mongoid/persistence/operations/remove.rb +33 -0
  152. data/lib/mongoid/persistence/operations/update.rb +53 -0
  153. data/lib/mongoid/railtie.rb +21 -33
  154. data/lib/mongoid/railties/database.rake +12 -12
  155. data/lib/mongoid/relations.rb +9 -5
  156. data/lib/mongoid/relations/accessors.rb +15 -36
  157. data/lib/mongoid/relations/auto_save.rb +2 -2
  158. data/lib/mongoid/relations/binding.rb +28 -1
  159. data/lib/mongoid/relations/bindings/embedded/in.rb +17 -30
  160. data/lib/mongoid/relations/bindings/embedded/many.rb +16 -21
  161. data/lib/mongoid/relations/bindings/embedded/one.rb +11 -16
  162. data/lib/mongoid/relations/bindings/referenced/in.rb +31 -32
  163. data/lib/mongoid/relations/bindings/referenced/many.rb +19 -61
  164. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +15 -63
  165. data/lib/mongoid/relations/bindings/referenced/one.rb +18 -26
  166. data/lib/mongoid/relations/builder.rb +4 -2
  167. data/lib/mongoid/relations/builders.rb +21 -2
  168. data/lib/mongoid/relations/builders/embedded/in.rb +5 -1
  169. data/lib/mongoid/relations/builders/embedded/many.rb +12 -4
  170. data/lib/mongoid/relations/builders/embedded/one.rb +5 -1
  171. data/lib/mongoid/relations/builders/nested_attributes/many.rb +2 -2
  172. data/lib/mongoid/relations/builders/nested_attributes/one.rb +1 -1
  173. data/lib/mongoid/relations/builders/referenced/in.rb +2 -5
  174. data/lib/mongoid/relations/builders/referenced/many.rb +2 -3
  175. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +14 -5
  176. data/lib/mongoid/relations/builders/referenced/one.rb +2 -3
  177. data/lib/mongoid/relations/embedded/atomic.rb +2 -2
  178. data/lib/mongoid/relations/embedded/in.rb +72 -41
  179. data/lib/mongoid/relations/embedded/many.rb +116 -120
  180. data/lib/mongoid/relations/embedded/one.rb +59 -41
  181. data/lib/mongoid/relations/embedded/sort.rb +31 -0
  182. data/lib/mongoid/relations/macros.rb +28 -24
  183. data/lib/mongoid/relations/many.rb +10 -103
  184. data/lib/mongoid/relations/metadata.rb +335 -38
  185. data/lib/mongoid/relations/one.rb +7 -32
  186. data/lib/mongoid/relations/options.rb +47 -0
  187. data/lib/mongoid/relations/proxy.rb +29 -28
  188. data/lib/mongoid/relations/referenced/batch.rb +2 -3
  189. data/lib/mongoid/relations/referenced/in.rb +66 -53
  190. data/lib/mongoid/relations/referenced/many.rb +216 -143
  191. data/lib/mongoid/relations/referenced/many_to_many.rb +132 -163
  192. data/lib/mongoid/relations/referenced/one.rb +76 -58
  193. data/lib/mongoid/relations/synchronization.rb +113 -0
  194. data/lib/mongoid/relations/targets.rb +2 -0
  195. data/lib/mongoid/relations/targets/enumerable.rb +329 -0
  196. data/lib/mongoid/safety.rb +24 -156
  197. data/lib/mongoid/serialization.rb +21 -0
  198. data/lib/mongoid/state.rb +34 -0
  199. data/lib/mongoid/threaded.rb +175 -0
  200. data/lib/mongoid/timestamps/updated.rb +1 -1
  201. data/lib/mongoid/validations.rb +3 -7
  202. data/lib/mongoid/version.rb +1 -1
  203. data/lib/mongoid/versioning.rb +61 -7
  204. data/lib/rack/mongoid.rb +2 -0
  205. data/lib/rack/mongoid/middleware/identity_map.rb +38 -0
  206. data/lib/rails/generators/mongoid/model/model_generator.rb +1 -1
  207. data/lib/rails/generators/mongoid/model/templates/{model.rb → model.rb.tt} +0 -0
  208. data/lib/rails/generators/mongoid/observer/observer_generator.rb +1 -1
  209. data/lib/rails/generators/mongoid/observer/templates/{observer.rb → observer.rb.tt} +0 -0
  210. data/lib/rails/mongoid.rb +17 -17
  211. metadata +136 -102
  212. data/lib/mongoid/atomicity.rb +0 -111
  213. data/lib/mongoid/collections/cyclic_iterator.rb +0 -34
  214. data/lib/mongoid/collections/slaves.rb +0 -61
  215. data/lib/mongoid/extensions/array/conversions.rb +0 -23
  216. data/lib/mongoid/extensions/array/parentization.rb +0 -13
  217. data/lib/mongoid/extensions/big_decimal/conversions.rb +0 -19
  218. data/lib/mongoid/extensions/binary/conversions.rb +0 -17
  219. data/lib/mongoid/extensions/boolean/conversions.rb +0 -27
  220. data/lib/mongoid/extensions/date/conversions.rb +0 -25
  221. data/lib/mongoid/extensions/datetime/conversions.rb +0 -12
  222. data/lib/mongoid/extensions/float/conversions.rb +0 -20
  223. data/lib/mongoid/extensions/hash/conversions.rb +0 -19
  224. data/lib/mongoid/extensions/integer/conversions.rb +0 -20
  225. data/lib/mongoid/extensions/object/conversions.rb +0 -25
  226. data/lib/mongoid/extensions/range/conversions.rb +0 -25
  227. data/lib/mongoid/extensions/set/conversions.rb +0 -20
  228. data/lib/mongoid/extensions/symbol/conversions.rb +0 -21
  229. data/lib/mongoid/extensions/time_conversions.rb +0 -38
  230. data/lib/mongoid/field.rb +0 -162
  231. data/lib/mongoid/paths.rb +0 -61
  232. data/lib/mongoid/persistence/command.rb +0 -71
  233. data/lib/mongoid/persistence/insert.rb +0 -53
  234. data/lib/mongoid/persistence/insert_embedded.rb +0 -43
  235. data/lib/mongoid/persistence/remove.rb +0 -44
  236. data/lib/mongoid/persistence/remove_all.rb +0 -40
  237. data/lib/mongoid/persistence/remove_embedded.rb +0 -48
  238. data/lib/mongoid/persistence/update.rb +0 -77
  239. data/lib/mongoid/safe.rb +0 -23
  240. data/lib/mongoid/validations/referenced.rb +0 -58
@@ -14,11 +14,13 @@ module Mongoid #:nodoc:
14
14
  # @example Proxy the driver save.
15
15
  # collection.save({ :name => "Al" })
16
16
  Operations::ALL.each do |name|
17
- define_method(name) do |*args|
18
- retry_on_connection_failure do
19
- collection.send(name, *args)
17
+ class_eval <<-EOS, __FILE__, __LINE__
18
+ def #{name}(*args)
19
+ retry_on_connection_failure do
20
+ collection.#{name}(*args)
21
+ end
20
22
  end
21
- end
23
+ EOS
22
24
  end
23
25
 
24
26
  # Create the new database writer. Will create a collection from the
@@ -2,6 +2,7 @@
2
2
  module Mongoid #:nodoc:
3
3
  module Collections #:nodoc:
4
4
  module Operations #:nodoc:
5
+
5
6
  # Constant definining all the read operations available for a
6
7
  # Mongo:Collection. This is used in delegation.
7
8
  READ = [
@@ -31,9 +31,16 @@ module Mongoid #:nodoc:
31
31
  retries += 1
32
32
  raise ex if retries > Mongoid.max_retries_on_connection_failure
33
33
  Kernel.sleep(0.5)
34
+ log_retry retries
34
35
  retry
35
36
  end
36
37
  end
38
+
39
+ private
40
+
41
+ def log_retry(retry_number)
42
+ Mongoid.logger.warn "A Mongo::ConnectionFailure was raised. Retry attempt ##{retry_number}."
43
+ end
37
44
  end
38
45
  end
39
46
  end
@@ -16,7 +16,7 @@ module Mongoid #:nodoc
16
16
  include ActiveModel::Observing
17
17
  include ActiveModel::Serializers::JSON
18
18
  include ActiveModel::Serializers::Xml
19
- include Mongoid::Atomicity
19
+ include Mongoid::Atomic
20
20
  include Mongoid::Attributes
21
21
  include Mongoid::Collections
22
22
  include Mongoid::Copyable
@@ -32,7 +32,6 @@ module Mongoid #:nodoc
32
32
  include Mongoid::Matchers
33
33
  include Mongoid::NamedScope
34
34
  include Mongoid::NestedAttributes
35
- include Mongoid::Paths
36
35
  include Mongoid::Persistence
37
36
  include Mongoid::Relations
38
37
  include Mongoid::Safety
@@ -41,5 +40,6 @@ module Mongoid #:nodoc
41
40
  include Mongoid::State
42
41
  include Mongoid::Validations
43
42
  include Mongoid::Callbacks
43
+ include Mongoid::MultiDatabase
44
44
  end
45
45
  end
@@ -13,8 +13,9 @@ module Mongoid #:nodoc
13
13
  extend self
14
14
  include ActiveModel::Observing
15
15
 
16
- attr_accessor :master, :slaves, :settings
16
+ attr_accessor :master, :settings, :defaults
17
17
  @settings = {}
18
+ @defaults = {}
18
19
 
19
20
  # Define a configuration option with a default.
20
21
  #
@@ -28,22 +29,33 @@ module Mongoid #:nodoc
28
29
  #
29
30
  # @since 2.0.0.rc.1
30
31
  def option(name, options = {})
31
- define_method(name) do
32
- settings.has_key?(name) ? settings[name] : options[:default]
33
- end
34
- define_method("#{name}=") { |value| settings[name] = value }
35
- define_method("#{name}?") { send(name) }
32
+ defaults[name] = settings[name] = options[:default]
33
+
34
+ class_eval <<-RUBY
35
+ def #{name}
36
+ settings[#{name.inspect}]
37
+ end
38
+
39
+ def #{name}=(value)
40
+ settings[#{name.inspect}] = value
41
+ end
42
+
43
+ def #{name}?
44
+ #{name}
45
+ end
46
+ RUBY
36
47
  end
37
48
 
38
49
  option :allow_dynamic_fields, :default => true
39
50
  option :autocreate_indexes, :default => false
40
51
  option :binding_defaults, :default => { :binding => false, :continue => true }
41
52
  option :embedded_object_id, :default => true
53
+ option :identity_map_enabled, :default => false
42
54
  option :include_root_in_json, :default => false
43
55
  option :max_retries_on_connection_failure, :default => 0
44
56
  option :parameterize_keys, :default => true
45
57
  option :persist_in_safe_mode, :default => false
46
- option :preload_models, :default => true
58
+ option :preload_models, :default => false
47
59
  option :raise_not_found_error, :default => true
48
60
  option :skip_version_check, :default => false
49
61
  option :time_zone, :default => nil
@@ -125,7 +137,7 @@ module Mongoid #:nodoc
125
137
  #
126
138
  # @since 2.0.1
127
139
  def load!(path)
128
- environment = defined?(Rails) ? Rails.env : ENV["RACK_ENV"]
140
+ environment = defined?(Rails) && Rails.respond_to?(:env) ? Rails.env : ENV["RACK_ENV"]
129
141
  settings = YAML.load(ERB.new(File.new(path).read).result)[environment]
130
142
  if settings.present?
131
143
  from_hash(settings)
@@ -139,7 +151,7 @@ module Mongoid #:nodoc
139
151
  #
140
152
  # @return [ Logger ] The default Logger instance.
141
153
  def default_logger
142
- defined?(Rails) ? Rails.logger : ::Logger.new($stdout)
154
+ defined?(Rails) && Rails.respond_to?(:logger) ? Rails.logger : ::Logger.new($stdout)
143
155
  end
144
156
 
145
157
  # Returns the logger, or defaults to Rails logger or stdout logger.
@@ -177,30 +189,18 @@ module Mongoid #:nodoc
177
189
 
178
190
  # Sets whether the times returned from the database use the ruby or
179
191
  # the ActiveSupport time zone.
180
- # If you omit this setting, then times will use the ruby time zone.
181
192
  #
182
- # Example:
193
+ # @note If you omit this setting, then times will use the ruby time zone.
183
194
  #
184
- # <tt>Config.use_activesupport_time_zone = true</tt>
195
+ # @example Set the time zone config.
196
+ # Config.use_activesupport_time_zone = true
185
197
  #
186
- # Returns:
198
+ # @param [ true, false ] value Whether to use Active Support time zones.
187
199
  #
188
- # A boolean
200
+ # @return [ true, false ] The supplied value or false if nil.
189
201
  def use_activesupport_time_zone=(value)
190
202
  @use_activesupport_time_zone = value || false
191
203
  end
192
-
193
- # Sets whether the times returned from the database use the ruby or
194
- # the ActiveSupport time zone.
195
- # If the setting is false, then times will use the ruby time zone.
196
- #
197
- # Example:
198
- #
199
- # <tt>Config.use_activesupport_time_zone</tt>
200
- #
201
- # Returns:
202
- #
203
- # A boolean
204
204
  attr_reader :use_activesupport_time_zone
205
205
  alias_method :use_activesupport_time_zone?, :use_activesupport_time_zone
206
206
 
@@ -265,39 +265,17 @@ module Mongoid #:nodoc
265
265
  # @example Reset the configuration options.
266
266
  # config.reset
267
267
  def reset
268
- settings.clear
268
+ settings.replace(defaults)
269
269
  end
270
270
 
271
- # Sets the Mongo::DB slave databases to be used. If the objects provided
272
- # are not valid +Mongo::DBs+ an error will be raised.
273
- #
274
- # @example Set the slaves.
275
- # config.slaves = [ Mongo::Connection.db("test") ]
276
- #
277
- # @param [ Array<Mongo::DB> ] dbs The slave databases.
278
- #
279
- # @raise [ Errors::InvalidDatabase ] If the slaves arent valid objects.
280
- #
281
- # @return [ Array<Mongo::DB> ] The slave DB instances.
282
- def slaves=(dbs)
283
- return unless dbs
284
- dbs.each do |db|
285
- check_database!(db)
286
- end
287
- @slaves = dbs
271
+ # @deprecated User replica sets instead.
272
+ def slaves
273
+ slave_warning!
288
274
  end
289
275
 
290
- # Returns the slave databases or nil if none have been set.
291
- #
292
- # @example Get the slaves.
293
- # config.slaves
294
- #
295
- # @return [ Array<Mongo::DB>, nil ] The slave databases.
296
- def slaves
297
- unless @slaves
298
- @master, @slaves = configure_databases(@settings) if @settings && @settings[:database]
299
- end
300
- @slaves
276
+ # @deprecated User replica sets instead.
277
+ def slaves=(dbs)
278
+ slave_warning!
301
279
  end
302
280
 
303
281
  protected
@@ -358,5 +336,14 @@ module Mongoid #:nodoc
358
336
  end
359
337
  end
360
338
  end
339
+
340
+ # Temporarily here so people can move to replica sets.
341
+ def slave_warning!
342
+ warn(
343
+ "Using Mongoid for traditional slave databases will be removed in the " +
344
+ "next release in preference of replica sets. Please change your setup " +
345
+ "accordingly."
346
+ )
347
+ end
361
348
  end
362
349
  end
@@ -6,6 +6,9 @@ module Mongoid #:nodoc:
6
6
  # database from options.
7
7
  class Database < Hash
8
8
 
9
+ # keys to remove from self to not pass through to Mongo::Connection
10
+ PRIVATE_OPTIONS = %w(uri database username password)
11
+
9
12
  # Configure the database connections. This will return an array
10
13
  # containing the master and an array of slaves.
11
14
  #
@@ -142,11 +145,12 @@ module Mongoid #:nodoc:
142
145
  #
143
146
  # @since 2.0.0.rc.1
144
147
  def optional(slave = false)
145
- {
148
+ ({
146
149
  :pool_size => pool_size,
147
150
  :logger => Mongoid::Logger.new,
148
151
  :slave_ok => slave
149
- }
152
+ }).merge(self).reject { |k,v| PRIVATE_OPTIONS.include? k }.
153
+ inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo} # mongo likes symbols
150
154
  end
151
155
 
152
156
  # Get a Mongo compliant URI for the database connection.
@@ -14,9 +14,13 @@ module Mongoid #:nodoc:
14
14
  #
15
15
  # @since 2.0.0.rc.5
16
16
  def configure
17
- #yes, construction is weird but the driver wants "A list of host-port pairs ending with a hash containing any options"
18
- #mongo likes symbols
19
- options = self.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo}
17
+ # yes, construction is weird but the driver wants
18
+ # "A list of host-port pairs ending with a hash containing any options"
19
+ # mongo likes symbols
20
+ options = self.inject({ :logger => Mongoid::Logger.new }) do |memo, (k, v)|
21
+ memo[k.to_sym] = v
22
+ memo
23
+ end
20
24
  connection = Mongo::ReplSetConnection.new(*(hosts << options))
21
25
 
22
26
  if authenticating?
@@ -4,15 +4,21 @@ require "mongoid/contexts/mongo"
4
4
 
5
5
  module Mongoid
6
6
  module Contexts
7
+ extend self
8
+
7
9
  # Determines the context to be used for this criteria. If the class is an
8
10
  # embedded document, then the context will be the array in the has_many
9
11
  # association it is in. If the class is a root, then the database itself
10
12
  # will be the context.
11
13
  #
12
- # Example:
14
+ # @example Get the context for the criteria.
15
+ # Contexts.context_for(criteria)
16
+ #
17
+ # @param [ Criteria ] criteria The criteria to use.
18
+ # @param [ true, false ] embedded Whether this is on embedded documents.
13
19
  #
14
- # <tt>Contexts.context_for(criteria)</tt>
15
- def self.context_for(criteria, embedded = false)
20
+ # @return [ Enumerable, Mongo ] The appropriate context.
21
+ def context_for(criteria, embedded = false)
16
22
  embedded ? Enumerable.new(criteria) : Mongo.new(criteria)
17
23
  end
18
24
  end
@@ -56,7 +56,9 @@ module Mongoid #:nodoc:
56
56
  def delete_all
57
57
  atomically(:$pull) do
58
58
  set_collection
59
- count.tap { filter.each(&:delete) }
59
+ count.tap do
60
+ filter.each { |doc| doc.delete }
61
+ end
60
62
  end
61
63
  end
62
64
  alias :delete :delete_all
@@ -72,7 +74,9 @@ module Mongoid #:nodoc:
72
74
  def destroy_all
73
75
  atomically(:$pull) do
74
76
  set_collection
75
- count.tap { filter.each(&:destroy) }
77
+ count.tap do
78
+ filter.each { |doc| doc.destroy }
79
+ end
76
80
  end
77
81
  end
78
82
  alias :destroy :destroy_all
@@ -252,7 +256,7 @@ module Mongoid #:nodoc:
252
256
  #
253
257
  # @return [ Collection ] The root collection.
254
258
  def set_collection
255
- root = documents.first._root
259
+ root = documents.first.try(:_root)
256
260
  @collection = root.collection if root && !root.embedded?
257
261
  end
258
262
 
@@ -6,18 +6,34 @@ module Mongoid #:nodoc:
6
6
 
7
7
  delegate :klass, :options, :field_list, :selector, :to => :criteria
8
8
 
9
+ # Perform an add to set on the matching documents.
10
+ #
11
+ # @example Add to set on all matching.
12
+ # Person.where(:name => "Alex").add_to_set(:aliases, "value")
13
+ #
14
+ # @param [ String ] field The field to add to.
15
+ # @param [ Object ] value The value to add.
16
+ #
17
+ # @return [ Object ] The update value.
18
+ #
19
+ # @since 2.1.0
20
+ def add_to_set(field, value)
21
+ klass.collection.update(
22
+ selector,
23
+ { "$addToSet" => { field => value } },
24
+ :multi => true
25
+ )
26
+ end
27
+
9
28
  # Aggregate the context. This will take the internally built selector and options
10
29
  # and pass them on to the Ruby driver's +group()+ method on the collection. The
11
30
  # collection itself will be retrieved from the class provided, and once the
12
31
  # query has returned it will provided a grouping of keys with counts.
13
32
  #
14
- # Example:
15
- #
16
- # <tt>context.aggregate</tt>
33
+ # @example Aggreate the context.
34
+ # context.aggregate
17
35
  #
18
- # Returns:
19
- #
20
- # A +Hash+ with field values as keys, counts as values
36
+ # @return [ Hash ] A +Hash+ with field values as keys, counts as values
21
37
  def aggregate
22
38
  klass.collection.group(
23
39
  :key => field_list,
@@ -34,13 +50,12 @@ module Mongoid #:nodoc:
34
50
  # collection itself will be retrieved from the class provided, and once the
35
51
  # query has returned it will provided a grouping of keys with averages.
36
52
  #
37
- # Example:
38
- #
39
- # <tt>context.avg(:age)</tt>
53
+ # @example Get the average for a field.
54
+ # context.avg(:age)
40
55
  #
41
- # Returns:
56
+ # @param [ Symbol ] field The field to get the average for.
42
57
  #
43
- # A numeric value that is the average.
58
+ # @return [ Numeric ] A numeric value that is the average.
44
59
  def avg(field)
45
60
  total = sum(field)
46
61
  total ? (total / count) : nil
@@ -49,9 +64,10 @@ module Mongoid #:nodoc:
49
64
  # Determine if the context is empty or blank given the criteria. Will
50
65
  # perform a quick has_one asking only for the id.
51
66
  #
52
- # Example:
67
+ # @example Is the context empty?
68
+ # context.blank?a
53
69
  #
54
- # <tt>context.blank?</tt>
70
+ # @return [ true, false ] True if blank.
55
71
  def blank?
56
72
  klass.collection.find_one(selector, { :fields => [ :_id ] }).nil?
57
73
  end
@@ -102,9 +118,12 @@ module Mongoid #:nodoc:
102
118
  # Gets an array of distinct values for the supplied field across the
103
119
  # entire collection or the susbset given the criteria.
104
120
  #
105
- # Example:
121
+ # @example Get the distinct values.
122
+ # context.distinct(:title)
123
+ #
124
+ # @param [ Symbol ] field The field to get the values for.
106
125
  #
107
- # <tt>context.distinct(:title)</tt>
126
+ # @return [ Array<Object> ] The distinct values for the field.
108
127
  def distinct(field)
109
128
  klass.collection.distinct(field, selector)
110
129
  end
@@ -114,29 +133,35 @@ module Mongoid #:nodoc:
114
133
  # collection itself will be retrieved from the class provided, and once the
115
134
  # query has returned new documents of the type of class provided will be instantiated.
116
135
  #
117
- # Example:
136
+ # @example Execute the criteria on the context.
137
+ # context.execute
118
138
  #
119
- # <tt>context.execute</tt>
120
- #
121
- # Returns:
122
- #
123
- # An enumerable +Cursor+.
139
+ # @return [ Cursor ] An enumerable +Cursor+ of results.
124
140
  def execute
125
141
  klass.collection.find(selector, process_options) || []
126
142
  end
127
143
 
144
+ # Return the first result for the +Context+.
145
+ #
146
+ # @example Get the first document.
147
+ # context.one
148
+ #
149
+ # @return [ Document ] The first document in the collection.
150
+ def first
151
+ attributes = klass.collection.find_one(selector, process_options)
152
+ attributes ? Mongoid::Factory.from_db(klass, attributes) : nil
153
+ end
154
+ alias :one :first
155
+
128
156
  # Groups the context. This will take the internally built selector and options
129
157
  # and pass them on to the Ruby driver's +group()+ method on the collection. The
130
158
  # collection itself will be retrieved from the class provided, and once the
131
159
  # query has returned it will provided a grouping of keys with objects.
132
160
  #
133
- # Example:
161
+ # @example Get the criteria as a group.
162
+ # context.group
134
163
  #
135
- # <tt>context.group</tt>
136
- #
137
- # Returns:
138
- #
139
- # A +Hash+ with field values as keys, arrays of documents as values.
164
+ # @return [ Hash ] Hash with field values as keys, arrays of documents as values.
140
165
  def group
141
166
  klass.collection.group(
142
167
  :key => field_list,
@@ -154,24 +179,23 @@ module Mongoid #:nodoc:
154
179
  # Create the new mongo context. This will execute the queries given the
155
180
  # selector and options against the database.
156
181
  #
157
- # Example:
182
+ # @example Create a new context.
183
+ # Mongoid::Contexts::Mongo.new(criteria)
158
184
  #
159
- # <tt>Mongoid::Contexts::Mongo.new(criteria)</tt>
185
+ # @param [ Criteria ] criteria The criteria to create with.
160
186
  def initialize(criteria)
161
187
  @criteria = criteria
162
188
  if klass.hereditary? && !criteria.selector.keys.include?(:_type)
163
189
  @criteria = criteria.in(:_type => criteria.klass._types)
164
190
  end
165
- @criteria.enslave if klass.enslaved?
166
191
  @criteria.cache if klass.cached?
167
192
  end
168
193
 
169
194
  # Iterate over each +Document+ in the results. This can take an optional
170
195
  # block to pass to each argument in the results.
171
196
  #
172
- # Example:
173
- #
174
- # <tt>context.iterate { |doc| p doc }</tt>
197
+ # @example Iterate over the results.
198
+ # context.iterate { |doc| p doc }
175
199
  def iterate(&block)
176
200
  return caching(&block) if criteria.cached?
177
201
  if block_given?
@@ -183,18 +207,15 @@ module Mongoid #:nodoc:
183
207
  # the collection with the sorting reversed. If no sorting parameters have
184
208
  # been provided it will default to ids.
185
209
  #
186
- # Example:
210
+ # @example Get the last document.
211
+ # context.last
187
212
  #
188
- # <tt>context.last</tt>
189
- #
190
- # Returns:
191
- #
192
- # The last document in the collection.
213
+ # @return [ Document ] The last document in the collection.
193
214
  def last
194
215
  opts = process_options
195
- sorting = opts[:sort]
196
- sorting = [[:_id, :asc]] unless sorting
197
- opts[:sort] = sorting.collect { |option| [ option[0], option[1].invert ] }
216
+ sorting = opts[:sort] ||= []
217
+ sorting << [:_id, :asc]
218
+ opts[:sort] = sorting.map{ |option| [ option[0], option[1].invert ] }.uniq
198
219
  attributes = klass.collection.find_one(selector, opts)
199
220
  attributes ? Mongoid::Factory.from_db(klass, attributes) : nil
200
221
  end
@@ -206,13 +227,12 @@ module Mongoid #:nodoc:
206
227
  # collection itself will be retrieved from the class provided, and once the
207
228
  # query has returned it will provided a grouping of keys with sums.
208
229
  #
209
- # Example:
210
- #
211
- # <tt>context.max(:age)</tt>
230
+ # @example Get the max value.
231
+ # context.max(:age)
212
232
  #
213
- # Returns:
233
+ # @param [ Symbol ] field The field to get the max for.
214
234
  #
215
- # A numeric max value.
235
+ # @return [ Numeric ] A numeric max value.
216
236
  def max(field)
217
237
  grouped(:max, field.to_s, Javascript.max)
218
238
  end
@@ -224,43 +244,44 @@ module Mongoid #:nodoc:
224
244
  # collection itself will be retrieved from the class provided, and once the
225
245
  # query has returned it will provided a grouping of keys with sums.
226
246
  #
227
- # Example:
247
+ # @example Get the min value.
248
+ # context.min(:age)
228
249
  #
229
- # <tt>context.min(:age)</tt>
250
+ # @param [ Symbol ] field The field to get the min for.
230
251
  #
231
- # Returns:
232
- #
233
- # A numeric minimum value.
252
+ # @return [ Numeric ] A numeric minimum value.
234
253
  def min(field)
235
254
  grouped(:min, field.to_s, Javascript.min)
236
255
  end
237
256
 
238
- # Return the first result for the +Context+.
257
+ # Perform a pull on the matching documents.
239
258
  #
240
- # Example:
259
+ # @example Pull on all matching.
260
+ # Person.where(:name => "Alex").pull(:aliases, "value")
241
261
  #
242
- # <tt>context.one</tt>
262
+ # @param [ String ] field The field to pull from.
263
+ # @param [ Object ] value The value to pull.
243
264
  #
244
- # Return:
265
+ # @return [ Object ] The update value.
245
266
  #
246
- # The first document in the collection.
247
- def one
248
- attributes = klass.collection.find_one(selector, process_options)
249
- attributes ? Mongoid::Factory.from_db(klass, attributes) : nil
267
+ # @since 2.1.0
268
+ def pull(field, value)
269
+ klass.collection.update(
270
+ selector,
271
+ { "$pull" => { field => value } },
272
+ :multi => true
273
+ )
250
274
  end
251
275
 
252
- alias :first :one
253
-
254
276
  # Return the first result for the +Context+ and skip it
255
277
  # for successive calls.
256
278
  #
257
- # Returns:
279
+ # @example Get the first document and shift.
280
+ # context.shift
258
281
  #
259
- # The first document in the collection.
282
+ # @return [ Document ] The first document in the collection.
260
283
  def shift
261
- document = first
262
- criteria.skip((options[:skip] || 0) + 1)
263
- document
284
+ first.tap { criteria.skip((options[:skip] || 0) + 1) }
264
285
  end
265
286
 
266
287
  # Sum the context.
@@ -270,43 +291,16 @@ module Mongoid #:nodoc:
270
291
  # collection itself will be retrieved from the class provided, and once the
271
292
  # query has returned it will provided a grouping of keys with sums.
272
293
  #
273
- # Example:
274
- #
275
- # <tt>context.sum(:age)</tt>
294
+ # @example Get the sum for a field.
295
+ # context.sum(:age)
276
296
  #
277
- # Returns:
297
+ # @param [ Symbol ] field The field who's values to sum.
278
298
  #
279
- # A numeric value that is the sum.
299
+ # @return [ Numeric ] A numeric value that is the sum.
280
300
  def sum(field)
281
301
  grouped(:sum, field.to_s, Javascript.sum)
282
302
  end
283
303
 
284
- # Common functionality for grouping operations. Currently used by min, max
285
- # and sum. Will gsub the field name in the supplied reduce function.
286
- def grouped(start, field, reduce)
287
- collection = klass.collection.group(
288
- :cond => selector,
289
- :initial => { start => "start" },
290
- :reduce => reduce.gsub("[field]", field)
291
- )
292
- collection.empty? ? nil : collection.first[start.to_s]
293
- end
294
-
295
- # Filters the field list. If no fields have been supplied, then it will be
296
- # empty. If fields have been defined then _type will be included as well.
297
- def process_options
298
- fields = options[:fields]
299
- if fields && fields.size > 0 && !fields.include?(:_type)
300
- if fields.kind_of?(Hash)
301
- fields[:_type] = 1 if fields.first.last != 0 # Not excluding
302
- else
303
- fields << :type
304
- end
305
- options[:fields] = fields
306
- end
307
- options.dup
308
- end
309
-
310
304
  # Very basic update that will perform a simple atomic $set of the
311
305
  # attributes provided in the hash. Can be expanded to later for more
312
306
  # robust functionality.
@@ -321,15 +315,19 @@ module Mongoid #:nodoc:
321
315
  klass.collection.update(
322
316
  selector,
323
317
  { "$set" => attributes },
324
- :multi => true,
325
- :safe => Mongoid.persist_in_safe_mode
326
- )
318
+ Safety.merge_safety_options(:multi => true)
319
+ ).tap do
320
+ Threaded.clear_safety_options!
321
+ end
327
322
  end
328
323
  alias :update :update_all
329
324
 
330
325
  protected
331
326
 
332
327
  # Iterate over each +Document+ in the results and cache the collection.
328
+ #
329
+ # @example Execute with caching.
330
+ # context.caching
333
331
  def caching(&block)
334
332
  if defined? @collection
335
333
  @collection.each(&block)
@@ -341,6 +339,46 @@ module Mongoid #:nodoc:
341
339
  end
342
340
  end
343
341
  end
342
+
343
+ # Common functionality for grouping operations. Currently used by min, max
344
+ # and sum. Will gsub the field name in the supplied reduce function.
345
+ #
346
+ # @example Execute the group function.
347
+ # context.group(0, :avg, "")
348
+ #
349
+ # @param [ Object ] start The value to start the map/reduce with.
350
+ # @param [ String ] field The field to aggregate.
351
+ # @param [ String ] reduce The reduce JS function.
352
+ #
353
+ # @return [ Numeric ] A numeric result.
354
+ def grouped(start, field, reduce)
355
+ collection = klass.collection.group(
356
+ :cond => selector,
357
+ :initial => { start => "start" },
358
+ :reduce => reduce.gsub("[field]", field)
359
+ )
360
+ collection.empty? ? nil : collection.first[start.to_s]
361
+ end
362
+
363
+ # Filters the field list. If no fields have been supplied, then it will be
364
+ # empty. If fields have been defined then _type will be included as well.
365
+ #
366
+ # @example Process the field list.
367
+ # context.process_options
368
+ #
369
+ # @return [ Hash ] The options.
370
+ def process_options
371
+ fields = options[:fields]
372
+ if fields && fields.size > 0 && !fields.include?(:_type)
373
+ if fields.kind_of?(Hash)
374
+ fields[:_type] = 1 if fields.first.last != 0 # Not excluding
375
+ else
376
+ fields << :type
377
+ end
378
+ options[:fields] = fields
379
+ end
380
+ options.dup
381
+ end
344
382
  end
345
383
  end
346
384
  end