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
@@ -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)