mongoid 1.2.8 → 1.2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/Rakefile +1 -1
  2. data/VERSION +1 -1
  3. data/lib/mongoid.rb +2 -3
  4. data/lib/mongoid/associations.rb +5 -3
  5. data/lib/mongoid/associations/belongs_to_related.rb +6 -9
  6. data/lib/mongoid/associations/has_many.rb +2 -0
  7. data/lib/mongoid/associations/has_many_related.rb +10 -0
  8. data/lib/mongoid/attributes.rb +6 -1
  9. data/lib/mongoid/commands.rb +2 -10
  10. data/lib/mongoid/components.rb +11 -12
  11. data/lib/mongoid/contexts/enumerable.rb +21 -11
  12. data/lib/mongoid/contexts/mongo.rb +40 -1
  13. data/lib/mongoid/criteria.rb +3 -29
  14. data/lib/mongoid/criterion/inclusion.rb +2 -1
  15. data/lib/mongoid/document.rb +5 -6
  16. data/lib/mongoid/extensions.rb +10 -0
  17. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  18. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  19. data/lib/mongoid/{caching.rb → extras.rb} +26 -3
  20. data/lib/mongoid/field.rb +20 -7
  21. data/lib/mongoid/finders.rb +10 -80
  22. data/mongoid.gemspec +15 -13
  23. data/spec/integration/mongoid/document_spec.rb +1 -1
  24. data/spec/models/person.rb +1 -0
  25. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +4 -0
  26. data/spec/unit/mongoid/associations/has_many_related_spec.rb +42 -13
  27. data/spec/unit/mongoid/associations/has_many_spec.rb +12 -7
  28. data/spec/unit/mongoid/associations_spec.rb +16 -0
  29. data/spec/unit/mongoid/attributes_spec.rb +23 -0
  30. data/spec/unit/mongoid/commands/destroy_spec.rb +3 -0
  31. data/spec/unit/mongoid/commands_spec.rb +4 -11
  32. data/spec/unit/mongoid/contexts/enumerable_spec.rb +16 -0
  33. data/spec/unit/mongoid/contexts/mongo_spec.rb +96 -0
  34. data/spec/unit/mongoid/criteria_spec.rb +11 -4
  35. data/spec/unit/mongoid/document_spec.rb +11 -0
  36. data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +22 -0
  37. data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +22 -0
  38. data/spec/unit/mongoid/{enslavement_spec.rb → extras_spec.rb} +55 -2
  39. data/spec/unit/mongoid/field_spec.rb +62 -0
  40. data/spec/unit/mongoid/finders_spec.rb +36 -0
  41. metadata +69 -37
  42. data/HISTORY +0 -342
  43. data/lib/mongoid/enslavement.rb +0 -38
  44. data/spec/unit/mongoid/caching_spec.rb +0 -63
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ begin
15
15
  gem.add_dependency("activesupport", "<= 2.3.5")
16
16
  gem.add_dependency("mongo", ">= 0.18.3")
17
17
  gem.add_dependency("durran-validatable", ">= 2.0.1")
18
- gem.add_dependency("will_paginate", "< 3.0.pre")
18
+ gem.add_dependency("will_paginate", "< 2.9")
19
19
 
20
20
  gem.add_development_dependency("rspec", ">= 1.2.9")
21
21
  gem.add_development_dependency("mocha", ">= 0.9.8")
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.8
1
+ 1.2.9
@@ -24,7 +24,7 @@ require "rubygems"
24
24
  gem "activesupport", ">= 2.2.2", "<3.0.pre"
25
25
  gem "mongo", ">= 0.18.3"
26
26
  gem "durran-validatable", ">= 2.0.1"
27
- gem "will_paginate", ">= 2.3.11", "<3.0.pre"
27
+ gem "will_paginate", ">= 2.3.11", "< 2.9"
28
28
 
29
29
  require "delegate"
30
30
  require "observer"
@@ -39,7 +39,6 @@ require "will_paginate/collection"
39
39
  require "mongo"
40
40
  require "mongoid/associations"
41
41
  require "mongoid/attributes"
42
- require "mongoid/caching"
43
42
  require "mongoid/callbacks"
44
43
  require "mongoid/collection"
45
44
  require "mongoid/commands"
@@ -47,8 +46,8 @@ require "mongoid/config"
47
46
  require "mongoid/contexts"
48
47
  require "mongoid/criteria"
49
48
  require "mongoid/cursor"
50
- require "mongoid/enslavement"
51
49
  require "mongoid/extensions"
50
+ require "mongoid/extras"
52
51
  require "mongoid/errors"
53
52
  require "mongoid/factory"
54
53
  require "mongoid/field"
@@ -93,8 +93,8 @@ module Mongoid # :nodoc:
93
93
  options.merge(:name => name, :extend => block, :foreign_key => foreign_key(name, options))
94
94
  )
95
95
  add_association(Associations::BelongsToRelated, opts)
96
- field opts.foreign_key
97
- index opts.foreign_key unless self.embedded
96
+ field(opts.foreign_key, :type => Mongoid.use_object_ids ? Mongo::ObjectID : String)
97
+ index(opts.foreign_key) unless self.embedded
98
98
  end
99
99
 
100
100
  # Adds the association from a parent document to its children. The name
@@ -249,7 +249,9 @@ module Mongoid # :nodoc:
249
249
  name = options.name.to_s
250
250
  define_method("create_#{name}") do |attrs|
251
251
  document = send("build_#{name}", attrs)
252
- document.save; document
252
+ document.run_callbacks(:before_create)
253
+ document.save
254
+ document.run_callbacks(:after_create); document
253
255
  end
254
256
  end
255
257
 
@@ -41,19 +41,16 @@ module Mongoid #:nodoc:
41
41
  #
42
42
  # Options:
43
43
  #
44
- # related: The related object
45
- # parent: The parent +Document+ to update.
44
+ # target: The target(parent) object
45
+ # document: The +Document+ to update.
46
46
  # options: The association +Options+
47
47
  #
48
48
  # Example:
49
49
  #
50
- # <tt>BelongsToRelated.update(game, person, options)</tt>
51
- def update(target, parent, options)
52
- if target
53
- parent.send("#{options.foreign_key}=", target.id)
54
- return instantiate(parent, options, target)
55
- end
56
- target
50
+ # <tt>BelongsToRelated.update(person, game, options)</tt>
51
+ def update(target, document, options)
52
+ document.send("#{options.foreign_key}=", target ? target.id : nil)
53
+ instantiate(document, options, target)
57
54
  end
58
55
  end
59
56
 
@@ -54,7 +54,9 @@ module Mongoid #:nodoc:
54
54
  # Rhe newly created Document.
55
55
  def create(attrs = {}, type = nil)
56
56
  object = build(attrs, type)
57
+ object.run_callbacks(:before_create)
57
58
  object.save
59
+ object.run_callbacks(:after_create)
58
60
  object
59
61
  end
60
62
 
@@ -7,6 +7,7 @@ module Mongoid #:nodoc:
7
7
  # Appends the object to the +Array+, setting its parent in
8
8
  # the process.
9
9
  def <<(*objects)
10
+ load_target
10
11
  objects.flatten.each do |object|
11
12
  object.send("#{@foreign_key}=", @parent.id)
12
13
  @target << object
@@ -20,6 +21,7 @@ module Mongoid #:nodoc:
20
21
  #
21
22
  # Returns the newly created object.
22
23
  def build(attributes = {})
24
+ load_target
23
25
  name = @parent.class.to_s.underscore
24
26
  object = @klass.instantiate(attributes.merge(name => @parent))
25
27
  @target << object
@@ -39,7 +41,9 @@ module Mongoid #:nodoc:
39
41
  # Returns the newly created object.
40
42
  def create(attributes)
41
43
  object = build(attributes)
44
+ object.run_callbacks(:before_create)
42
45
  object.save
46
+ object.run_callbacks(:after_create)
43
47
  object
44
48
  end
45
49
 
@@ -69,6 +73,12 @@ module Mongoid #:nodoc:
69
73
  self << objects
70
74
  end
71
75
 
76
+ protected
77
+ # Load the target entries if the document is new.
78
+ def load_target
79
+ @target = @target.entries if @parent.new_record?
80
+ end
81
+
72
82
  class << self
73
83
  # Preferred method for creating the new +HasManyRelated+ association.
74
84
  #
@@ -42,7 +42,7 @@ module Mongoid #:nodoc:
42
42
  (attrs || {}).each_pair do |key, value|
43
43
  if set_allowed?(key)
44
44
  @attributes[key.to_s] = value
45
- else
45
+ elsif write_allowed?(key)
46
46
  send("#{key}=", value)
47
47
  end
48
48
  end
@@ -148,6 +148,11 @@ module Mongoid #:nodoc:
148
148
  end
149
149
  end
150
150
 
151
+ # Return true if writing to the given field is allowed
152
+ def write_allowed?(key)
153
+ return true unless fields[key.to_s]
154
+ fields[key.to_s].accessible?
155
+ end
151
156
  end
152
157
 
153
158
  module ClassMethods
@@ -62,11 +62,7 @@ module Mongoid #:nodoc:
62
62
  def save(validate = true)
63
63
  new = new_record?
64
64
  run_callbacks(:before_create) if new
65
- begin
66
- saved = Save.execute(self, validate)
67
- rescue Mongo::OperationFailure => e
68
- errors.add(:mongoid, e.message)
69
- end
65
+ saved = Save.execute(self, validate)
70
66
  run_callbacks(:after_create) if new && saved
71
67
  saved
72
68
  end
@@ -125,11 +121,7 @@ module Mongoid #:nodoc:
125
121
  # Returns: the +Document+.
126
122
  def create(attributes = {})
127
123
  document = new(attributes)
128
- begin
129
- Create.execute(document)
130
- rescue Mongo::OperationFailure => e
131
- document.errors.add(:mongoid, e.message)
132
- end
124
+ Create.execute(document)
133
125
  document
134
126
  end
135
127
 
@@ -5,20 +5,19 @@ module Mongoid #:nodoc
5
5
  base.class_eval do
6
6
  # All modules that a +Document+ is composed of are defined in this
7
7
  # module, to keep the document class from getting too cluttered.
8
- include Associations
9
- include Attributes
10
- include Caching
11
- include Callbacks
12
- include Commands
13
- include Enslavement
14
- include Fields
15
- include Indexes
16
- include Matchers
17
- include Memoization
8
+ include Mongoid::Associations
9
+ include Mongoid::Attributes
10
+ include Mongoid::Callbacks
11
+ include Mongoid::Commands
12
+ include Mongoid::Extras
13
+ include Mongoid::Fields
14
+ include Mongoid::Indexes
15
+ include Mongoid::Matchers
16
+ include Mongoid::Memoization
18
17
  include Observable
19
18
  include Validatable
20
- extend Finders
21
- extend NamedScope
19
+ extend Mongoid::Finders
20
+ extend Mongoid::NamedScope
22
21
  end
23
22
  end
24
23
  end
@@ -5,7 +5,7 @@ module Mongoid #:nodoc:
5
5
  include Ids, Paging
6
6
  attr_reader :criteria
7
7
 
8
- delegate :first, :last, :to => :execute
8
+ delegate :blank?, :empty?, :first, :last, :to => :execute
9
9
  delegate :documents, :options, :selector, :to => :criteria
10
10
 
11
11
  # Return aggregation counts of the grouped documents. This will count by
@@ -25,16 +25,6 @@ module Mongoid #:nodoc:
25
25
  @count ||= documents.size
26
26
  end
27
27
 
28
- # Groups the documents by the first field supplied in the field options.
29
- #
30
- # Returns:
31
- #
32
- # A +Hash+ with field values as keys, arrays of documents as values.
33
- def group
34
- field = options[:fields].first
35
- documents.group_by { |doc| doc.send(field) }
36
- end
37
-
38
28
  # Enumerable implementation of execute. Returns matching documents for
39
29
  # the selector, and adds options if supplied.
40
30
  #
@@ -45,6 +35,16 @@ module Mongoid #:nodoc:
45
35
  limit(documents.select { |document| document.matches?(selector) })
46
36
  end
47
37
 
38
+ # Groups the documents by the first field supplied in the field options.
39
+ #
40
+ # Returns:
41
+ #
42
+ # A +Hash+ with field values as keys, arrays of documents as values.
43
+ def group
44
+ field = options[:fields].first
45
+ documents.group_by { |doc| doc.send(field) }
46
+ end
47
+
48
48
  # Create the new enumerable context. This will need the selector and
49
49
  # options from a +Criteria+ and a documents array that is the underlying
50
50
  # array of embedded documents from a has many association.
@@ -56,6 +56,16 @@ module Mongoid #:nodoc:
56
56
  @criteria = criteria
57
57
  end
58
58
 
59
+ # Iterate over each +Document+ in the results. This can take an optional
60
+ # block to pass to each argument in the results.
61
+ #
62
+ # Example:
63
+ #
64
+ # <tt>context.iterate { |doc| p doc }</tt>
65
+ def iterate(&block)
66
+ execute.each(&block)
67
+ end
68
+
59
69
  # Get the largest value for the field in all the documents.
60
70
  #
61
71
  # Returns:
@@ -23,6 +23,18 @@ module Mongoid #:nodoc:
23
23
  klass.collection.group(options[:fields], selector, { :count => 0 }, Javascript.aggregate, true)
24
24
  end
25
25
 
26
+ # Determine if the context is empty or blank given the criteria. Will
27
+ # perform a quick has_one asking only for the id.
28
+ #
29
+ # Example:
30
+ #
31
+ # <tt>context.blank?</tt>
32
+ def blank?
33
+ klass.collection.find_one(selector, { :fields => [ :_id ] }).nil?
34
+ end
35
+
36
+ alias :empty? :blank?
37
+
26
38
  # Get the count of matching documents in the database for the context.
27
39
  #
28
40
  # Example:
@@ -43,7 +55,7 @@ module Mongoid #:nodoc:
43
55
  #
44
56
  # Example:
45
57
  #
46
- # <tt>mongo.execute</tt>
58
+ # <tt>context.execute</tt>
47
59
  #
48
60
  # Returns:
49
61
  #
@@ -100,6 +112,19 @@ module Mongoid #:nodoc:
100
112
  criteria.cache if klass.cached?
101
113
  end
102
114
 
115
+ # Iterate over each +Document+ in the results. This can take an optional
116
+ # block to pass to each argument in the results.
117
+ #
118
+ # Example:
119
+ #
120
+ # <tt>context.iterate { |doc| p doc }</tt>
121
+ def iterate(&block)
122
+ return caching(&block) if criteria.cached?
123
+ if block_given?
124
+ execute.each { |doc| yield doc }
125
+ end
126
+ end
127
+
103
128
  # Return the last result for the +Context+. Essentially does a find_one on
104
129
  # the collection with the sorting reversed. If no sorting parameters have
105
130
  # been provided it will default to ids.
@@ -214,6 +239,20 @@ module Mongoid #:nodoc:
214
239
  options.dup
215
240
  end
216
241
 
242
+ protected
243
+
244
+ # Iterate over each +Document+ in the results and cache the collection.
245
+ def caching(&block)
246
+ if defined? @collection
247
+ @collection.each(&block)
248
+ else
249
+ @collection = []
250
+ execute.each do |doc|
251
+ @collection << doc
252
+ yield doc if block_given?
253
+ end
254
+ end
255
+ end
217
256
  end
218
257
  end
219
258
  end
@@ -31,7 +31,9 @@ module Mongoid #:nodoc:
31
31
 
32
32
  delegate \
33
33
  :aggregate,
34
+ :blank?,
34
35
  :count,
36
+ :empty?,
35
37
  :execute,
36
38
  :first,
37
39
  :group,
@@ -76,17 +78,6 @@ module Mongoid #:nodoc:
76
78
  end
77
79
  end
78
80
 
79
- # Returns true if the criteria is empty.
80
- #
81
- # Example:
82
- #
83
- # <tt>criteria.blank?</tt>
84
- def blank?
85
- count < 1
86
- end
87
-
88
- alias :empty? :blank?
89
-
90
81
  # Return or create the context in which this criteria should be executed.
91
82
  #
92
83
  # This will return an Enumerable context if the class is embedded,
@@ -102,10 +93,7 @@ module Mongoid #:nodoc:
102
93
  #
103
94
  # <tt>criteria.each { |doc| p doc }</tt>
104
95
  def each(&block)
105
- return caching(&block) if cached?
106
- if block_given?
107
- execute.each { |doc| yield doc }
108
- end
96
+ context.iterate(&block)
109
97
  self
110
98
  end
111
99
 
@@ -213,20 +201,6 @@ module Mongoid #:nodoc:
213
201
 
214
202
  protected
215
203
 
216
- # Iterate over each +Document+ in the results and cache the collection.
217
- def caching(&block)
218
- @collection ||= execute
219
- if block_given?
220
- docs = []
221
- @collection.each do |doc|
222
- docs << doc
223
- yield doc
224
- end
225
- @collection = docs
226
- end
227
- self
228
- end
229
-
230
204
  # Filters the unused options out of the options +Hash+. Currently this
231
205
  # takes into account the "page" and "per_page" options that would be passed
232
206
  # in if using will_paginate.
@@ -22,6 +22,7 @@ module Mongoid #:nodoc:
22
22
  def all(attributes = {})
23
23
  update_selector(attributes, "$all")
24
24
  end
25
+ alias :all_in :all
25
26
 
26
27
  # Adds a criterion to the +Criteria+ that specifies values that must
27
28
  # be matched in order to return results. This is similar to a SQL "WHERE"
@@ -61,7 +62,7 @@ module Mongoid #:nodoc:
61
62
  def in(attributes = {})
62
63
  update_selector(attributes, "$in")
63
64
  end
64
- alias any_in in
65
+ alias :any_in :in
65
66
 
66
67
  # Adds a criterion to the +Criteria+ that specifies values that must
67
68
  # be matched in order to return results. This is similar to a SQL "WHERE"
@@ -78,8 +78,6 @@ module Mongoid #:nodoc:
78
78
  #
79
79
  # class Person
80
80
  # include Mongoid::Document
81
- # field :first_name
82
- # field :last_name
83
81
  # key :first_name, :last_name
84
82
  # end
85
83
  def key(*fields)
@@ -132,10 +130,6 @@ module Mongoid #:nodoc:
132
130
  #
133
131
  # parent: The +Document+ to assimilate with.
134
132
  # options: The association +Options+ for the child.
135
- #
136
- # Example:
137
- #
138
- # <tt>name.assimilate(person, options)</tt>
139
133
  def assimilate(parent, options)
140
134
  parentize(parent, options.name); notify; self
141
135
  end
@@ -193,6 +187,11 @@ module Mongoid #:nodoc:
193
187
  @new_record = saved
194
188
  end
195
189
 
190
+ # Checks if the document has been saved to the database.
191
+ def persisted?
192
+ !new_record?
193
+ end
194
+
196
195
  # Set the changed state of the +Document+ then notify observers that it has changed.
197
196
  #
198
197
  # Example: