mongoid 2.0.0.beta.5 → 2.0.0.beta.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.
- data/lib/mongoid.rb +10 -2
- data/lib/mongoid/associations.rb +82 -58
- data/lib/mongoid/associations/embeds_one.rb +6 -6
- data/lib/mongoid/associations/foreign_key.rb +35 -0
- data/lib/mongoid/associations/meta_data.rb +9 -0
- data/lib/mongoid/associations/options.rb +1 -1
- data/lib/mongoid/associations/proxy.rb +9 -0
- data/lib/mongoid/associations/{belongs_to_related.rb → referenced_in.rb} +6 -5
- data/lib/mongoid/associations/{has_many_related.rb → references_many.rb} +69 -26
- data/lib/mongoid/associations/references_many_as_array.rb +78 -0
- data/lib/mongoid/associations/{has_one_related.rb → references_one.rb} +16 -2
- data/lib/mongoid/atomicity.rb +42 -0
- data/lib/mongoid/attributes.rb +148 -146
- data/lib/mongoid/callbacks.rb +5 -1
- data/lib/mongoid/collections.rb +31 -1
- data/lib/mongoid/components.rb +4 -1
- data/lib/mongoid/config.rb +2 -1
- data/lib/mongoid/criteria.rb +9 -0
- data/lib/mongoid/dirty.rb +211 -212
- data/lib/mongoid/document.rb +126 -185
- data/lib/mongoid/extensions.rb +5 -0
- data/lib/mongoid/extensions/array/conversions.rb +3 -5
- data/lib/mongoid/extensions/hash/conversions.rb +19 -22
- data/lib/mongoid/extensions/object/conversions.rb +3 -5
- data/lib/mongoid/extensions/set/conversions.rb +20 -0
- data/lib/mongoid/field.rb +11 -0
- data/lib/mongoid/finders.rb +8 -0
- data/lib/mongoid/hierarchy.rb +76 -0
- data/lib/mongoid/identity.rb +37 -29
- data/lib/mongoid/paths.rb +46 -47
- data/lib/mongoid/persistence.rb +111 -113
- data/lib/mongoid/persistence/insert.rb +1 -1
- data/lib/mongoid/persistence/insert_embedded.rb +10 -5
- data/lib/mongoid/persistence/remove_all.rb +3 -2
- data/lib/mongoid/persistence/update.rb +8 -3
- data/lib/mongoid/railtie.rb +3 -0
- data/lib/mongoid/railties/database.rake +33 -18
- data/lib/mongoid/timestamps.rb +9 -12
- data/lib/mongoid/validations/uniqueness.rb +16 -4
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/versioning.rb +10 -11
- data/lib/rails/generators/mongoid/config/config_generator.rb +0 -16
- metadata +64 -24
data/lib/mongoid/document.rb
CHANGED
@@ -5,22 +5,20 @@ module Mongoid #:nodoc:
|
|
5
5
|
included do
|
6
6
|
include Mongoid::Components
|
7
7
|
|
8
|
-
cattr_accessor :primary_key
|
9
|
-
self.hereditary = false
|
8
|
+
cattr_accessor :primary_key
|
10
9
|
|
11
|
-
attr_accessor :association_name
|
10
|
+
attr_accessor :association_name
|
12
11
|
attr_reader :new_record
|
13
12
|
|
14
|
-
delegate :
|
13
|
+
delegate :primary_key, :to => "self.class"
|
15
14
|
end
|
16
15
|
|
17
|
-
module ClassMethods
|
18
|
-
# Return the database associated with this class.
|
19
|
-
def db
|
20
|
-
collection.db
|
21
|
-
end
|
16
|
+
module ClassMethods #:nodoc:
|
22
17
|
|
23
18
|
# Perform default behavior but mark the hierarchy as being hereditary.
|
19
|
+
#
|
20
|
+
# This method must remain in the +Document+ module, even though its
|
21
|
+
# behavior affects items in the Hierarchy module.
|
24
22
|
def inherited(subclass)
|
25
23
|
super(subclass)
|
26
24
|
self.hereditary = true
|
@@ -61,202 +59,145 @@ module Mongoid #:nodoc:
|
|
61
59
|
end
|
62
60
|
|
63
61
|
# Returns all types to query for when using this class as the base.
|
62
|
+
# *subclasses* is from activesupport. Note that a bug in *subclasses*
|
63
|
+
# causes the first call to only return direct children, hence
|
64
|
+
# the double call and unique.
|
64
65
|
def _types
|
65
|
-
@_type ||=
|
66
|
-
end
|
67
|
-
|
68
|
-
# return the list of subclassses for an object
|
69
|
-
def subclasses_of(*superclasses) #:nodoc:
|
70
|
-
subclasses = []
|
71
|
-
superclasses.each do |sup|
|
72
|
-
ObjectSpace.each_object(class << sup; self; end) do |k|
|
73
|
-
if k != sup && (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
|
74
|
-
subclasses << k
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
subclasses
|
66
|
+
@_type ||= [subclasses + subclasses + [self.name]].flatten.uniq
|
79
67
|
end
|
80
68
|
end
|
81
69
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
# Delegates to ==
|
91
|
-
def eql?(comparison_object)
|
92
|
-
self == (comparison_object)
|
93
|
-
end
|
94
|
-
|
95
|
-
# Delegates to id in order to allow two records of the same type and id to work with something like:
|
96
|
-
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
|
97
|
-
def hash
|
98
|
-
id.hash
|
99
|
-
end
|
100
|
-
|
101
|
-
# Is inheritance in play here?
|
102
|
-
#
|
103
|
-
# Returns:
|
104
|
-
#
|
105
|
-
# <tt>true</tt> if inheritance used, <tt>false</tt> if not.
|
106
|
-
def hereditary?
|
107
|
-
!!self.hereditary
|
108
|
-
end
|
109
|
-
|
110
|
-
# Introduces a child object into the +Document+ object graph. This will
|
111
|
-
# set up the relationships between the parent and child and update the
|
112
|
-
# attributes of the parent +Document+.
|
113
|
-
#
|
114
|
-
# Options:
|
115
|
-
#
|
116
|
-
# parent: The +Document+ to assimilate with.
|
117
|
-
# options: The association +Options+ for the child.
|
118
|
-
def assimilate(parent, options)
|
119
|
-
parentize(parent, options.name); notify; self
|
120
|
-
end
|
121
|
-
|
122
|
-
# Return the attributes hash with indifferent access.
|
123
|
-
def attributes
|
124
|
-
@attributes.with_indifferent_access
|
125
|
-
end
|
70
|
+
# Performs equality checking on the document ids. For more robust
|
71
|
+
# equality checking please override this method.
|
72
|
+
def ==(other)
|
73
|
+
return false unless other.is_a?(Document)
|
74
|
+
id == other.id
|
75
|
+
end
|
126
76
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
end
|
77
|
+
# Delegates to ==
|
78
|
+
def eql?(comparison_object)
|
79
|
+
self == (comparison_object)
|
80
|
+
end
|
132
81
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
82
|
+
# Delegates to id in order to allow two records of the same type and id to work with something like:
|
83
|
+
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
|
84
|
+
def hash
|
85
|
+
id.hash
|
86
|
+
end
|
137
87
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
@attributes = default_attributes
|
150
|
-
process(attrs)
|
151
|
-
@new_record = true
|
152
|
-
document = yield self if block_given?
|
153
|
-
identify
|
154
|
-
end
|
88
|
+
# Introduces a child object into the +Document+ object graph. This will
|
89
|
+
# set up the relationships between the parent and child and update the
|
90
|
+
# attributes of the parent +Document+.
|
91
|
+
#
|
92
|
+
# Options:
|
93
|
+
#
|
94
|
+
# parent: The +Document+ to assimilate with.
|
95
|
+
# options: The association +Options+ for the child.
|
96
|
+
def assimilate(parent, options)
|
97
|
+
parentize(parent, options.name); notify; self
|
98
|
+
end
|
155
99
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
dynamic_keys = @attributes.keys - fields.keys - associations.keys - ["_id", "_type"]
|
161
|
-
attrs += dynamic_keys.map { |name| "#{name}: #{@attributes[name].inspect}" }
|
162
|
-
end
|
163
|
-
"#<#{self.class.name} _id: #{id}, #{attrs * ', '}>"
|
164
|
-
end
|
100
|
+
# Return the attributes hash with indifferent access.
|
101
|
+
def attributes
|
102
|
+
@attributes.with_indifferent_access
|
103
|
+
end
|
165
104
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
def notify
|
172
|
-
notify_observers(self)
|
173
|
-
end
|
105
|
+
# Clone the current +Document+. This will return all attributes with the
|
106
|
+
# exception of the document's id and versions.
|
107
|
+
def clone
|
108
|
+
self.class.instantiate(@attributes.except("_id").except("versions").dup, true)
|
109
|
+
end
|
174
110
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
# Options:
|
180
|
-
#
|
181
|
-
# abject: The parent object that needs to be set for the child.
|
182
|
-
# association_name: The name of the association for the child.
|
183
|
-
#
|
184
|
-
# Example:
|
185
|
-
#
|
186
|
-
# <tt>address.parentize(person, :addresses)</tt>
|
187
|
-
def parentize(object, association_name)
|
188
|
-
self._parent = object
|
189
|
-
self.association_name = association_name.to_s
|
190
|
-
add_observer(object)
|
191
|
-
end
|
111
|
+
# Generate an id for this +Document+.
|
112
|
+
def identify
|
113
|
+
Identity.new(self).create
|
114
|
+
end
|
192
115
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
116
|
+
# Instantiate a new +Document+, setting the Document's attributes if
|
117
|
+
# given. If no attributes are provided, they will be initialized with
|
118
|
+
# an empty +Hash+.
|
119
|
+
#
|
120
|
+
# If a primary key is defined, the document's id will be set to that key,
|
121
|
+
# otherwise it will be set to a fresh +BSON::ObjectID+ string.
|
122
|
+
#
|
123
|
+
# Options:
|
124
|
+
#
|
125
|
+
# attrs: The attributes +Hash+ to set up the document with.
|
126
|
+
def initialize(attrs = nil)
|
127
|
+
@attributes = default_attributes
|
128
|
+
process(attrs)
|
129
|
+
@new_record = true
|
130
|
+
document = yield self if block_given?
|
131
|
+
identify
|
132
|
+
end
|
197
133
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
@attributes = {}.merge(reloaded || {})
|
205
|
-
self.associations.keys.each { |association_name| unmemoize(association_name) }; self
|
134
|
+
# Returns the class name plus its attributes.
|
135
|
+
def inspect
|
136
|
+
attrs = fields.map { |name, field| "#{name}: #{@attributes[name].inspect}" }
|
137
|
+
if Mongoid.allow_dynamic_fields
|
138
|
+
dynamic_keys = @attributes.keys - fields.keys - associations.keys - ["_id", "_type"]
|
139
|
+
attrs += dynamic_keys.map { |name| "#{name}: #{@attributes[name].inspect}" }
|
206
140
|
end
|
141
|
+
"#<#{self.class.name} _id: #{id}, #{attrs * ', '}>"
|
142
|
+
end
|
207
143
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
144
|
+
# Notify observers of an update.
|
145
|
+
#
|
146
|
+
# Example:
|
147
|
+
#
|
148
|
+
# <tt>person.notify</tt>
|
149
|
+
def notify
|
150
|
+
notify_observers(self)
|
151
|
+
end
|
215
152
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
while (object._parent) do object = object._parent; end
|
221
|
-
object || self
|
222
|
-
end
|
153
|
+
# Return the attributes hash.
|
154
|
+
def raw_attributes
|
155
|
+
@attributes
|
156
|
+
end
|
223
157
|
|
224
|
-
|
225
|
-
|
226
|
-
|
158
|
+
# Reloads the +Document+ attributes from the database.
|
159
|
+
def reload
|
160
|
+
reloaded = collection.find_one(:_id => id)
|
161
|
+
if Mongoid.raise_not_found_error
|
162
|
+
raise Errors::DocumentNotFound.new(self.class, id) if reloaded.nil?
|
227
163
|
end
|
164
|
+
@attributes = {}.merge(reloaded || {})
|
165
|
+
self.associations.keys.each { |association_name| unmemoize(association_name) }; self
|
166
|
+
end
|
228
167
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
168
|
+
# Remove a child document from this parent +Document+. Will reset the
|
169
|
+
# memoized association and notify the parent of the change.
|
170
|
+
def remove(child)
|
171
|
+
name = child.association_name
|
172
|
+
reset(name) { @attributes.remove(name, child.raw_attributes) }
|
173
|
+
notify
|
174
|
+
end
|
233
175
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
176
|
+
# Return an array with this +Document+ only in it.
|
177
|
+
def to_a
|
178
|
+
[ self ]
|
179
|
+
end
|
238
180
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
end
|
181
|
+
# Observe a notify call from a child +Document+. This will either update
|
182
|
+
# existing attributes on the +Document+ or clear them out for the child if
|
183
|
+
# the clear boolean is provided.
|
184
|
+
#
|
185
|
+
# Options:
|
186
|
+
#
|
187
|
+
# child: The child +Document+ that sent the notification.
|
188
|
+
# clear: Will clear out the child's attributes if set to true.
|
189
|
+
#
|
190
|
+
# This will also cause the observing +Document+ to notify it's parent if
|
191
|
+
# there is any.
|
192
|
+
def observe(child, clear = false)
|
193
|
+
name = child.association_name
|
194
|
+
attrs = child.instance_variable_get(:@attributes)
|
195
|
+
if clear
|
196
|
+
@attributes.delete(name)
|
197
|
+
else
|
198
|
+
@attributes.insert(name, attrs) unless @attributes[name] && @attributes[name].include?(attrs)
|
199
|
+
end
|
200
|
+
notify
|
260
201
|
end
|
261
202
|
end
|
262
203
|
end
|
data/lib/mongoid/extensions.rb
CHANGED
@@ -5,6 +5,7 @@ require "mongoid/extensions/array/aliasing"
|
|
5
5
|
require "mongoid/extensions/array/assimilation"
|
6
6
|
require "mongoid/extensions/array/conversions"
|
7
7
|
require "mongoid/extensions/array/parentization"
|
8
|
+
require "mongoid/extensions/set/conversions"
|
8
9
|
require "mongoid/extensions/big_decimal/conversions"
|
9
10
|
require "mongoid/extensions/binary/conversions"
|
10
11
|
require "mongoid/extensions/boolean/conversions"
|
@@ -32,6 +33,10 @@ class Array #:nodoc
|
|
32
33
|
include Mongoid::Extensions::Array::Parentization
|
33
34
|
end
|
34
35
|
|
36
|
+
class Set #:nodoc
|
37
|
+
include Mongoid::Extensions::Set::Conversions
|
38
|
+
end
|
39
|
+
|
35
40
|
class BigDecimal #:nodoc
|
36
41
|
extend Mongoid::Extensions::BigDecimal::Conversions
|
37
42
|
end
|
@@ -6,11 +6,9 @@ module Mongoid #:nodoc:
|
|
6
6
|
module Conversions #:nodoc:
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
collect { |obj| obj.attributes }
|
13
|
-
end
|
9
|
+
# Converts this array into an array of hashes.
|
10
|
+
def mongoidize
|
11
|
+
collect { |obj| obj.attributes }
|
14
12
|
end
|
15
13
|
|
16
14
|
module ClassMethods #:nodoc:
|
@@ -5,30 +5,27 @@ module Mongoid #:nodoc:
|
|
5
5
|
module Conversions #:nodoc:
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
if
|
26
|
-
new_value = other[key]
|
27
|
-
changes[key] = [ value, new_value ] if new_value != value
|
28
|
-
end
|
8
|
+
# Get the difference between 2 hashes. This will give back a new hash
|
9
|
+
# with the keys and pairs of [ old, new ] values.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# first = { :field => "value" }
|
14
|
+
# second = { :field => "new" }
|
15
|
+
# first.difference(second) # => { :field => [ "value", "new" ] }
|
16
|
+
#
|
17
|
+
# Returns:
|
18
|
+
#
|
19
|
+
# A +Hash+ of modifications.
|
20
|
+
def difference(other)
|
21
|
+
changes = {}
|
22
|
+
each_pair do |key, value|
|
23
|
+
if other.has_key?(key)
|
24
|
+
new_value = other[key]
|
25
|
+
changes[key] = [ value, new_value ] if new_value != value
|
29
26
|
end
|
30
|
-
changes
|
31
27
|
end
|
28
|
+
changes
|
32
29
|
end
|
33
30
|
|
34
31
|
module ClassMethods #:nodoc:
|
@@ -5,11 +5,9 @@ module Mongoid #:nodoc:
|
|
5
5
|
# This module converts objects into mongoid related objects.
|
6
6
|
module Conversions #:nodoc:
|
7
7
|
extend ActiveSupport::Concern
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
self.raw_attributes
|
12
|
-
end
|
8
|
+
# Converts this object to a hash of attributes
|
9
|
+
def mongoidize
|
10
|
+
self.raw_attributes
|
13
11
|
end
|
14
12
|
|
15
13
|
module ClassMethods
|