mongoid 2.0.1 → 2.0.2

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