mongoid 2.0.1 → 2.0.2

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 (61) hide show
  1. data/Rakefile +4 -4
  2. data/lib/config/locales/{pt-br.yml → pt-BR.yml} +5 -5
  3. data/lib/config/locales/ru.yml +1 -1
  4. data/lib/config/locales/zh-CN.yml +2 -0
  5. data/lib/mongoid.rb +0 -1
  6. data/lib/mongoid/attributes.rb +9 -6
  7. data/lib/mongoid/collection.rb +21 -0
  8. data/lib/mongoid/config.rb +31 -8
  9. data/lib/mongoid/config/replset_database.rb +32 -2
  10. data/lib/mongoid/contexts.rb +0 -1
  11. data/lib/mongoid/contexts/enumerable.rb +73 -36
  12. data/lib/mongoid/contexts/mongo.rb +5 -12
  13. data/lib/mongoid/copyable.rb +2 -2
  14. data/lib/mongoid/criteria.rb +4 -23
  15. data/lib/mongoid/criterion/exclusion.rb +15 -0
  16. data/lib/mongoid/criterion/inclusion.rb +1 -1
  17. data/lib/mongoid/criterion/optional.rb +0 -1
  18. data/lib/mongoid/criterion/unconvertable.rb +20 -0
  19. data/lib/mongoid/cursor.rb +3 -3
  20. data/lib/mongoid/dirty.rb +8 -8
  21. data/lib/mongoid/document.rb +33 -36
  22. data/lib/mongoid/extensions.rb +7 -0
  23. data/lib/mongoid/extensions/object/checks.rb +32 -0
  24. data/lib/mongoid/extensions/object/conversions.rb +1 -1
  25. data/lib/mongoid/extensions/object_id/conversions.rb +6 -1
  26. data/lib/mongoid/extensions/range/conversions.rb +25 -0
  27. data/lib/mongoid/factory.rb +27 -10
  28. data/lib/mongoid/field.rb +50 -0
  29. data/lib/mongoid/fields.rb +42 -7
  30. data/lib/mongoid/finders.rb +5 -17
  31. data/lib/mongoid/identity.rb +1 -1
  32. data/lib/mongoid/inspection.rb +17 -21
  33. data/lib/mongoid/matchers.rb +6 -2
  34. data/lib/mongoid/matchers/strategies.rb +2 -2
  35. data/lib/mongoid/named_scope.rb +1 -1
  36. data/lib/mongoid/observer.rb +45 -14
  37. data/lib/mongoid/paranoia.rb +2 -2
  38. data/lib/mongoid/persistence.rb +2 -2
  39. data/lib/mongoid/persistence/update.rb +2 -1
  40. data/lib/mongoid/railtie.rb +3 -5
  41. data/lib/mongoid/relations.rb +1 -0
  42. data/lib/mongoid/relations/builders.rb +3 -3
  43. data/lib/mongoid/relations/builders/embedded/in.rb +1 -1
  44. data/lib/mongoid/relations/builders/embedded/many.rb +1 -1
  45. data/lib/mongoid/relations/builders/embedded/one.rb +1 -2
  46. data/lib/mongoid/relations/builders/referenced/in.rb +0 -3
  47. data/lib/mongoid/relations/builders/referenced/many.rb +21 -1
  48. data/lib/mongoid/relations/builders/referenced/one.rb +0 -4
  49. data/lib/mongoid/relations/embedded/many.rb +1 -17
  50. data/lib/mongoid/relations/macros.rb +3 -2
  51. data/lib/mongoid/relations/many.rb +2 -0
  52. data/lib/mongoid/relations/proxy.rb +1 -1
  53. data/lib/mongoid/relations/referenced/batch.rb +71 -0
  54. data/lib/mongoid/relations/referenced/batch/insert.rb +57 -0
  55. data/lib/mongoid/relations/referenced/many.rb +61 -2
  56. data/lib/mongoid/serialization.rb +1 -1
  57. data/lib/mongoid/validations/uniqueness.rb +1 -1
  58. data/lib/mongoid/version.rb +1 -1
  59. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +8 -11
  60. metadata +22 -64
  61. data/lib/mongoid/contexts/paging.rb +0 -50
@@ -49,7 +49,7 @@ module Mongoid #:nodoc:
49
49
  # true
50
50
  def remove(options = {})
51
51
  now = Time.now
52
- collection.update({ :_id => self.id }, { '$set' => { :deleted_at => Time.now } })
52
+ collection.update({ :_id => id }, { '$set' => { :deleted_at => now } })
53
53
  @attributes["deleted_at"] = now
54
54
  true
55
55
  end
@@ -72,7 +72,7 @@ module Mongoid #:nodoc:
72
72
  #
73
73
  # <tt>document.restore</tt>
74
74
  def restore
75
- collection.update({ :_id => self.id }, { '$unset' => { :deleted_at => true } })
75
+ collection.update({ :_id => id }, { '$unset' => { :deleted_at => true } })
76
76
  @attributes.delete("deleted_at")
77
77
  end
78
78
 
@@ -57,7 +57,7 @@ module Mongoid #:nodoc:
57
57
  # @return [ TrueClass ] True.
58
58
  def remove(options = {})
59
59
  if Remove.new(self, options).persist
60
- raw_attributes.freeze
60
+ attributes.freeze
61
61
  self.destroyed = true
62
62
  cascade!
63
63
  end; true
@@ -102,7 +102,7 @@ module Mongoid #:nodoc:
102
102
  #
103
103
  # @since 2.0.0.rc.6
104
104
  def update_attribute(name, value)
105
- write_attribute(name, value) and save(:validate => false)
105
+ write_attribute(name, value) ? save(:validate => false) : true
106
106
  end
107
107
 
108
108
  # Update the document attributes in the datbase.
@@ -50,11 +50,12 @@ module Mongoid #:nodoc:
50
50
  child.move_changes
51
51
  child.new_record = false if child.new_record?
52
52
  end
53
+ true
53
54
  else
54
55
  return false
55
56
  end
56
57
  end
57
- end; true
58
+ end
58
59
  end
59
60
 
60
61
  protected
@@ -45,8 +45,9 @@ module Rails #:nodoc:
45
45
  #
46
46
  # @example mongoid.yml
47
47
  #
48
- # defaults: &defaults
48
+ # development:
49
49
  # host: localhost
50
+ # database: mongoid
50
51
  # slaves:
51
52
  # # - host: localhost
52
53
  # # port: 27018
@@ -56,9 +57,6 @@ module Rails #:nodoc:
56
57
  # parameterize_keys: false
57
58
  # persist_in_safe_mode: false
58
59
  #
59
- # development:
60
- # <<: *defaults
61
- # database: mongoid
62
60
  initializer "setup database" do
63
61
  config_file = Rails.root.join("config", "mongoid.yml")
64
62
  if config_file.file?
@@ -131,7 +129,7 @@ module Rails #:nodoc:
131
129
  config.after_initialize do
132
130
  ::Mongoid.instantiate_observers
133
131
 
134
- ActionDispatch::Callbacks.to_prepare(:mongoid_instantiate_observers) do
132
+ ActionDispatch::Callbacks.to_prepare do
135
133
  ::Mongoid.instantiate_observers
136
134
  end
137
135
  end
@@ -14,6 +14,7 @@ require "mongoid/relations/embedded/atomic"
14
14
  require "mongoid/relations/embedded/in"
15
15
  require "mongoid/relations/embedded/many"
16
16
  require "mongoid/relations/embedded/one"
17
+ require "mongoid/relations/referenced/batch"
17
18
  require "mongoid/relations/referenced/in"
18
19
  require "mongoid/relations/referenced/many"
19
20
  require "mongoid/relations/referenced/many_to_many"
@@ -45,11 +45,11 @@ module Mongoid # :nodoc:
45
45
  # @return [ Class ] The class being set up.
46
46
  #
47
47
  # @since 2.0.0.rc.1
48
- def builder(name)
48
+ def builder(name, metadata)
49
49
  tap do
50
50
  define_method("build_#{name}") do |*args|
51
- attributes = (args.any? ? args : []) + [{:binding => true}]
52
- send("#{name}=", *attributes)
51
+ document = Factory.build(metadata.klass, args.first || {})
52
+ send("#{name}=", document, :binding => true)
53
53
  end
54
54
  end
55
55
  end
@@ -16,7 +16,7 @@ module Mongoid # :nodoc:
16
16
  # @return [ Document ] A single document.
17
17
  def build(type = nil)
18
18
  return object unless object.is_a?(Hash)
19
- Mongoid::Factory.build(metadata.klass, object)
19
+ Mongoid::Factory.from_db(metadata.klass, object)
20
20
  end
21
21
  end
22
22
  end
@@ -21,7 +21,7 @@ module Mongoid # :nodoc:
21
21
  return object if object.first.is_a?(Document)
22
22
  object.inject([]) do |documents, attrs|
23
23
  documents.tap do |docs|
24
- docs << Mongoid::Factory.build(metadata.klass, attrs)
24
+ docs << Mongoid::Factory.from_db(metadata.klass, attrs)
25
25
  end
26
26
  end
27
27
  end
@@ -17,8 +17,7 @@ module Mongoid # :nodoc:
17
17
  # @return [ Document ] A single document.
18
18
  def build(type = nil)
19
19
  return object unless object.is_a?(Hash)
20
- object.delete(:binding)
21
- Mongoid::Factory.build(metadata.klass, object)
20
+ Mongoid::Factory.from_db(metadata.klass, object)
22
21
  end
23
22
  end
24
23
  end
@@ -16,9 +16,6 @@ module Mongoid # :nodoc:
16
16
  # @return [ Document ] A single document.
17
17
  def build(type = nil)
18
18
  return object unless query?
19
- if object.is_a?(Hash)
20
- return Mongoid::Factory.build(metadata.klass, object)
21
- end
22
19
  begin
23
20
  (type ? type.constantize : metadata.klass).find(object)
24
21
  rescue Errors::DocumentNotFound
@@ -18,7 +18,27 @@ module Mongoid # :nodoc:
18
18
  return object unless query?
19
19
  return [] if object.is_a?(Array)
20
20
  key = metadata.foreign_key
21
- metadata.klass.all(:conditions => { key => object })
21
+ metadata.klass.where(key => convertable(metadata, object))
22
+ end
23
+
24
+ private
25
+
26
+ # Get the value for the foreign key in convertable or unconvertable
27
+ # form.
28
+ #
29
+ # @example Get the value.
30
+ # builder.convertable
31
+ #
32
+ # @return [ String, Unconvertable, BSON::ObjectId ] The string or object id.
33
+ #
34
+ # @since 2.0.2
35
+ def convertable(metadata, object)
36
+ inverse = metadata.inverse_klass
37
+ if inverse.using_object_ids? || object.is_a?(BSON::ObjectId)
38
+ object
39
+ else
40
+ Mongoid::Criterion::Unconvertable.new(object)
41
+ end
22
42
  end
23
43
  end
24
44
  end
@@ -16,10 +16,6 @@ module Mongoid # :nodoc:
16
16
  # @return [ Document ] A single document.
17
17
  def build(type = nil)
18
18
  return object unless query?
19
- if object.is_a?(Hash)
20
- object.delete(:binding)
21
- return Mongoid::Factory.build(metadata.klass, object)
22
- end
23
19
  metadata.klass.first(
24
20
  :conditions => { metadata.foreign_key => object }
25
21
  )
@@ -232,22 +232,6 @@ module Mongoid # :nodoc:
232
232
  end
233
233
  end
234
234
 
235
- # Paginate the association. Will create a new criteria, set the documents
236
- # on it and execute in an enumerable context.
237
- #
238
- # @example Paginate the relation.
239
- # person.addresses.paginate(:page => 1, :per_page => 20)
240
- #
241
- # @param [ Hash ] options The pagination options.
242
- #
243
- # @option options [ Integer ] :page The page number.
244
- # @option options [ Integer ] :per_page The number on each page.
245
- #
246
- # @return [ WillPaginate::Collection ] The paginated documents.
247
- def paginate(options)
248
- criteria.paginate(options)
249
- end
250
-
251
235
  # Substitutes the supplied target documents for the existing documents
252
236
  # in the relation.
253
237
  #
@@ -370,7 +354,7 @@ module Mongoid # :nodoc:
370
354
  load!(:binding => true) and return super if target.respond_to?(name)
371
355
  klass = metadata.klass
372
356
  klass.send(:with_scope, criteria) do
373
- criteria.send(name, *args)
357
+ criteria.send(name, *args, &block)
374
358
  end
375
359
  end
376
360
 
@@ -104,7 +104,7 @@ module Mongoid # :nodoc:
104
104
  def embeds_one(name, options = {}, &block)
105
105
  characterize(name, Embedded::One, options, &block).tap do |meta|
106
106
  relate(name, meta)
107
- builder(name).creator(name)
107
+ builder(name, meta).creator(name)
108
108
  validates_relation(meta)
109
109
  end
110
110
  end
@@ -131,6 +131,7 @@ module Mongoid # :nodoc:
131
131
  characterize(name, Referenced::In, options, &block).tap do |meta|
132
132
  relate(name, meta)
133
133
  reference(meta)
134
+ autosave(meta)
134
135
  validates_relation(meta)
135
136
  end
136
137
  end
@@ -218,7 +219,7 @@ module Mongoid # :nodoc:
218
219
  characterize(name, Referenced::One, options, &block).tap do |meta|
219
220
  relate(name, meta)
220
221
  reference(meta)
221
- builder(name).creator(name).autosave(meta)
222
+ builder(name, meta).creator(name).autosave(meta)
222
223
  validates_relation(meta)
223
224
  end
224
225
  end
@@ -6,6 +6,8 @@ module Mongoid #:nodoc:
6
6
  # proxies.
7
7
  class Many < Proxy
8
8
 
9
+ delegate :avg, :max, :min, :sum, :to => :criteria
10
+
9
11
  # Appends a document or array of documents to the relation. Will set
10
12
  # the parent and update the index in the process.
11
13
  #
@@ -62,7 +62,7 @@ module Mongoid # :nodoc:
62
62
  #
63
63
  # @since 2.0.0.rc.1
64
64
  def instantiated(type = nil)
65
- type ? type.instantiate : metadata.klass.instantiate
65
+ type ? type.new : metadata.klass.new
66
66
  end
67
67
 
68
68
  # Determines if the target been loaded into memory or not.
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+ require "mongoid/relations/referenced/batch/insert"
3
+
4
+ module Mongoid #:nodoc:
5
+ module Relations #:nodoc:
6
+ module Referenced #:nodoc:
7
+
8
+ # This module provides the ability for single insert calls to be batch
9
+ # inserted.
10
+ module Batch
11
+
12
+ private
13
+
14
+ # Executes a number of save calls in a single batch. Mongoid will
15
+ # intercept all database inserts while in this block and combine them
16
+ # into a single database call. When the block concludes the batch
17
+ # insert will occur.
18
+ #
19
+ # Since the collection is accessed through the class it would not be
20
+ # thread safe to give it state so we access the atomic updater via the
21
+ # current thread.
22
+ #
23
+ # @note This operation is not safe when attemping to do illegal updates
24
+ # for different objects or collections, since the updator is not
25
+ # scoped on the thread. This is meant for Mongoid internal use only
26
+ # to keep existing design clean.
27
+ #
28
+ # @example Batch update multiple appends.
29
+ # batched do
30
+ # person.posts << [ post_one, post_two, post_three ]
31
+ # end
32
+ #
33
+ # @param [ Proc ] block The block to execute.
34
+ #
35
+ # @return [ Object ] The result of the operation.
36
+ #
37
+ # @since 2.0.2, batch-relational-insert
38
+ def batched(&block)
39
+ inserter = Thread.current[:mongoid_batch_insert] ||= Insert.new
40
+ count_executions(&block)
41
+ ensure
42
+ if @executions.zero?
43
+ Thread.current[:mongoid_batch_insert] = nil
44
+ raise_mixed if embedded?
45
+ inserter.execute(collection)
46
+ end
47
+ end
48
+
49
+ # Execute the block, incrementing the executions before the call and
50
+ # decrementing them after in order to be able to nest blocks within
51
+ # each other.
52
+ #
53
+ # @todo Durran: Combine common code with embedded atomics.
54
+ #
55
+ # @example Execute and increment.
56
+ # execute { block.call }
57
+ #
58
+ # @param [ Proc ] block The block to call.
59
+ #
60
+ # @since 2.0.2, batch-relational-insert
61
+ def count_executions
62
+ @executions ||= 0
63
+ @executions += 1
64
+ yield
65
+ ensure
66
+ @executions -=1
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Relations #:nodoc:
4
+ module Referenced #:nodoc:
5
+ module Batch #:nodoc:
6
+
7
+ # Handles all the batch insert collection.
8
+ class Insert
9
+ attr_accessor :documents, :options
10
+
11
+ # Consumes an execution that was supposed to hit the database, but is
12
+ # now being deferred to later in favor of a single batch insert.
13
+ #
14
+ # @example Consume the operation.
15
+ # set.consume({ "field" => "value" }, { :safe => true })
16
+ #
17
+ # @param [ Hash ] document The document to collect.
18
+ # @param [ Hash ] options The persistence options.
19
+ #
20
+ # @option options [ true, false ] :safe Persist in safe mode.
21
+ #
22
+ # @since 2.0.2, batch-relational-insert
23
+ def consume(document, options = {})
24
+ @consumed, @options = true, options
25
+ (@documents ||= []).push(document)
26
+ end
27
+
28
+ # Has this operation consumed any executions?
29
+ #
30
+ # @example Is this consumed?
31
+ # insert.consumed?
32
+ #
33
+ # @return [ true, false ] If the operation has consumed anything.
34
+ #
35
+ # @since 2.0.2, batch-relational-insert
36
+ def consumed?
37
+ !!@consumed
38
+ end
39
+
40
+ # Execute the batch insert operation on the collection.
41
+ #
42
+ # @example Execute the operation.
43
+ # insert.execute(collection)
44
+ #
45
+ # @param [ Collection ] collection The root collection.
46
+ #
47
+ # @since 2.0.2, batch-relational-insert
48
+ def execute(collection)
49
+ if collection && consumed?
50
+ collection.insert(documents, options)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -6,6 +6,33 @@ module Mongoid #:nodoc:
6
6
  # This class defines the behaviour for all relations that are a
7
7
  # one-to-many between documents in different collections.
8
8
  class Many < Relations::Many
9
+ include Batch
10
+
11
+ # Appends a document or array of documents to the relation. Will set
12
+ # the parent and update the index in the process.
13
+ #
14
+ # @example Append a document.
15
+ # person.posts << post
16
+ #
17
+ # @example Push a document.
18
+ # person.posts.push(post)
19
+ #
20
+ # @example Concat with other documents.
21
+ # person.posts.concat([ post_one, post_two ])
22
+ #
23
+ # @param [ Document, Array<Document> ] *args Any number of documents.
24
+ def <<(*args)
25
+ options = default_options(args)
26
+ batched do
27
+ args.flatten.each do |doc|
28
+ return doc unless doc
29
+ append(doc, options)
30
+ doc.save if base.persisted? && !options[:binding]
31
+ end
32
+ end
33
+ end
34
+ alias :concat :<<
35
+ alias :push :<<
9
36
 
10
37
  # Binds the base object to the inverse of the relation. This is so we
11
38
  # are referenced to the actual objects themselves and dont hit the
@@ -286,6 +313,38 @@ module Mongoid #:nodoc:
286
313
  Bindings::Referenced::Many.new(base, new_target || target, metadata)
287
314
  end
288
315
 
316
+ # Get the collection of the relation in question.
317
+ #
318
+ # @example Get the collection of the relation.
319
+ # relation.collection
320
+ #
321
+ # @return [ Collection ] The collection of the relation.
322
+ #
323
+ # @since 2.0.2, batch-relational-insert
324
+ def collection
325
+ metadata.klass.collection
326
+ end
327
+
328
+ # Get the value for the foreign key in convertable or unconvertable
329
+ # form.
330
+ #
331
+ # @todo Durran: Find a common place for this.
332
+ #
333
+ # @example Get the value.
334
+ # relation.convertable
335
+ #
336
+ # @return [ String, Unconvertable, BSON::ObjectId ] The string or object id.
337
+ #
338
+ # @since 2.0.2
339
+ def convertable
340
+ inverse = metadata.inverse_klass
341
+ if inverse.using_object_ids? || base.id.is_a?(BSON::ObjectId)
342
+ base.id
343
+ else
344
+ Mongoid::Criterion::Unconvertable.new(base.id)
345
+ end
346
+ end
347
+
289
348
  # Returns the criteria object for the target class with its documents set
290
349
  # to target.
291
350
  #
@@ -295,7 +354,7 @@ module Mongoid #:nodoc:
295
354
  # @return [ Criteria ] A new criteria.
296
355
  def criteria
297
356
  raise_mixed if klass.embedded?
298
- metadata.klass.where(metadata.foreign_key => base.id)
357
+ metadata.klass.where(metadata.foreign_key => convertable)
299
358
  end
300
359
 
301
360
  # Tells if the target array been initialized.
@@ -341,7 +400,7 @@ module Mongoid #:nodoc:
341
400
  load!(:binding => true) and return super if [].respond_to?(name)
342
401
  klass = metadata.klass
343
402
  klass.send(:with_scope, criteria) do
344
- criteria.send(name, *args)
403
+ criteria.send(name, *args, &block)
345
404
  end
346
405
  end
347
406