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
@@ -2,7 +2,6 @@
2
2
  module Mongoid #:nodoc:
3
3
  module Contexts #:nodoc:
4
4
  class Mongo
5
- include Paging
6
5
  attr_accessor :criteria
7
6
 
8
7
  delegate :klass, :options, :field_list, :selector, :to => :criteria
@@ -122,14 +121,8 @@ module Mongoid #:nodoc:
122
121
  # Returns:
123
122
  #
124
123
  # An enumerable +Cursor+.
125
- def execute(paginating = false)
126
- cursor = klass.collection.find(selector, process_options)
127
- if cursor
128
- @count = cursor.count if paginating
129
- cursor
130
- else
131
- []
132
- end
124
+ def execute
125
+ klass.collection.find(selector, process_options) || []
133
126
  end
134
127
 
135
128
  # Groups the context. This will take the internally built selector and options
@@ -152,7 +145,7 @@ module Mongoid #:nodoc:
152
145
  :reduce => Javascript.group
153
146
  ).collect do |docs|
154
147
  docs["group"] = docs["group"].collect do |attrs|
155
- Mongoid::Factory.build(klass, attrs)
148
+ Mongoid::Factory.from_db(klass, attrs)
156
149
  end
157
150
  docs
158
151
  end
@@ -203,7 +196,7 @@ module Mongoid #:nodoc:
203
196
  sorting = [[:_id, :asc]] unless sorting
204
197
  opts[:sort] = sorting.collect { |option| [ option[0], option[1].invert ] }
205
198
  attributes = klass.collection.find_one(selector, opts)
206
- attributes ? Mongoid::Factory.build(klass, attributes) : nil
199
+ attributes ? Mongoid::Factory.from_db(klass, attributes) : nil
207
200
  end
208
201
 
209
202
  # Return the max value for a field.
@@ -253,7 +246,7 @@ module Mongoid #:nodoc:
253
246
  # The first document in the collection.
254
247
  def one
255
248
  attributes = klass.collection.find_one(selector, process_options)
256
- attributes ? Mongoid::Factory.build(klass, attributes) : nil
249
+ attributes ? Mongoid::Factory.from_db(klass, attributes) : nil
257
250
  end
258
251
 
259
252
  alias :first :one
@@ -37,8 +37,8 @@ module Mongoid #:nodoc:
37
37
  value = other.instance_variable_get(name)
38
38
  instance_variable_set(name, value ? value.dup : nil)
39
39
  end
40
- @attributes.delete("_id")
41
- @attributes.delete("versions")
40
+ attributes.delete("_id")
41
+ attributes.delete("versions")
42
42
  @new_record = true
43
43
  identify
44
44
  end
@@ -7,6 +7,7 @@ require "mongoid/criterion/inclusion"
7
7
  require "mongoid/criterion/inspection"
8
8
  require "mongoid/criterion/optional"
9
9
  require "mongoid/criterion/selector"
10
+ require "mongoid/criterion/unconvertable"
10
11
 
11
12
  module Mongoid #:nodoc:
12
13
 
@@ -61,9 +62,6 @@ module Mongoid #:nodoc:
61
62
  :max,
62
63
  :min,
63
64
  :one,
64
- :page,
65
- :paginate,
66
- :per_page,
67
65
  :shift,
68
66
  :sum,
69
67
  :update,
@@ -202,12 +200,13 @@ module Mongoid #:nodoc:
202
200
  #
203
201
  # name: The name of the class method on the +Document+ to chain.
204
202
  # args: The arguments passed to the method.
203
+ # block: Optional block to pass
205
204
  #
206
205
  # Returns: <tt>Criteria</tt>
207
- def method_missing(name, *args)
206
+ def method_missing(name, *args, &block)
208
207
  if @klass.respond_to?(name)
209
208
  @klass.send(:with_scope, self) do
210
- @klass.send(name, *args)
209
+ @klass.send(name, *args, &block)
211
210
  end
212
211
  else
213
212
  return entries.send(name, *args)
@@ -308,24 +307,6 @@ module Mongoid #:nodoc:
308
307
  other.is_a?(Criteria) ? other.entries : other
309
308
  end
310
309
 
311
- # Filters the unused options out of the options +Hash+. Currently this
312
- # takes into account the "page" and "per_page" options that would be passed
313
- # in if using will_paginate.
314
- #
315
- # Example:
316
- #
317
- # Given a criteria with a selector of { :page => 1, :per_page => 40 }
318
- #
319
- # <tt>criteria.filter_options</tt> # selector: { :skip => 0, :limit => 40 }
320
- def filter_options
321
- page_num = @options.delete(:page)
322
- per_page_num = @options.delete(:per_page)
323
- if (page_num || per_page_num)
324
- @options[:limit] = limits = (per_page_num || 20).to_i
325
- @options[:skip] = (page_num || 1).to_i * limits - limits
326
- end
327
- end
328
-
329
310
  # Clone or dup the current +Criteria+. This will return a new criteria with
330
311
  # the selector, options, klass, embedded options, etc intact.
331
312
  #
@@ -24,6 +24,21 @@ module Mongoid #:nodoc:
24
24
  update_selector(attributes, "$ne")
25
25
  end
26
26
 
27
+ # Used when wanting to set the fields options directly using a hash
28
+ # instead of going through only or without.
29
+ #
30
+ # @example Set the limited fields.
31
+ # criteria.fields(:field => 1)
32
+ #
33
+ # @param [ Hash ] attributes The field options.
34
+ #
35
+ # @return [ Criteria ] A newly cloned copy.
36
+ #
37
+ # @since 2.0.2
38
+ def fields(attributes = nil)
39
+ clone.tap { |crit| crit.options[:fields] = attributes || {} }
40
+ end
41
+
27
42
  # Adds a criterion to the +Criteria+ that specifies values where none
28
43
  # should match in order to return results. This is similar to an SQL
29
44
  # "NOT IN" clause. The MongoDB conditional operator that will be
@@ -189,7 +189,7 @@ module Mongoid #:nodoc:
189
189
  def execute_or_raise(args, criteria)
190
190
  (args[0].is_a?(Array) ? criteria.entries : criteria.one).tap do |result|
191
191
  if Mongoid.raise_not_found_error && !args.flatten.blank?
192
- raise Errors::DocumentNotFound.new(klass, args) if result.blank?
192
+ raise Errors::DocumentNotFound.new(klass, args) if result._vacant?
193
193
  end
194
194
  end
195
195
  end
@@ -86,7 +86,6 @@ module Mongoid #:nodoc:
86
86
  def extras(extras)
87
87
  clone.tap do |crit|
88
88
  crit.options.merge!(extras)
89
- crit.filter_options
90
89
  end
91
90
  end
92
91
 
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+
5
+ # Wrapper class for strings that should not be converted into
6
+ # BSON::ObjectIds.
7
+ class Unconvertable < String
8
+
9
+ # Initialize just like a normal string, and quack like it to.
10
+ #
11
+ # @example Create the new Unconvertable.
12
+ # Unconvertable.new("testing")
13
+ #
14
+ # @param [ String ] value The string.
15
+ #
16
+ # @since 2.0.2
17
+ def initialize(value); super; end
18
+ end
19
+ end
20
+ end
@@ -46,7 +46,7 @@ module Mongoid #:nodoc
46
46
  # <tt>cursor.each { |doc| p doc.title }</tt>
47
47
  def each
48
48
  @cursor.each do |document|
49
- yield Mongoid::Factory.build(@klass, document)
49
+ yield Mongoid::Factory.from_db(@klass, document)
50
50
  end
51
51
  end
52
52
 
@@ -71,7 +71,7 @@ module Mongoid #:nodoc
71
71
  #
72
72
  # <tt>cursor.next_document</tt>
73
73
  def next_document
74
- Mongoid::Factory.build(@klass, @cursor.next_document)
74
+ Mongoid::Factory.from_db(@klass, @cursor.next_document)
75
75
  end
76
76
 
77
77
  # Returns an array of all the documents in the cursor.
@@ -80,7 +80,7 @@ module Mongoid #:nodoc
80
80
  #
81
81
  # <tt>cursor.to_a</tt>
82
82
  def to_a
83
- @cursor.to_a.collect { |attrs| Mongoid::Factory.build(@klass, attrs) }
83
+ @cursor.to_a.collect { |attrs| Mongoid::Factory.from_db(@klass, attrs) }
84
84
  end
85
85
  end
86
86
  end
@@ -46,7 +46,7 @@ module Mongoid #:nodoc:
46
46
  # The old field value.
47
47
  def attribute_was(name)
48
48
  change = modifications[name]
49
- change ? change[0] : @attributes[name]
49
+ change ? change[0] : attributes[name]
50
50
  end
51
51
 
52
52
  # Gets the names of all the fields that have changed in the document.
@@ -157,7 +157,7 @@ module Mongoid #:nodoc:
157
157
  # The old field value.
158
158
  def reset_attribute!(name)
159
159
  value = attribute_was(name)
160
- value ? @attributes[name] = value : @attributes.delete(name)
160
+ value ? attributes[name] = value : attributes.delete(name)
161
161
  modifications.delete(name)
162
162
  end
163
163
 
@@ -210,7 +210,7 @@ module Mongoid #:nodoc:
210
210
  def modifications
211
211
  reset_modifications unless @modifications && @accessed
212
212
  @accessed.each_pair do |field, value|
213
- current = @attributes[field]
213
+ current = attributes[field]
214
214
  @modifications[field] = [ value, current ] if current != value
215
215
  end
216
216
  @accessed.clear
@@ -223,7 +223,7 @@ module Mongoid #:nodoc:
223
223
  #
224
224
  # <tt>person.modify("name", "Jack", "John")</tt>
225
225
  def modify(name, old_value, new_value)
226
- @attributes[name] = new_value
226
+ attributes[name] = new_value
227
227
  if @modifications && (old_value != new_value)
228
228
  original = @modifications[name].first if @modifications[name]
229
229
  @modifications[name] = [ (original || old_value), new_value ]
@@ -243,10 +243,10 @@ module Mongoid #:nodoc:
243
243
  # person.title_was # "Sir"
244
244
  # person.reset_title!
245
245
  def add_dirty_methods(name)
246
- define_method("#{name}_change") { attribute_change(name) } unless instance_methods.include?("#{name}_change")
247
- define_method("#{name}_changed?") { attribute_changed?(name) } unless instance_methods.include?("#{name}_changed?")
248
- define_method("#{name}_was") { attribute_was(name) } unless instance_methods.include?("#{name}_was")
249
- define_method("reset_#{name}!") { reset_attribute!(name) } unless instance_methods.include?("reset_#{name}!")
246
+ define_method("#{name}_change") { attribute_change(name) } unless instance_methods.include?("#{name}_change") || instance_methods.include?(:"#{name}_change")
247
+ define_method("#{name}_changed?") { attribute_changed?(name) } unless instance_methods.include?("#{name}_changed?") || instance_methods.include?(:"#{name}_changed?")
248
+ define_method("#{name}_was") { attribute_was(name) } unless instance_methods.include?("#{name}_was") || instance_methods.include?(:"#{name}_was")
249
+ define_method("reset_#{name}!") { reset_attribute!(name) } unless instance_methods.include?("reset_#{name}!") || instance_methods.include?(:"reset_#{name}!")
250
250
  end
251
251
  end
252
252
  end
@@ -21,7 +21,7 @@ module Mongoid #:nodoc:
21
21
  #
22
22
  # @return [ Integer ] -1, 0, 1.
23
23
  def <=>(other)
24
- raw_attributes["_id"].to_s <=> other.raw_attributes["_id"].to_s
24
+ attributes["_id"].to_s <=> other.attributes["_id"].to_s
25
25
  end
26
26
 
27
27
  # Performs equality checking on the document ids. For more robust
@@ -35,7 +35,7 @@ module Mongoid #:nodoc:
35
35
  # @return [ true, false ] True if the ids are equal, false if not.
36
36
  def ==(other)
37
37
  self.class == other.class &&
38
- raw_attributes["_id"] == other.raw_attributes["_id"]
38
+ attributes["_id"] == other.attributes["_id"]
39
39
  end
40
40
 
41
41
  # Performs class equality checking.
@@ -71,7 +71,7 @@ module Mongoid #:nodoc:
71
71
  #
72
72
  # @since 2.0.0
73
73
  def freeze
74
- raw_attributes.freeze
74
+ attributes.freeze
75
75
  self
76
76
  end
77
77
 
@@ -101,18 +101,6 @@ module Mongoid #:nodoc:
101
101
  raw_attributes["_id"].hash
102
102
  end
103
103
 
104
- # Return the attributes hash with indifferent access. Used mostly for
105
- # convenience - use +Document#raw_attributes+ where you dont care if the
106
- # keys are all strings.
107
- #
108
- # @example Get the attributes.
109
- # person.attributes
110
- #
111
- # @return [ HashWithIndifferentAccess ] The attributes.
112
- def attributes
113
- raw_attributes.with_indifferent_access
114
- end
115
-
116
104
  # Generate an id for this +Document+.
117
105
  #
118
106
  # @example Create the id.
@@ -146,16 +134,6 @@ module Mongoid #:nodoc:
146
134
  run_callbacks(:initialize) { self }
147
135
  end
148
136
 
149
- # Return the attributes hash.
150
- #
151
- # @example Get the untouched attributes.
152
- # person.raw_attributes
153
- #
154
- # @return [ Hash ] This document's attributes.
155
- def raw_attributes
156
- @attributes
157
- end
158
-
159
137
  # Reloads the +Document+ attributes from the database. If the document has
160
138
  # not been saved then an error will get raised if the configuration option
161
139
  # was set.
@@ -220,8 +198,8 @@ module Mongoid #:nodoc:
220
198
  #
221
199
  # @return [ Hash ] A hash of all attributes in the hierarchy.
222
200
  def as_document
223
- attributes = raw_attributes
224
- attributes.tap do |attrs|
201
+ attribs = attributes
202
+ attribs.tap do |attrs|
225
203
  relations.select { |name, meta| meta.embedded? }.each do |name, meta|
226
204
  relation = send(name, false, :continue => false)
227
205
  attrs[name] = relation.as_document unless relation.blank?
@@ -229,6 +207,29 @@ module Mongoid #:nodoc:
229
207
  end
230
208
  end
231
209
 
210
+ # Returns an instance of the specified class with the attributes
211
+ # and errors of the current document.
212
+ #
213
+ # @example Return a subclass document as a superclass instance.
214
+ # manager.becomes(Person)
215
+ #
216
+ # @raise [ ArgumentError ] If the class doesn't include Mongoid::Document
217
+ #
218
+ # @param [ Class ] klass The class to become.
219
+ #
220
+ # @return [ Document ] An instance of the specified class.
221
+ def becomes(klass)
222
+ unless klass.include?(Mongoid::Document)
223
+ raise ArgumentError, 'A class which includes Mongoid::Document is expected'
224
+ end
225
+ became = klass.new
226
+ became.instance_variable_set('@attributes', @attributes)
227
+ became.instance_variable_set('@errors', @errors)
228
+ became.instance_variable_set('@new_record', new_record?)
229
+ became.instance_variable_set('@destroyed', destroyed?)
230
+ became
231
+ end
232
+
232
233
  module ClassMethods #:nodoc:
233
234
 
234
235
  # Performs class equality checking.
@@ -256,15 +257,11 @@ module Mongoid #:nodoc:
256
257
  # @return [ Document ] A new document.
257
258
  def instantiate(attrs = nil)
258
259
  attributes = attrs || {}
259
- if attributes["_id"]
260
- allocate.tap do |doc|
261
- doc.instance_variable_set(:@attributes, attributes)
262
- doc.send(:apply_default_attributes)
263
- doc.setup_modifications
264
- doc.run_callbacks(:initialize) { doc }
265
- end
266
- else
267
- new(attrs)
260
+ allocate.tap do |doc|
261
+ doc.instance_variable_set(:@attributes, attributes)
262
+ doc.send(:apply_default_attributes)
263
+ doc.setup_modifications
264
+ doc.run_callbacks(:initialize) { doc }
268
265
  end
269
266
  end
270
267
 
@@ -15,10 +15,12 @@ require "mongoid/extensions/hash/criteria_helpers"
15
15
  require "mongoid/extensions/hash/scoping"
16
16
  require "mongoid/extensions/integer/conversions"
17
17
  require "mongoid/extensions/nil/collectionization"
18
+ require "mongoid/extensions/object/checks"
18
19
  require "mongoid/extensions/object/conversions"
19
20
  require "mongoid/extensions/object/reflections"
20
21
  require "mongoid/extensions/object/yoda"
21
22
  require "mongoid/extensions/proc/scoping"
23
+ require "mongoid/extensions/range/conversions"
22
24
  require "mongoid/extensions/string/conversions"
23
25
  require "mongoid/extensions/string/inflections"
24
26
  require "mongoid/extensions/symbol/inflections"
@@ -80,6 +82,7 @@ class NilClass #:nodoc
80
82
  end
81
83
 
82
84
  class Object #:nodoc:
85
+ include Mongoid::Extensions::Object::Checks
83
86
  include Mongoid::Extensions::Object::Conversions
84
87
  include Mongoid::Extensions::Object::Reflections
85
88
  include Mongoid::Extensions::Object::Yoda
@@ -89,6 +92,10 @@ class Proc #:nodoc:
89
92
  include Mongoid::Extensions::Proc::Scoping
90
93
  end
91
94
 
95
+ class Range
96
+ include Mongoid::Extensions::Range::Conversions
97
+ end
98
+
92
99
  class String #:nodoc
93
100
  include Mongoid::Extensions::String::Inflections
94
101
  include Mongoid::Extensions::String::Conversions
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module Object #:nodoc:
5
+
6
+ # This module has object checks in it.
7
+ module Checks #:nodoc:
8
+
9
+ # Since Active Support's blank? check looks to see if the object
10
+ # responds to #empty? and will call it if it does, we need another way
11
+ # to check if the object is empty or nil in case the user has defined a
12
+ # field called "empty" on the document.
13
+ #
14
+ # @example Is the array vacant?
15
+ # [].vacant?
16
+ #
17
+ # @example Is the hash vacant?
18
+ # {}.vacant?
19
+ #
20
+ # @example Is the object vacant?
21
+ # nil.vacant?
22
+ #
23
+ # @return [ true, false ] True if empty or nil, false if not.
24
+ #
25
+ # @since 2.0.2
26
+ def _vacant?
27
+ is_a?(::Enumerable) || is_a?(::String) ? empty? : !self
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -8,7 +8,7 @@ module Mongoid #:nodoc:
8
8
 
9
9
  module ClassMethods
10
10
  def set(value)
11
- value.respond_to?(:raw_attributes) ? value.raw_attributes : value
11
+ value.respond_to?(:attributes) ? value.attributes : value
12
12
  end
13
13
 
14
14
  def get(value)