mongoid 2.1.9 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/CHANGELOG.md +281 -0
  2. data/{README.rdoc → README.md} +24 -14
  3. data/Rakefile +1 -1
  4. data/lib/config/locales/bg.yml +5 -0
  5. data/lib/config/locales/de.yml +5 -0
  6. data/lib/config/locales/en-GB.yml +5 -0
  7. data/lib/config/locales/en.yml +5 -0
  8. data/lib/config/locales/es.yml +3 -0
  9. data/lib/config/locales/fr.yml +5 -0
  10. data/lib/config/locales/hi.yml +5 -0
  11. data/lib/config/locales/hu.yml +5 -0
  12. data/lib/config/locales/id.yml +5 -0
  13. data/lib/config/locales/it.yml +5 -0
  14. data/lib/config/locales/ja.yml +5 -0
  15. data/lib/config/locales/kr.yml +5 -0
  16. data/lib/config/locales/nl.yml +5 -0
  17. data/lib/config/locales/pl.yml +5 -0
  18. data/lib/config/locales/pt-BR.yml +5 -0
  19. data/lib/config/locales/pt.yml +5 -0
  20. data/lib/config/locales/ro.yml +5 -0
  21. data/lib/config/locales/ru.yml +5 -0
  22. data/lib/config/locales/sv.yml +5 -0
  23. data/lib/config/locales/vi.yml +5 -0
  24. data/lib/config/locales/zh-CN.yml +5 -0
  25. data/lib/mongoid/atomic.rb +61 -10
  26. data/lib/mongoid/atomic/modifiers.rb +156 -24
  27. data/lib/mongoid/attributes.rb +38 -10
  28. data/lib/mongoid/collection.rb +21 -3
  29. data/lib/mongoid/collections.rb +52 -6
  30. data/lib/mongoid/collections/master.rb +8 -2
  31. data/lib/mongoid/collections/operations.rb +1 -0
  32. data/lib/mongoid/config.rb +5 -2
  33. data/lib/mongoid/config/database.rb +15 -2
  34. data/lib/mongoid/contexts/mongo.rb +3 -0
  35. data/lib/mongoid/criteria.rb +27 -3
  36. data/lib/mongoid/criterion/inclusion.rb +58 -0
  37. data/lib/mongoid/dirty.rb +2 -0
  38. data/lib/mongoid/document.rb +23 -0
  39. data/lib/mongoid/errors.rb +3 -0
  40. data/lib/mongoid/errors/callback.rb +26 -0
  41. data/lib/mongoid/errors/eager_load.rb +25 -0
  42. data/lib/mongoid/errors/invalid_find.rb +19 -0
  43. data/lib/mongoid/extensions.rb +3 -1
  44. data/lib/mongoid/extensions/object_id/conversions.rb +1 -1
  45. data/lib/mongoid/extras.rb +12 -2
  46. data/lib/mongoid/fields.rb +41 -2
  47. data/lib/mongoid/fields/serializable.rb +36 -0
  48. data/lib/mongoid/fields/serializable/foreign_keys/array.rb +13 -14
  49. data/lib/mongoid/fields/serializable/foreign_keys/object.rb +13 -14
  50. data/lib/mongoid/finders.rb +4 -4
  51. data/lib/mongoid/identity_map.rb +33 -20
  52. data/lib/mongoid/keys.rb +24 -1
  53. data/lib/mongoid/nested_attributes.rb +16 -4
  54. data/lib/mongoid/persistence.rb +50 -6
  55. data/lib/mongoid/persistence/operations.rb +1 -4
  56. data/lib/mongoid/persistence/operations/update.rb +3 -1
  57. data/lib/mongoid/relations/builders/nested_attributes/many.rb +27 -44
  58. data/lib/mongoid/relations/builders/referenced/many.rb +2 -1
  59. data/lib/mongoid/relations/builders/referenced/one.rb +1 -1
  60. data/lib/mongoid/relations/cascading.rb +12 -1
  61. data/lib/mongoid/relations/embedded/many.rb +11 -4
  62. data/lib/mongoid/relations/embedded/one.rb +6 -2
  63. data/lib/mongoid/relations/macros.rb +19 -12
  64. data/lib/mongoid/relations/metadata.rb +17 -0
  65. data/lib/mongoid/relations/polymorphic.rb +12 -1
  66. data/lib/mongoid/relations/proxy.rb +24 -0
  67. data/lib/mongoid/relations/referenced/in.rb +20 -0
  68. data/lib/mongoid/relations/referenced/many.rb +30 -6
  69. data/lib/mongoid/relations/referenced/many_to_many.rb +18 -2
  70. data/lib/mongoid/relations/referenced/one.rb +19 -0
  71. data/lib/mongoid/relations/reflections.rb +23 -3
  72. data/lib/mongoid/relations/targets/enumerable.rb +29 -1
  73. data/lib/mongoid/serialization.rb +1 -1
  74. data/lib/mongoid/sharding.rb +12 -2
  75. data/lib/mongoid/threaded.rb +98 -0
  76. data/lib/mongoid/version.rb +1 -1
  77. data/lib/mongoid/versioning.rb +12 -2
  78. metadata +25 -21
@@ -178,6 +178,23 @@ module Mongoid # :nodoc:
178
178
  !!dependent
179
179
  end
180
180
 
181
+ # Get the criteria needed to eager load this relation.
182
+ #
183
+ # @example Get the eager loading criteria.
184
+ # metadata.eager_load(criteria)
185
+ #
186
+ # @param [ Criteria ] criteria The criteria to load from.
187
+ #
188
+ # @return [ Criteria ] The eager loading criteria.
189
+ #
190
+ # @since 2.2.0
191
+ def eager_load(criteria)
192
+ relation.eager_load(
193
+ self,
194
+ criteria.clone.tap { |crit| crit.inclusions.clear }
195
+ )
196
+ end
197
+
181
198
  # Will determine if the relation is an embedded one or not. Currently
182
199
  # only checks against embeds one and many.
183
200
  #
@@ -9,7 +9,18 @@ module Mongoid # :nodoc:
9
9
 
10
10
  included do
11
11
  class_attribute :polymorphic
12
- delegate :polymorphic?, :to => "self.class"
12
+ end
13
+
14
+ # Is the document in a polymorphic relation?
15
+ #
16
+ # @note Refactored from using delegate for class load performance.
17
+ #
18
+ # @example Is the document polymorphic?
19
+ # model.polymorphic?
20
+ #
21
+ # @return [ true, false ] If the document is in a polymorphic relation.
22
+ def polymorphic?
23
+ self.class.polymorphic?
13
24
  end
14
25
 
15
26
  module ClassMethods #:nodoc:
@@ -50,6 +50,18 @@ module Mongoid # :nodoc:
50
50
 
51
51
  protected
52
52
 
53
+ # Is the current thread in assigning mode?
54
+ #
55
+ # @example Is the current thread in assigning mode?
56
+ # proxy.assigning?
57
+ #
58
+ # @return [ true, false ] If the thread is assigning.
59
+ #
60
+ # @since 2.1.0
61
+ def assigning?
62
+ Threaded.assigning?
63
+ end
64
+
53
65
  # Is the current thread in binding mode?
54
66
  #
55
67
  # @example Is the current thread in binding mode?
@@ -74,6 +86,18 @@ module Mongoid # :nodoc:
74
86
  Threaded.building?
75
87
  end
76
88
 
89
+ # Is the current thread in creating mode?
90
+ #
91
+ # @example Is the current thread in creating mode?
92
+ # proxy.creating?
93
+ #
94
+ # @return [ true, false ] If the thread is creating.
95
+ #
96
+ # @since 2.1.0
97
+ def creating?
98
+ Threaded.creating?
99
+ end
100
+
77
101
  # Get the collection from the root of the hierarchy.
78
102
  #
79
103
  # @example Get the collection.
@@ -109,6 +109,26 @@ module Mongoid # :nodoc:
109
109
  type.where(:_id => object)
110
110
  end
111
111
 
112
+ # Get the criteria that is used to eager load a relation of this
113
+ # type.
114
+ #
115
+ # @example Get the eager load criteria.
116
+ # Proxy.eager_load(metadata, criteria)
117
+ #
118
+ # @param [ Metadata ] metadata The relation metadata.
119
+ # @param [ Criteria ] criteria The criteria being used.
120
+ #
121
+ # @return [ Criteria ] The criteria to eager load the relation.
122
+ #
123
+ # @since 2.2.0
124
+ def eager_load(metadata, criteria)
125
+ raise Errors::EagerLoad.new(metadata.name) if metadata.polymorphic?
126
+ klass, foreign_key = metadata.klass, metadata.foreign_key
127
+ klass.any_in("_id" => criteria.load_ids(foreign_key).uniq).each do |doc|
128
+ IdentityMap.set(doc)
129
+ end
130
+ end
131
+
112
132
  # Returns true if the relation is an embedded one. In this case
113
133
  # always false.
114
134
  #
@@ -245,10 +245,14 @@ module Mongoid #:nodoc:
245
245
  #
246
246
  # @since 2.0.0.beta.1
247
247
  def purge
248
- criteria.delete_all
249
- target.clear do |doc|
250
- unbind_one(doc)
251
- doc.destroyed = true
248
+ unless metadata.destructive?
249
+ nullify
250
+ else
251
+ criteria.delete_all
252
+ target.clear do |doc|
253
+ unbind_one(doc)
254
+ doc.destroyed = true
255
+ end
252
256
  end
253
257
  end
254
258
  alias :clear :purge
@@ -267,8 +271,10 @@ module Mongoid #:nodoc:
267
271
  # @since 2.0.0.rc.1
268
272
  def substitute(replacement)
269
273
  tap do |proxy|
270
- proxy.purge
271
- proxy.push(replacement.compact) if replacement
274
+ if replacement != proxy.in_memory
275
+ proxy.purge
276
+ proxy.push(replacement.compact) if replacement
277
+ end
272
278
  end
273
279
  end
274
280
 
@@ -464,6 +470,24 @@ module Mongoid #:nodoc:
464
470
  metadata.klass.where(metadata.foreign_key => object)
465
471
  end
466
472
 
473
+ # Eager load the relation based on the criteria.
474
+ #
475
+ # @example Eager load the criteria.
476
+ # Proxy.eager_load(metadata, criteria)
477
+ #
478
+ # @param [ Metadata ] metadata The relation metadata.
479
+ # @param [ Criteria ] criteria The criteria being used.
480
+ #
481
+ # @return [ Criteria ] The criteria to eager load the relation.
482
+ #
483
+ # @since 2.2.0
484
+ def eager_load(metadata, criteria)
485
+ klass, foreign_key = metadata.klass, metadata.foreign_key
486
+ klass.any_in(foreign_key => criteria.load_ids("_id").uniq).each do |doc|
487
+ IdentityMap.set_many(doc, foreign_key => doc.send(foreign_key))
488
+ end
489
+ end
490
+
467
491
  # Returns true if the relation is an embedded one. In this case
468
492
  # always false.
469
493
  #
@@ -30,14 +30,14 @@ module Mongoid # :nodoc:
30
30
  args.flatten.each do |doc|
31
31
  next unless doc
32
32
  append(doc)
33
- if persistable?
33
+ if persistable? || creating?
34
34
  ids.push(doc.id)
35
35
  doc.save
36
36
  else
37
37
  base.send(metadata.foreign_key).push(doc.id)
38
38
  end
39
39
  end
40
- if persistable?
40
+ if persistable? || creating?
41
41
  base.push_all(metadata.foreign_key, ids)
42
42
  base.synced[metadata.foreign_key] = false
43
43
  end
@@ -232,6 +232,22 @@ module Mongoid # :nodoc:
232
232
  metadata.klass.any_in(:_id => object)
233
233
  end
234
234
 
235
+ # Get the criteria that is used to eager load a relation of this
236
+ # type.
237
+ #
238
+ # @example Get the eager load criteria.
239
+ # Proxy.eager_load(metadata, criteria)
240
+ #
241
+ # @param [ Metadata ] metadata The relation metadata.
242
+ # @param [ Criteria ] criteria The criteria being used.
243
+ #
244
+ # @return [ Criteria ] The criteria to eager load the relation.
245
+ #
246
+ # @since 2.2.0
247
+ def eager_load(metadata, criteria)
248
+ raise Errors::EagerLoad.new(metadata.name)
249
+ end
250
+
235
251
  # Returns true if the relation is an embedded one. In this case
236
252
  # always false.
237
253
  #
@@ -122,6 +122,25 @@ module Mongoid # :nodoc:
122
122
  metadata.klass.where(metadata.foreign_key => object)
123
123
  end
124
124
 
125
+ # Get the criteria that is used to eager load a relation of this
126
+ # type.
127
+ #
128
+ # @example Get the eager load criteria.
129
+ # Proxy.eager_load(metadata, criteria)
130
+ #
131
+ # @param [ Metadata ] metadata The relation metadata.
132
+ # @param [ Criteria ] criteria The criteria being used.
133
+ #
134
+ # @return [ Criteria ] The criteria to eager load the relation.
135
+ #
136
+ # @since 2.2.0
137
+ def eager_load(metadata, criteria)
138
+ klass, foreign_key = metadata.klass, metadata.foreign_key
139
+ klass.any_in(foreign_key => criteria.load_ids("_id").uniq).each do |doc|
140
+ IdentityMap.set_one(doc, foreign_key => doc.send(foreign_key))
141
+ end
142
+ end
143
+
125
144
  # Returns true if the relation is an embedded one. In this case
126
145
  # always false.
127
146
  #
@@ -7,9 +7,29 @@ module Mongoid # :nodoc:
7
7
  module Reflections
8
8
  extend ActiveSupport::Concern
9
9
 
10
- delegate \
11
- :reflect_on_association,
12
- :reflect_on_all_associations, :to => "self.class"
10
+ # Returns the relation metadata for the supplied name.
11
+ #
12
+ # @example Find relation metadata by name.
13
+ # person.reflect_on_association(:addresses)
14
+ #
15
+ # @param [ String, Symbol ] name The name of the relation to find.
16
+ #
17
+ # @return [ Metadata ] The matching relation metadata.
18
+ def reflect_on_association(name)
19
+ self.class.reflect_on_association(name)
20
+ end
21
+
22
+ # Returns all relation metadata for the supplied macros.
23
+ #
24
+ # @example Find multiple relation metadata by macro.
25
+ # person.reflect_on_all_associations(:embeds_many)
26
+ #
27
+ # @param [ Array<String, Symbol> ] *macros The relation macros.
28
+ #
29
+ # @return [ Array<Metadata> ] The matching relation metadata.
30
+ def reflect_on_all_associations(*macros)
31
+ self.class.reflect_on_all_associations(*macros)
32
+ end
13
33
 
14
34
  module ClassMethods #:nodoc
15
35
 
@@ -189,7 +189,7 @@ module Mongoid #:nodoc:
189
189
  #
190
190
  # @since 2.1.0
191
191
  def first
192
- (loaded? ? loaded.first : unloaded.first) || added.first
192
+ added.first || (loaded? ? loaded.first : unloaded.first)
193
193
  end
194
194
 
195
195
  # Initialize the new enumerable either with a criteria or an array.
@@ -320,6 +320,34 @@ module Mongoid #:nodoc:
320
320
  end
321
321
  alias :length :size
322
322
 
323
+ # Send #to_json to the entries.
324
+ #
325
+ # @example Get the enumerable as json.
326
+ # enumerable.to_json
327
+ #
328
+ # @param [ Hash ] options Optional parameters.
329
+ #
330
+ # @return [ String ] The entries all loaded as a string.
331
+ #
332
+ # @since 2.2.0
333
+ def to_json(options = {})
334
+ entries.to_json(options)
335
+ end
336
+
337
+ # Send #as_json to the entries, without encoding.
338
+ #
339
+ # @example Get the enumerable as json.
340
+ # enumerable.as_json
341
+ #
342
+ # @param [ Hash ] options Optional parameters.
343
+ #
344
+ # @return [ Hash ] The entries all loaded as a hash.
345
+ #
346
+ # @since 2.2.0
347
+ def as_json(options = {})
348
+ entries.as_json(options)
349
+ end
350
+
323
351
  # Return all the unique documents in the enumerable.
324
352
  #
325
353
  # @note This operation loads all documents from the database.
@@ -74,7 +74,7 @@ module Mongoid # :nodoc:
74
74
  inclusions = options[:include]
75
75
  relation_names(inclusions).each do |name|
76
76
  metadata = relations[name.to_s]
77
- relation = send(metadata.name, false, :eager => true)
77
+ relation = send(metadata.name)
78
78
  if relation
79
79
  attributes[metadata.name.to_s] =
80
80
  relation.serializable_hash(relation_options(inclusions, options, name))
@@ -5,13 +5,23 @@ module Mongoid #:nodoc
5
5
  module Sharding
6
6
  extend ActiveSupport::Concern
7
7
 
8
- delegate :shard_key_fields, :to => "self.class"
9
-
10
8
  included do
11
9
  cattr_accessor :shard_key_fields
12
10
  self.shard_key_fields = []
13
11
  end
14
12
 
13
+ # Get the shard key fields.
14
+ #
15
+ # @note Refactored from using delegate for class load performance.
16
+ #
17
+ # @example Get the shard key fields.
18
+ # model.shard_key_fields
19
+ #
20
+ # @return [ Array<String> ] The shard key field names.
21
+ def shard_key_fields
22
+ self.class.shard_key_fields
23
+ end
24
+
15
25
  # Get the document selector with the defined shard keys.
16
26
  #
17
27
  # @example Get the selector for the shard keys.
@@ -6,6 +6,18 @@ module Mongoid #:nodoc:
6
6
  module Threaded
7
7
  extend self
8
8
 
9
+ # Begins a assigning block.
10
+ #
11
+ # @example Begin the assign.
12
+ # Threaded.begin_assign
13
+ #
14
+ # @return [ true ] Always true.
15
+ #
16
+ # @since 2.1.9
17
+ def begin_assign
18
+ assign_stack.push(true)
19
+ end
20
+
9
21
  # Begins a binding block.
10
22
  #
11
23
  # @example Begin the bind.
@@ -30,6 +42,18 @@ module Mongoid #:nodoc:
30
42
  build_stack.push(true)
31
43
  end
32
44
 
45
+ # Begins a creating block.
46
+ #
47
+ # @example Begin the create.
48
+ # Threaded.begin_create
49
+ #
50
+ # @return [ true ] Always true.
51
+ #
52
+ # @since 2.1.9
53
+ def begin_create
54
+ create_stack.push(true)
55
+ end
56
+
33
57
  # Begin validating a document on the current thread.
34
58
  #
35
59
  # @example Begin validation.
@@ -42,6 +66,18 @@ module Mongoid #:nodoc:
42
66
  validations_for(document.class).push(document.id)
43
67
  end
44
68
 
69
+ # Is the current thread in assigning mode?
70
+ #
71
+ # @example Is the thread in assigning mode?
72
+ # Threaded.assigning?
73
+ #
74
+ # @return [ true, false ] If the thread is in assigning mode?
75
+ #
76
+ # @since 2.1.0
77
+ def assigning?
78
+ !assign_stack.empty?
79
+ end
80
+
45
81
  # Is the current thread in binding mode?
46
82
  #
47
83
  # @example Is the thread in binding mode?
@@ -66,6 +102,31 @@ module Mongoid #:nodoc:
66
102
  !build_stack.empty?
67
103
  end
68
104
 
105
+ # Is the current thread in creating mode?
106
+ #
107
+ # @example Is the thread in creating mode?
108
+ # Threaded.creating?
109
+ #
110
+ # @return [ true, false ] If the thread is in creating mode?
111
+ #
112
+ # @since 2.1.0
113
+ def creating?
114
+ !create_stack.empty?
115
+ end
116
+
117
+ # Get the assign stack for the current thread. Is simply an array of calls
118
+ # to Mongoid's assigning method.
119
+ #
120
+ # @example Get the assign stack.
121
+ # Threaded.assign_stack
122
+ #
123
+ # @return [ Array ] The array of assign calls.
124
+ #
125
+ # @since 2.1.9
126
+ def assign_stack
127
+ Thread.current[:"[mongoid]:assign-stack"] ||= []
128
+ end
129
+
69
130
  # Get the bind stack for the current thread. Is simply an array of calls
70
131
  # to Mongoid's binding method.
71
132
  #
@@ -92,6 +153,19 @@ module Mongoid #:nodoc:
92
153
  Thread.current[:"[mongoid]:build-stack"] ||= []
93
154
  end
94
155
 
156
+ # Get the create stack for the current thread. Is simply an array of calls
157
+ # to Mongoid's creating method.
158
+ #
159
+ # @example Get the create stack.
160
+ # Threaded.create_stack
161
+ #
162
+ # @return [ Array ] The array of create calls.
163
+ #
164
+ # @since 2.1.9
165
+ def create_stack
166
+ Thread.current[:"[mongoid]:create-stack"] ||= []
167
+ end
168
+
95
169
  # Clear out all the safety options set using the safely proxy.
96
170
  #
97
171
  # @example Clear out the options.
@@ -104,6 +178,18 @@ module Mongoid #:nodoc:
104
178
  Thread.current[:"[mongoid]:safety-options"] = nil
105
179
  end
106
180
 
181
+ # Exit the assigning block.
182
+ #
183
+ # @example Exit the assigning block.
184
+ # Threaded.exit_assign
185
+ #
186
+ # @return [ true ] The last element in the stack.
187
+ #
188
+ # @since 2.1.9
189
+ def exit_assign
190
+ assign_stack.pop
191
+ end
192
+
107
193
  # Exit the binding block.
108
194
  #
109
195
  # @example Exit the binding block.
@@ -128,6 +214,18 @@ module Mongoid #:nodoc:
128
214
  build_stack.pop
129
215
  end
130
216
 
217
+ # Exit the creating block.
218
+ #
219
+ # @example Exit the creating block.
220
+ # Threaded.exit_create
221
+ #
222
+ # @return [ true ] The last element in the stack.
223
+ #
224
+ # @since 2.1.9
225
+ def exit_create
226
+ create_stack.pop
227
+ end
228
+
131
229
  # Exit validating a document on the current thread.
132
230
  #
133
231
  # @example Exit validation.