mongoid 1.2.6 → 1.2.7

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 (52) hide show
  1. data/VERSION +1 -1
  2. data/lib/mongoid.rb +1 -0
  3. data/lib/mongoid/associations.rb +1 -1
  4. data/lib/mongoid/attributes.rb +1 -0
  5. data/lib/mongoid/collection.rb +1 -1
  6. data/lib/mongoid/commands.rb +1 -1
  7. data/lib/mongoid/commands/delete_all.rb +2 -1
  8. data/lib/mongoid/commands/destroy_all.rb +1 -1
  9. data/lib/mongoid/components.rb +1 -0
  10. data/lib/mongoid/config.rb +3 -1
  11. data/lib/mongoid/contexts.rb +21 -0
  12. data/lib/mongoid/contexts/enumerable.rb +15 -12
  13. data/lib/mongoid/contexts/ids.rb +25 -0
  14. data/lib/mongoid/contexts/mongo.rb +25 -23
  15. data/lib/mongoid/contexts/paging.rb +2 -2
  16. data/lib/mongoid/criteria.rb +5 -43
  17. data/lib/mongoid/document.rb +1 -0
  18. data/lib/mongoid/enslavement.rb +38 -0
  19. data/lib/mongoid/fields.rb +5 -2
  20. data/lib/mongoid/identity.rb +7 -1
  21. data/lib/mongoid/named_scope.rb +2 -0
  22. data/mongoid.gemspec +8 -2
  23. data/spec/integration/mongoid/commands_spec.rb +2 -2
  24. data/spec/integration/mongoid/contexts/enumerable_spec.rb +13 -0
  25. data/spec/integration/mongoid/criteria_spec.rb +2 -2
  26. data/spec/integration/mongoid/document_spec.rb +5 -1
  27. data/spec/integration/mongoid/finders_spec.rb +85 -28
  28. data/spec/models/person.rb +1 -0
  29. data/spec/unit/mongoid/associations_spec.rb +12 -0
  30. data/spec/unit/mongoid/attributes_spec.rb +60 -51
  31. data/spec/unit/mongoid/collection_spec.rb +30 -0
  32. data/spec/unit/mongoid/commands/delete_all_spec.rb +3 -3
  33. data/spec/unit/mongoid/commands_spec.rb +16 -0
  34. data/spec/unit/mongoid/config_spec.rb +7 -0
  35. data/spec/unit/mongoid/contexts/enumerable_spec.rb +151 -11
  36. data/spec/unit/mongoid/contexts/mongo_spec.rb +168 -42
  37. data/spec/unit/mongoid/contexts_spec.rb +25 -0
  38. data/spec/unit/mongoid/criteria_spec.rb +49 -75
  39. data/spec/unit/mongoid/criterion/exclusion_spec.rb +3 -13
  40. data/spec/unit/mongoid/criterion/inclusion_spec.rb +17 -19
  41. data/spec/unit/mongoid/criterion/optional_spec.rb +25 -8
  42. data/spec/unit/mongoid/document_spec.rb +4 -0
  43. data/spec/unit/mongoid/enslavement_spec.rb +63 -0
  44. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +2 -2
  45. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +2 -2
  46. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +1 -1
  47. data/spec/unit/mongoid/fields_spec.rb +10 -0
  48. data/spec/unit/mongoid/finders_spec.rb +1 -1
  49. data/spec/unit/mongoid/identity_spec.rb +23 -3
  50. data/spec/unit/mongoid/named_scope_spec.rb +15 -2
  51. data/spec/unit/mongoid/scope_spec.rb +1 -1
  52. metadata +8 -2
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.6
1
+ 1.2.7
@@ -47,6 +47,7 @@ require "mongoid/config"
47
47
  require "mongoid/contexts"
48
48
  require "mongoid/criteria"
49
49
  require "mongoid/cursor"
50
+ require "mongoid/enslavement"
50
51
  require "mongoid/extensions"
51
52
  require "mongoid/errors"
52
53
  require "mongoid/factory"
@@ -240,7 +240,7 @@ module Mongoid # :nodoc:
240
240
  def add_builder(type, options)
241
241
  name = options.name.to_s
242
242
  define_method("build_#{name}") do |attrs|
243
- reset(name) { type.new(self, attrs.stringify_keys, options) }
243
+ reset(name) { type.new(self, (attrs || {}).stringify_keys, options) }
244
244
  end
245
245
  end
246
246
 
@@ -129,6 +129,7 @@ module Mongoid #:nodoc:
129
129
  identify if id.blank?
130
130
  notify
131
131
  end
132
+ alias :attributes= write_attributes
132
133
 
133
134
  protected
134
135
  # Return true is dynamic field setting is enabled.
@@ -30,7 +30,7 @@ module Mongoid #:nodoc
30
30
  #
31
31
  # Either a +Master+ or +Slaves+ collection.
32
32
  def directed(options = {})
33
- enslave = options.delete(:enslave)
33
+ enslave = options.delete(:enslave) || @klass.enslaved?
34
34
  enslave ? master_or_slaves : master
35
35
  end
36
36
 
@@ -67,7 +67,7 @@ module Mongoid #:nodoc:
67
67
  rescue Mongo::OperationFailure => e
68
68
  errors.add(:mongoid, e.message)
69
69
  end
70
- run_callbacks(:after_create) if new
70
+ run_callbacks(:after_create) if new && saved
71
71
  saved
72
72
  end
73
73
 
@@ -14,8 +14,9 @@ module Mongoid #:nodoc:
14
14
  #
15
15
  # <tt>DeleteAll.execute(Person, :conditions => { :field => "value" })</tt>
16
16
  def self.execute(klass, params = {})
17
+ safe = Mongoid.persist_in_safe_mode
17
18
  collection = klass.collection
18
- collection.remove((params[:conditions] || {}).merge(:_type => klass.name))
19
+ collection.remove((params[:conditions] || {}).merge(:_type => klass.name), :safe => safe)
19
20
  end
20
21
  end
21
22
  end
@@ -16,7 +16,7 @@ module Mongoid #:nodoc:
16
16
  def self.execute(klass, params)
17
17
  conditions = params[:conditions] || {}
18
18
  params[:conditions] = conditions.merge(:_type => klass.name)
19
- klass.find(:all, params).each { |doc| Destroy.execute(doc) }
19
+ klass.find(:all, params).each { |doc| Destroy.execute(doc) }; true
20
20
  end
21
21
  end
22
22
  end
@@ -9,6 +9,7 @@ module Mongoid #:nodoc
9
9
  include Attributes
10
10
  include Callbacks
11
11
  include Commands
12
+ include Enslavement
12
13
  include Fields
13
14
  include Indexes
14
15
  include Matchers
@@ -8,7 +8,8 @@ module Mongoid #:nodoc
8
8
  :reconnect_time,
9
9
  :parameterize_keys,
10
10
  :persist_in_safe_mode,
11
- :raise_not_found_error
11
+ :raise_not_found_error,
12
+ :use_object_ids
12
13
 
13
14
  # Defaults the configuration options to true.
14
15
  def initialize
@@ -17,6 +18,7 @@ module Mongoid #:nodoc
17
18
  @persist_in_safe_mode = true
18
19
  @raise_not_found_error = true
19
20
  @reconnect_time = 3
21
+ @use_object_ids = false
20
22
  end
21
23
 
22
24
  # Sets the Mongo::DB master database to be used. If the object trying to me
@@ -1,4 +1,25 @@
1
1
  # encoding: utf-8
2
+ require "mongoid/contexts/ids"
2
3
  require "mongoid/contexts/paging"
3
4
  require "mongoid/contexts/enumerable"
4
5
  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
@@ -2,10 +2,11 @@
2
2
  module Mongoid #:nodoc:
3
3
  module Contexts #:nodoc:
4
4
  class Enumerable
5
- include Paging
6
- attr_reader :selector, :options, :documents
5
+ include Ids, Paging
6
+ attr_reader :criteria
7
7
 
8
8
  delegate :first, :last, :to => :execute
9
+ delegate :documents, :options, :selector, :to => :criteria
9
10
 
10
11
  # Return aggregation counts of the grouped documents. This will count by
11
12
  # the first field provided in the fields array.
@@ -21,7 +22,7 @@ module Mongoid #:nodoc:
21
22
 
22
23
  # Gets the number of documents in the array. Delegates to size.
23
24
  def count
24
- @count ||= @documents.size
25
+ @count ||= documents.size
25
26
  end
26
27
 
27
28
  # Groups the documents by the first field supplied in the field options.
@@ -30,8 +31,8 @@ module Mongoid #:nodoc:
30
31
  #
31
32
  # A +Hash+ with field values as keys, arrays of documents as values.
32
33
  def group
33
- field = @options[:fields].first
34
- @documents.group_by { |doc| doc.send(field) }
34
+ field = options[:fields].first
35
+ documents.group_by { |doc| doc.send(field) }
35
36
  end
36
37
 
37
38
  # Enumerable implementation of execute. Returns matching documents for
@@ -41,7 +42,7 @@ module Mongoid #:nodoc:
41
42
  #
42
43
  # An +Array+ of documents that matched the selector.
43
44
  def execute(paginating = false)
44
- limit(@documents.select { |document| document.matches?(@selector) })
45
+ limit(documents.select { |document| document.matches?(selector) })
45
46
  end
46
47
 
47
48
  # Create the new enumerable context. This will need the selector and
@@ -50,9 +51,9 @@ module Mongoid #:nodoc:
50
51
  #
51
52
  # Example:
52
53
  #
53
- # <tt>Mongoid::Contexts::Enumerable.new(selector, options, docs)</tt>
54
- def initialize(selector, options, documents)
55
- @selector, @options, @documents = selector, options, documents
54
+ # <tt>Mongoid::Contexts::Enumerable.new(criteria)</tt>
55
+ def initialize(criteria)
56
+ @criteria = criteria
56
57
  end
57
58
 
58
59
  # Get the largest value for the field in all the documents.
@@ -86,7 +87,7 @@ module Mongoid #:nodoc:
86
87
  #
87
88
  # The numerical sum of all the document field values.
88
89
  def sum(field)
89
- sum = @documents.inject(nil) do |memo, doc|
90
+ sum = documents.inject(nil) do |memo, doc|
90
91
  value = doc.send(field)
91
92
  memo ? memo += value : value
92
93
  end
@@ -95,7 +96,7 @@ module Mongoid #:nodoc:
95
96
  protected
96
97
  # If the field exists, perform the comparison and set if true.
97
98
  def determine(field, operator)
98
- matching = @documents.inject(nil) do |memo, doc|
99
+ matching = documents.inject(nil) do |memo, doc|
99
100
  value = doc.send(field)
100
101
  (memo && memo.send(operator, value)) ? memo : value
101
102
  end
@@ -103,9 +104,11 @@ module Mongoid #:nodoc:
103
104
 
104
105
  # Limits the result set if skip and limit options.
105
106
  def limit(documents)
106
- skip, limit = @options[:skip], @options[:limit]
107
+ skip, limit = options[:skip], options[:limit]
107
108
  if skip && limit
108
109
  return documents.slice(skip, limit)
110
+ elsif limit
111
+ return documents.first(limit)
109
112
  end
110
113
  documents
111
114
  end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Contexts #:nodoc:
4
+ module Ids
5
+ # Return documents based on an id search. Will handle if a single id has
6
+ # been passed or mulitple ids.
7
+ #
8
+ # Example:
9
+ #
10
+ # context.id_criteria([1, 2, 3])
11
+ #
12
+ # Returns:
13
+ #
14
+ # The single or multiple documents.
15
+ def id_criteria(params)
16
+ criteria.id(params)
17
+ result = params.is_a?(Array) ? criteria.entries : one
18
+ if Mongoid.raise_not_found_error
19
+ raise Errors::DocumentNotFound.new(klass, params) if result.blank?
20
+ end
21
+ return result
22
+ end
23
+ end
24
+ end
25
+ end
@@ -2,8 +2,10 @@
2
2
  module Mongoid #:nodoc:
3
3
  module Contexts #:nodoc:
4
4
  class Mongo
5
- include Paging
6
- attr_reader :selector, :options, :klass
5
+ include Ids, Paging
6
+ attr_reader :criteria
7
+
8
+ delegate :klass, :options, :selector, :to => :criteria
7
9
 
8
10
  AGGREGATE_REDUCE = "function(obj, prev) { prev.count++; }"
9
11
  # Aggregate the context. This will take the internally built selector and options
@@ -19,7 +21,7 @@ module Mongoid #:nodoc:
19
21
  #
20
22
  # A +Hash+ with field values as keys, counts as values
21
23
  def aggregate
22
- @klass.collection.group(@options[:fields], @selector, { :count => 0 }, AGGREGATE_REDUCE, true)
24
+ klass.collection.group(options[:fields], selector, { :count => 0 }, AGGREGATE_REDUCE, true)
23
25
  end
24
26
 
25
27
  # Get the count of matching documents in the database for the context.
@@ -32,7 +34,7 @@ module Mongoid #:nodoc:
32
34
  #
33
35
  # An +Integer+ count of documents.
34
36
  def count
35
- @count ||= @klass.collection.find(@selector, process_options).count
37
+ @count ||= klass.collection.find(selector, process_options).count
36
38
  end
37
39
 
38
40
  # Execute the context. This will take the selector and options
@@ -48,7 +50,7 @@ module Mongoid #:nodoc:
48
50
  #
49
51
  # An enumerable +Cursor+.
50
52
  def execute(paginating = false)
51
- cursor = @klass.collection.find(@selector, process_options)
53
+ cursor = klass.collection.find(selector, process_options)
52
54
  if cursor
53
55
  @count = cursor.count if paginating
54
56
  cursor
@@ -71,15 +73,15 @@ module Mongoid #:nodoc:
71
73
  #
72
74
  # A +Hash+ with field values as keys, arrays of documents as values.
73
75
  def group
74
- @klass.collection.group(
75
- @options[:fields],
76
- @selector,
76
+ klass.collection.group(
77
+ options[:fields],
78
+ selector,
77
79
  { :group => [] },
78
80
  GROUP_REDUCE,
79
81
  true
80
82
  ).collect do |docs|
81
83
  docs["group"] = docs["group"].collect do |attrs|
82
- Mongoid::Factory.build(@klass, attrs)
84
+ Mongoid::Factory.build(klass, attrs)
83
85
  end
84
86
  docs
85
87
  end
@@ -90,11 +92,11 @@ module Mongoid #:nodoc:
90
92
  #
91
93
  # Example:
92
94
  #
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
95
+ # <tt>Mongoid::Contexts::Mongo.new(criteria)</tt>
96
+ def initialize(criteria)
97
+ @criteria = criteria
98
+ if criteria.klass.hereditary
99
+ criteria.in(:_type => criteria.klass._types)
98
100
  end
99
101
  end
100
102
 
@@ -114,8 +116,8 @@ module Mongoid #:nodoc:
114
116
  sorting = opts[:sort]
115
117
  sorting = [[:_id, :asc]] unless sorting
116
118
  opts[:sort] = sorting.collect { |option| [ option[0], option[1].invert ] }
117
- attributes = @klass.collection.find_one(@selector, opts)
118
- attributes ? Mongoid::Factory.build(@klass, attributes) : nil
119
+ attributes = klass.collection.find_one(selector, opts)
120
+ attributes ? Mongoid::Factory.build(klass, attributes) : nil
119
121
  end
120
122
 
121
123
  MAX_REDUCE = "function(obj, prev) { if (prev.max == 'start') { prev.max = obj.[field]; } " +
@@ -168,8 +170,8 @@ module Mongoid #:nodoc:
168
170
  #
169
171
  # The first document in the collection.
170
172
  def one
171
- attributes = @klass.collection.find_one(@selector, process_options)
172
- attributes ? Mongoid::Factory.build(@klass, attributes) : nil
173
+ attributes = klass.collection.find_one(selector, process_options)
174
+ attributes ? Mongoid::Factory.build(klass, attributes) : nil
173
175
  end
174
176
 
175
177
  alias :first :one
@@ -196,9 +198,9 @@ module Mongoid #:nodoc:
196
198
  # Common functionality for grouping operations. Currently used by min, max
197
199
  # and sum. Will gsub the field name in the supplied reduce function.
198
200
  def grouped(start, field, reduce)
199
- collection = @klass.collection.group(
201
+ collection = klass.collection.group(
200
202
  nil,
201
- @selector,
203
+ selector,
202
204
  { start => "start" },
203
205
  reduce.gsub("[field]", field),
204
206
  true
@@ -209,12 +211,12 @@ module Mongoid #:nodoc:
209
211
  # Filters the field list. If no fields have been supplied, then it will be
210
212
  # empty. If fields have been defined then _type will be included as well.
211
213
  def process_options
212
- fields = @options[:fields]
214
+ fields = options[:fields]
213
215
  if fields && fields.size > 0 && !fields.include?(:_type)
214
216
  fields << :_type
215
- @options[:fields] = fields
217
+ options[:fields] = fields
216
218
  end
217
- @options.dup
219
+ options.dup
218
220
  end
219
221
 
220
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
@@ -35,6 +35,7 @@ module Mongoid #:nodoc:
35
35
  :execute,
36
36
  :first,
37
37
  :group,
38
+ :id_criteria,
38
39
  :last,
39
40
  :max,
40
41
  :min,
@@ -91,7 +92,7 @@ module Mongoid #:nodoc:
91
92
  # This will return an Enumerable context if the class is embedded,
92
93
  # otherwise it will return a Mongo context for root classes.
93
94
  def context
94
- @context ||= determine_context
95
+ @context ||= Contexts.context_for(self)
95
96
  end
96
97
 
97
98
  # Iterate over each +Document+ in the results. This can take an optional
@@ -101,7 +102,7 @@ module Mongoid #:nodoc:
101
102
  #
102
103
  # <tt>criteria.each { |doc| p doc }</tt>
103
104
  def each(&block)
104
- return each_cached(&block) if cached?
105
+ return caching(&block) if cached?
105
106
  if block_given?
106
107
  execute.each { |doc| yield doc }
107
108
  end
@@ -134,10 +135,6 @@ module Mongoid #:nodoc:
134
135
  # klass: The class to execute on.
135
136
  def initialize(klass)
136
137
  @selector, @options, @klass, @documents = {}, {}, klass, []
137
- if klass.hereditary
138
- @selector = { :_type => { "$in" => klass._types } }
139
- @hereditary = true
140
- end
141
138
  end
142
139
 
143
140
  # Merges another object into this +Criteria+. The other object may be a
@@ -204,29 +201,15 @@ module Mongoid #:nodoc:
204
201
  klass = args[0]
205
202
  params = args[1] || {}
206
203
  unless params.is_a?(Hash)
207
- return id_criteria(klass, params)
204
+ return new(klass).id_criteria(params)
208
205
  end
209
206
  return new(klass).where(params.delete(:conditions) || {}).extras(params)
210
207
  end
211
208
 
212
209
  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
210
 
228
211
  # Iterate over each +Document+ in the results and cache the collection.
229
- def each_cached(&block)
212
+ def caching(&block)
230
213
  @collection ||= execute
231
214
  if block_given?
232
215
  docs = []
@@ -272,26 +255,5 @@ module Mongoid #:nodoc:
272
255
  def update_selector(attributes, operator)
273
256
  attributes.each { |key, value| @selector[key] = { operator => value } }; self
274
257
  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
296
258
  end
297
259
  end