stonegao-mongoid 2.0.0.rc.6
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/LICENSE +20 -0
- data/README.rdoc +50 -0
- data/Rakefile +51 -0
- data/lib/config/locales/bg.yml +44 -0
- data/lib/config/locales/de.yml +44 -0
- data/lib/config/locales/en.yml +45 -0
- data/lib/config/locales/es.yml +44 -0
- data/lib/config/locales/fr.yml +45 -0
- data/lib/config/locales/hu.yml +47 -0
- data/lib/config/locales/it.yml +42 -0
- data/lib/config/locales/kr.yml +68 -0
- data/lib/config/locales/nl.yml +42 -0
- data/lib/config/locales/pl.yml +42 -0
- data/lib/config/locales/pt-br.yml +43 -0
- data/lib/config/locales/pt.yml +43 -0
- data/lib/config/locales/ro.yml +49 -0
- data/lib/config/locales/sv.yml +43 -0
- data/lib/config/locales/zh-CN.yml +34 -0
- data/lib/mongoid/atomicity.rb +111 -0
- data/lib/mongoid/attributes.rb +251 -0
- data/lib/mongoid/callbacks.rb +13 -0
- data/lib/mongoid/collection.rb +137 -0
- data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
- data/lib/mongoid/collections/master.rb +29 -0
- data/lib/mongoid/collections/operations.rb +42 -0
- data/lib/mongoid/collections/slaves.rb +45 -0
- data/lib/mongoid/collections.rb +70 -0
- data/lib/mongoid/components.rb +45 -0
- data/lib/mongoid/config/database.rb +167 -0
- data/lib/mongoid/config/replset_database.rb +48 -0
- data/lib/mongoid/config.rb +343 -0
- data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
- data/lib/mongoid/contexts/enumerable.rb +226 -0
- data/lib/mongoid/contexts/ids.rb +25 -0
- data/lib/mongoid/contexts/mongo.rb +345 -0
- data/lib/mongoid/contexts/paging.rb +50 -0
- data/lib/mongoid/contexts.rb +21 -0
- data/lib/mongoid/copyable.rb +44 -0
- data/lib/mongoid/criteria.rb +325 -0
- data/lib/mongoid/criterion/complex.rb +34 -0
- data/lib/mongoid/criterion/creational.rb +34 -0
- data/lib/mongoid/criterion/exclusion.rb +67 -0
- data/lib/mongoid/criterion/inclusion.rb +134 -0
- data/lib/mongoid/criterion/inspection.rb +20 -0
- data/lib/mongoid/criterion/optional.rb +213 -0
- data/lib/mongoid/criterion/selector.rb +74 -0
- data/lib/mongoid/cursor.rb +81 -0
- data/lib/mongoid/default_scope.rb +28 -0
- data/lib/mongoid/dirty.rb +251 -0
- data/lib/mongoid/document.rb +256 -0
- data/lib/mongoid/errors/document_not_found.rb +29 -0
- data/lib/mongoid/errors/invalid_collection.rb +19 -0
- data/lib/mongoid/errors/invalid_database.rb +20 -0
- data/lib/mongoid/errors/invalid_field.rb +19 -0
- data/lib/mongoid/errors/invalid_options.rb +16 -0
- data/lib/mongoid/errors/invalid_type.rb +26 -0
- data/lib/mongoid/errors/mongoid_error.rb +27 -0
- data/lib/mongoid/errors/too_many_nested_attribute_records.rb +21 -0
- data/lib/mongoid/errors/unsaved_document.rb +23 -0
- data/lib/mongoid/errors/unsupported_version.rb +21 -0
- data/lib/mongoid/errors/validations.rb +24 -0
- data/lib/mongoid/errors.rb +12 -0
- data/lib/mongoid/extensions/array/conversions.rb +23 -0
- data/lib/mongoid/extensions/array/parentization.rb +13 -0
- data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
- data/lib/mongoid/extensions/binary/conversions.rb +17 -0
- data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
- data/lib/mongoid/extensions/date/conversions.rb +25 -0
- data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
- data/lib/mongoid/extensions/false_class/equality.rb +13 -0
- data/lib/mongoid/extensions/float/conversions.rb +20 -0
- data/lib/mongoid/extensions/hash/conversions.rb +19 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +22 -0
- data/lib/mongoid/extensions/hash/scoping.rb +12 -0
- data/lib/mongoid/extensions/integer/conversions.rb +20 -0
- data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
- data/lib/mongoid/extensions/object/conversions.rb +25 -0
- data/lib/mongoid/extensions/object/reflections.rb +17 -0
- data/lib/mongoid/extensions/object/yoda.rb +27 -0
- data/lib/mongoid/extensions/object_id/conversions.rb +57 -0
- data/lib/mongoid/extensions/proc/scoping.rb +12 -0
- data/lib/mongoid/extensions/set/conversions.rb +20 -0
- data/lib/mongoid/extensions/string/conversions.rb +34 -0
- data/lib/mongoid/extensions/string/inflections.rb +97 -0
- data/lib/mongoid/extensions/symbol/conversions.rb +21 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
- data/lib/mongoid/extensions/time_conversions.rb +38 -0
- data/lib/mongoid/extensions/true_class/equality.rb +13 -0
- data/lib/mongoid/extensions.rb +116 -0
- data/lib/mongoid/extras.rb +61 -0
- data/lib/mongoid/factory.rb +20 -0
- data/lib/mongoid/field.rb +95 -0
- data/lib/mongoid/fields.rb +138 -0
- data/lib/mongoid/finders.rb +173 -0
- data/lib/mongoid/hierarchy.rb +85 -0
- data/lib/mongoid/identity.rb +89 -0
- data/lib/mongoid/indexes.rb +38 -0
- data/lib/mongoid/inspection.rb +58 -0
- data/lib/mongoid/javascript/functions.yml +37 -0
- data/lib/mongoid/javascript.rb +21 -0
- data/lib/mongoid/json.rb +16 -0
- data/lib/mongoid/keys.rb +77 -0
- data/lib/mongoid/logger.rb +18 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +27 -0
- data/lib/mongoid/matchers/exists.rb +13 -0
- data/lib/mongoid/matchers/gt.rb +11 -0
- data/lib/mongoid/matchers/gte.rb +11 -0
- data/lib/mongoid/matchers/in.rb +11 -0
- data/lib/mongoid/matchers/lt.rb +11 -0
- data/lib/mongoid/matchers/lte.rb +11 -0
- data/lib/mongoid/matchers/ne.rb +11 -0
- data/lib/mongoid/matchers/nin.rb +11 -0
- data/lib/mongoid/matchers/size.rb +11 -0
- data/lib/mongoid/matchers.rb +55 -0
- data/lib/mongoid/modifiers/command.rb +18 -0
- data/lib/mongoid/modifiers/inc.rb +24 -0
- data/lib/mongoid/modifiers.rb +24 -0
- data/lib/mongoid/multi_database.rb +11 -0
- data/lib/mongoid/multi_parameter_attributes.rb +80 -0
- data/lib/mongoid/named_scope.rb +36 -0
- data/lib/mongoid/nested_attributes.rb +43 -0
- data/lib/mongoid/paranoia.rb +103 -0
- data/lib/mongoid/paths.rb +61 -0
- data/lib/mongoid/persistence/command.rb +59 -0
- data/lib/mongoid/persistence/insert.rb +53 -0
- data/lib/mongoid/persistence/insert_embedded.rb +42 -0
- data/lib/mongoid/persistence/remove.rb +44 -0
- data/lib/mongoid/persistence/remove_all.rb +40 -0
- data/lib/mongoid/persistence/remove_embedded.rb +48 -0
- data/lib/mongoid/persistence/update.rb +76 -0
- data/lib/mongoid/persistence.rb +237 -0
- data/lib/mongoid/railtie.rb +129 -0
- data/lib/mongoid/railties/database.rake +171 -0
- data/lib/mongoid/railties/document.rb +12 -0
- data/lib/mongoid/relations/accessors.rb +157 -0
- data/lib/mongoid/relations/auto_save.rb +34 -0
- data/lib/mongoid/relations/binding.rb +26 -0
- data/lib/mongoid/relations/bindings/embedded/in.rb +82 -0
- data/lib/mongoid/relations/bindings/embedded/many.rb +98 -0
- data/lib/mongoid/relations/bindings/embedded/one.rb +66 -0
- data/lib/mongoid/relations/bindings/referenced/in.rb +74 -0
- data/lib/mongoid/relations/bindings/referenced/many.rb +96 -0
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +99 -0
- data/lib/mongoid/relations/bindings/referenced/one.rb +66 -0
- data/lib/mongoid/relations/bindings.rb +9 -0
- data/lib/mongoid/relations/builder.rb +42 -0
- data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
- data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
- data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
- data/lib/mongoid/relations/builders/nested_attributes/many.rb +116 -0
- data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
- data/lib/mongoid/relations/builders/referenced/in.rb +32 -0
- data/lib/mongoid/relations/builders/referenced/many.rb +26 -0
- data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
- data/lib/mongoid/relations/builders/referenced/one.rb +30 -0
- data/lib/mongoid/relations/builders.rb +79 -0
- data/lib/mongoid/relations/cascading/delete.rb +19 -0
- data/lib/mongoid/relations/cascading/destroy.rb +19 -0
- data/lib/mongoid/relations/cascading/nullify.rb +18 -0
- data/lib/mongoid/relations/cascading/strategy.rb +26 -0
- data/lib/mongoid/relations/cascading.rb +55 -0
- data/lib/mongoid/relations/constraint.rb +45 -0
- data/lib/mongoid/relations/cyclic.rb +97 -0
- data/lib/mongoid/relations/embedded/in.rb +173 -0
- data/lib/mongoid/relations/embedded/many.rb +483 -0
- data/lib/mongoid/relations/embedded/one.rb +170 -0
- data/lib/mongoid/relations/macros.rb +306 -0
- data/lib/mongoid/relations/many.rb +171 -0
- data/lib/mongoid/relations/metadata.rb +533 -0
- data/lib/mongoid/relations/nested_builder.rb +68 -0
- data/lib/mongoid/relations/one.rb +47 -0
- data/lib/mongoid/relations/polymorphic.rb +54 -0
- data/lib/mongoid/relations/proxy.rb +128 -0
- data/lib/mongoid/relations/referenced/in.rb +216 -0
- data/lib/mongoid/relations/referenced/many.rb +443 -0
- data/lib/mongoid/relations/referenced/many_to_many.rb +344 -0
- data/lib/mongoid/relations/referenced/one.rb +206 -0
- data/lib/mongoid/relations/reflections.rb +45 -0
- data/lib/mongoid/relations.rb +105 -0
- data/lib/mongoid/safe.rb +23 -0
- data/lib/mongoid/safety.rb +207 -0
- data/lib/mongoid/scope.rb +31 -0
- data/lib/mongoid/serialization.rb +99 -0
- data/lib/mongoid/state.rb +66 -0
- data/lib/mongoid/timestamps.rb +38 -0
- data/lib/mongoid/validations/associated.rb +42 -0
- data/lib/mongoid/validations/uniqueness.rb +85 -0
- data/lib/mongoid/validations.rb +117 -0
- data/lib/mongoid/version.rb +4 -0
- data/lib/mongoid/versioning.rb +51 -0
- data/lib/mongoid.rb +139 -0
- data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +23 -0
- data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
- data/lib/rails/generators/mongoid/model/templates/model.rb +17 -0
- data/lib/rails/generators/mongoid_generator.rb +61 -0
- data/lib/rails/mongoid.rb +57 -0
- metadata +380 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid # :nodoc:
|
|
3
|
+
module Relations #:nodoc:
|
|
4
|
+
|
|
5
|
+
# The "Grand Poobah" of information about any relation is this class. It
|
|
6
|
+
# contains everything you could ever possible want to know.
|
|
7
|
+
class Metadata < Hash
|
|
8
|
+
|
|
9
|
+
delegate :foreign_key_default, :stores_foreign_key?, :to => :relation
|
|
10
|
+
|
|
11
|
+
# Gets a relation builder associated with the relation this metadata is
|
|
12
|
+
# for.
|
|
13
|
+
#
|
|
14
|
+
# @example Get the builder.
|
|
15
|
+
# metadata.builder(document)
|
|
16
|
+
#
|
|
17
|
+
# @param [ Object ] object A document or attributes to give the builder.
|
|
18
|
+
#
|
|
19
|
+
# @return [ Builder ] The builder for the relation.
|
|
20
|
+
#
|
|
21
|
+
# @since 2.0.0.rc.1
|
|
22
|
+
def builder(object)
|
|
23
|
+
relation.builder(self, object)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns the name of the strategy used for handling dependent relations.
|
|
27
|
+
#
|
|
28
|
+
# @example Get the strategy.
|
|
29
|
+
# metadata.cascade_strategy
|
|
30
|
+
#
|
|
31
|
+
# @return [ Object ] The cascading strategy to use.
|
|
32
|
+
#
|
|
33
|
+
# @since 2.0.0.rc.1
|
|
34
|
+
def cascade_strategy
|
|
35
|
+
if dependent?
|
|
36
|
+
strategy =
|
|
37
|
+
%{Mongoid::Relations::Cascading::#{dependent.to_s.classify}}
|
|
38
|
+
strategy.constantize
|
|
39
|
+
else
|
|
40
|
+
return nil
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Returns the name of the class that this relation contains. If the
|
|
45
|
+
# class_name was provided as an option this will return that, otherwise
|
|
46
|
+
# it will determine the name from the name property.
|
|
47
|
+
#
|
|
48
|
+
# @example Get the class name.
|
|
49
|
+
# metadata.class_name
|
|
50
|
+
#
|
|
51
|
+
# @return [ String ] The name of the relation's proxied class.
|
|
52
|
+
#
|
|
53
|
+
# @since 2.0.0.rc.1
|
|
54
|
+
def class_name
|
|
55
|
+
@class_name ||= (self[:class_name] || classify)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def constraint
|
|
59
|
+
@constraint ||= Constraint.new(self)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Will determine if the relation is an embedded one or not. Currently
|
|
63
|
+
# only checks against embeds one and many.
|
|
64
|
+
#
|
|
65
|
+
# @example Is the document embedded.
|
|
66
|
+
# metadata.embedded?
|
|
67
|
+
#
|
|
68
|
+
# @return [ true, false ] True if embedded, false if not.
|
|
69
|
+
#
|
|
70
|
+
# @since 2.0.0.rc.1
|
|
71
|
+
def embedded?
|
|
72
|
+
@embedded ||= (macro == :embeds_one || macro == :embeds_many)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Returns the extension of the relation. This can be a proc or module.
|
|
76
|
+
#
|
|
77
|
+
# @example Get the relation extension.
|
|
78
|
+
# metadata.extension
|
|
79
|
+
#
|
|
80
|
+
# @return [ Proc ] The extension or nil.
|
|
81
|
+
#
|
|
82
|
+
# @since 2.0.0.rc.1
|
|
83
|
+
def extension
|
|
84
|
+
self[:extend]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Tells whether an extension definition exist for this relation.
|
|
88
|
+
#
|
|
89
|
+
# @example Is an extension defined?
|
|
90
|
+
# metadata.extension?
|
|
91
|
+
#
|
|
92
|
+
# @return [ true, false ] True if an extension exists, false if not.
|
|
93
|
+
#
|
|
94
|
+
# @since 2.0.0.rc.1
|
|
95
|
+
def extension?
|
|
96
|
+
!!extension
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Handles all the logic for figuring out what the foreign_key is for each
|
|
100
|
+
# relations query. The logic is as follows:
|
|
101
|
+
#
|
|
102
|
+
# 1. If the developer defined a custom key, use that.
|
|
103
|
+
# 2. If the relation stores a foreign key,
|
|
104
|
+
# use the class_name_id strategy.
|
|
105
|
+
# 3. If the relation does not store the key,
|
|
106
|
+
# use the inverse_class_name_id strategy.
|
|
107
|
+
#
|
|
108
|
+
# @example Get the foreign key.
|
|
109
|
+
# metadata.foreign_key
|
|
110
|
+
#
|
|
111
|
+
# @return [ String ] The foreign key for the relation.
|
|
112
|
+
#
|
|
113
|
+
# @since 2.0.0.rc.1
|
|
114
|
+
def foreign_key
|
|
115
|
+
@foreign_key ||= determine_foreign_key
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Returns the name of the method used to set the foreign key on a
|
|
119
|
+
# document.
|
|
120
|
+
#
|
|
121
|
+
# @example Get the setter for the foreign key.
|
|
122
|
+
# metadata.foreign_key_setter
|
|
123
|
+
#
|
|
124
|
+
# @return [ String ] The foreign_key plus =.
|
|
125
|
+
#
|
|
126
|
+
# @since 2.0.0.rc.1
|
|
127
|
+
def foreign_key_setter
|
|
128
|
+
@foreign_key_setter ||= "#{foreign_key}="
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Tells whether a foreign key index exists on the relation.
|
|
132
|
+
#
|
|
133
|
+
# @example Is the key indexed?
|
|
134
|
+
# metadata.indexed?
|
|
135
|
+
#
|
|
136
|
+
# @return [ true, false ] True if an index exists, false if not.
|
|
137
|
+
#
|
|
138
|
+
# @since 2.0.0.rc.1
|
|
139
|
+
def indexed?
|
|
140
|
+
!!self[:index]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Instantiate new metadata for a relation.
|
|
144
|
+
#
|
|
145
|
+
# @example Create the new metadata.
|
|
146
|
+
# Metadata.new(:name => :addresses)
|
|
147
|
+
#
|
|
148
|
+
# @param [ Hash ] properties The relation options.
|
|
149
|
+
#
|
|
150
|
+
# @since 2.0.0.rc.1
|
|
151
|
+
def initialize(properties = {})
|
|
152
|
+
merge!(properties)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Since a lot of the information from the metadata is inferred and not
|
|
156
|
+
# explicitly stored in the hash, the inspection needs to be much more
|
|
157
|
+
# detailed.
|
|
158
|
+
#
|
|
159
|
+
# @example Inspect the metadata.
|
|
160
|
+
# metadata.inspect
|
|
161
|
+
#
|
|
162
|
+
# @return [ String ] Oodles of information in a nice format.
|
|
163
|
+
#
|
|
164
|
+
# @since 2.0.0.rc.1
|
|
165
|
+
def inspect
|
|
166
|
+
"#<Mongoid::Relations::Metadata\n" <<
|
|
167
|
+
" class_name: #{class_name},\n" <<
|
|
168
|
+
" cyclic: #{cyclic || "No"},\n" <<
|
|
169
|
+
" dependent: #{dependent || "None"},\n" <<
|
|
170
|
+
" inverse_of: #{inverse_of || "N/A"},\n" <<
|
|
171
|
+
" inverse_setter: #{inverse_setter},\n" <<
|
|
172
|
+
" inverse_type: #{inverse_type || "N/A"},\n" <<
|
|
173
|
+
" inverse_type_setter: #{inverse_type_setter || "N/A"},\n" <<
|
|
174
|
+
" key: #{key},\n" <<
|
|
175
|
+
" macro: #{macro},\n" <<
|
|
176
|
+
" name: #{name},\n" <<
|
|
177
|
+
" polymorphic: #{polymorphic? ? "Yes" : "No"},\n" <<
|
|
178
|
+
" relation: #{relation},\n" <<
|
|
179
|
+
" setter: #{setter}>\n"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Get the name of the inverse relation if it exists. If this is a
|
|
183
|
+
# polymorphic relation then just return the :as option that was defined.
|
|
184
|
+
#
|
|
185
|
+
# @example Get the name of the inverse.
|
|
186
|
+
# metadata.inverse
|
|
187
|
+
#
|
|
188
|
+
# @param [ Document ] other The document to aid in the discovery.
|
|
189
|
+
#
|
|
190
|
+
# @return [ Symbol ] The inverse name.
|
|
191
|
+
#
|
|
192
|
+
# @since 2.0.0.rc.1
|
|
193
|
+
def inverse(other = nil)
|
|
194
|
+
return self[:inverse_of] if inverse_of?
|
|
195
|
+
return self[:as] || lookup_inverse(other) if polymorphic?
|
|
196
|
+
@inverse ||= (cyclic? ? cyclic_inverse : inverse_relation)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Used for relational many to many only. This determines the name of the
|
|
200
|
+
# foreign key field on the inverse side of the relation, since in this
|
|
201
|
+
# case there are keys on both sides.
|
|
202
|
+
#
|
|
203
|
+
# @example Find the inverse foreign key
|
|
204
|
+
# metadata.inverse_foreign_key
|
|
205
|
+
#
|
|
206
|
+
# @return [ String ] The foreign key on the inverse.
|
|
207
|
+
#
|
|
208
|
+
# @since 2.0.0.rc.1
|
|
209
|
+
def inverse_foreign_key
|
|
210
|
+
@inverse_foreign_key ||=
|
|
211
|
+
(inverse_class_name.underscore << relation.foreign_key_suffix)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Returns the inverse class of the proxied relation.
|
|
215
|
+
#
|
|
216
|
+
# @example Get the inverse class.
|
|
217
|
+
# metadata.inverse_klass
|
|
218
|
+
#
|
|
219
|
+
# @return [ Class ] The class of the inverse of the relation.
|
|
220
|
+
#
|
|
221
|
+
# @since 2.0.0.rc.1
|
|
222
|
+
def inverse_klass
|
|
223
|
+
@inverse_klass ||= inverse_class_name.constantize
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Returns the setter for the inverse side of the relation.
|
|
227
|
+
#
|
|
228
|
+
# @example Get the inverse setter.
|
|
229
|
+
# metadata.inverse_setter
|
|
230
|
+
#
|
|
231
|
+
# @param [ Document ] other A document to aid in the discovery.
|
|
232
|
+
#
|
|
233
|
+
# @return [ String ] The inverse setter name.
|
|
234
|
+
#
|
|
235
|
+
# @since 2.0.0.rc.1
|
|
236
|
+
def inverse_setter(other = nil)
|
|
237
|
+
inverse(other).to_s << "="
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Returns the name of the field in which to store the name of the class
|
|
241
|
+
# for the polymorphic relation.
|
|
242
|
+
#
|
|
243
|
+
# @example Get the name of the field.
|
|
244
|
+
# metadata.inverse_type
|
|
245
|
+
#
|
|
246
|
+
# @return [ String ] The name of the field for storing the type.
|
|
247
|
+
#
|
|
248
|
+
# @since 2.0.0.rc.1
|
|
249
|
+
def inverse_type
|
|
250
|
+
if relation.stores_foreign_key? && polymorphic?
|
|
251
|
+
(polymorphic? ? name.to_s : class_name.underscore) << "_type"
|
|
252
|
+
else
|
|
253
|
+
return nil
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Gets the setter for the field that sets the type of document on a
|
|
258
|
+
# polymorphic relation.
|
|
259
|
+
#
|
|
260
|
+
# @example Get the inverse type setter.
|
|
261
|
+
# metadata.inverse_type_setter
|
|
262
|
+
#
|
|
263
|
+
# @return [ String ] The name of the setter.
|
|
264
|
+
#
|
|
265
|
+
# @since 2.0.0.rc.1
|
|
266
|
+
def inverse_type_setter
|
|
267
|
+
inverse_type ? inverse_type << "=" : nil
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# This returns the key that is to be used to grab the attributes for the
|
|
271
|
+
# relation or the foreign key or id that a referenced relation will use
|
|
272
|
+
# to query for the object.
|
|
273
|
+
#
|
|
274
|
+
# @example Get the lookup key.
|
|
275
|
+
# metadata.key
|
|
276
|
+
#
|
|
277
|
+
# @return [ String ] The association name, foreign key name, or _id.
|
|
278
|
+
#
|
|
279
|
+
# @since 2.0.0.rc.1
|
|
280
|
+
def key
|
|
281
|
+
@key ||= determine_key
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Returns the class of the proxied relation.
|
|
285
|
+
#
|
|
286
|
+
# @example Get the class.
|
|
287
|
+
# metadata.klass
|
|
288
|
+
#
|
|
289
|
+
# @return [ Class ] The class of the relation.
|
|
290
|
+
#
|
|
291
|
+
# @since 2.0.0.rc.1
|
|
292
|
+
def klass
|
|
293
|
+
@klass ||= class_name.constantize
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Returns the macro for the relation of this metadata.
|
|
297
|
+
#
|
|
298
|
+
# @example Get the macro.
|
|
299
|
+
# metadata.macro
|
|
300
|
+
#
|
|
301
|
+
# @return [ Symbol ] The macro.
|
|
302
|
+
#
|
|
303
|
+
# @since 2.0.0.rc.1
|
|
304
|
+
def macro
|
|
305
|
+
relation.macro
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Gets a relation nested builder associated with the relation this metadata
|
|
309
|
+
# is for. Nested builders are used in conjunction with nested attributes.
|
|
310
|
+
#
|
|
311
|
+
# @example Get the nested builder.
|
|
312
|
+
# metadata.nested_builder(attributes, options)
|
|
313
|
+
#
|
|
314
|
+
# @param [ Hash ] attributes The attributes to build the relation with.
|
|
315
|
+
# @param [ Hash ] options Options for the nested builder.
|
|
316
|
+
#
|
|
317
|
+
# @return [ NestedBuilder ] The nested builder for the relation.
|
|
318
|
+
#
|
|
319
|
+
# @since 2.0.0.rc.1
|
|
320
|
+
def nested_builder(attributes, options)
|
|
321
|
+
relation.nested_builder(self, attributes, options)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# Returns true if the relation is polymorphic.
|
|
325
|
+
#
|
|
326
|
+
# @example Is the relation polymorphic?
|
|
327
|
+
# metadata.polymorphic?
|
|
328
|
+
#
|
|
329
|
+
# @return [ true, false ] True if the relation is polymorphic, false if not.
|
|
330
|
+
#
|
|
331
|
+
# @since 2.0.0.rc.1
|
|
332
|
+
def polymorphic?
|
|
333
|
+
@polymorphic ||= (!!self[:as] || !!self[:polymorphic])
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Gets the method name used to set this relation.
|
|
337
|
+
#
|
|
338
|
+
# @example Get the setter.
|
|
339
|
+
# metadata = Metadata.new(:name => :person)
|
|
340
|
+
# metadata.setter # => "person="
|
|
341
|
+
#
|
|
342
|
+
# @return [ String ] The name plus "=".
|
|
343
|
+
#
|
|
344
|
+
# @since 2.0.0.rc.1
|
|
345
|
+
def setter
|
|
346
|
+
@setter ||= "#{name.to_s}="
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Are we validating this relation automatically?
|
|
350
|
+
#
|
|
351
|
+
# @example Is automatic validation on?
|
|
352
|
+
# metadata.validate?
|
|
353
|
+
#
|
|
354
|
+
# @return [ true, false ] True unless explictly set to false.
|
|
355
|
+
#
|
|
356
|
+
# @since 2.0.0.rc.1
|
|
357
|
+
def validate?
|
|
358
|
+
self[:validate] != false
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
private
|
|
362
|
+
|
|
363
|
+
# Returns the class name for the relation.
|
|
364
|
+
#
|
|
365
|
+
# @example Get the class name.
|
|
366
|
+
# metadata.classify
|
|
367
|
+
#
|
|
368
|
+
# @return [ String ] If embedded_in, the camelized, else classified.
|
|
369
|
+
#
|
|
370
|
+
# @since 2.0.0.rc.1
|
|
371
|
+
def classify
|
|
372
|
+
macro == :embedded_in ? name.to_s.camelize : name.to_s.classify
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# Get the name of the inverse relation in a cyclic relation.
|
|
376
|
+
#
|
|
377
|
+
# @example Get the cyclic inverse name.
|
|
378
|
+
#
|
|
379
|
+
# class Role
|
|
380
|
+
# include Mongoid::Document
|
|
381
|
+
# embedded_in :parent_role, :cyclic => true
|
|
382
|
+
# embeds_many :child_roles, :cyclic => true
|
|
383
|
+
# end
|
|
384
|
+
#
|
|
385
|
+
# metadata = Metadata.new(:name => :parent_role)
|
|
386
|
+
# metadata.cyclic_inverse # => "child_roles"
|
|
387
|
+
#
|
|
388
|
+
# @return [ String ] The cyclic inverse name.
|
|
389
|
+
#
|
|
390
|
+
# @since 2.0.0.rc.1
|
|
391
|
+
def cyclic_inverse
|
|
392
|
+
@cyclic_inverse ||= determine_cyclic_inverse
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Determine the cyclic inverse. Performance improvement with the
|
|
396
|
+
# memoization.
|
|
397
|
+
#
|
|
398
|
+
# @example Determine the inverse.
|
|
399
|
+
# metadata.determine_cyclic_inverse
|
|
400
|
+
#
|
|
401
|
+
# @return [ String ] The cyclic inverse name.
|
|
402
|
+
#
|
|
403
|
+
# @since 2.0.0.rc.1
|
|
404
|
+
def determine_cyclic_inverse
|
|
405
|
+
klass.relations.each_pair do |key, meta|
|
|
406
|
+
if key =~ /#{inverse_klass.name.underscore}/ &&
|
|
407
|
+
meta.relation != relation
|
|
408
|
+
return key.to_sym
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# Determine the value for the relation's foreign key. Performance
|
|
414
|
+
# improvement.
|
|
415
|
+
#
|
|
416
|
+
# @example Determine the foreign key.
|
|
417
|
+
# metadata.determine_foreign_key
|
|
418
|
+
#
|
|
419
|
+
# @return [ String ] The foreign key.
|
|
420
|
+
#
|
|
421
|
+
# @since 2.0.0.rc.1
|
|
422
|
+
def determine_foreign_key
|
|
423
|
+
return self[:foreign_key].to_s if self[:foreign_key]
|
|
424
|
+
suffix = relation.foreign_key_suffix
|
|
425
|
+
if relation.stores_foreign_key?
|
|
426
|
+
if relation.macro == :references_and_referenced_in_many
|
|
427
|
+
name.to_s.singularize << suffix
|
|
428
|
+
else
|
|
429
|
+
name.to_s << suffix
|
|
430
|
+
end
|
|
431
|
+
else
|
|
432
|
+
polymorphic? ? "#{self[:as]}#{suffix}" : inverse_class_name.foreign_key
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
# Determine the inverse relation. Memoizing #inverse_relation and adding
|
|
437
|
+
# this method dropped 5 seconds off the test suite as a performance
|
|
438
|
+
# improvement.
|
|
439
|
+
#
|
|
440
|
+
# @example Determine the inverse.
|
|
441
|
+
# metadata.determine_inverse_relation
|
|
442
|
+
#
|
|
443
|
+
# @return [ Symbol ] The name of the inverse.
|
|
444
|
+
#
|
|
445
|
+
# @since 2.0.0.rc.1
|
|
446
|
+
def determine_inverse_relation
|
|
447
|
+
klass.relations.each_pair do |key, meta|
|
|
448
|
+
if key == inverse_klass.name.underscore ||
|
|
449
|
+
meta.class_name == inverse_class_name
|
|
450
|
+
return key.to_sym
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
return nil
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# Determine the key for the relation in the attributes.
|
|
457
|
+
#
|
|
458
|
+
# @example Get the key.
|
|
459
|
+
# metadata.determine_key
|
|
460
|
+
#
|
|
461
|
+
# @return [ String ] The key in the attributes.
|
|
462
|
+
#
|
|
463
|
+
# @since 2.0.0.rc.1
|
|
464
|
+
def determine_key
|
|
465
|
+
return name.to_s if relation.embedded?
|
|
466
|
+
relation.stores_foreign_key? ? foreign_key : "_id"
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
# Determine the name of the inverse relation.
|
|
470
|
+
#
|
|
471
|
+
# @example Get the inverse name.
|
|
472
|
+
# metadata.inverse_relation
|
|
473
|
+
#
|
|
474
|
+
# @return [ Symbol ] The name of the inverse relation.
|
|
475
|
+
#
|
|
476
|
+
# @since 2.0.0.rc.1
|
|
477
|
+
def inverse_relation
|
|
478
|
+
@inverse_relation ||= determine_inverse_relation
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
# Infer the name of the inverse relation from the class.
|
|
482
|
+
#
|
|
483
|
+
# @example Get the inverse name
|
|
484
|
+
# metadata.inverse_name
|
|
485
|
+
#
|
|
486
|
+
# @return [ String ] The inverse class name underscored.
|
|
487
|
+
#
|
|
488
|
+
# @since 2.0.0.rc.1
|
|
489
|
+
def inverse_name
|
|
490
|
+
@inverse_name ||= inverse_klass.name.underscore
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
# For polymorphic children, we need to figure out the inverse from the
|
|
494
|
+
# actual instance on the other side, since we cannot know the exact class
|
|
495
|
+
# name to infer it from at load time.
|
|
496
|
+
#
|
|
497
|
+
# @example Find the inverse.
|
|
498
|
+
# metadata.lookup_inverse(other)
|
|
499
|
+
#
|
|
500
|
+
# @param [ Document ] : The inverse document.
|
|
501
|
+
#
|
|
502
|
+
# @return [ String ] The inverse name.
|
|
503
|
+
#
|
|
504
|
+
# @since 2.0.0.rc.1
|
|
505
|
+
def lookup_inverse(other)
|
|
506
|
+
return nil unless other
|
|
507
|
+
other.to_a.first.relations.each_pair do |key, meta|
|
|
508
|
+
return meta.name if meta.as == name
|
|
509
|
+
end
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
# Handles two different cases - the first is a convenience for JSON like
|
|
513
|
+
# access to the hash instead of having to call []. The second is a
|
|
514
|
+
# delegation of the "*?" methods to has_key? as a convenience to check
|
|
515
|
+
# for existence of a value.
|
|
516
|
+
#
|
|
517
|
+
# @example Extras provided by this method.
|
|
518
|
+
# metadata.name
|
|
519
|
+
# metadata.name?
|
|
520
|
+
#
|
|
521
|
+
# @param [ Symbol ] name The name of the method.
|
|
522
|
+
# @param [ Array ] args The arguments passed to the method.
|
|
523
|
+
#
|
|
524
|
+
# @return [ Object ] Either the value or a boolen.
|
|
525
|
+
#
|
|
526
|
+
# @since 2.0.0.rc.1
|
|
527
|
+
def method_missing(name, *args)
|
|
528
|
+
method = name.to_s
|
|
529
|
+
method =~ /\?/ ? has_key?(method.sub('?', '').to_sym) : self[name]
|
|
530
|
+
end
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid # :nodoc:
|
|
3
|
+
module Relations #:nodoc:
|
|
4
|
+
|
|
5
|
+
# This is the superclass for builders that are in charge of handling
|
|
6
|
+
# creation, deletion, and updates of documents through that ever so lovely
|
|
7
|
+
# #accepts_nested_attributes_for.
|
|
8
|
+
class NestedBuilder
|
|
9
|
+
attr_accessor :attributes, :existing, :metadata, :options
|
|
10
|
+
|
|
11
|
+
# Determines if destroys are allowed for this document.
|
|
12
|
+
#
|
|
13
|
+
# @example Do we allow a destroy?
|
|
14
|
+
# builder.allow_destroy?
|
|
15
|
+
#
|
|
16
|
+
# @return [ true, false ] True if the allow destroy option was set.
|
|
17
|
+
#
|
|
18
|
+
# @since 2.0.0.rc.1
|
|
19
|
+
def allow_destroy?
|
|
20
|
+
options[:allow_destroy] || false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns the reject if option defined with the macro.
|
|
24
|
+
#
|
|
25
|
+
# @example Is there a reject proc?
|
|
26
|
+
# builder.reject?
|
|
27
|
+
#
|
|
28
|
+
# @param [ Hash ] attrs The attributes to check for rejection.
|
|
29
|
+
#
|
|
30
|
+
# @return [ true, false ] True and call proc if rejectable, false if not.
|
|
31
|
+
#
|
|
32
|
+
# @since 2.0.0.rc.1
|
|
33
|
+
def reject?(attrs)
|
|
34
|
+
criteria = options[:reject_if]
|
|
35
|
+
criteria ? criteria.call(attrs) : false
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Determines if only updates can occur. Only valid for one-to-one
|
|
39
|
+
# relations.
|
|
40
|
+
#
|
|
41
|
+
# @example Is this update only?
|
|
42
|
+
# builder.update_only?
|
|
43
|
+
#
|
|
44
|
+
# @return [ true, false ] True if the update_only option was set.
|
|
45
|
+
#
|
|
46
|
+
# @since 2.0.0.rc.1
|
|
47
|
+
def update_only?
|
|
48
|
+
options[:update_only] || false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Convert an id to its appropriate type.
|
|
52
|
+
#
|
|
53
|
+
# @todo Durran: Move this into a common reusable place.
|
|
54
|
+
#
|
|
55
|
+
# @example Convert the id.
|
|
56
|
+
# builder.convert_id("4d371b444835d98b8b000010")
|
|
57
|
+
#
|
|
58
|
+
# @param [ String ] id The id, usually coming from the form.
|
|
59
|
+
#
|
|
60
|
+
# @return [ BSON::ObjectId, String, Object ] The converted id.
|
|
61
|
+
#
|
|
62
|
+
# @since 2.0.0.rc.6
|
|
63
|
+
def convert_id(id)
|
|
64
|
+
metadata.constraint.convert(id)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid # :nodoc:
|
|
3
|
+
module Relations #:nodoc:
|
|
4
|
+
|
|
5
|
+
# This is the superclass for one to one relations and defines the common
|
|
6
|
+
# behaviour or those proxies.
|
|
7
|
+
class One < Proxy
|
|
8
|
+
|
|
9
|
+
# Will load the target into an array if the target had not already been
|
|
10
|
+
# loaded.
|
|
11
|
+
#
|
|
12
|
+
# @example Load the relation into memory.
|
|
13
|
+
# relation.load!
|
|
14
|
+
#
|
|
15
|
+
# @return [ One ] The relation.
|
|
16
|
+
#
|
|
17
|
+
# @since 2.0.0.rc.5
|
|
18
|
+
def load!(options = {})
|
|
19
|
+
tap do |relation|
|
|
20
|
+
unless relation.loaded?
|
|
21
|
+
relation.bind(options)
|
|
22
|
+
relation.loaded = true
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Substitutes the supplied target documents for the existing document
|
|
28
|
+
# in the relation.
|
|
29
|
+
#
|
|
30
|
+
# @example Substitute the new document.
|
|
31
|
+
# person.name.substitute(new_name)
|
|
32
|
+
#
|
|
33
|
+
# @param [ Document ] other A document to replace the target.
|
|
34
|
+
#
|
|
35
|
+
# @return [ Document, nil ] The relation or nil.
|
|
36
|
+
#
|
|
37
|
+
# @since 2.0.0.rc.1
|
|
38
|
+
def substitute(new_target, options = {})
|
|
39
|
+
old_target = target
|
|
40
|
+
tap do |relation|
|
|
41
|
+
relation.target = new_target
|
|
42
|
+
new_target ? bind(options) : (unbind(old_target, options) and return nil)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid # :nodoc:
|
|
3
|
+
module Relations #:nodoc:
|
|
4
|
+
|
|
5
|
+
# This module contains the behaviour for handling polymorphic relational
|
|
6
|
+
# associations.
|
|
7
|
+
module Polymorphic
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
class_attribute :polymorphic
|
|
12
|
+
delegate :polymorphic?, :to => "self.class"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module ClassMethods #:nodoc:
|
|
16
|
+
|
|
17
|
+
# Attempts to set up the information needed to handle a polymorphic
|
|
18
|
+
# relation, if the metadata checks out.
|
|
19
|
+
#
|
|
20
|
+
# @example Set up the polymorphic information.
|
|
21
|
+
# Movie.polymorph(metadata)
|
|
22
|
+
#
|
|
23
|
+
# @param [ Metadata ] metadata The relation metadata.
|
|
24
|
+
#
|
|
25
|
+
# @return [ Class ] The class being set up.
|
|
26
|
+
#
|
|
27
|
+
# @since 2.0.0.rc.1
|
|
28
|
+
def polymorph(metadata)
|
|
29
|
+
tap do |klass|
|
|
30
|
+
if metadata.polymorphic?
|
|
31
|
+
klass.polymorphic = true
|
|
32
|
+
if metadata.relation.stores_foreign_key?
|
|
33
|
+
field(metadata.inverse_type, :type => String)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Determines if the class is in a polymorphic relations, and thus must
|
|
40
|
+
# store the _type field in the database.
|
|
41
|
+
#
|
|
42
|
+
# @example Check if the class is polymorphic.
|
|
43
|
+
# Movie.polymorphic?
|
|
44
|
+
#
|
|
45
|
+
# @return [ true, false ] True if polymorphic, false if not.
|
|
46
|
+
#
|
|
47
|
+
# @since 2.0.0.rc.1
|
|
48
|
+
def polymorphic?
|
|
49
|
+
!!polymorphic
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|