mongoid 2.0.0.rc.7 → 2.0.0.rc.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/lib/config/locales/en.yml +3 -0
  2. data/lib/config/locales/id.yml +46 -0
  3. data/lib/config/locales/ja.yml +40 -0
  4. data/lib/config/locales/vi.yml +45 -0
  5. data/lib/mongoid.rb +5 -3
  6. data/lib/mongoid/attributes.rb +24 -63
  7. data/lib/mongoid/attributes/processing.rb +5 -2
  8. data/lib/mongoid/callbacks.rb +10 -0
  9. data/lib/mongoid/collection.rb +24 -0
  10. data/lib/mongoid/collections/master.rb +14 -6
  11. data/lib/mongoid/collections/operations.rb +1 -1
  12. data/lib/mongoid/collections/retry.rb +39 -0
  13. data/lib/mongoid/collections/slaves.rb +26 -10
  14. data/lib/mongoid/components.rb +4 -4
  15. data/lib/mongoid/config.rb +6 -3
  16. data/lib/mongoid/contexts.rb +0 -1
  17. data/lib/mongoid/contexts/enumerable.rb +19 -7
  18. data/lib/mongoid/contexts/mongo.rb +9 -5
  19. data/lib/mongoid/copyable.rb +10 -8
  20. data/lib/mongoid/criteria.rb +83 -61
  21. data/lib/mongoid/criterion/builder.rb +34 -0
  22. data/lib/mongoid/criterion/creational.rb +2 -2
  23. data/lib/mongoid/criterion/exclusion.rb +58 -32
  24. data/lib/mongoid/criterion/inclusion.rb +49 -10
  25. data/lib/mongoid/criterion/optional.rb +1 -1
  26. data/lib/mongoid/criterion/selector.rb +80 -11
  27. data/lib/mongoid/cursor.rb +6 -1
  28. data/lib/mongoid/default_scope.rb +27 -19
  29. data/lib/mongoid/document.rb +26 -1
  30. data/lib/mongoid/errors.rb +1 -0
  31. data/lib/mongoid/errors/mixed_relations.rb +37 -0
  32. data/lib/mongoid/extensions/object_id/conversions.rb +7 -4
  33. data/lib/mongoid/factory.rb +1 -1
  34. data/lib/mongoid/field.rb +47 -30
  35. data/lib/mongoid/fields.rb +9 -2
  36. data/lib/mongoid/finders.rb +15 -49
  37. data/lib/mongoid/identity.rb +6 -4
  38. data/lib/mongoid/keys.rb +85 -31
  39. data/lib/mongoid/multi_parameter_attributes.rb +2 -2
  40. data/lib/mongoid/named_scope.rb +129 -28
  41. data/lib/mongoid/observer.rb +36 -0
  42. data/lib/mongoid/paranoia.rb +3 -3
  43. data/lib/mongoid/paths.rb +1 -1
  44. data/lib/mongoid/persistence.rb +2 -0
  45. data/lib/mongoid/persistence/atomic.rb +88 -0
  46. data/lib/mongoid/persistence/atomic/add_to_set.rb +30 -0
  47. data/lib/mongoid/persistence/atomic/inc.rb +28 -0
  48. data/lib/mongoid/persistence/atomic/operation.rb +44 -0
  49. data/lib/mongoid/persistence/atomic/pull_all.rb +33 -0
  50. data/lib/mongoid/persistence/atomic/push.rb +28 -0
  51. data/lib/mongoid/railtie.rb +13 -1
  52. data/lib/mongoid/relations.rb +1 -0
  53. data/lib/mongoid/relations/accessors.rb +20 -2
  54. data/lib/mongoid/relations/builders/embedded/one.rb +1 -0
  55. data/lib/mongoid/relations/builders/nested_attributes/many.rb +17 -6
  56. data/lib/mongoid/relations/builders/referenced/many.rb +2 -1
  57. data/lib/mongoid/relations/builders/referenced/one.rb +1 -0
  58. data/lib/mongoid/relations/embedded/atomic.rb +86 -0
  59. data/lib/mongoid/relations/embedded/atomic/operation.rb +63 -0
  60. data/lib/mongoid/relations/embedded/atomic/pull.rb +65 -0
  61. data/lib/mongoid/relations/embedded/atomic/push_all.rb +59 -0
  62. data/lib/mongoid/relations/embedded/atomic/set.rb +61 -0
  63. data/lib/mongoid/relations/embedded/atomic/unset.rb +41 -0
  64. data/lib/mongoid/relations/embedded/many.rb +57 -25
  65. data/lib/mongoid/relations/macros.rb +6 -4
  66. data/lib/mongoid/relations/many.rb +51 -10
  67. data/lib/mongoid/relations/metadata.rb +4 -2
  68. data/lib/mongoid/relations/proxy.rb +39 -24
  69. data/lib/mongoid/relations/referenced/many.rb +47 -26
  70. data/lib/mongoid/relations/referenced/many_to_many.rb +47 -14
  71. data/lib/mongoid/relations/referenced/one.rb +14 -0
  72. data/lib/mongoid/sharding.rb +51 -0
  73. data/lib/mongoid/state.rb +3 -2
  74. data/lib/mongoid/timestamps.rb +5 -29
  75. data/lib/mongoid/timestamps/created.rb +31 -0
  76. data/lib/mongoid/timestamps/updated.rb +33 -0
  77. data/lib/mongoid/validations.rb +10 -3
  78. data/lib/mongoid/validations/referenced.rb +58 -0
  79. data/lib/mongoid/version.rb +1 -1
  80. data/lib/mongoid/versioning.rb +67 -5
  81. data/lib/rails/generators/mongoid/model/templates/model.rb +2 -0
  82. data/lib/rails/generators/mongoid/observer/observer_generator.rb +17 -0
  83. data/lib/rails/generators/mongoid/observer/templates/observer.rb +4 -0
  84. data/lib/rails/generators/mongoid_generator.rb +10 -1
  85. data/lib/rails/mongoid.rb +1 -0
  86. metadata +29 -8
  87. data/lib/mongoid/contexts/ids.rb +0 -25
  88. data/lib/mongoid/modifiers.rb +0 -24
  89. data/lib/mongoid/modifiers/command.rb +0 -18
  90. data/lib/mongoid/modifiers/inc.rb +0 -24
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Relations #:nodoc:
4
+ module Embedded #:nodoc:
5
+ module Atomic #:nodoc:
6
+
7
+ class Pull < Operation
8
+
9
+ # Get the merged operations for the single atomic set.
10
+ #
11
+ # @example Get the operations
12
+ # set.operations
13
+ #
14
+ # @return [ Hash ] The pull operations.
15
+ #
16
+ # @since 2.0.0
17
+ def operations
18
+ { "$pull" =>
19
+ { path =>
20
+ { "_id" =>
21
+ { "$in" => documents.map { |doc| doc["_id"] } }
22
+ }
23
+ }
24
+ }
25
+ end
26
+
27
+ private
28
+
29
+ # Parses the incoming operations to get the documents to set.
30
+ #
31
+ # @example Parse the operations.
32
+ # set.parse(
33
+ # { "$pull" => { "addresses" => { "_id" => "street" } } }
34
+ # )
35
+ #
36
+ # @param [ Hash ] operations The ops to parse.
37
+ #
38
+ # @since 2.0.0
39
+ def parse(operations)
40
+ modifier = operations.keys.first
41
+ extract(modifier, operations[modifier])
42
+ end
43
+
44
+ # Extract a document from the operation.
45
+ #
46
+ # @example Extract the document.
47
+ # set.extract({ "$pull" => [{ "_id" => "street" }] })
48
+ #
49
+ # @param [ Hash ] operation The op to extract from.
50
+ #
51
+ # @since 2.0.0
52
+ def extract(modifier, operations)
53
+ @path = operations.keys.first
54
+ case modifier
55
+ when "$pull"
56
+ documents.push(operations[path])
57
+ when "$pullAll"
58
+ documents.concat(operations[path])
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Relations #:nodoc:
4
+ module Embedded #:nodoc:
5
+ module Atomic #:nodoc:
6
+
7
+ class PushAll < Operation
8
+
9
+ # Get the merged operations for the single atomic set.
10
+ #
11
+ # @example Get the operations
12
+ # set.operations
13
+ #
14
+ # @return [ Hash ] The set operations.
15
+ #
16
+ # @since 2.0.0
17
+ def operations
18
+ { "$pushAll" => { path => documents } }
19
+ end
20
+
21
+ private
22
+
23
+ # Parses the incoming operations to get the documents to set.
24
+ #
25
+ # @example Parse the operations.
26
+ # set.parse(
27
+ # { "$push" => { "addresses" => { "_id" => "street" } } }
28
+ # )
29
+ #
30
+ # @param [ Hash ] operations The ops to parse.
31
+ #
32
+ # @since 2.0.0
33
+ def parse(operations)
34
+ modifier = operations.keys.first
35
+ extract(modifier, operations[modifier])
36
+ end
37
+
38
+ # Extract a document from the operation.
39
+ #
40
+ # @example Extract the document.
41
+ # set.extract({ "$pushAll" => [{ "_id" => "street" }] })
42
+ #
43
+ # @param [ Hash ] operation The op to extract from.
44
+ #
45
+ # @since 2.0.0
46
+ def extract(modifier, operations)
47
+ @path = operations.keys.first
48
+ case modifier
49
+ when "$push"
50
+ documents.push(operations[path])
51
+ when "$pushAll"
52
+ documents.concat(operations[path])
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Relations #:nodoc:
4
+ module Embedded #:nodoc:
5
+ module Atomic #:nodoc:
6
+
7
+ class Set < Operation
8
+
9
+ # Get the merged operations for the single atomic set.
10
+ #
11
+ # @example Get the operations
12
+ # set.operations
13
+ #
14
+ # @return [ Hash ] The set operations.
15
+ #
16
+ # @since 2.0.0
17
+ def operations
18
+ { "$set" => { path => documents } }
19
+ end
20
+
21
+ private
22
+
23
+ # Parses the incoming operations to get the documents to set.
24
+ #
25
+ # @example Parse the operations.
26
+ # set.parse(
27
+ # { "addresses" => { "$pushAll" => [{ "_id" => "street" }] } }
28
+ # )
29
+ #
30
+ # @param [ Hash ] operations The ops to parse.
31
+ #
32
+ # @since 2.0.0
33
+ def parse(operations)
34
+ modifier = operations.keys.first
35
+ extract(modifier, operations[modifier])
36
+ end
37
+
38
+ # Extract a document from the operation.
39
+ #
40
+ # @example Extract the document.
41
+ # set.extract({ "$pushAll" => [{ "_id" => "street" }] })
42
+ #
43
+ # @param [ Hash ] operation The op to extract from.
44
+ #
45
+ # @since 2.0.0
46
+ def extract(modifier, operations)
47
+ @path = operations.keys.first
48
+ case modifier
49
+ when "$push"
50
+ documents.push(operations[path])
51
+ when "$pushAll"
52
+ documents.push(operations[path].first)
53
+ when "$set"
54
+ @documents = operations[path]
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Relations #:nodoc:
4
+ module Embedded #:nodoc:
5
+ module Atomic #:nodoc:
6
+
7
+ class Unset < Operation
8
+
9
+ # Get the merged operations for the single atomic set.
10
+ #
11
+ # @example Get the operations
12
+ # set.operations
13
+ #
14
+ # @return [ Hash ] The set operations.
15
+ #
16
+ # @since 2.0.0
17
+ def operations
18
+ { "$unset" => { path => true } }
19
+ end
20
+
21
+ private
22
+
23
+ # Parses the incoming operations to get the documents to set.
24
+ #
25
+ # @example Parse the operations.
26
+ # set.parse(
27
+ # { "addresses" => { "$pushAll" => [{ "_id" => "street" }] } }
28
+ # )
29
+ #
30
+ # @param [ Hash ] operations The ops to parse.
31
+ #
32
+ # @since 2.0.0
33
+ def parse(operations)
34
+ modifier = operations.keys.first
35
+ @path ||= operations[modifier].keys.first
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -6,6 +6,31 @@ module Mongoid # :nodoc:
6
6
  # This class handles the behaviour for a document that embeds many other
7
7
  # documents within in it as an array.
8
8
  class Many < Relations::Many
9
+ include Atomic
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.addresses << address
16
+ #
17
+ # @example Push a document.
18
+ # person.addresses.push(address)
19
+ #
20
+ # @example Concat with other documents.
21
+ # person.addresses.concat([ address_one, address_two ])
22
+ #
23
+ # @param [ Document, Array<Document> ] *args Any number of documents.
24
+ def <<(*args)
25
+ options = default_options(args)
26
+ atomically(:$pushAll) 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
9
34
 
10
35
  # Binds the base object to the inverse of the relation. This is so we
11
36
  # are referenced to the actual objects themselves and dont hit the
@@ -26,7 +51,9 @@ module Mongoid # :nodoc:
26
51
  # @since 2.0.0.rc.1
27
52
  def bind(options = {})
28
53
  binding.bind(options)
29
- target.each(&:save) if base.persisted? && !options[:binding]
54
+ if base.persisted? && !options[:binding]
55
+ atomically(:$set) { target.each(&:save) }
56
+ end
30
57
  end
31
58
 
32
59
  # Bind the inverse relation between a single document in this proxy
@@ -80,8 +107,8 @@ module Mongoid # :nodoc:
80
107
  # @param [ Class ] type Optional class to create the document with.
81
108
  #
82
109
  # @return [ Document ] The newly created document.
83
- def create(attributes = {}, type = nil)
84
- build(attributes, type).tap(&:save)
110
+ def create(attributes = {}, type = nil, &block)
111
+ build(attributes, type, &block).tap(&:save)
85
112
  end
86
113
 
87
114
  # Create a new document in the relation. This is essentially the same
@@ -97,15 +124,15 @@ module Mongoid # :nodoc:
97
124
  # @raise [ Errors::Validations ] If a validation error occured.
98
125
  #
99
126
  # @return [ Document ] The newly created document.
100
- def create!(attributes = {}, type = nil)
101
- build(attributes, type).tap(&:save!)
127
+ def create!(attributes = {}, type = nil, &block)
128
+ build(attributes, type, &block).tap(&:save!)
102
129
  end
103
130
 
104
131
  # Delete the supplied document from the target. This method is proxied
105
132
  # in order to reindex the array after the operation occurs.
106
133
  #
107
134
  # @example Delete the document from the relation.
108
- # perosn.addresses.delete(address)
135
+ # person.addresses.delete(address)
109
136
  #
110
137
  # @param [ Document ] document The document to be deleted.
111
138
  #
@@ -128,7 +155,7 @@ module Mongoid # :nodoc:
128
155
  #
129
156
  # @return [ Integer ] The number of documents deleted.
130
157
  def delete_all(conditions = {})
131
- remove_all(conditions, false)
158
+ atomically(:$pull) { remove_all(conditions, :delete) }
132
159
  end
133
160
 
134
161
  # Destroy all the documents in the association whilst running callbacks.
@@ -143,7 +170,7 @@ module Mongoid # :nodoc:
143
170
  #
144
171
  # @return [ Integer ] The number of documents destroyed.
145
172
  def destroy_all(conditions = {})
146
- remove_all(conditions, true)
173
+ atomically(:$pull) { remove_all(conditions, :destroy) }
147
174
  end
148
175
 
149
176
  # Finds a document in this association through several different
@@ -164,15 +191,7 @@ module Mongoid # :nodoc:
164
191
  #
165
192
  # @return [ Array<Document>, Document ] A single or multiple documents.
166
193
  def find(*args)
167
- type, criteria = Criteria.parse!(self, true, *args)
168
- case type
169
- when :first then return criteria.one
170
- when :last then return criteria.last
171
- else
172
- criteria.tap do |crit|
173
- crit.documents = target if crit.is_a?(Criteria)
174
- end
175
- end
194
+ criteria.find(*args)
176
195
  end
177
196
 
178
197
  # Instantiate a new embeds_many relation.
@@ -226,8 +245,6 @@ module Mongoid # :nodoc:
226
245
  #
227
246
  # @return [ WillPaginate::Collection ] The paginated documents.
228
247
  def paginate(options)
229
- criteria = Mongoid::Criteria.translate(metadata.klass, true, options)
230
- criteria.documents = target
231
248
  criteria.paginate(options)
232
249
  end
233
250
 
@@ -248,10 +265,9 @@ module Mongoid # :nodoc:
248
265
  tap do |relation|
249
266
  relation.target = new_target || []
250
267
  if !new_target.blank?
251
- unbind(old_target, options)
252
- bind(options)
268
+ atomically(:$set) { rebind(old_target, options) }
253
269
  else
254
- unbind(old_target, options)
270
+ atomically(:$unset) { unbind(old_target, options) }
255
271
  end
256
272
  end
257
273
  end
@@ -382,17 +398,33 @@ module Mongoid # :nodoc:
382
398
  # @param [ true, false ] destroy If true then destroy, else delete.
383
399
  #
384
400
  # @return [ Integer ] The number of documents removed.
385
- def remove_all(conditions = {}, destroy = false)
386
- criteria = find(conditions || {})
401
+ def remove_all(conditions = {}, method = :delete)
402
+ criteria = find(:all, conditions || {})
387
403
  criteria.size.tap do
388
404
  criteria.each do |doc|
389
405
  target.delete(doc)
390
- destroy ? doc.destroy : doc.delete
406
+ doc.send(method)
391
407
  end
392
408
  reindex
393
409
  end
394
410
  end
395
411
 
412
+ # Convenience method to clean up the substitute code. Unbinds the old
413
+ # target and reindexes.
414
+ #
415
+ # @example Rebind the relation.
416
+ # relation.rebind([])
417
+ #
418
+ # @param [ Array<Document> ] old_target The old target.
419
+ # @param [ Hash ] options The options passed to substitute.
420
+ #
421
+ # @since 2.0.0
422
+ def rebind(old_target, options)
423
+ reindex
424
+ unbind(old_target, options)
425
+ bind(options)
426
+ end
427
+
396
428
  class << self
397
429
 
398
430
  # Return the builder that is responsible for generating the documents
@@ -78,7 +78,7 @@ module Mongoid # :nodoc:
78
78
  def embeds_many(name, options = {}, &block)
79
79
  characterize(name, Embedded::Many, options, &block).tap do |meta|
80
80
  relate(name, meta)
81
- validate_relation(meta)
81
+ validates_relation(meta)
82
82
  end
83
83
  end
84
84
 
@@ -105,7 +105,7 @@ module Mongoid # :nodoc:
105
105
  characterize(name, Embedded::One, options, &block).tap do |meta|
106
106
  relate(name, meta)
107
107
  builder(name).creator(name)
108
- validate_relation(meta)
108
+ validates_relation(meta)
109
109
  end
110
110
  end
111
111
 
@@ -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
+ validates_relation(meta)
134
135
  end
135
136
  end
136
137
  alias :belongs_to_related :referenced_in
@@ -160,7 +161,7 @@ module Mongoid # :nodoc:
160
161
  relate(name, meta)
161
162
  reference(meta)
162
163
  autosave(meta)
163
- validate_relation(meta)
164
+ validates_relation(meta)
164
165
  end
165
166
  end
166
167
  alias :has_many_related :references_many
@@ -190,6 +191,7 @@ module Mongoid # :nodoc:
190
191
  characterize(name, Referenced::ManyToMany, options, &block).tap do |meta|
191
192
  relate(name, meta)
192
193
  reference(meta)
194
+ validates_relation(meta)
193
195
  end
194
196
  end
195
197
  alias :has_and_belongs_to_many :references_and_referenced_in_many
@@ -217,7 +219,7 @@ module Mongoid # :nodoc:
217
219
  relate(name, meta)
218
220
  reference(meta)
219
221
  builder(name).creator(name).autosave(meta)
220
- validate_relation(meta)
222
+ validates_relation(meta)
221
223
  end
222
224
  end
223
225
  alias :has_one_related :references_one
@@ -16,7 +16,7 @@ module Mongoid #:nodoc:
16
16
  # person.addresses.push(address)
17
17
  #
18
18
  # @example Concat with other documents.
19
- # perosn.addresses.concat([ address_one, address_two ])
19
+ # person.addresses.concat([ address_one, address_two ])
20
20
  #
21
21
  # @param [ Document, Array<Document> ] *args Any number of documents.
22
22
  def <<(*args)
@@ -40,11 +40,12 @@ module Mongoid #:nodoc:
40
40
  # @param [ Class ] type Optional class to build the document with.
41
41
  #
42
42
  # @return [ Document ] The new document.
43
- def build(attributes = {}, type = nil)
43
+ def build(attributes = {}, type = nil, &block)
44
44
  instantiated(type).tap do |doc|
45
- append(doc, default_options(:binding => true))
46
45
  doc.write_attributes(attributes)
47
46
  doc.identify
47
+ append(doc, default_options(:binding => true))
48
+ block.call(doc) if block
48
49
  end
49
50
  end
50
51
  alias :new :build
@@ -59,8 +60,9 @@ module Mongoid #:nodoc:
59
60
  # @param [ Class ] type The optional type of document to create.
60
61
  #
61
62
  # @return [ Document ] The newly created document.
62
- def create(attributes = nil, type = nil)
63
+ def create(attributes = nil, type = nil, &block)
63
64
  build(attributes, type).tap do |doc|
65
+ block.call(doc) if block
64
66
  doc.save if base.persisted?
65
67
  end
66
68
  end
@@ -103,8 +105,8 @@ module Mongoid #:nodoc:
103
105
  # @param [ Hash ] attrs The attributes to search or create with.
104
106
  #
105
107
  # @return [ Document ] An existing document or newly created one.
106
- def find_or_create_by(attrs = {})
107
- find_or(:create, attrs)
108
+ def find_or_create_by(attrs = {}, &block)
109
+ find_or(:create, attrs, &block)
108
110
  end
109
111
 
110
112
  # Find the first +Document+ given the conditions, or instantiates a new document
@@ -116,8 +118,34 @@ module Mongoid #:nodoc:
116
118
  # @param [ Hash ] attrs The attributes to search or initialize with.
117
119
  #
118
120
  # @return [ Document ] An existing document or newly instantiated one.
119
- def find_or_initialize_by(attrs = {})
120
- find_or(:build, attrs)
121
+ def find_or_initialize_by(attrs = {}, &block)
122
+ find_or(:build, attrs, &block)
123
+ end
124
+
125
+ # This proxy can never be nil.
126
+ #
127
+ # @example Is the proxy nil?
128
+ # relation.nil?
129
+ #
130
+ # @return [ false ] Always false.
131
+ #
132
+ # @since 2.0.0
133
+ def nil?
134
+ false
135
+ end
136
+
137
+ # Since method_missing is overridden we should override this as well.
138
+ #
139
+ # @example Does the proxy respond to the method?
140
+ # relation.respond_to?(:name)
141
+ #
142
+ # @param [ Symbol ] name The method name.
143
+ #
144
+ # @return [ true, false ] If the proxy responds to the method.
145
+ #
146
+ # @since 2.0.0
147
+ def respond_to?(name)
148
+ [].respond_to?(name) || methods.include?(name)
121
149
  end
122
150
 
123
151
  # Gets the document as a serializable hash, used by ActiveModel's JSON and
@@ -140,6 +168,19 @@ module Mongoid #:nodoc:
140
168
  target.map { |document| document.serializable_hash(options) }
141
169
  end
142
170
 
171
+ # Always returns the number of documents that are in memory.
172
+ #
173
+ # @example Get the number of loaded documents.
174
+ # relation.size
175
+ #
176
+ # @return [ Integer ] The number of documents in memory.
177
+ #
178
+ # @since 2.0.0
179
+ def size
180
+ target.size
181
+ end
182
+ alias :length :size
183
+
143
184
  private
144
185
 
145
186
  # Get the default options used in binding functions.
@@ -164,8 +205,8 @@ module Mongoid #:nodoc:
164
205
  # @param [ Hash ] attrs The attributes to build with.
165
206
  #
166
207
  # @return [ Document ] A matching document or a new/created one.
167
- def find_or(method, attrs = {})
168
- find(:first, :conditions => attrs) || send(method, attrs)
208
+ def find_or(method, attrs = {}, &block)
209
+ find(:first, :conditions => attrs) || send(method, attrs, &block)
169
210
  end
170
211
  end
171
212
  end