mongoid-pre 2.0.0.beta1 → 2.0.0.pre

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 (135) hide show
  1. data/.watchr +15 -10
  2. data/HISTORY +342 -0
  3. data/README.rdoc +8 -1
  4. data/Rakefile +2 -3
  5. data/VERSION +1 -1
  6. data/lib/mongoid/associations/{embedded_in.rb → belongs_to.rb} +4 -4
  7. data/lib/mongoid/associations/belongs_to_related.rb +9 -6
  8. data/lib/mongoid/associations/{embeds_many.rb → has_many.rb} +20 -33
  9. data/lib/mongoid/associations/has_many_related.rb +4 -28
  10. data/lib/mongoid/associations/{embeds_one.rb → has_one.rb} +6 -6
  11. data/lib/mongoid/associations/options.rb +6 -1
  12. data/lib/mongoid/associations.rb +32 -41
  13. data/lib/mongoid/attributes.rb +6 -13
  14. data/lib/mongoid/collection.rb +1 -2
  15. data/lib/mongoid/commands/delete.rb +1 -1
  16. data/lib/mongoid/commands/delete_all.rb +1 -4
  17. data/lib/mongoid/commands/destroy.rb +1 -1
  18. data/lib/mongoid/commands/destroy_all.rb +1 -3
  19. data/lib/mongoid/commands/save.rb +0 -1
  20. data/lib/mongoid/commands.rb +13 -2
  21. data/lib/mongoid/components.rb +1 -6
  22. data/lib/mongoid/config.rb +1 -5
  23. data/lib/mongoid/contexts/enumerable.rb +17 -54
  24. data/lib/mongoid/contexts/mongo.rb +38 -101
  25. data/lib/mongoid/contexts/paging.rb +2 -2
  26. data/lib/mongoid/contexts.rb +0 -21
  27. data/lib/mongoid/criteria.rb +73 -15
  28. data/lib/mongoid/criterion/inclusion.rb +0 -2
  29. data/lib/mongoid/criterion/optional.rb +2 -10
  30. data/lib/mongoid/document.rb +30 -41
  31. data/lib/mongoid/extensions.rb +0 -15
  32. data/lib/mongoid/field.rb +7 -20
  33. data/lib/mongoid/fields.rb +10 -15
  34. data/lib/mongoid/finders.rb +98 -10
  35. data/lib/mongoid/identity.rb +2 -8
  36. data/lib/mongoid/named_scope.rb +0 -2
  37. data/lib/mongoid/validations/associated.rb +8 -3
  38. data/lib/mongoid/validations/uniqueness.rb +7 -2
  39. data/lib/mongoid/validations.rb +2 -2
  40. data/lib/mongoid/versioning.rb +1 -1
  41. data/lib/mongoid.rb +5 -21
  42. data/mongoid.gemspec +19 -59
  43. data/spec/integration/mongoid/associations_spec.rb +3 -42
  44. data/spec/integration/mongoid/attributes_spec.rb +2 -2
  45. data/spec/integration/mongoid/commands_spec.rb +13 -27
  46. data/spec/integration/mongoid/contexts/enumerable_spec.rb +0 -13
  47. data/spec/integration/mongoid/criteria_spec.rb +3 -50
  48. data/spec/integration/mongoid/document_spec.rb +5 -72
  49. data/spec/integration/mongoid/finders_spec.rb +28 -85
  50. data/spec/models/address.rb +3 -3
  51. data/spec/models/animal.rb +2 -2
  52. data/spec/models/country_code.rb +2 -2
  53. data/spec/models/game.rb +1 -2
  54. data/spec/models/inheritance.rb +5 -5
  55. data/spec/models/location.rb +2 -2
  56. data/spec/models/name.rb +3 -3
  57. data/spec/models/namespacing.rb +2 -2
  58. data/spec/models/patient.rb +0 -2
  59. data/spec/models/person.rb +4 -6
  60. data/spec/models/pet.rb +3 -3
  61. data/spec/models/pet_owner.rb +3 -3
  62. data/spec/models/phone.rb +3 -3
  63. data/spec/models/post.rb +1 -1
  64. data/spec/models/translation.rb +2 -2
  65. data/spec/models/vet_visit.rb +2 -2
  66. data/spec/spec_helper.rb +2 -2
  67. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +0 -4
  68. data/spec/unit/mongoid/associations/{embedded_in_spec.rb → belongs_to_spec.rb} +11 -11
  69. data/spec/unit/mongoid/associations/has_many_related_spec.rb +14 -45
  70. data/spec/unit/mongoid/associations/{embeds_many_spec.rb → has_many_spec.rb} +34 -79
  71. data/spec/unit/mongoid/associations/{embeds_one_spec.rb → has_one_spec.rb} +18 -18
  72. data/spec/unit/mongoid/associations/options_spec.rb +19 -20
  73. data/spec/unit/mongoid/associations_spec.rb +12 -74
  74. data/spec/unit/mongoid/attributes_spec.rb +51 -83
  75. data/spec/unit/mongoid/collection_spec.rb +0 -46
  76. data/spec/unit/mongoid/commands/delete_all_spec.rb +8 -9
  77. data/spec/unit/mongoid/commands/delete_spec.rb +3 -6
  78. data/spec/unit/mongoid/commands/destroy_all_spec.rb +2 -0
  79. data/spec/unit/mongoid/commands/destroy_spec.rb +3 -10
  80. data/spec/unit/mongoid/commands_spec.rb +11 -20
  81. data/spec/unit/mongoid/config_spec.rb +0 -18
  82. data/spec/unit/mongoid/contexts/enumerable_spec.rb +11 -198
  83. data/spec/unit/mongoid/contexts/mongo_spec.rb +54 -357
  84. data/spec/unit/mongoid/criteria_spec.rb +78 -107
  85. data/spec/unit/mongoid/criterion/exclusion_spec.rb +13 -3
  86. data/spec/unit/mongoid/criterion/inclusion_spec.rb +19 -25
  87. data/spec/unit/mongoid/criterion/optional_spec.rb +18 -25
  88. data/spec/unit/mongoid/document_spec.rb +34 -71
  89. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +2 -2
  90. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +3 -0
  91. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +2 -16
  92. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +1 -1
  93. data/spec/unit/mongoid/field_spec.rb +0 -62
  94. data/spec/unit/mongoid/fields_spec.rb +0 -33
  95. data/spec/unit/mongoid/finders_spec.rb +1 -37
  96. data/spec/unit/mongoid/identity_spec.rb +6 -47
  97. data/spec/unit/mongoid/named_scope_spec.rb +2 -15
  98. data/spec/unit/mongoid/scope_spec.rb +1 -1
  99. data/spec/unit/mongoid/validations/uniqueness_spec.rb +3 -3
  100. data/spec/unit/mongoid_spec.rb +2 -11
  101. metadata +14 -64
  102. data/lib/mongoid/associations/meta_data.rb +0 -28
  103. data/lib/mongoid/contexts/ids.rb +0 -25
  104. data/lib/mongoid/deprecation.rb +0 -22
  105. data/lib/mongoid/dirty.rb +0 -203
  106. data/lib/mongoid/extensions/big_decimal/conversions.rb +0 -19
  107. data/lib/mongoid/extensions/binary/conversions.rb +0 -17
  108. data/lib/mongoid/extensions/objectid/conversions.rb +0 -15
  109. data/lib/mongoid/extras.rb +0 -61
  110. data/lib/mongoid/javascript/functions.yml +0 -37
  111. data/lib/mongoid/javascript.rb +0 -21
  112. data/lib/mongoid/observable.rb +0 -30
  113. data/lib/mongoid/paths.rb +0 -54
  114. data/lib/mongoid/persistence/command.rb +0 -20
  115. data/lib/mongoid/persistence/insert.rb +0 -71
  116. data/lib/mongoid/persistence/update.rb +0 -78
  117. data/lib/mongoid/persistence.rb +0 -27
  118. data/lib/mongoid/state.rb +0 -32
  119. data/spec/integration/mongoid/dirty_spec.rb +0 -70
  120. data/spec/integration/mongoid/persistence/update_spec.rb +0 -46
  121. data/spec/models/callbacks.rb +0 -18
  122. data/spec/unit/mongoid/associations/meta_data_spec.rb +0 -88
  123. data/spec/unit/mongoid/contexts_spec.rb +0 -25
  124. data/spec/unit/mongoid/deprecation_spec.rb +0 -24
  125. data/spec/unit/mongoid/dirty_spec.rb +0 -286
  126. data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +0 -22
  127. data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +0 -22
  128. data/spec/unit/mongoid/extras_spec.rb +0 -102
  129. data/spec/unit/mongoid/javascript_spec.rb +0 -48
  130. data/spec/unit/mongoid/observable_spec.rb +0 -46
  131. data/spec/unit/mongoid/paths_spec.rb +0 -124
  132. data/spec/unit/mongoid/persistence/insert_spec.rb +0 -175
  133. data/spec/unit/mongoid/persistence/update_spec.rb +0 -148
  134. data/spec/unit/mongoid/persistence_spec.rb +0 -40
  135. data/spec/unit/mongoid/state_spec.rb +0 -83
@@ -2,11 +2,10 @@
2
2
  module Mongoid #:nodoc:
3
3
  module Contexts #:nodoc:
4
4
  class Mongo
5
- include Ids, Paging
6
- attr_reader :criteria
7
-
8
- delegate :klass, :options, :selector, :to => :criteria
5
+ include Paging
6
+ attr_reader :selector, :options, :klass
9
7
 
8
+ AGGREGATE_REDUCE = "function(obj, prev) { prev.count++; }"
10
9
  # Aggregate the context. This will take the internally built selector and options
11
10
  # and pass them on to the Ruby driver's +group()+ method on the collection. The
12
11
  # collection itself will be retrieved from the class provided, and once the
@@ -20,40 +19,9 @@ module Mongoid #:nodoc:
20
19
  #
21
20
  # A +Hash+ with field values as keys, counts as values
22
21
  def aggregate
23
- klass.collection.group(options[:fields], selector, { :count => 0 }, Javascript.aggregate, true)
24
- end
25
-
26
- # Get the average value for the supplied field.
27
- #
28
- # This will take the internally built selector and options
29
- # and pass them on to the Ruby driver's +group()+ method on the collection. The
30
- # collection itself will be retrieved from the class provided, and once the
31
- # query has returned it will provided a grouping of keys with averages.
32
- #
33
- # Example:
34
- #
35
- # <tt>context.avg(:age)</tt>
36
- #
37
- # Returns:
38
- #
39
- # A numeric value that is the average.
40
- def avg(field)
41
- total = sum(field)
42
- total ? (total / count) : nil
43
- end
44
-
45
- # Determine if the context is empty or blank given the criteria. Will
46
- # perform a quick has_one asking only for the id.
47
- #
48
- # Example:
49
- #
50
- # <tt>context.blank?</tt>
51
- def blank?
52
- klass.collection.find_one(selector, { :fields => [ :_id ] }).nil?
22
+ @klass.collection.group(@options[:fields], @selector, { :count => 0 }, AGGREGATE_REDUCE, true)
53
23
  end
54
24
 
55
- alias :empty? :blank?
56
-
57
25
  # Get the count of matching documents in the database for the context.
58
26
  #
59
27
  # Example:
@@ -64,17 +32,7 @@ module Mongoid #:nodoc:
64
32
  #
65
33
  # An +Integer+ count of documents.
66
34
  def count
67
- @count ||= klass.collection.find(selector, process_options).count
68
- end
69
-
70
- # Gets an array of distinct values for the supplied field across the
71
- # entire collection or the susbset given the criteria.
72
- #
73
- # Example:
74
- #
75
- # <tt>context.distinct(:title)</tt>
76
- def distinct(field)
77
- klass.collection.distinct(field, selector)
35
+ @count ||= @klass.collection.find(@selector, process_options).count
78
36
  end
79
37
 
80
38
  # Execute the context. This will take the selector and options
@@ -84,13 +42,13 @@ module Mongoid #:nodoc:
84
42
  #
85
43
  # Example:
86
44
  #
87
- # <tt>context.execute</tt>
45
+ # <tt>mongo.execute</tt>
88
46
  #
89
47
  # Returns:
90
48
  #
91
49
  # An enumerable +Cursor+.
92
50
  def execute(paginating = false)
93
- cursor = klass.collection.find(selector, process_options)
51
+ cursor = @klass.collection.find(@selector, process_options)
94
52
  if cursor
95
53
  @count = cursor.count if paginating
96
54
  cursor
@@ -99,6 +57,7 @@ module Mongoid #:nodoc:
99
57
  end
100
58
  end
101
59
 
60
+ GROUP_REDUCE = "function(obj, prev) { prev.group.push(obj); }"
102
61
  # Groups the context. This will take the internally built selector and options
103
62
  # and pass them on to the Ruby driver's +group()+ method on the collection. The
104
63
  # collection itself will be retrieved from the class provided, and once the
@@ -112,14 +71,15 @@ module Mongoid #:nodoc:
112
71
  #
113
72
  # A +Hash+ with field values as keys, arrays of documents as values.
114
73
  def group
115
- klass.collection.group(
116
- options[:fields],
117
- selector,
74
+ @klass.collection.group(
75
+ @options[:fields],
76
+ @selector,
118
77
  { :group => [] },
119
- Javascript.group
78
+ GROUP_REDUCE,
79
+ true
120
80
  ).collect do |docs|
121
81
  docs["group"] = docs["group"].collect do |attrs|
122
- Mongoid::Factory.build(klass, attrs)
82
+ Mongoid::Factory.build(@klass, attrs)
123
83
  end
124
84
  docs
125
85
  end
@@ -130,26 +90,11 @@ module Mongoid #:nodoc:
130
90
  #
131
91
  # Example:
132
92
  #
133
- # <tt>Mongoid::Contexts::Mongo.new(criteria)</tt>
134
- def initialize(criteria)
135
- @criteria = criteria
136
- if klass.hereditary && Mongoid.persist_types
137
- criteria.in(:_type => criteria.klass._types)
138
- end
139
- criteria.enslave if klass.enslaved?
140
- criteria.cache if klass.cached?
141
- end
142
-
143
- # Iterate over each +Document+ in the results. This can take an optional
144
- # block to pass to each argument in the results.
145
- #
146
- # Example:
147
- #
148
- # <tt>context.iterate { |doc| p doc }</tt>
149
- def iterate(&block)
150
- return caching(&block) if criteria.cached?
151
- if block_given?
152
- execute.each { |doc| yield doc }
93
+ # <tt>Mongoid::Contexts::Mongo.new(selector, options, klass)</tt>
94
+ def initialize(selector, options, klass)
95
+ @selector, @options, @klass = selector, options, klass
96
+ if klass.hereditary
97
+ @hereditary = true
153
98
  end
154
99
  end
155
100
 
@@ -169,10 +114,12 @@ module Mongoid #:nodoc:
169
114
  sorting = opts[:sort]
170
115
  sorting = [[:_id, :asc]] unless sorting
171
116
  opts[:sort] = sorting.collect { |option| [ option[0], option[1].invert ] }
172
- attributes = klass.collection.find_one(selector, opts)
173
- attributes ? Mongoid::Factory.build(klass, attributes) : nil
117
+ attributes = @klass.collection.find_one(@selector, opts)
118
+ attributes ? Mongoid::Factory.build(@klass, attributes) : nil
174
119
  end
175
120
 
121
+ MAX_REDUCE = "function(obj, prev) { if (prev.max == 'start') { prev.max = obj.[field]; } " +
122
+ "if (prev.max < obj.[field]) { prev.max = obj.[field]; } }"
176
123
  # Return the max value for a field.
177
124
  #
178
125
  # This will take the internally built selector and options
@@ -188,9 +135,11 @@ module Mongoid #:nodoc:
188
135
  #
189
136
  # A numeric max value.
190
137
  def max(field)
191
- grouped(:max, field.to_s, Javascript.max)
138
+ grouped(:max, field.to_s, MAX_REDUCE)
192
139
  end
193
140
 
141
+ MIN_REDUCE = "function(obj, prev) { if (prev.min == 'start') { prev.min = obj.[field]; } " +
142
+ "if (prev.min > obj.[field]) { prev.min = obj.[field]; } }"
194
143
  # Return the min value for a field.
195
144
  #
196
145
  # This will take the internally built selector and options
@@ -206,7 +155,7 @@ module Mongoid #:nodoc:
206
155
  #
207
156
  # A numeric minimum value.
208
157
  def min(field)
209
- grouped(:min, field.to_s, Javascript.min)
158
+ grouped(:min, field.to_s, MIN_REDUCE)
210
159
  end
211
160
 
212
161
  # Return the first result for the +Context+.
@@ -219,12 +168,13 @@ module Mongoid #:nodoc:
219
168
  #
220
169
  # The first document in the collection.
221
170
  def one
222
- attributes = klass.collection.find_one(selector, process_options)
223
- attributes ? Mongoid::Factory.build(klass, attributes) : nil
171
+ attributes = @klass.collection.find_one(@selector, process_options)
172
+ attributes ? Mongoid::Factory.build(@klass, attributes) : nil
224
173
  end
225
174
 
226
175
  alias :first :one
227
176
 
177
+ SUM_REDUCE = "function(obj, prev) { if (prev.sum == 'start') { prev.sum = 0; } prev.sum += obj.[field]; }"
228
178
  # Sum the context.
229
179
  #
230
180
  # This will take the internally built selector and options
@@ -240,17 +190,18 @@ module Mongoid #:nodoc:
240
190
  #
241
191
  # A numeric value that is the sum.
242
192
  def sum(field)
243
- grouped(:sum, field.to_s, Javascript.sum)
193
+ grouped(:sum, field.to_s, SUM_REDUCE)
244
194
  end
245
195
 
246
196
  # Common functionality for grouping operations. Currently used by min, max
247
197
  # and sum. Will gsub the field name in the supplied reduce function.
248
198
  def grouped(start, field, reduce)
249
- collection = klass.collection.group(
199
+ collection = @klass.collection.group(
250
200
  nil,
251
- selector,
201
+ @selector,
252
202
  { start => "start" },
253
- reduce.gsub("[field]", field)
203
+ reduce.gsub("[field]", field),
204
+ true
254
205
  )
255
206
  collection.empty? ? nil : collection.first[start.to_s]
256
207
  end
@@ -258,28 +209,14 @@ module Mongoid #:nodoc:
258
209
  # Filters the field list. If no fields have been supplied, then it will be
259
210
  # empty. If fields have been defined then _type will be included as well.
260
211
  def process_options
261
- fields = options[:fields]
212
+ fields = @options[:fields]
262
213
  if fields && fields.size > 0 && !fields.include?(:_type)
263
214
  fields << :_type
264
- options[:fields] = fields
215
+ @options[:fields] = fields
265
216
  end
266
- options.dup
217
+ @options.dup
267
218
  end
268
219
 
269
- protected
270
-
271
- # Iterate over each +Document+ in the results and cache the collection.
272
- def caching(&block)
273
- if defined? @collection
274
- @collection.each(&block)
275
- else
276
- @collection = []
277
- execute.each do |doc|
278
- @collection << doc
279
- yield doc if block_given?
280
- end
281
- end
282
- end
283
220
  end
284
221
  end
285
222
  end
@@ -25,7 +25,7 @@ module Mongoid #:nodoc:
25
25
  #
26
26
  # An +Integer+ page number.
27
27
  def page
28
- skips, limits = options[:skip], options[:limit]
28
+ skips, limits = @options[:skip], @options[:limit]
29
29
  (skips && limits) ? (skips + limits) / limits : 1
30
30
  end
31
31
 
@@ -35,7 +35,7 @@ module Mongoid #:nodoc:
35
35
  #
36
36
  # The +Integer+ number of documents in each page.
37
37
  def per_page
38
- (options[:limit] || 20).to_i
38
+ (@options[:limit] || 20).to_i
39
39
  end
40
40
  end
41
41
  end
@@ -1,25 +1,4 @@
1
1
  # encoding: utf-8
2
- require "mongoid/contexts/ids"
3
2
  require "mongoid/contexts/paging"
4
3
  require "mongoid/contexts/enumerable"
5
4
  require "mongoid/contexts/mongo"
6
-
7
- module Mongoid
8
- module Contexts
9
- # Determines the context to be used for this criteria. If the class is an
10
- # embedded document, then the context will be the array in the has_many
11
- # association it is in. If the class is a root, then the database itself
12
- # will be the context.
13
- #
14
- # Example:
15
- #
16
- # <tt>Contexts.context_for(criteria)</tt>
17
- def self.context_for(criteria)
18
- if criteria.klass.embedded
19
- return Contexts::Enumerable.new(criteria)
20
- end
21
- Contexts::Mongo.new(criteria)
22
- end
23
-
24
- end
25
- end
@@ -26,19 +26,15 @@ module Mongoid #:nodoc:
26
26
  include Enumerable
27
27
 
28
28
  attr_reader :collection, :ids, :klass, :options, :selector
29
+
29
30
  attr_accessor :documents
30
31
 
31
32
  delegate \
32
33
  :aggregate,
33
- :avg,
34
- :blank?,
35
34
  :count,
36
- :distinct,
37
- :empty?,
38
35
  :execute,
39
36
  :first,
40
37
  :group,
41
- :id_criteria,
42
38
  :last,
43
39
  :max,
44
40
  :min,
@@ -79,12 +75,23 @@ module Mongoid #:nodoc:
79
75
  end
80
76
  end
81
77
 
78
+ # Returns true if the criteria is empty.
79
+ #
80
+ # Example:
81
+ #
82
+ # <tt>criteria.blank?</tt>
83
+ def blank?
84
+ count < 1
85
+ end
86
+
87
+ alias :empty? :blank?
88
+
82
89
  # Return or create the context in which this criteria should be executed.
83
90
  #
84
91
  # This will return an Enumerable context if the class is embedded,
85
92
  # otherwise it will return a Mongo context for root classes.
86
93
  def context
87
- @context ||= Contexts.context_for(self)
94
+ @context ||= determine_context
88
95
  end
89
96
 
90
97
  # Iterate over each +Document+ in the results. This can take an optional
@@ -94,7 +101,10 @@ module Mongoid #:nodoc:
94
101
  #
95
102
  # <tt>criteria.each { |doc| p doc }</tt>
96
103
  def each(&block)
97
- context.iterate(&block)
104
+ return each_cached(&block) if cached?
105
+ if block_given?
106
+ execute.each { |doc| yield doc }
107
+ end
98
108
  self
99
109
  end
100
110
 
@@ -124,6 +134,10 @@ module Mongoid #:nodoc:
124
134
  # klass: The class to execute on.
125
135
  def initialize(klass)
126
136
  @selector, @options, @klass, @documents = {}, {}, klass, []
137
+ if klass.hereditary
138
+ @selector = { :_type => { "$in" => klass._types } }
139
+ @hereditary = true
140
+ end
127
141
  end
128
142
 
129
143
  # Merges another object into this +Criteria+. The other object may be a
@@ -154,7 +168,7 @@ module Mongoid #:nodoc:
154
168
  # Returns: <tt>Criteria</tt>
155
169
  def method_missing(name, *args)
156
170
  if @klass.respond_to?(name)
157
- new_scope = @klass.send(name, *args)
171
+ new_scope = @klass.send(name)
158
172
  new_scope.merge(self)
159
173
  return new_scope
160
174
  else
@@ -190,17 +204,40 @@ module Mongoid #:nodoc:
190
204
  klass = args[0]
191
205
  params = args[1] || {}
192
206
  unless params.is_a?(Hash)
193
- return new(klass).id_criteria(params)
207
+ return id_criteria(klass, params)
194
208
  end
195
- conditions = params.delete(:conditions) || {}
196
- if conditions.include?(:id)
197
- conditions[:_id] = conditions[:id]
198
- conditions.delete(:id)
199
- end
200
- return new(klass).where(conditions).extras(params)
209
+ return new(klass).where(params.delete(:conditions) || {}).extras(params)
201
210
  end
202
211
 
203
212
  protected
213
+ # Determines the context to be used for this criteria. If the class is an
214
+ # embedded document, then thw context will be the array in the has_many
215
+ # association it is in. If the class is a root, then the database itself
216
+ # will be the context.
217
+ #
218
+ # Example:
219
+ #
220
+ # <tt>criteria#determine_context</tt>
221
+ def determine_context
222
+ if @klass.embedded
223
+ return Contexts::Enumerable.new(@selector, @options, @documents)
224
+ end
225
+ Contexts::Mongo.new(@selector, @options, @klass)
226
+ end
227
+
228
+ # Iterate over each +Document+ in the results and cache the collection.
229
+ def each_cached(&block)
230
+ @collection ||= execute
231
+ if block_given?
232
+ docs = []
233
+ @collection.each do |doc|
234
+ docs << doc
235
+ yield doc
236
+ end
237
+ @collection = docs
238
+ end
239
+ self
240
+ end
204
241
 
205
242
  # Filters the unused options out of the options +Hash+. Currently this
206
243
  # takes into account the "page" and "per_page" options that would be passed
@@ -235,5 +272,26 @@ module Mongoid #:nodoc:
235
272
  def update_selector(attributes, operator)
236
273
  attributes.each { |key, value| @selector[key] = { operator => value } }; self
237
274
  end
275
+
276
+ class << self
277
+ # Create a criteria or single document based on an id search. Will handle
278
+ # if a single id has been passed or mulitple ids.
279
+ #
280
+ # Example:
281
+ #
282
+ # Criteria.id_criteria(Person, [1, 2, 3])
283
+ #
284
+ # Returns:
285
+ #
286
+ # The single or multiple documents.
287
+ def id_criteria(klass, params)
288
+ criteria = new(klass).id(params)
289
+ result = params.is_a?(String) ? criteria.one : criteria.entries
290
+ if Mongoid.raise_not_found_error
291
+ raise Errors::DocumentNotFound.new(klass, params) if result.blank?
292
+ end
293
+ return result
294
+ end
295
+ end
238
296
  end
239
297
  end
@@ -22,7 +22,6 @@ module Mongoid #:nodoc:
22
22
  def all(attributes = {})
23
23
  update_selector(attributes, "$all")
24
24
  end
25
- alias :all_in :all
26
25
 
27
26
  # Adds a criterion to the +Criteria+ that specifies values that must
28
27
  # be matched in order to return results. This is similar to a SQL "WHERE"
@@ -62,7 +61,6 @@ module Mongoid #:nodoc:
62
61
  def in(attributes = {})
63
62
  update_selector(attributes, "$in")
64
63
  end
65
- alias :any_in :in
66
64
 
67
65
  # Adds a criterion to the +Criteria+ that specifies values that must
68
66
  # be matched in order to return results. This is similar to a SQL "WHERE"
@@ -20,7 +20,8 @@ module Mongoid #:nodoc:
20
20
  #
21
21
  # <tt>criteria.cached?</tt>
22
22
  def cached?
23
- @options[:cache] == true
23
+ @cached ||= @options.delete(:cache)
24
+ @cached == true
24
25
  end
25
26
 
26
27
  # Flags the criteria to execute against a read-only slave in the pool
@@ -33,15 +34,6 @@ module Mongoid #:nodoc:
33
34
  @options.merge!(:enslave => true); self
34
35
  end
35
36
 
36
- # Will return true if the criteria is enslaved.
37
- #
38
- # Example:
39
- #
40
- # <tt>criteria.enslaved?</tt>
41
- def enslaved?
42
- @options[:enslave] == true
43
- end
44
-
45
37
  # Adds a criterion to the +Criteria+ that specifies additional options
46
38
  # to be passed to the Ruby driver, in the exact format for the driver.
47
39
  #
@@ -5,7 +5,12 @@ module Mongoid #:nodoc:
5
5
  included do
6
6
  include Mongoid::Components
7
7
 
8
- cattr_accessor :_collection, :collection_name, :embedded, :primary_key, :hereditary
8
+ cattr_accessor \
9
+ :_collection,
10
+ :collection_name,
11
+ :embedded,
12
+ :primary_key,
13
+ :hereditary
9
14
 
10
15
  self.embedded = false
11
16
  self.hereditary = false
@@ -51,7 +56,6 @@ module Mongoid #:nodoc:
51
56
  if attributes["_id"] || allocating
52
57
  document = allocate
53
58
  document.instance_variable_set(:@attributes, attributes)
54
- document.setup_modifications
55
59
  return document
56
60
  else
57
61
  return new(attrs)
@@ -67,6 +71,8 @@ module Mongoid #:nodoc:
67
71
  #
68
72
  # class Person
69
73
  # include Mongoid::Document
74
+ # field :first_name
75
+ # field :last_name
70
76
  # key :first_name, :last_name
71
77
  # end
72
78
  def key(*fields)
@@ -88,10 +94,11 @@ module Mongoid #:nodoc:
88
94
  def _types
89
95
  @_type ||= (subclasses_of(self).map { |o| o.to_s } + [ self.name ])
90
96
  end
91
-
97
+
92
98
  # return the list of subclassses for an object
93
99
  def subclasses_of(*superclasses) #:nodoc:
94
100
  subclasses = []
101
+
95
102
  superclasses.each do |sup|
96
103
  ObjectSpace.each_object(class << sup; self; end) do |k|
97
104
  if k != sup && (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
@@ -99,6 +106,7 @@ module Mongoid #:nodoc:
99
106
  end
100
107
  end
101
108
  end
109
+
102
110
  subclasses
103
111
  end
104
112
  end
@@ -112,17 +120,6 @@ module Mongoid #:nodoc:
112
120
  other.attributes.except(:modified_at).except(:created_at)
113
121
  end
114
122
 
115
- # Delegates to ==
116
- def eql?(comparison_object)
117
- self == (comparison_object)
118
- end
119
-
120
- # Delegates to id in order to allow two records of the same type and id to work with something like:
121
- # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
122
- def hash
123
- id.hash
124
- end
125
-
126
123
  # Introduces a child object into the +Document+ object graph. This will
127
124
  # set up the relationships between the parent and child and update the
128
125
  # attributes of the parent +Document+.
@@ -131,6 +128,10 @@ module Mongoid #:nodoc:
131
128
  #
132
129
  # parent: The +Document+ to assimilate with.
133
130
  # options: The association +Options+ for the child.
131
+ #
132
+ # Example:
133
+ #
134
+ # <tt>name.assimilate(person, options)</tt>
134
135
  def assimilate(parent, options)
135
136
  parentize(parent, options.name); notify; self
136
137
  end
@@ -176,12 +177,25 @@ module Mongoid #:nodoc:
176
177
  "#<#{self.class.name} _id: #{id}, #{attrs}>"
177
178
  end
178
179
 
179
- # Notify observers of an update.
180
+ # Returns true is the +Document+ has not been persisted to the database,
181
+ # false if it has. This is determined by the variable @new_record
182
+ # and NOT if the object has an id.
183
+ def new_record?
184
+ @new_record == true
185
+ end
186
+
187
+ # Sets the new_record boolean - used after document is saved.
188
+ def new_record=(saved)
189
+ @new_record = saved
190
+ end
191
+
192
+ # Set the changed state of the +Document+ then notify observers that it has changed.
180
193
  #
181
194
  # Example:
182
195
  #
183
196
  # <tt>person.notify</tt>
184
197
  def notify
198
+ changed(true)
185
199
  notify_observers(self)
186
200
  end
187
201
 
@@ -211,7 +225,6 @@ module Mongoid #:nodoc:
211
225
  # Reloads the +Document+ attributes from the database.
212
226
  def reload
213
227
  @attributes = collection.find_one(:_id => id)
214
- self
215
228
  end
216
229
 
217
230
  # Remove a child document from this parent +Document+. Will reset the
@@ -246,30 +259,6 @@ module Mongoid #:nodoc:
246
259
  attributes.to_json(options)
247
260
  end
248
261
 
249
- # Return an object to be encoded into a JSON string.
250
- # Used by Rails 3's object->JSON chain to create JSON
251
- # in a backend-agnostic way
252
- #
253
- # Example:
254
- #
255
- # <tt>person.as_json</tt>
256
- def as_json(options = nil)
257
- attributes
258
- end
259
-
260
- # Return this document as an object to be encoded as JSON,
261
- # with any particular items modified on a per-encoder basis.
262
- # Nothing special is required here since Mongoid bubbles up
263
- # all the child associations to the parent attribute +Hash+
264
- # using observers throughout the +Document+ lifecycle.
265
- #
266
- # Example:
267
- #
268
- # <tt>person.encode_json(encoder)</tt>
269
- def encode_json(encoder)
270
- attributes
271
- end
272
-
273
262
  # Returns the id of the Document, used in Rails compatibility.
274
263
  def to_param
275
264
  id
@@ -286,7 +275,7 @@ module Mongoid #:nodoc:
286
275
  #
287
276
  # This will also cause the observing +Document+ to notify it's parent if
288
277
  # there is any.
289
- def observe(child, clear = false)
278
+ def update(child, clear = false)
290
279
  name = child.association_name
291
280
  attrs = child.instance_variable_get(:@attributes)
292
281
  clear ? @attributes.delete(name) : @attributes.insert(name, attrs)
@@ -4,8 +4,6 @@ require "mongoid/extensions/array/aliasing"
4
4
  require "mongoid/extensions/array/assimilation"
5
5
  require "mongoid/extensions/array/conversions"
6
6
  require "mongoid/extensions/array/parentization"
7
- require "mongoid/extensions/big_decimal/conversions"
8
- require "mongoid/extensions/binary/conversions"
9
7
  require "mongoid/extensions/boolean/conversions"
10
8
  require "mongoid/extensions/date/conversions"
11
9
  require "mongoid/extensions/datetime/conversions"
@@ -23,7 +21,6 @@ require "mongoid/extensions/string/conversions"
23
21
  require "mongoid/extensions/string/inflections"
24
22
  require "mongoid/extensions/symbol/inflections"
25
23
  require "mongoid/extensions/time/conversions"
26
- require "mongoid/extensions/objectid/conversions"
27
24
 
28
25
  class Array #:nodoc
29
26
  include Mongoid::Extensions::Array::Accessors
@@ -32,14 +29,6 @@ class Array #:nodoc
32
29
  include Mongoid::Extensions::Array::Parentization
33
30
  end
34
31
 
35
- class BigDecimal #:nodoc
36
- extend Mongoid::Extensions::BigDecimal::Conversions
37
- end
38
-
39
- class Binary #:nodoc
40
- extend Mongoid::Extensions::Binary::Conversions
41
- end
42
-
43
32
  class Boolean #:nodoc
44
33
  extend Mongoid::Extensions::Boolean::Conversions
45
34
  end
@@ -93,7 +82,3 @@ end
93
82
  class Time #:nodoc
94
83
  extend Mongoid::Extensions::Time::Conversions
95
84
  end
96
-
97
- class Mongo::ObjectID #:nodoc
98
- extend Mongoid::Extensions::ObjectID::Conversions
99
- end