mongoid 3.0.15 → 3.0.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,41 @@
1
1
  # Overview
2
2
 
3
3
  For instructions on upgrading to newer versions, visit
4
- [mongoid.org](http://mongoid.org/docs/upgrading.html).
4
+ [mongoid.org](http://mongoid.org/en/mongoid/docs/upgrading.html).
5
+
6
+ ## 3.0.16
7
+
8
+ ### Resolved Issues
9
+
10
+ * \#2661 Implement instance level `model_name` for documents.
11
+
12
+ * \#2651 Ensure `Criteria#type` works properly with both symbol and string
13
+ keys in the selector.
14
+
15
+ * \#2647 Ensure `deleted?` and `destroyed?` on paranoid documents return the
16
+ same value.
17
+
18
+ * \#2646 Set unloaded doc in memory on enumerable targets before yielding to
19
+ the block.
20
+
21
+ * \#2645 Take caching into consideration when asking for counts.
22
+ (Arthur Nogueira Neves)
23
+
24
+ * \#2642 Don't batch push empty arrays on embedded documents. (Laszlo Bacsi)
25
+
26
+ * \#2639 Avoid extra unnecesary queries on new records when building relations
27
+ off of them.
28
+
29
+ * \#2638 When a criteria is eager loading, calling `first` or `last` then
30
+ iterating the entire results properly eager loads the full request.
31
+
32
+ * \#2618 Validating uniqueness now always uses string consistency by default.
33
+
34
+ * \#2564 Fixed infinite recursion for cases where a relation getter was
35
+ overridden and called the setter from that method.
36
+
37
+ * \#2554 Ensure `unscoped` on an `embeds_many` does not include documents
38
+ flagged for destruction.
5
39
 
6
40
  ## 3.0.15
7
41
 
@@ -0,0 +1,158 @@
1
+ # encoding: utf-8
2
+ module Mongoid
3
+ module Contextual
4
+ module Eager
5
+
6
+ # @attribute [rw] eager_loaded Has the context been eager loaded?
7
+ attr_accessor :eager_loaded
8
+
9
+ private
10
+
11
+ # Eager load the inclusions for the provided documents.
12
+ #
13
+ # @api private
14
+ #
15
+ # @example Eager load the inclusions.
16
+ # context.eager_load(docs)
17
+ #
18
+ # @param [ Array<Document> ] docs The docs returning from the db.
19
+ #
20
+ # @return [ true ] Always true.
21
+ #
22
+ # @since 3.0.0
23
+ def eager_load(docs)
24
+ load_inclusions(docs)
25
+ self.eager_loaded = true
26
+ end
27
+
28
+ # Eager load the inclusions for the provided document.
29
+ #
30
+ # @api private
31
+ #
32
+ # @example Eager load the inclusions.
33
+ # context.eager_load(doc)
34
+ #
35
+ # @param [ Document ] doc The doc returning from the db.
36
+ #
37
+ # @return [ true ] Always true.
38
+ #
39
+ # @since 3.0.16
40
+ def eager_load_one(doc)
41
+ load_inclusions([ doc ])
42
+ inclusions_loaded[doc.id] = true
43
+ end
44
+
45
+ # Get the ids that to be used to eager load documents.
46
+ #
47
+ # @api private
48
+ #
49
+ # @example Get the ids.
50
+ # context.eager_load(docs, metadata)
51
+ #
52
+ # @param [ Array<Document> ] docs The pre-loaded documents.
53
+ # @param [ Metadata ] metadata The relation metadata.
54
+ #
55
+ # @return [ Array<Object> ] The ids.
56
+ #
57
+ # @since 3.0.0
58
+ def eager_loaded_ids(docs, metadata)
59
+ if metadata.stores_foreign_key?
60
+ docs.flat_map{ |doc| doc.send(metadata.foreign_key) }
61
+ else
62
+ docs.map(&:id)
63
+ end
64
+ end
65
+
66
+ # Is this context able to be eager loaded?
67
+ #
68
+ # @api private
69
+ #
70
+ # @example Is the context eager loadable?
71
+ # context.eager_loadable?
72
+ #
73
+ # @example Is the single document eager loadable?
74
+ # context.eager_loadable?(document)
75
+ #
76
+ # @param [ Document ] document The single document to load for.
77
+ #
78
+ # @return [ true, false ] If the context is able to be eager loaded.
79
+ #
80
+ # @since 3.0.0
81
+ def eager_loadable?(document = nil)
82
+ return false if criteria.inclusions.empty?
83
+ document ? !inclusions_loaded?(document) : !eager_loaded
84
+ end
85
+
86
+ # Has a hash of individual documents that have had their relations reager
87
+ # loaded.
88
+ #
89
+ # @api private
90
+ #
91
+ # @example Get the documents with relations eager loaded.
92
+ # context.inclusions_loaded
93
+ #
94
+ # @return [ Hash ] The documents that have had eager loaded inclusions.
95
+ #
96
+ # @since 3.0.16
97
+ def inclusions_loaded
98
+ @inclusions_loaded ||= {}
99
+ end
100
+
101
+ # Has the document had its inclusions loaded?
102
+ #
103
+ # @api private
104
+ #
105
+ # @example Has the document had its inclusions loaded?
106
+ # context.inclusions_loaded?(document)
107
+ #
108
+ # @param [ Document ] document The document to check.
109
+ #
110
+ # @return [ true, false ] If the document had it's inclusions loaded.
111
+ #
112
+ # @since 3.0.16
113
+ def inclusions_loaded?(document)
114
+ inclusions_loaded.has_key?(document.id)
115
+ end
116
+
117
+ # Eager load the inclusions for the provided documents.
118
+ #
119
+ # @api private
120
+ #
121
+ # @example Eager load the inclusions.
122
+ # context.load_inclusions(docs)
123
+ #
124
+ # @param [ Array<Document> ] docs The docs returning from the db.
125
+ #
126
+ # @return [ true ] Always true.
127
+ #
128
+ # @since 3.0.16
129
+ def load_inclusions(docs)
130
+ criteria.inclusions.each do |metadata|
131
+ metadata.eager_load(eager_loaded_ids(docs, metadata)) if !docs.empty?
132
+ end
133
+ end
134
+
135
+ # If the provided document exists, eager load its dependencies or return
136
+ # nil.
137
+ #
138
+ # @api private
139
+ #
140
+ # @example Eager load if the document is not nil.
141
+ # context.with_eager_loading(document)
142
+ #
143
+ # @param [ Hash ] document The document from the database.
144
+ #
145
+ # @return [ Document, nil ] The instantiated model document.
146
+ #
147
+ # @since 3.0.0
148
+ def with_eager_loading(document)
149
+ selecting do
150
+ return nil unless document
151
+ doc = Factory.from_db(klass, document, criteria.object_id)
152
+ eager_load_one(doc) if eager_loadable?(doc)
153
+ doc
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -2,6 +2,7 @@
2
2
  require "mongoid/contextual/atomic"
3
3
  require "mongoid/contextual/aggregable/mongo"
4
4
  require "mongoid/contextual/command"
5
+ require "mongoid/contextual/eager"
5
6
  require "mongoid/contextual/find_and_modify"
6
7
  require "mongoid/contextual/map_reduce"
7
8
 
@@ -11,6 +12,7 @@ module Mongoid
11
12
  include Enumerable
12
13
  include Aggregable::Mongo
13
14
  include Atomic
15
+ include Eager
14
16
 
15
17
  # @attribute [r] collection The collection to query against.
16
18
  # @attribute [r] criteria The criteria for the context.
@@ -18,9 +20,6 @@ module Mongoid
18
20
  # @attribute [r] query The Moped query.
19
21
  attr_reader :collection, :criteria, :klass, :query
20
22
 
21
- # @attribute [rw] eager_loaded Has the context been eager loaded?
22
- attr_accessor :eager_loaded
23
-
24
23
  # Is the enumerable of matching documents empty?
25
24
  #
26
25
  # @example Is the context empty?
@@ -66,7 +65,7 @@ module Mongoid
66
65
  # @since 3.0.0
67
66
  def count(document = nil, &block)
68
67
  return super(&block) if block_given?
69
- return query.count unless document
68
+ return (cached? ? @count ||= query.count : query.count) unless document
70
69
  collection.find(criteria.and(_id: document.id).selector).count
71
70
  end
72
71
 
@@ -79,7 +78,7 @@ module Mongoid
79
78
  #
80
79
  # @since 3.0.0
81
80
  def delete
82
- query.count.tap do
81
+ self.count.tap do
83
82
  query.remove_all
84
83
  end
85
84
  end
@@ -94,7 +93,7 @@ module Mongoid
94
93
  #
95
94
  # @since 3.0.0
96
95
  def destroy
97
- destroyed = query.count
96
+ destroyed = self.count
98
97
  each do |doc|
99
98
  doc.destroy
100
99
  end
@@ -242,7 +241,7 @@ module Mongoid
242
241
  #
243
242
  # @since 3.0.0
244
243
  def length
245
- @length ||= query.count
244
+ @length ||= self.count
246
245
  end
247
246
  alias :size :length
248
247
 
@@ -523,56 +522,6 @@ module Mongoid
523
522
  end
524
523
  end
525
524
 
526
- # Eager load the inclusions for the provided documents.
527
- #
528
- # @example Eager load the inclusions.
529
- # context.eager_load(docs)
530
- #
531
- # @param [ Array<Document> ] docs The docs returning from the db.
532
- #
533
- # @return [ true ] Always true.
534
- #
535
- # @since 3.0.0
536
- def eager_load(docs)
537
- criteria.inclusions.reject! do |metadata|
538
- metadata.eager_load(eager_loaded_ids(docs, metadata)) if !docs.empty?
539
- end
540
- self.eager_loaded = true
541
- end
542
-
543
- # Get the ids that to be used to eager load documents.
544
- #
545
- # @api private
546
- #
547
- # @example Get the ids.
548
- # context.eager_load(docs, metadata)
549
- #
550
- # @param [ Array<Document> ] docs The pre-loaded documents.
551
- # @param [ Metadata ] metadata The relation metadata.
552
- #
553
- # @return [ Array<Object> ] The ids.
554
- #
555
- # @since 3.0.0
556
- def eager_loaded_ids(docs, metadata)
557
- if metadata.stores_foreign_key?
558
- docs.flat_map{ |doc| doc.send(metadata.foreign_key) }
559
- else
560
- docs.map(&:id)
561
- end
562
- end
563
-
564
- # Is this context able to be eager loaded?
565
- #
566
- # @example Is the context eager loadable?
567
- # context.eager_loadable?
568
- #
569
- # @return [ true, false ] If the context is able to be eager loaded.
570
- #
571
- # @since 3.0.0
572
- def eager_loadable?
573
- !eager_loaded && !criteria.inclusions.empty?
574
- end
575
-
576
525
  # Apply all the optional criterion.
577
526
  #
578
527
  # @example Apply the options.
@@ -608,26 +557,6 @@ module Mongoid
608
557
  end
609
558
  end
610
559
 
611
- # If the provided document exists, eager load it's dependencies or return
612
- # nil.
613
- #
614
- # @example Eager load if the document is not nil.
615
- # context.with_eager_loading(document)
616
- #
617
- # @param [ Hash ] document The document from the database.
618
- #
619
- # @return [ Document, nil ] The instantiated model document.
620
- #
621
- # @since 3.0.0
622
- def with_eager_loading(document)
623
- selecting do
624
- return nil unless document
625
- doc = Factory.from_db(klass, document, criteria.object_id)
626
- eager_load([ doc ]) if eager_loadable?
627
- doc
628
- end
629
- end
630
-
631
560
  # Yield to the document.
632
561
  #
633
562
  # @api private
@@ -747,7 +747,9 @@ module Mongoid
747
747
  #
748
748
  # @since 3.0.3
749
749
  def type_selectable?
750
- klass.hereditary? && !selector.keys.include?(:_type)
750
+ klass.hereditary? &&
751
+ !selector.keys.include?("_type") &&
752
+ !selector.keys.include?(:_type)
751
753
  end
752
754
 
753
755
  # Get the selector for type selection.
@@ -153,6 +153,18 @@ module Mongoid
153
153
  end
154
154
  end
155
155
 
156
+ # Return the model name of the document.
157
+ #
158
+ # @example Return the model name.
159
+ # document.model_name
160
+ #
161
+ # @return [ String ] The model name.
162
+ #
163
+ # @since 3.0.16
164
+ def model_name
165
+ self.class.model_name
166
+ end
167
+
156
168
  # Return the key value for the document.
157
169
  #
158
170
  # @example Return the key.
@@ -99,6 +99,9 @@ module Mongoid
99
99
  opts = options || {}
100
100
  opts[:dropDups] = opts.delete(:drop_dups) if opts.has_key?(:drop_dups)
101
101
  opts[:bucketSize] = opts.delete(:bucket_size) if opts.has_key?(:bucket_size)
102
+ if opts.has_key?(:expire_after_seconds)
103
+ opts[:expireAfterSeconds] = opts.delete(:expire_after_seconds)
104
+ end
102
105
  opts
103
106
  end
104
107
 
@@ -7,7 +7,19 @@ module Mongoid
7
7
  module Options
8
8
  extend self
9
9
 
10
- VALID_OPTIONS = [ :background, :drop_dups, :name, :sparse, :unique, :max, :min, :bits, :bucket_size ]
10
+ VALID_OPTIONS = [
11
+ :background,
12
+ :drop_dups,
13
+ :name,
14
+ :sparse,
15
+ :unique,
16
+ :max,
17
+ :min,
18
+ :bits,
19
+ :bucket_size,
20
+ :expire_after_seconds
21
+ ]
22
+
11
23
  VALID_TYPES = [ 1, -1, "2d", "geoHaystack" ]
12
24
 
13
25
  # Validate the index specification.
@@ -80,6 +80,7 @@ module Mongoid
80
80
  def destroyed?
81
81
  (@destroyed ||= false) || !!deleted_at
82
82
  end
83
+ alias :deleted? :destroyed?
83
84
 
84
85
  # Restores a previously soft-deleted document. Handles this by removing the
85
86
  # deleted_at flag.
@@ -91,6 +91,43 @@ module Mongoid
91
91
 
92
92
  private
93
93
 
94
+ # Get the relation. Extracted out from the getter method to avoid
95
+ # infinite recursion when overriding the getter.
96
+ #
97
+ # @api private
98
+ #
99
+ # @example Get the relation.
100
+ # document.get_relation(:name, metadata)
101
+ #
102
+ # @param [ Symbol ] name The name of the relation.
103
+ # @param [ Metadata ] metadata The relation metadata.
104
+ # @param [ true, false ] reload If the relation is to be reloaded.
105
+ #
106
+ # @return [ Proxy ] The relation.
107
+ #
108
+ # @since 3.0.16
109
+ def get_relation(name, metadata, reload = false)
110
+ variable = "@#{name}"
111
+ value = if instance_variable_defined?(variable) && !reload
112
+ instance_variable_get(variable)
113
+ else
114
+ _building do
115
+ _loading do
116
+ # @note In the case where the record is new and we are binding,
117
+ # we want to avoid an extra database query when we know it is not
118
+ # necessary.
119
+ key = (new_record? && _binding?) ? nil : attributes[metadata.key]
120
+ __build__(name, key, metadata)
121
+ end
122
+ end
123
+ end
124
+ if value.nil? && metadata.autobuilding? && !without_autobuild?
125
+ send("build_#{name}")
126
+ else
127
+ value
128
+ end
129
+ end
130
+
94
131
  # Is the current code executing without autobuild functionality?
95
132
  #
96
133
  # @example Is autobuild disabled?
@@ -162,20 +199,8 @@ module Mongoid
162
199
  #
163
200
  # @since 2.0.0.rc.1
164
201
  def getter(name, metadata)
165
- re_define_method(name) do |*args|
166
- reload, variable = args.first, "@#{name}"
167
- value = if instance_variable_defined?(variable) && !reload
168
- instance_variable_get(variable)
169
- else
170
- _building do
171
- _loading { __build__(name, attributes[metadata.key], metadata) }
172
- end
173
- end
174
- if value.nil? && metadata.autobuilding? && !without_autobuild?
175
- send("build_#{name}")
176
- else
177
- value
178
- end
202
+ re_define_method(name) do |reload = false|
203
+ get_relation(name, metadata, reload)
179
204
  end
180
205
  self
181
206
  end
@@ -216,8 +241,8 @@ module Mongoid
216
241
  def setter(name, metadata)
217
242
  re_define_method("#{name}=") do |object|
218
243
  without_autobuild do
219
- if metadata.many? || send(name)
220
- set_relation(name, send(name).substitute(object.substitutable))
244
+ if metadata.many? || get_relation(name, metadata)
245
+ set_relation(name, get_relation(name, metadata).substitute(object.substitutable))
221
246
  else
222
247
  __build__(name, object.substitutable, metadata)
223
248
  end
@@ -48,8 +48,7 @@ module Mongoid
48
48
 
49
49
  # Set up the autosave behaviour for references many and references one
50
50
  # relations. When the option is set to true, these relations will get
51
- # saved automatically when the parent is first saved, but not if the
52
- # parent already exists in the database.
51
+ # saved automatically when the parent saved, if they are dirty.
53
52
  #
54
53
  # @example Set up autosave options.
55
54
  # Person.autosave(metadata)
@@ -59,7 +59,7 @@ module Mongoid
59
59
  #
60
60
  # @since 2.4.0
61
61
  def concat(docs)
62
- batch_insert(docs)
62
+ batch_insert(docs) unless docs.empty?
63
63
  self
64
64
  end
65
65
 
@@ -302,7 +302,7 @@ module Mongoid
302
302
  def unscoped
303
303
  criterion = klass.unscoped
304
304
  criterion.embedded = true
305
- criterion.documents = _unscoped
305
+ criterion.documents = _unscoped.delete_if(&:marked_for_destruction?)
306
306
  criterion
307
307
  end
308
308
 
@@ -165,8 +165,8 @@ module Mongoid
165
165
  else
166
166
  _unloaded.each do |doc|
167
167
  document = _added.delete(doc.id) || _loaded.delete(doc.id) || doc
168
- yield(document)
169
168
  _loaded[document.id] = document
169
+ yield(document)
170
170
  end
171
171
  end
172
172
  _added.each_pair do |id, doc|
@@ -267,7 +267,9 @@ module Mongoid
267
267
  # @since 2.4.10
268
268
  def validate_root(document, attribute, value)
269
269
  criteria = create_criteria(klass, document, attribute, value)
270
- add_error(document, attribute, value) if criteria.exists?
270
+ if criteria.with(consistency: :strong).exists?
271
+ add_error(document, attribute, value)
272
+ end
271
273
  end
272
274
 
273
275
  # Are we required to validate the document?
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid
3
- VERSION = "3.0.15"
3
+ VERSION = "3.0.16"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.15
4
+ version: 3.0.16
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-17 00:00:00.000000000 Z
12
+ date: 2012-12-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -107,6 +107,7 @@ files:
107
107
  - lib/mongoid/contextual/aggregable/mongo.rb
108
108
  - lib/mongoid/contextual/atomic.rb
109
109
  - lib/mongoid/contextual/command.rb
110
+ - lib/mongoid/contextual/eager.rb
110
111
  - lib/mongoid/contextual/find_and_modify.rb
111
112
  - lib/mongoid/contextual/map_reduce.rb
112
113
  - lib/mongoid/contextual/memory.rb