mongoid 2.0.0.beta.5 → 2.0.0.beta.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/lib/mongoid.rb +10 -2
  2. data/lib/mongoid/associations.rb +82 -58
  3. data/lib/mongoid/associations/embeds_one.rb +6 -6
  4. data/lib/mongoid/associations/foreign_key.rb +35 -0
  5. data/lib/mongoid/associations/meta_data.rb +9 -0
  6. data/lib/mongoid/associations/options.rb +1 -1
  7. data/lib/mongoid/associations/proxy.rb +9 -0
  8. data/lib/mongoid/associations/{belongs_to_related.rb → referenced_in.rb} +6 -5
  9. data/lib/mongoid/associations/{has_many_related.rb → references_many.rb} +69 -26
  10. data/lib/mongoid/associations/references_many_as_array.rb +78 -0
  11. data/lib/mongoid/associations/{has_one_related.rb → references_one.rb} +16 -2
  12. data/lib/mongoid/atomicity.rb +42 -0
  13. data/lib/mongoid/attributes.rb +148 -146
  14. data/lib/mongoid/callbacks.rb +5 -1
  15. data/lib/mongoid/collections.rb +31 -1
  16. data/lib/mongoid/components.rb +4 -1
  17. data/lib/mongoid/config.rb +2 -1
  18. data/lib/mongoid/criteria.rb +9 -0
  19. data/lib/mongoid/dirty.rb +211 -212
  20. data/lib/mongoid/document.rb +126 -185
  21. data/lib/mongoid/extensions.rb +5 -0
  22. data/lib/mongoid/extensions/array/conversions.rb +3 -5
  23. data/lib/mongoid/extensions/hash/conversions.rb +19 -22
  24. data/lib/mongoid/extensions/object/conversions.rb +3 -5
  25. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  26. data/lib/mongoid/field.rb +11 -0
  27. data/lib/mongoid/finders.rb +8 -0
  28. data/lib/mongoid/hierarchy.rb +76 -0
  29. data/lib/mongoid/identity.rb +37 -29
  30. data/lib/mongoid/paths.rb +46 -47
  31. data/lib/mongoid/persistence.rb +111 -113
  32. data/lib/mongoid/persistence/insert.rb +1 -1
  33. data/lib/mongoid/persistence/insert_embedded.rb +10 -5
  34. data/lib/mongoid/persistence/remove_all.rb +3 -2
  35. data/lib/mongoid/persistence/update.rb +8 -3
  36. data/lib/mongoid/railtie.rb +3 -0
  37. data/lib/mongoid/railties/database.rake +33 -18
  38. data/lib/mongoid/timestamps.rb +9 -12
  39. data/lib/mongoid/validations/uniqueness.rb +16 -4
  40. data/lib/mongoid/version.rb +1 -1
  41. data/lib/mongoid/versioning.rb +10 -11
  42. data/lib/rails/generators/mongoid/config/config_generator.rb +0 -16
  43. metadata +64 -24
@@ -11,7 +11,11 @@ module Mongoid #:nodoc:
11
11
  :destroy,
12
12
  :save,
13
13
  :update,
14
- :validate
14
+ :validation
15
+ end
16
+
17
+ def valid?(*) #nodoc
18
+ _run_validation_callbacks { super }
15
19
  end
16
20
  end
17
21
  end
@@ -7,7 +7,8 @@ module Mongoid #:nodoc
7
7
  included do
8
8
  cattr_accessor :_collection, :collection_name
9
9
  self.collection_name = self.name.collectionize
10
- delegate :collection, :to => "self.class"
10
+
11
+ delegate :collection, :db, :to => "self.class"
11
12
  end
12
13
 
13
14
  module ClassMethods #:nodoc:
@@ -22,6 +23,35 @@ module Mongoid #:nodoc
22
23
  add_indexes; self._collection
23
24
  end
24
25
 
26
+ # Return the database associated with this collection.
27
+ #
28
+ # Example:
29
+ #
30
+ # <tt>Person.db</tt>
31
+ def db
32
+ collection.db
33
+ end
34
+
35
+ # Convenience method for getting index information from the collection.
36
+ #
37
+ # Example:
38
+ #
39
+ # <tt>Person.index_information</tt>
40
+ def index_information
41
+ collection.index_information
42
+ end
43
+
44
+ # The MongoDB logger is not exposed through the driver to be changed
45
+ # after initialization of the connection, this is a hacky way around that
46
+ # if logging needs to be changed at runtime.
47
+ #
48
+ # Example:
49
+ #
50
+ # <tt>Person.logger = Logger.new($stdout)</tt>
51
+ def logger=(logger)
52
+ db.connection.instance_variable_set(:@logger, logger)
53
+ end
54
+
25
55
  # Macro for setting the collection name to store in.
26
56
  #
27
57
  # Example:
@@ -9,13 +9,15 @@ module Mongoid #:nodoc
9
9
  include ActiveModel::Naming
10
10
  include ActiveModel::Serialization
11
11
  include ActiveModel::Serializers::JSON
12
+ include ActiveModel::Serializers::Xml
12
13
  include Mongoid::Associations
14
+ include Mongoid::Atomicity
13
15
  include Mongoid::Attributes
14
- include Mongoid::Callbacks
15
16
  include Mongoid::Collections
16
17
  include Mongoid::Dirty
17
18
  include Mongoid::Extras
18
19
  include Mongoid::Fields
20
+ include Mongoid::Hierarchy
19
21
  include Mongoid::Indexes
20
22
  include Mongoid::Matchers
21
23
  include Mongoid::Memoization
@@ -24,6 +26,7 @@ module Mongoid #:nodoc
24
26
  include Mongoid::Persistence
25
27
  include Mongoid::State
26
28
  include Mongoid::Validations
29
+ include Mongoid::Callbacks
27
30
  extend ActiveModel::Translation
28
31
  extend Mongoid::Finders
29
32
  extend Mongoid::NamedScope
@@ -193,10 +193,11 @@ module Mongoid #:nodoc
193
193
  name = settings["database"] || mongo_uri.path.to_s.sub("/", "")
194
194
  host = settings["host"] || mongo_uri.host || "localhost"
195
195
  port = settings["port"] || mongo_uri.port || 27017
196
+ pool_size = settings["pool_size"] || 1
196
197
  username = settings["username"] || mongo_uri.user
197
198
  password = settings["password"] || mongo_uri.password
198
199
 
199
- connection = Mongo::Connection.new(host, port, :logger => logger)
200
+ connection = Mongo::Connection.new(host, port, :logger => logger, :pool_size => pool_size)
200
201
  if username || password
201
202
  connection.add_auth(name, username, password)
202
203
  connection.apply_saved_authentication
@@ -82,6 +82,15 @@ module Mongoid #:nodoc:
82
82
  self
83
83
  end
84
84
 
85
+ # Return true if the criteria has some Document or not
86
+ #
87
+ # Example:
88
+ #
89
+ # <tt>criteria.exists?</tt>
90
+ def exists?
91
+ context.count > 0
92
+ end
93
+
85
94
  # Merges the supplied argument hash into a single criteria
86
95
  #
87
96
  # Options:
data/lib/mongoid/dirty.rb CHANGED
@@ -2,231 +2,230 @@
2
2
  module Mongoid #:nodoc:
3
3
  module Dirty #:nodoc:
4
4
  extend ActiveSupport::Concern
5
- module InstanceMethods #:nodoc:
6
- # Gets the changes for a specific field.
7
- #
8
- # Example:
9
- #
10
- # person = Person.new(:title => "Sir")
11
- # person.title = "Madam"
12
- # person.attribute_change("title") # [ "Sir", "Madam" ]
13
- #
14
- # Returns:
15
- #
16
- # An +Array+ containing the old and new values.
17
- def attribute_change(name)
18
- modifications[name]
19
- end
20
5
 
21
- # Determines if a specific field has chaged.
22
- #
23
- # Example:
24
- #
25
- # person = Person.new(:title => "Sir")
26
- # person.title = "Madam"
27
- # person.attribute_changed?("title") # true
28
- #
29
- # Returns:
30
- #
31
- # +true+ if changed, +false+ if not.
32
- def attribute_changed?(name)
33
- modifications.include?(name)
34
- end
6
+ # Gets the changes for a specific field.
7
+ #
8
+ # Example:
9
+ #
10
+ # person = Person.new(:title => "Sir")
11
+ # person.title = "Madam"
12
+ # person.attribute_change("title") # [ "Sir", "Madam" ]
13
+ #
14
+ # Returns:
15
+ #
16
+ # An +Array+ containing the old and new values.
17
+ def attribute_change(name)
18
+ modifications[name]
19
+ end
35
20
 
36
- # Gets the old value for a specific field.
37
- #
38
- # Example:
39
- #
40
- # person = Person.new(:title => "Sir")
41
- # person.title = "Madam"
42
- # person.attribute_was("title") # "Sir"
43
- #
44
- # Returns:
45
- #
46
- # The old field value.
47
- def attribute_was(name)
48
- change = modifications[name]
49
- change ? change[0] : nil
50
- end
21
+ # Determines if a specific field has chaged.
22
+ #
23
+ # Example:
24
+ #
25
+ # person = Person.new(:title => "Sir")
26
+ # person.title = "Madam"
27
+ # person.attribute_changed?("title") # true
28
+ #
29
+ # Returns:
30
+ #
31
+ # +true+ if changed, +false+ if not.
32
+ def attribute_changed?(name)
33
+ modifications.include?(name)
34
+ end
51
35
 
52
- # Gets the names of all the fields that have changed in the document.
53
- #
54
- # Example:
55
- #
56
- # person = Person.new(:title => "Sir")
57
- # person.title = "Madam"
58
- # person.changed # returns [ "title" ]
59
- #
60
- # Returns:
61
- #
62
- # An +Array+ of changed field names.
63
- def changed
64
- modifications.keys
65
- end
36
+ # Gets the old value for a specific field.
37
+ #
38
+ # Example:
39
+ #
40
+ # person = Person.new(:title => "Sir")
41
+ # person.title = "Madam"
42
+ # person.attribute_was("title") # "Sir"
43
+ #
44
+ # Returns:
45
+ #
46
+ # The old field value.
47
+ def attribute_was(name)
48
+ change = modifications[name]
49
+ change ? change[0] : nil
50
+ end
66
51
 
67
- # Alerts to whether the document has been modified or not.
68
- #
69
- # Example:
70
- #
71
- # person = Person.new(:title => "Sir")
72
- # person.title = "Madam"
73
- # person.changed? # returns true
74
- #
75
- # Returns:
76
- #
77
- # +true+ if changed, +false+ if not.
78
- def changed?
79
- !modifications.empty?
80
- end
52
+ # Gets the names of all the fields that have changed in the document.
53
+ #
54
+ # Example:
55
+ #
56
+ # person = Person.new(:title => "Sir")
57
+ # person.title = "Madam"
58
+ # person.changed # returns [ "title" ]
59
+ #
60
+ # Returns:
61
+ #
62
+ # An +Array+ of changed field names.
63
+ def changed
64
+ modifications.keys
65
+ end
81
66
 
82
- # Gets all the modifications that have happened to the object as a +Hash+
83
- # with the keys being the names of the fields, and the values being an
84
- # +Array+ with the old value and new value.
85
- #
86
- # Example:
87
- #
88
- # person = Person.new(:title => "Sir")
89
- # person.title = "Madam"
90
- # person.changes # returns { "title" => [ "Sir", "Madam" ] }
91
- #
92
- # Returns:
93
- #
94
- # A +Hash+ of changes.
95
- def changes
96
- modifications
97
- end
67
+ # Alerts to whether the document has been modified or not.
68
+ #
69
+ # Example:
70
+ #
71
+ # person = Person.new(:title => "Sir")
72
+ # person.title = "Madam"
73
+ # person.changed? # returns true
74
+ #
75
+ # Returns:
76
+ #
77
+ # +true+ if changed, +false+ if not.
78
+ def changed?
79
+ !modifications.empty?
80
+ end
98
81
 
99
- # Call this method after save, so the changes can be properly switched.
100
- #
101
- # Example:
102
- #
103
- # <tt>person.move_changes</tt>
104
- def move_changes
105
- @previous_modifications = modifications.dup
106
- @modifications = {}
107
- end
82
+ # Gets all the modifications that have happened to the object as a +Hash+
83
+ # with the keys being the names of the fields, and the values being an
84
+ # +Array+ with the old value and new value.
85
+ #
86
+ # Example:
87
+ #
88
+ # person = Person.new(:title => "Sir")
89
+ # person.title = "Madam"
90
+ # person.changes # returns { "title" => [ "Sir", "Madam" ] }
91
+ #
92
+ # Returns:
93
+ #
94
+ # A +Hash+ of changes.
95
+ def changes
96
+ modifications
97
+ end
108
98
 
109
- # Gets all the new values for each of the changed fields, to be passed to
110
- # a MongoDB $set modifier.
111
- #
112
- # Example:
113
- #
114
- # person = Person.new(:title => "Sir")
115
- # person.title = "Madam"
116
- # person.setters # returns { "title" => "Madam" }
117
- #
118
- # Returns:
119
- #
120
- # A +Hash+ of new values.
121
- def setters
122
- modifications.inject({}) do |sets, (field, changes)|
123
- key = embedded? ? "#{_position}.#{field}" : field
124
- sets[key] = changes[1]; sets
125
- end
126
- end
99
+ # Call this method after save, so the changes can be properly switched.
100
+ #
101
+ # Example:
102
+ #
103
+ # <tt>person.move_changes</tt>
104
+ def move_changes
105
+ @previous_modifications = modifications.dup
106
+ @modifications = {}
107
+ end
127
108
 
128
- # Gets all the modifications that have happened to the object before the
129
- # object was saved.
130
- #
131
- # Example:
132
- #
133
- # person = Person.new(:title => "Sir")
134
- # person.title = "Madam"
135
- # person.save!
136
- # person.previous_changes # returns { "title" => [ "Sir", "Madam" ] }
137
- #
138
- # Returns:
139
- #
140
- # A +Hash+ of changes before save.
141
- def previous_changes
142
- @previous_modifications
109
+ # Gets all the new values for each of the changed fields, to be passed to
110
+ # a MongoDB $set modifier.
111
+ #
112
+ # Example:
113
+ #
114
+ # person = Person.new(:title => "Sir")
115
+ # person.title = "Madam"
116
+ # person.setters # returns { "title" => "Madam" }
117
+ #
118
+ # Returns:
119
+ #
120
+ # A +Hash+ of new values.
121
+ def setters
122
+ modifications.inject({}) do |sets, (field, changes)|
123
+ key = embedded? ? "#{_position}.#{field}" : field
124
+ sets[key] = changes[1]; sets
143
125
  end
126
+ end
144
127
 
145
- # Resets a changed field back to its old value.
146
- #
147
- # Example:
148
- #
149
- # person = Person.new(:title => "Sir")
150
- # person.title = "Madam"
151
- # person.reset_attribute!("title")
152
- # person.title # "Sir"
153
- #
154
- # Returns:
155
- #
156
- # The old field value.
157
- def reset_attribute!(name)
158
- value = attribute_was(name)
159
- if value
160
- @attributes[name] = value
161
- modifications.delete(name)
162
- end
163
- end
128
+ # Gets all the modifications that have happened to the object before the
129
+ # object was saved.
130
+ #
131
+ # Example:
132
+ #
133
+ # person = Person.new(:title => "Sir")
134
+ # person.title = "Madam"
135
+ # person.save!
136
+ # person.previous_changes # returns { "title" => [ "Sir", "Madam" ] }
137
+ #
138
+ # Returns:
139
+ #
140
+ # A +Hash+ of changes before save.
141
+ def previous_changes
142
+ @previous_modifications
143
+ end
164
144
 
165
- # Sets up the modifications hash. This occurs just after the document is
166
- # instantiated.
167
- #
168
- # Example:
169
- #
170
- # <tt>document.setup_notifications</tt>
171
- def setup_modifications
172
- @accessed ||= {}
173
- @modifications ||= {}
174
- @previous_modifications ||= {}
145
+ # Resets a changed field back to its old value.
146
+ #
147
+ # Example:
148
+ #
149
+ # person = Person.new(:title => "Sir")
150
+ # person.title = "Madam"
151
+ # person.reset_attribute!("title")
152
+ # person.title # "Sir"
153
+ #
154
+ # Returns:
155
+ #
156
+ # The old field value.
157
+ def reset_attribute!(name)
158
+ value = attribute_was(name)
159
+ if value
160
+ @attributes[name] = value
161
+ modifications.delete(name)
175
162
  end
163
+ end
176
164
 
177
- # Reset all modifications for the document. This will wipe all the marked
178
- # changes, but not reset the values.
179
- #
180
- # Example:
181
- #
182
- # <tt>document.reset_modifications</tt>
183
- def reset_modifications
184
- @accessed = {}
185
- @modifications = {}
186
- end
165
+ # Sets up the modifications hash. This occurs just after the document is
166
+ # instantiated.
167
+ #
168
+ # Example:
169
+ #
170
+ # <tt>document.setup_notifications</tt>
171
+ def setup_modifications
172
+ @accessed ||= {}
173
+ @modifications ||= {}
174
+ @previous_modifications ||= {}
175
+ end
187
176
 
188
- protected
177
+ # Reset all modifications for the document. This will wipe all the marked
178
+ # changes, but not reset the values.
179
+ #
180
+ # Example:
181
+ #
182
+ # <tt>document.reset_modifications</tt>
183
+ def reset_modifications
184
+ @accessed = {}
185
+ @modifications = {}
186
+ end
189
187
 
190
- # Audit the original value for a field that can be modified in place.
191
- #
192
- # Example:
193
- #
194
- # <tt>person.accessed("aliases", [ "007" ])</tt>
195
- def accessed(name, value)
196
- @accessed ||= {}
197
- @accessed[name] = value.dup if (value.is_a?(Array) || value.is_a?(Hash)) && !@accessed.has_key?(name)
198
- value
199
- end
188
+ protected
189
+
190
+ # Audit the original value for a field that can be modified in place.
191
+ #
192
+ # Example:
193
+ #
194
+ # <tt>person.accessed("aliases", [ "007" ])</tt>
195
+ def accessed(name, value)
196
+ @accessed ||= {}
197
+ @accessed[name] = value.dup if (value.is_a?(Array) || value.is_a?(Hash)) && !@accessed.has_key?(name)
198
+ value
199
+ end
200
200
 
201
- # Get all normal modifications plus in place potential changes.
202
- #
203
- # Example:
204
- #
205
- # <tt>person.modifications</tt>
206
- #
207
- # Returns:
208
- #
209
- # All changes to the document.
210
- def modifications
211
- @accessed.each_pair do |field, value|
212
- current = @attributes[field]
213
- @modifications[field] = [ value, current ] if current != value
214
- end
215
- @accessed.clear
216
- @modifications
217
- end
201
+ # Get all normal modifications plus in place potential changes.
202
+ #
203
+ # Example:
204
+ #
205
+ # <tt>person.modifications</tt>
206
+ #
207
+ # Returns:
208
+ #
209
+ # All changes to the document.
210
+ def modifications
211
+ @accessed.each_pair do |field, value|
212
+ current = @attributes[field]
213
+ @modifications[field] = [ value, current ] if current != value
214
+ end
215
+ @accessed.clear
216
+ @modifications
217
+ end
218
218
 
219
- # Audit the change of a field's value.
220
- #
221
- # Example:
222
- #
223
- # <tt>person.modify("name", "Jack", "John")</tt>
224
- def modify(name, old_value, new_value)
225
- @attributes[name] = new_value
226
- if @modifications && (old_value != new_value)
227
- original = @modifications[name].first if @modifications[name]
228
- @modifications[name] = [ (original || old_value), new_value ]
229
- end
219
+ # Audit the change of a field's value.
220
+ #
221
+ # Example:
222
+ #
223
+ # <tt>person.modify("name", "Jack", "John")</tt>
224
+ def modify(name, old_value, new_value)
225
+ @attributes[name] = new_value
226
+ if @modifications && (old_value != new_value)
227
+ original = @modifications[name].first if @modifications[name]
228
+ @modifications[name] = [ (original || old_value), new_value ]
230
229
  end
231
230
  end
232
231
 
@@ -243,10 +242,10 @@ module Mongoid #:nodoc:
243
242
  # person.title_was # "Sir"
244
243
  # person.reset_title!
245
244
  def add_dirty_methods(name)
246
- define_method("#{name}_change") { attribute_change(name) }
247
- define_method("#{name}_changed?") { attribute_changed?(name) }
248
- define_method("#{name}_was") { attribute_was(name) }
249
- define_method("reset_#{name}!") { reset_attribute!(name) }
245
+ define_method("#{name}_change") { attribute_change(name) } unless instance_methods.include?("#{name}_change")
246
+ define_method("#{name}_changed?") { attribute_changed?(name) } unless instance_methods.include?("#{name}_changed?")
247
+ define_method("#{name}_was") { attribute_was(name) } unless instance_methods.include?("#{name}_was")
248
+ define_method("reset_#{name}!") { reset_attribute!(name) } unless instance_methods.include?("reset_#{name}!")
250
249
  end
251
250
  end
252
251
  end