mongoid 2.2.0 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/CHANGELOG.md +57 -3
  2. data/Rakefile +1 -1
  3. data/lib/mongoid/atomic/modifiers.rb +2 -1
  4. data/lib/mongoid/config.rb +0 -1
  5. data/lib/mongoid/config/replset_database.rb +2 -2
  6. data/lib/mongoid/contexts/mongo.rb +14 -5
  7. data/lib/mongoid/criteria.rb +4 -4
  8. data/lib/mongoid/criterion/inclusion.rb +16 -1
  9. data/lib/mongoid/document.rb +2 -4
  10. data/lib/mongoid/extensions.rb +7 -0
  11. data/lib/mongoid/extensions/integer/checks.rb +23 -0
  12. data/lib/mongoid/extensions/object/yoda.rb +16 -0
  13. data/lib/mongoid/extensions/object_id/conversions.rb +1 -1
  14. data/lib/mongoid/extensions/string/checks.rb +24 -0
  15. data/lib/mongoid/extensions/string/inflections.rb +1 -1
  16. data/lib/mongoid/fields.rb +4 -2
  17. data/lib/mongoid/fields/serializable.rb +26 -18
  18. data/lib/mongoid/fields/serializable/array.rb +0 -1
  19. data/lib/mongoid/fields/serializable/boolean.rb +0 -1
  20. data/lib/mongoid/fields/serializable/float.rb +0 -1
  21. data/lib/mongoid/fields/serializable/integer.rb +1 -2
  22. data/lib/mongoid/fields/serializable/object_id.rb +0 -1
  23. data/lib/mongoid/fields/serializable/string.rb +0 -1
  24. data/lib/mongoid/fields/serializable/symbol.rb +0 -1
  25. data/lib/mongoid/matchers/strategies.rb +25 -2
  26. data/lib/mongoid/nested_attributes.rb +1 -1
  27. data/lib/mongoid/persistence/atomic.rb +2 -2
  28. data/lib/mongoid/persistence/atomic/{set.rb → sets.rb} +1 -1
  29. data/lib/mongoid/persistence/deletion.rb +1 -1
  30. data/lib/mongoid/relations/bindings/referenced/in.rb +5 -5
  31. data/lib/mongoid/relations/bindings/referenced/many.rb +4 -4
  32. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +2 -2
  33. data/lib/mongoid/relations/bindings/referenced/one.rb +4 -4
  34. data/lib/mongoid/relations/builder.rb +1 -2
  35. data/lib/mongoid/relations/builders/nested_attributes/many.rb +5 -4
  36. data/lib/mongoid/relations/builders/nested_attributes/one.rb +1 -1
  37. data/lib/mongoid/relations/builders/referenced/many.rb +4 -2
  38. data/lib/mongoid/relations/cascading/destroy.rb +8 -1
  39. data/lib/mongoid/relations/embedded/in.rb +1 -1
  40. data/lib/mongoid/relations/embedded/many.rb +15 -2
  41. data/lib/mongoid/relations/embedded/one.rb +1 -1
  42. data/lib/mongoid/relations/nested_builder.rb +11 -4
  43. data/lib/mongoid/relations/referenced/many.rb +4 -2
  44. data/lib/mongoid/relations/referenced/many_to_many.rb +2 -1
  45. data/lib/mongoid/relations/synchronization.rb +39 -2
  46. data/lib/mongoid/relations/targets/enumerable.rb +2 -2
  47. data/lib/mongoid/serialization.rb +1 -1
  48. data/lib/mongoid/state.rb +1 -1
  49. data/lib/mongoid/version.rb +1 -1
  50. data/lib/mongoid/versioning.rb +15 -1
  51. metadata +26 -22
  52. data/lib/mongoid/criterion/unconvertable.rb +0 -20
@@ -2,14 +2,68 @@
2
2
 
3
3
  For instructions on upgrading to newer versions, visit [mongoid.org](http://mongoid.org/docs/upgrading.html).
4
4
 
5
+ ## 2.2.1
6
+
7
+ ### Resolved Issues
8
+
9
+ * \#1210, \#517 Allow embedded document relation queries to use dot notation.
10
+ (Scott Ellard)
11
+
12
+ * \#1198 Enumerable target should use criteria count if loaded has no docs.
13
+
14
+ * \#1164 Get rid of remaining no method in_memory errors.
15
+
16
+ * \#1070 Allow custom field serializers to have their own constructors.
17
+
18
+ * \#1176 Allow access to parent documents from embedded docs in after_destroy
19
+ callbacks.
20
+
21
+ * \#1191 Context group methods (min, max, sum) no longer return NaN but instead
22
+ return nil if field doesn't exist or have values.
23
+
24
+ * \#1193, \#1271 Always return Integers for integer fields with .000 precisions,
25
+ not floats.
26
+
27
+ * \#1199 Fixed performance issues of hash and array field access when reading
28
+ multiple times.
29
+
30
+ * \#1218 Fixed issues with relations referencing models with integer foreign keys.
31
+
32
+ * \#1219 Fixed various conflicting modifications issues when pushing and pulling
33
+ from the same embedded document in a single call.
34
+
35
+ * \#1220 Metadata should not get overwritten by nil on binding.
36
+
37
+ * \#1231 Renamed Mongoid's atomic set class to Sets to avoid conflicts with Ruby's
38
+ native Set after document inclusion.
39
+
40
+ * \#1232 Fix access to related models during before_destroy callbacks when
41
+ cascading.
42
+
43
+ * \#1234 Fixed HABTM foreign key synchronization issues when destroying
44
+ documents.
45
+
46
+ * \#1243 Polymorphic relations dont convert to object ids when querying if the
47
+ ids are defined as strings.
48
+
49
+ * \#1247 Force Model.first to sort by ascending id to guarantee first document.
50
+
51
+ * \#1248 Added #unscoped to embedded many relations.
52
+
53
+ * \#1249 Destroy flags in nested attributes now actually destroy the document
54
+ for has_many instead of just breaking the relation.
55
+
56
+ * \#1272 Don't modify configuration options in place when creating replica set
57
+ connections.
58
+
5
59
  ## 2.2.0
6
60
 
7
61
  ### New Features
8
62
 
9
- * Mongoid now contains eager loading in the form of `Criteria#includes(|*args)`.
10
- This works on all relational associations and requires the identity map to
63
+ * Mongoid now contains eager loading in the form of `Criteria#includes(*args)`.
64
+ This works on has_one, has_many, belongs_to associations and requires the identity map to
11
65
  be enabled in order to function. Set `identity_map_enabled: true` in your
12
- `mongoid.yml`.
66
+ `mongoid.yml`. Ex: `Person.where(title: "Sir").includes(:posts, :game)`
13
67
 
14
68
  * Relations can now take a module as a value to the `:extend` option. (Roman
15
69
  Shterenzon)
data/Rakefile CHANGED
@@ -19,7 +19,7 @@ task :install => :build do
19
19
  end
20
20
 
21
21
  task :release => :build do
22
- system "git tag -a #{Mongoid::VERSION} -m 'Tagging #{Mongoid::VERSION}'"
22
+ system "git tag -a v#{Mongoid::VERSION} -m 'Tagging #{Mongoid::VERSION}'"
23
23
  system "git push --tags"
24
24
  system "gem push mongoid-#{Mongoid::VERSION}.gem"
25
25
  end
@@ -115,7 +115,8 @@ module Mongoid #:nodoc:
115
115
  #
116
116
  # @since 2.2.0
117
117
  def push_conflict?(field)
118
- set_fields.include?(field.split(".", 2)[0])
118
+ name = field.split(".", 2)[0]
119
+ set_fields.include?(name) || pull_fields.include?(name)
119
120
  end
120
121
 
121
122
  # Get the conflicting pull modifications.
@@ -48,7 +48,6 @@ module Mongoid #:nodoc
48
48
 
49
49
  option :allow_dynamic_fields, :default => true
50
50
  option :autocreate_indexes, :default => false
51
- option :binding_defaults, :default => { :binding => false, :continue => true }
52
51
  option :identity_map_enabled, :default => false
53
52
  option :include_root_in_json, :default => false
54
53
  option :max_retries_on_connection_failure, :default => 0
@@ -14,14 +14,14 @@ module Mongoid #:nodoc:
14
14
  #
15
15
  # @since 2.0.0.rc.5
16
16
  def configure
17
- # yes, construction is weird but the driver wants
17
+ # yes, construction is weird but the driver wants
18
18
  # "A list of host-port pairs ending with a hash containing any options"
19
19
  # mongo likes symbols
20
20
  options = self.inject({ :logger => Mongoid::Logger.new }) do |memo, (k, v)|
21
21
  memo[k.to_sym] = v
22
22
  memo
23
23
  end
24
- connection = Mongo::ReplSetConnection.new(*(hosts << options))
24
+ connection = Mongo::ReplSetConnection.new(*(hosts.clone << options))
25
25
 
26
26
  if authenticating?
27
27
  connection.add_auth(database, username, password)
@@ -4,7 +4,8 @@ module Mongoid #:nodoc:
4
4
  class Mongo
5
5
  attr_accessor :criteria
6
6
 
7
- delegate :klass, :options, :field_list, :selector, :to => :criteria
7
+ delegate :cached?, :klass, :options, :field_list, :selector, :to => :criteria
8
+ delegate :collection, :to => :klass
8
9
 
9
10
  # Perform an add to set on the matching documents.
10
11
  #
@@ -86,7 +87,11 @@ module Mongoid #:nodoc:
86
87
  #
87
88
  # @return [ Integer ] The count of documents.
88
89
  def count(extras = false)
89
- @count ||= klass.collection.find(selector, process_options).count(extras)
90
+ if cached?
91
+ @count ||= collection.find(selector, process_options).count(extras)
92
+ else
93
+ collection.find(selector, process_options).count(extras)
94
+ end
90
95
  end
91
96
  alias :size :count
92
97
  alias :length :count
@@ -153,7 +158,10 @@ module Mongoid #:nodoc:
153
158
  #
154
159
  # @return [ Document ] The first document in the collection.
155
160
  def first
156
- attributes = klass.collection.find_one(selector, process_options)
161
+ opts = process_options
162
+ sorting = opts[:sort] ||= []
163
+ sorting << [:_id, :asc]
164
+ attributes = klass.collection.find_one(selector, opts)
157
165
  attributes ? Mongoid::Factory.from_db(klass, attributes) : nil
158
166
  end
159
167
  alias :one :first
@@ -202,7 +210,7 @@ module Mongoid #:nodoc:
202
210
  # @example Iterate over the results.
203
211
  # context.iterate { |doc| p doc }
204
212
  def iterate(&block)
205
- return caching(&block) if criteria.cached?
213
+ return caching(&block) if cached?
206
214
  if block_given?
207
215
  execute.each { |doc| yield doc }
208
216
  end
@@ -362,7 +370,8 @@ module Mongoid #:nodoc:
362
370
  :initial => { start => "start" },
363
371
  :reduce => reduce.gsub("[field]", field)
364
372
  )
365
- collection.empty? ? nil : collection.first[start.to_s]
373
+ value = collection.empty? ? nil : collection.first[start.to_s]
374
+ value ? (value.nan? ? nil : value) : value
366
375
  end
367
376
 
368
377
  # Filters the field list. If no fields have been supplied, then it will be
@@ -7,7 +7,6 @@ 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"
11
10
 
12
11
  module Mongoid #:nodoc:
13
12
 
@@ -195,9 +194,10 @@ module Mongoid #:nodoc:
195
194
  @options, @klass, @documents, @embedded = {}, klass, [], embedded
196
195
  end
197
196
 
198
- # Merges another object into this +Criteria+. The other object may be a
199
- # +Criteria+ or a +Hash+. This is used to combine multiple scopes together,
200
- # where a chained scope situation may be desired.
197
+ # Merges another object with this +Criteria+ and returns a new criteria.
198
+ # The other object may be a +Criteria+ or a +Hash+. This is used to
199
+ # combine multiple scopes together, where a chained scope situation
200
+ # may be desired.
201
201
  #
202
202
  # @example Merge the criteria with a conditions hash.
203
203
  # criteria.merge({ :conditions => { :title => "Sir" } })
@@ -247,12 +247,27 @@ module Mongoid #:nodoc:
247
247
  #
248
248
  # @since 2.0.0
249
249
  def execute_or_raise(args, criteria)
250
- (args[0].is_a?(Array) ? criteria.entries : criteria.one).tap do |result|
250
+ (args[0].is_a?(Array) ? criteria.entries : from_map_or_db(criteria)).tap do |result|
251
251
  if Mongoid.raise_not_found_error && !args.flatten.blank?
252
252
  raise Errors::DocumentNotFound.new(klass, args) if result._vacant?
253
253
  end
254
254
  end
255
255
  end
256
+
257
+ # Get the document from the identity map, and if not found hit the
258
+ # database.
259
+ #
260
+ # @example Get the document from the map or criteria.
261
+ # criteria.from_map_or_db(criteria)
262
+ #
263
+ # @param [ Criteria ] The cloned criteria.
264
+ #
265
+ # @return [ Document ] The found document.
266
+ #
267
+ # @since 2.2.1
268
+ def from_map_or_db(criteria)
269
+ IdentityMap.get(klass, criteria.selector[:_id]) || criteria.one
270
+ end
256
271
  end
257
272
  end
258
273
  end
@@ -7,9 +7,7 @@ module Mongoid #:nodoc:
7
7
  extend ActiveSupport::Concern
8
8
  include Mongoid::Components
9
9
 
10
- included do
11
- attr_reader :new_record
12
- end
10
+ attr_reader :new_record
13
11
 
14
12
  # Default comparison is via the string version of the id.
15
13
  #
@@ -181,7 +179,7 @@ module Mongoid #:nodoc:
181
179
  attributes.tap do |attrs|
182
180
  relations.each_pair do |name, meta|
183
181
  if meta.embedded?
184
- relation = send(name, false, :continue => false)
182
+ relation = send(name)
185
183
  attrs[name] = relation.as_document unless relation.blank?
186
184
  end
187
185
  end
@@ -3,12 +3,14 @@ require "mongoid/extensions/array/deletion"
3
3
  require "mongoid/extensions/false_class/equality"
4
4
  require "mongoid/extensions/hash/criteria_helpers"
5
5
  require "mongoid/extensions/hash/scoping"
6
+ require "mongoid/extensions/integer/checks"
6
7
  require "mongoid/extensions/nil/collectionization"
7
8
  require "mongoid/extensions/object/checks"
8
9
  require "mongoid/extensions/object/reflections"
9
10
  require "mongoid/extensions/object/substitutable"
10
11
  require "mongoid/extensions/object/yoda"
11
12
  require "mongoid/extensions/proc/scoping"
13
+ require "mongoid/extensions/string/checks"
12
14
  require "mongoid/extensions/string/conversions"
13
15
  require "mongoid/extensions/string/inflections"
14
16
  require "mongoid/extensions/symbol/inflections"
@@ -33,6 +35,10 @@ class Hash #:nodoc
33
35
  include Mongoid::Extensions::Hash::Scoping
34
36
  end
35
37
 
38
+ class Integer #:nodoc
39
+ include Mongoid::Extensions::Integer::Checks
40
+ end
41
+
36
42
  class NilClass #:nodoc
37
43
  include Mongoid::Extensions::Nil::Collectionization
38
44
  end
@@ -49,6 +55,7 @@ class Proc #:nodoc:
49
55
  end
50
56
 
51
57
  class String #:nodoc
58
+ include Mongoid::Extensions::String::Checks
52
59
  include Mongoid::Extensions::String::Conversions
53
60
  include Mongoid::Extensions::String::Inflections
54
61
  end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module Integer #:nodoc:
5
+
6
+ # This module has object checks in it.
7
+ module Checks #:nodoc:
8
+
9
+ # Is the object not to be converted to bson on criteria creation?
10
+ #
11
+ # @example Is the object unconvertable?
12
+ # object.unconvertable_to_bson?
13
+ #
14
+ # @return [ true ] If the object is unconvertable.
15
+ #
16
+ # @since 2.2.1
17
+ def unconvertable_to_bson?
18
+ true
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -21,6 +21,22 @@ module Mongoid #:nodoc:
21
21
  def do_or_do_not(name, *args)
22
22
  respond_to?(name) ? send(name, *args) : nil
23
23
  end
24
+
25
+ # You must unlearn what you have learned. -- Yoda
26
+ #
27
+ # @example You must perform this execution.
28
+ # object.you_must(:use, "The Force")
29
+ #
30
+ # @param [ String, Symbol ] name The method name.
31
+ # @param [ Array ] *args The arguments.
32
+ #
33
+ # @return [ Object, nil ] The result of the method call or nil if the
34
+ # method does not exist. Nil if the object is frozen.
35
+ #
36
+ # @since 2.2.1
37
+ def you_must(name, *args)
38
+ frozen? ? nil : do_or_do_not(name, *args)
39
+ end
24
40
  end
25
41
  end
26
42
  end
@@ -35,7 +35,7 @@ module Mongoid #:nodoc:
35
35
  case args
36
36
  when ::String
37
37
  return nil if args.blank?
38
- if args.is_a?(Mongoid::Criterion::Unconvertable)
38
+ if args.unconvertable_to_bson?
39
39
  args
40
40
  else
41
41
  BSON::ObjectId.from_string(args)
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module String #:nodoc:
5
+
6
+ # This module has object checks in it.
7
+ module Checks #:nodoc:
8
+ attr_accessor :unconvertable_to_bson
9
+
10
+ # Is the object not to be converted to bson on criteria creation?
11
+ #
12
+ # @example Is the object unconvertable?
13
+ # object.unconvertable_to_bson?
14
+ #
15
+ # @return [ true, false ] If the object is unconvertable.
16
+ #
17
+ # @since 2.2.1
18
+ def unconvertable_to_bson?
19
+ !!@unconvertable_to_bson
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -8,7 +8,7 @@ module Mongoid #:nodoc:
8
8
  module Inflections
9
9
 
10
10
  ActiveSupport::Inflector.inflections do |inflect|
11
- inflect.singular("address", "address")
11
+ inflect.singular(/address$/, "address")
12
12
  inflect.singular("addresses", "address")
13
13
  inflect.irregular("canvas", "canvases")
14
14
  end
@@ -229,7 +229,7 @@ module Mongoid #:nodoc
229
229
  meth = options.delete(:as) || name
230
230
  Mappings.for(
231
231
  options[:type], options[:identity]
232
- ).new(name, options).tap do |field|
232
+ ).instantiate(name, options).tap do |field|
233
233
  fields[name] = field
234
234
  defaults << name unless field.default.nil?
235
235
  create_accessors(name, meth, options)
@@ -305,7 +305,9 @@ module Mongoid #:nodoc
305
305
  define_method(meth) do
306
306
  read_attribute(name).tap do |value|
307
307
  if value.is_a?(Array) || value.is_a?(Hash)
308
- changed_attributes[name] = value.clone unless attribute_changed?(name)
308
+ unless changed_attributes.include?(name)
309
+ changed_attributes[name] = value.clone
310
+ end
309
311
  end
310
312
  end
311
313
  end
@@ -23,9 +23,10 @@ module Mongoid #:nodoc:
23
23
  # end
24
24
  # end
25
25
  module Serializable
26
+ extend ActiveSupport::Concern
26
27
 
27
28
  # Set readers for the instance variables.
28
- attr_reader :default, :label, :name, :options
29
+ attr_accessor :default, :label, :name, :options
29
30
 
30
31
  # When reading the field do we need to cast the value? This holds true when
31
32
  # times are stored or for big decimals which are stored as strings.
@@ -88,23 +89,6 @@ module Mongoid #:nodoc:
88
89
  end
89
90
  end
90
91
 
91
- # Create the new field with a name and optional additional options.
92
- #
93
- # @example Create the new field.
94
- # Field.new(:name, :type => String)
95
- #
96
- # @param [ Hash ] options The field options.
97
- #
98
- # @option options [ Class ] :type The class of the field.
99
- # @option options [ Object ] :default The default value for the field.
100
- # @option options [ String ] :label The field's label.
101
- #
102
- # @since 2.1.0
103
- def initialize(name, options = {})
104
- @name, @options = name, options
105
- @default, @label = options[:default], options[:label]
106
- end
107
-
108
92
  # Get the metadata for the field if its a foreign key.
109
93
  #
110
94
  # @example Get the metadata.
@@ -165,6 +149,30 @@ module Mongoid #:nodoc:
165
149
  def versioned?
166
150
  @versioned ||= (options[:versioned].nil? ? true : options[:versioned])
167
151
  end
152
+
153
+ module ClassMethods #:nodoc:
154
+
155
+ # Create the new field with a name and optional additional options.
156
+ #
157
+ # @example Create the new field.
158
+ # Field.new(:name, :type => String)
159
+ #
160
+ # @param [ Hash ] options The field options.
161
+ #
162
+ # @option options [ Class ] :type The class of the field.
163
+ # @option options [ Object ] :default The default value for the field.
164
+ # @option options [ String ] :label The field's label.
165
+ #
166
+ # @since 2.1.0
167
+ def instantiate(name, options = {})
168
+ allocate.tap do |field|
169
+ field.name = name
170
+ field.options = options
171
+ field.default = options[:default]
172
+ field.label = options[:label]
173
+ end
174
+ end
175
+ end
168
176
  end
169
177
  end
170
178
  end