mongoid 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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