mongoid-locomotive 2.0.0.beta9
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/MIT_LICENSE +20 -0
- data/README.rdoc +47 -0
- data/lib/mongoid.rb +141 -0
- data/lib/mongoid/associations.rb +306 -0
- data/lib/mongoid/associations/embedded_in.rb +74 -0
- data/lib/mongoid/associations/embeds_many.rb +280 -0
- data/lib/mongoid/associations/embeds_one.rb +97 -0
- data/lib/mongoid/associations/foreign_key.rb +35 -0
- data/lib/mongoid/associations/meta_data.rb +38 -0
- data/lib/mongoid/associations/options.rb +62 -0
- data/lib/mongoid/associations/proxy.rb +33 -0
- data/lib/mongoid/associations/referenced_in.rb +59 -0
- data/lib/mongoid/associations/references_many.rb +245 -0
- data/lib/mongoid/associations/references_many_as_array.rb +78 -0
- data/lib/mongoid/associations/references_one.rb +99 -0
- data/lib/mongoid/atomicity.rb +55 -0
- data/lib/mongoid/attributes.rb +242 -0
- data/lib/mongoid/callbacks.rb +21 -0
- data/lib/mongoid/collection.rb +120 -0
- data/lib/mongoid/collections.rb +71 -0
- data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
- data/lib/mongoid/collections/master.rb +29 -0
- data/lib/mongoid/collections/operations.rb +41 -0
- data/lib/mongoid/collections/slaves.rb +45 -0
- data/lib/mongoid/components.rb +34 -0
- data/lib/mongoid/config.rb +263 -0
- data/lib/mongoid/contexts.rb +24 -0
- data/lib/mongoid/contexts/enumerable.rb +156 -0
- data/lib/mongoid/contexts/ids.rb +25 -0
- data/lib/mongoid/contexts/mongo.rb +285 -0
- data/lib/mongoid/contexts/paging.rb +50 -0
- data/lib/mongoid/criteria.rb +248 -0
- data/lib/mongoid/criterion/complex.rb +21 -0
- data/lib/mongoid/criterion/exclusion.rb +65 -0
- data/lib/mongoid/criterion/inclusion.rb +110 -0
- data/lib/mongoid/criterion/optional.rb +189 -0
- data/lib/mongoid/cursor.rb +81 -0
- data/lib/mongoid/deprecation.rb +21 -0
- data/lib/mongoid/dirty.rb +252 -0
- data/lib/mongoid/document.rb +210 -0
- data/lib/mongoid/errors.rb +131 -0
- data/lib/mongoid/extensions.rb +115 -0
- data/lib/mongoid/extensions/array/accessors.rb +17 -0
- data/lib/mongoid/extensions/array/assimilation.rb +26 -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 +24 -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/accessors.rb +42 -0
- data/lib/mongoid/extensions/hash/assimilation.rb +40 -0
- data/lib/mongoid/extensions/hash/conversions.rb +42 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
- data/lib/mongoid/extensions/hash/scoping.rb +12 -0
- data/lib/mongoid/extensions/integer/conversions.rb +20 -0
- data/lib/mongoid/extensions/nil/assimilation.rb +17 -0
- data/lib/mongoid/extensions/object/conversions.rb +21 -0
- data/lib/mongoid/extensions/objectid/conversions.rb +15 -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 +15 -0
- data/lib/mongoid/extensions/string/inflections.rb +97 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
- data/lib/mongoid/extensions/time_conversions.rb +35 -0
- data/lib/mongoid/extensions/true_class/equality.rb +13 -0
- data/lib/mongoid/extras.rb +61 -0
- data/lib/mongoid/factory.rb +20 -0
- data/lib/mongoid/field.rb +83 -0
- data/lib/mongoid/fields.rb +62 -0
- data/lib/mongoid/finders.rb +145 -0
- data/lib/mongoid/hierarchy.rb +74 -0
- data/lib/mongoid/identity.rb +47 -0
- data/lib/mongoid/indexes.rb +27 -0
- data/lib/mongoid/javascript.rb +21 -0
- data/lib/mongoid/javascript/functions.yml +37 -0
- data/lib/mongoid/logger.rb +19 -0
- data/lib/mongoid/matchers.rb +35 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +26 -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/memoization.rb +33 -0
- data/lib/mongoid/named_scope.rb +37 -0
- data/lib/mongoid/paranoia.rb +106 -0
- data/lib/mongoid/paths.rb +61 -0
- data/lib/mongoid/persistence.rb +216 -0
- data/lib/mongoid/persistence/command.rb +39 -0
- data/lib/mongoid/persistence/insert.rb +48 -0
- data/lib/mongoid/persistence/insert_embedded.rb +44 -0
- data/lib/mongoid/persistence/remove.rb +39 -0
- data/lib/mongoid/persistence/remove_all.rb +38 -0
- data/lib/mongoid/persistence/remove_embedded.rb +50 -0
- data/lib/mongoid/persistence/update.rb +71 -0
- data/lib/mongoid/railtie.rb +67 -0
- data/lib/mongoid/railties/database.rake +60 -0
- data/lib/mongoid/scope.rb +75 -0
- data/lib/mongoid/state.rb +32 -0
- data/lib/mongoid/timestamps.rb +27 -0
- data/lib/mongoid/validations.rb +51 -0
- data/lib/mongoid/validations/associated.rb +32 -0
- data/lib/mongoid/validations/locale/en.yml +5 -0
- data/lib/mongoid/validations/uniqueness.rb +56 -0
- data/lib/mongoid/version.rb +4 -0
- data/lib/mongoid/versioning.rb +26 -0
- data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +24 -0
- data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
- data/lib/rails/generators/mongoid/model/templates/model.rb +15 -0
- data/lib/rails/generators/mongoid_generator.rb +61 -0
- data/spec/integration/mongoid/association_attributes_spec.rb +71 -0
- data/spec/integration/mongoid/associations_spec.rb +768 -0
- data/spec/integration/mongoid/attributes_spec.rb +59 -0
- data/spec/integration/mongoid/callback_spec.rb +33 -0
- data/spec/integration/mongoid/contexts/enumerable_spec.rb +33 -0
- data/spec/integration/mongoid/criteria_spec.rb +281 -0
- data/spec/integration/mongoid/dirty_spec.rb +85 -0
- data/spec/integration/mongoid/document_spec.rb +741 -0
- data/spec/integration/mongoid/extensions_spec.rb +22 -0
- data/spec/integration/mongoid/finders_spec.rb +119 -0
- data/spec/integration/mongoid/inheritance_spec.rb +171 -0
- data/spec/integration/mongoid/named_scope_spec.rb +58 -0
- data/spec/integration/mongoid/paranoia_spec.rb +44 -0
- data/spec/integration/mongoid/persistence/update_spec.rb +46 -0
- data/spec/integration/mongoid/persistence_spec.rb +311 -0
- data/spec/integration/mongoid/validations/uniqueness_spec.rb +206 -0
- data/spec/models/account.rb +5 -0
- data/spec/models/address.rb +40 -0
- data/spec/models/agent.rb +7 -0
- data/spec/models/animal.rb +15 -0
- data/spec/models/answer.rb +4 -0
- data/spec/models/callbacks.rb +47 -0
- data/spec/models/category.rb +13 -0
- data/spec/models/comment.rb +10 -0
- data/spec/models/country_code.rb +6 -0
- data/spec/models/employer.rb +5 -0
- data/spec/models/favorite.rb +8 -0
- data/spec/models/game.rb +9 -0
- data/spec/models/inheritance.rb +72 -0
- data/spec/models/location.rb +5 -0
- data/spec/models/login.rb +6 -0
- data/spec/models/mixed_drink.rb +4 -0
- data/spec/models/name.rb +13 -0
- data/spec/models/namespacing.rb +11 -0
- data/spec/models/paranoid_post.rb +18 -0
- data/spec/models/parents.rb +32 -0
- data/spec/models/patient.rb +15 -0
- data/spec/models/person.rb +106 -0
- data/spec/models/pet.rb +7 -0
- data/spec/models/pet_owner.rb +6 -0
- data/spec/models/phone.rb +7 -0
- data/spec/models/post.rb +25 -0
- data/spec/models/preference.rb +7 -0
- data/spec/models/question.rb +8 -0
- data/spec/models/survey.rb +6 -0
- data/spec/models/translation.rb +5 -0
- data/spec/models/user.rb +6 -0
- data/spec/models/user_accout.rb +5 -0
- data/spec/models/vet_visit.rb +5 -0
- data/spec/models/video.rb +5 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/unit/mongoid/associations/embedded_in_spec.rb +193 -0
- data/spec/unit/mongoid/associations/embeds_many_spec.rb +626 -0
- data/spec/unit/mongoid/associations/embeds_one_spec.rb +287 -0
- data/spec/unit/mongoid/associations/foreign_key_spec.rb +90 -0
- data/spec/unit/mongoid/associations/meta_data_spec.rb +110 -0
- data/spec/unit/mongoid/associations/options_spec.rb +215 -0
- data/spec/unit/mongoid/associations/referenced_in_spec.rb +145 -0
- data/spec/unit/mongoid/associations/references_many_as_array_spec.rb +424 -0
- data/spec/unit/mongoid/associations/references_many_spec.rb +502 -0
- data/spec/unit/mongoid/associations/references_one_spec.rb +204 -0
- data/spec/unit/mongoid/associations_spec.rb +688 -0
- data/spec/unit/mongoid/atomicity_spec.rb +164 -0
- data/spec/unit/mongoid/attributes_spec.rb +646 -0
- data/spec/unit/mongoid/callbacks_spec.rb +85 -0
- data/spec/unit/mongoid/collection_spec.rb +187 -0
- data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
- data/spec/unit/mongoid/collections/master_spec.rb +41 -0
- data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
- data/spec/unit/mongoid/collections_spec.rb +98 -0
- data/spec/unit/mongoid/config_spec.rb +298 -0
- data/spec/unit/mongoid/contexts/enumerable_spec.rb +447 -0
- data/spec/unit/mongoid/contexts/mongo_spec.rb +703 -0
- data/spec/unit/mongoid/contexts_spec.rb +25 -0
- data/spec/unit/mongoid/criteria_spec.rb +873 -0
- data/spec/unit/mongoid/criterion/complex_spec.rb +17 -0
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +121 -0
- data/spec/unit/mongoid/criterion/inclusion_spec.rb +274 -0
- data/spec/unit/mongoid/criterion/optional_spec.rb +483 -0
- data/spec/unit/mongoid/cursor_spec.rb +80 -0
- data/spec/unit/mongoid/deprecation_spec.rb +24 -0
- data/spec/unit/mongoid/dirty_spec.rb +430 -0
- data/spec/unit/mongoid/document_spec.rb +623 -0
- data/spec/unit/mongoid/errors_spec.rb +154 -0
- data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
- data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
- data/spec/unit/mongoid/extensions/array/conversions_spec.rb +52 -0
- data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
- data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +36 -0
- data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +22 -0
- data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
- data/spec/unit/mongoid/extensions/date/conversions_spec.rb +145 -0
- data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +14 -0
- data/spec/unit/mongoid/extensions/false_class/equality_spec.rb +35 -0
- data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
- data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
- data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +59 -0
- data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +35 -0
- data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
- data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
- data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
- data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +29 -0
- data/spec/unit/mongoid/extensions/object/conversions_spec.rb +44 -0
- data/spec/unit/mongoid/extensions/objectid/conversions_spec.rb +22 -0
- data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
- data/spec/unit/mongoid/extensions/set/conversions_spec.rb +21 -0
- data/spec/unit/mongoid/extensions/string/conversions_spec.rb +28 -0
- data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
- data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +107 -0
- data/spec/unit/mongoid/extensions/time_conversions_spec.rb +186 -0
- data/spec/unit/mongoid/extensions/true_class/equality_spec.rb +35 -0
- data/spec/unit/mongoid/extras_spec.rb +102 -0
- data/spec/unit/mongoid/factory_spec.rb +31 -0
- data/spec/unit/mongoid/field_spec.rb +169 -0
- data/spec/unit/mongoid/fields_spec.rb +181 -0
- data/spec/unit/mongoid/finders_spec.rb +439 -0
- data/spec/unit/mongoid/hierarchy_spec.rb +68 -0
- data/spec/unit/mongoid/identity_spec.rb +109 -0
- data/spec/unit/mongoid/indexes_spec.rb +99 -0
- data/spec/unit/mongoid/javascript_spec.rb +48 -0
- data/spec/unit/mongoid/logger_spec.rb +38 -0
- data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
- data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
- data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
- data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
- data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
- data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
- data/spec/unit/mongoid/matchers_spec.rb +329 -0
- data/spec/unit/mongoid/memoization_spec.rb +75 -0
- data/spec/unit/mongoid/named_scope_spec.rb +123 -0
- data/spec/unit/mongoid/paranoia_spec.rb +108 -0
- data/spec/unit/mongoid/paths_spec.rb +272 -0
- data/spec/unit/mongoid/persistence/insert_embedded_spec.rb +154 -0
- data/spec/unit/mongoid/persistence/insert_spec.rb +144 -0
- data/spec/unit/mongoid/persistence/remove_all_spec.rb +82 -0
- data/spec/unit/mongoid/persistence/remove_embedded_spec.rb +152 -0
- data/spec/unit/mongoid/persistence/remove_spec.rb +89 -0
- data/spec/unit/mongoid/persistence/update_spec.rb +177 -0
- data/spec/unit/mongoid/persistence_spec.rb +452 -0
- data/spec/unit/mongoid/scope_spec.rb +240 -0
- data/spec/unit/mongoid/serialization_spec.rb +43 -0
- data/spec/unit/mongoid/state_spec.rb +94 -0
- data/spec/unit/mongoid/timestamps_spec.rb +30 -0
- data/spec/unit/mongoid/validations/associated_spec.rb +103 -0
- data/spec/unit/mongoid/validations/uniqueness_spec.rb +201 -0
- data/spec/unit/mongoid/validations_spec.rb +43 -0
- data/spec/unit/mongoid/versioning_spec.rb +41 -0
- data/spec/unit/mongoid_spec.rb +46 -0
- metadata +433 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Associations #:nodoc:
|
|
4
|
+
module ForeignKey #:nodoc:
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
module ClassMethods #:nodoc:
|
|
8
|
+
# Determine the value for the foreign key constriant field in the
|
|
9
|
+
# database, based on the type of association or if the actual value was
|
|
10
|
+
# supplied as an option.
|
|
11
|
+
#
|
|
12
|
+
# Example:
|
|
13
|
+
#
|
|
14
|
+
# <tt>contraint(:posts, {}, :references_one)</tt>
|
|
15
|
+
#
|
|
16
|
+
# Returns
|
|
17
|
+
#
|
|
18
|
+
# A +String+ for the foreign key field.
|
|
19
|
+
def constraint(name, options, association)
|
|
20
|
+
key = options[:foreign_key]
|
|
21
|
+
|
|
22
|
+
# Always return the supplied foreign_key option if it was supplied -
|
|
23
|
+
# the user should always be ble to override.
|
|
24
|
+
return key.to_s if key
|
|
25
|
+
|
|
26
|
+
case association
|
|
27
|
+
when :one, :many then self.name.foreign_key
|
|
28
|
+
when :many_as_array then "#{name.to_s.singularize}_ids"
|
|
29
|
+
else name.to_s.foreign_key
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Associations #:nodoc:
|
|
4
|
+
# This class contains metadata about association proxies.
|
|
5
|
+
class MetaData
|
|
6
|
+
|
|
7
|
+
attr_reader :association, :options
|
|
8
|
+
|
|
9
|
+
delegate :macro, :to => :association
|
|
10
|
+
|
|
11
|
+
# Delegate all methods on +Options+ to the options instance.
|
|
12
|
+
Associations::Options.public_instance_methods(false).each do |name|
|
|
13
|
+
define_method(name) { |*args| @options.send(name) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Return true if this meta data is for an embedded association.
|
|
17
|
+
#
|
|
18
|
+
# Example:
|
|
19
|
+
#
|
|
20
|
+
# <tt>metadata.embedded?</tt>
|
|
21
|
+
def embedded?
|
|
22
|
+
[ EmbedsOne, EmbedsMany ].include?(association)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Create the new associations MetaData object, which holds the type of
|
|
26
|
+
# the association and its options, with convenience methods for getting
|
|
27
|
+
# that information.
|
|
28
|
+
#
|
|
29
|
+
# Options:
|
|
30
|
+
#
|
|
31
|
+
# association: The association type as a class instance.
|
|
32
|
+
# options: The association options
|
|
33
|
+
def initialize(association, options)
|
|
34
|
+
@association, @options = association, options
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Associations #:nodoc:
|
|
4
|
+
class Options #:nodoc:
|
|
5
|
+
|
|
6
|
+
# Create the new +Options+ object, which provides convenience methods for
|
|
7
|
+
# accessing values out of an options +Hash+.
|
|
8
|
+
def initialize(attributes = {})
|
|
9
|
+
@attributes = attributes
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Returns the extension if it exists, nil if not.
|
|
13
|
+
def extension
|
|
14
|
+
@attributes[:extend]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Returns true is the options have extensions.
|
|
18
|
+
def extension?
|
|
19
|
+
!extension.nil?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Return the foreign key if it exists, otherwise inflect it from the
|
|
23
|
+
# associated class name.
|
|
24
|
+
def foreign_key
|
|
25
|
+
key = @attributes[:foreign_key] || klass.name.to_s.foreign_key
|
|
26
|
+
key.to_s
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns the name of the inverse_of association
|
|
30
|
+
def inverse_of
|
|
31
|
+
@attributes[:inverse_of]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Return a +Class+ for the options. See #class_name
|
|
35
|
+
def klass
|
|
36
|
+
class_name.constantize
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Return a +String+ representing the associated class_name. If a class_name
|
|
40
|
+
# was provided, then the constantized class_name will be returned. If not,
|
|
41
|
+
# a constant based on the association name will be returned.
|
|
42
|
+
def class_name
|
|
43
|
+
@attributes[:class_name] || name.to_s.classify
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns the association name of the options.
|
|
47
|
+
def name
|
|
48
|
+
@attributes[:name].to_s
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Returns whether or not this association is polymorphic.
|
|
52
|
+
def polymorphic
|
|
53
|
+
@attributes[:polymorphic] == true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Used with references_many to save as array of ids.
|
|
57
|
+
def stored_as
|
|
58
|
+
@attributes[:stored_as]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc
|
|
3
|
+
module Associations #:nodoc
|
|
4
|
+
class Proxy #:nodoc
|
|
5
|
+
instance_methods.each do |method|
|
|
6
|
+
undef_method(method) unless method =~ /(^__|^nil\?$|^send$|^object_id$|^extend$)/
|
|
7
|
+
end
|
|
8
|
+
attr_reader \
|
|
9
|
+
:options,
|
|
10
|
+
:target
|
|
11
|
+
|
|
12
|
+
# Default behavior of method missing should be to delegate all calls
|
|
13
|
+
# to the target of the proxy. This can be overridden in special cases.
|
|
14
|
+
def method_missing(name, *args, &block)
|
|
15
|
+
@target.send(name, *args, &block)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# If anonymous extensions are added this will take care of them.
|
|
19
|
+
def extends(options)
|
|
20
|
+
extend Module.new(&options.extension) if options.extension?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Sets up the parent, klass, foreign_key, options
|
|
24
|
+
def setup(document, options)
|
|
25
|
+
@parent = document
|
|
26
|
+
@klass = options.klass
|
|
27
|
+
@options = options
|
|
28
|
+
@foreign_key = options.foreign_key
|
|
29
|
+
extends(options)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Associations #:nodoc:
|
|
4
|
+
# Represents a relational association to a "parent" object.
|
|
5
|
+
class ReferencedIn < Proxy
|
|
6
|
+
|
|
7
|
+
# Initializing a related association only requires looking up the object
|
|
8
|
+
# by its id.
|
|
9
|
+
#
|
|
10
|
+
# Options:
|
|
11
|
+
#
|
|
12
|
+
# document: The +Document+ that contains the relationship.
|
|
13
|
+
# options: The association +Options+.
|
|
14
|
+
def initialize(document, foreign_key, options, target = nil)
|
|
15
|
+
@options = options
|
|
16
|
+
@target = target || options.klass.find(foreign_key)
|
|
17
|
+
extends(options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
# Instantiate a new +ReferencedIn+ or return nil if the foreign key is
|
|
22
|
+
# nil. It is preferrable to use this method over the traditional call
|
|
23
|
+
# to new.
|
|
24
|
+
#
|
|
25
|
+
# Options:
|
|
26
|
+
#
|
|
27
|
+
# document: The +Document+ that contains the relationship.
|
|
28
|
+
# options: The association +Options+.
|
|
29
|
+
def instantiate(document, options, target = nil)
|
|
30
|
+
foreign_key = document.send(options.foreign_key)
|
|
31
|
+
return nil if foreign_key.blank? && target.nil?
|
|
32
|
+
new(document, foreign_key, options, target)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Returns the macro used to create the association.
|
|
36
|
+
def macro
|
|
37
|
+
:referenced_in
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Perform an update of the relationship of the parent and child. This
|
|
41
|
+
# will assimilate the child +Document+ into the parent's object graph.
|
|
42
|
+
#
|
|
43
|
+
# Options:
|
|
44
|
+
#
|
|
45
|
+
# target: The target(parent) object
|
|
46
|
+
# document: The +Document+ to update.
|
|
47
|
+
# options: The association +Options+
|
|
48
|
+
#
|
|
49
|
+
# Example:
|
|
50
|
+
#
|
|
51
|
+
# <tt>ReferencedIn.update(person, game, options)</tt>
|
|
52
|
+
def update(target, document, options)
|
|
53
|
+
document.send("#{options.foreign_key}=", target ? target.id : nil)
|
|
54
|
+
instantiate(document, options, target)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Associations #:nodoc:
|
|
4
|
+
# Represents an relational one-to-many association with an object in a
|
|
5
|
+
# separate collection or database.
|
|
6
|
+
class ReferencesMany < Proxy
|
|
7
|
+
|
|
8
|
+
# Appends the object to the +Array+, setting its parent in
|
|
9
|
+
# the process.
|
|
10
|
+
def <<(*objects)
|
|
11
|
+
load_target
|
|
12
|
+
objects.flatten.each do |object|
|
|
13
|
+
object.send("#{@foreign_key}=", @parent.id)
|
|
14
|
+
@target << object
|
|
15
|
+
object.save unless @parent.new_record?
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
alias :concat :<<
|
|
20
|
+
alias :push :<<
|
|
21
|
+
|
|
22
|
+
# Builds a new Document and adds it to the association collection. The
|
|
23
|
+
# document created will be of the same class as the others in the
|
|
24
|
+
# association, and the attributes will be passed into the constructor.
|
|
25
|
+
#
|
|
26
|
+
# Returns the newly created object.
|
|
27
|
+
def build(attributes = nil)
|
|
28
|
+
load_target
|
|
29
|
+
name = determine_name
|
|
30
|
+
object = @klass.instantiate((attributes || {}).merge(name => @parent))
|
|
31
|
+
@target << object
|
|
32
|
+
object
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Creates a new Document and adds it to the association collection. The
|
|
36
|
+
# document created will be of the same class as the others in the
|
|
37
|
+
# association, and the attributes will be passed into the constructor and
|
|
38
|
+
# the new object will then be saved.
|
|
39
|
+
#
|
|
40
|
+
# Returns the newly created object.
|
|
41
|
+
def create(attributes)
|
|
42
|
+
build(attributes).tap(&:save)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Creates a new Document and adds it to the association collection. If
|
|
46
|
+
# validation fails an error is raised.
|
|
47
|
+
#
|
|
48
|
+
# Returns the newly created object.
|
|
49
|
+
def create!(attributes)
|
|
50
|
+
build(attributes).tap(&:save!)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Delete all the associated objects.
|
|
54
|
+
#
|
|
55
|
+
# Example:
|
|
56
|
+
#
|
|
57
|
+
# <tt>person.posts.delete_all</tt>
|
|
58
|
+
#
|
|
59
|
+
# Returns:
|
|
60
|
+
#
|
|
61
|
+
# The number of objects deleted.
|
|
62
|
+
def delete_all(conditions = {})
|
|
63
|
+
remove(:delete_all, conditions[:conditions])
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Destroy all the associated objects.
|
|
67
|
+
#
|
|
68
|
+
# Example:
|
|
69
|
+
#
|
|
70
|
+
# <tt>person.posts.destroy_all</tt>
|
|
71
|
+
#
|
|
72
|
+
# Returns:
|
|
73
|
+
#
|
|
74
|
+
# The number of objects destroyed.
|
|
75
|
+
def destroy_all(conditions = {})
|
|
76
|
+
remove(:destroy_all, conditions[:conditions])
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Finds a document in this association.
|
|
80
|
+
# If an id is passed, will return the document for that id.
|
|
81
|
+
def find(id_or_type, options = {})
|
|
82
|
+
return self.id_criteria(id_or_type) unless id_or_type.is_a?(Symbol)
|
|
83
|
+
options[:conditions] = (options[:conditions] || {}).merge(@foreign_key.to_sym => @parent.id)
|
|
84
|
+
@klass.find(id_or_type, options)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Initializing a related association only requires looking up the objects
|
|
88
|
+
# by their ids.
|
|
89
|
+
#
|
|
90
|
+
# Options:
|
|
91
|
+
#
|
|
92
|
+
# document: The +Document+ that contains the relationship.
|
|
93
|
+
# options: The association +Options+.
|
|
94
|
+
def initialize(document, options, target = nil)
|
|
95
|
+
setup(document, options)
|
|
96
|
+
@target = target || query.call
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Override the default behavior to allow the criteria to get reset on
|
|
100
|
+
# each call into the association.
|
|
101
|
+
#
|
|
102
|
+
# Example:
|
|
103
|
+
#
|
|
104
|
+
# person.posts.where(:title => "New")
|
|
105
|
+
# person.posts # resets the criteria
|
|
106
|
+
#
|
|
107
|
+
# Returns:
|
|
108
|
+
#
|
|
109
|
+
# A Criteria object or Array.
|
|
110
|
+
def method_missing(name, *args, &block)
|
|
111
|
+
@target = query.call unless @target.is_a?(Array)
|
|
112
|
+
@target.send(name, *args, &block)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Used for setting associations via a nested attributes setter from the
|
|
116
|
+
# parent +Document+.
|
|
117
|
+
#
|
|
118
|
+
# Options:
|
|
119
|
+
#
|
|
120
|
+
# attributes: A +Hash+ of integer keys and +Hash+ values.
|
|
121
|
+
#
|
|
122
|
+
# Returns:
|
|
123
|
+
#
|
|
124
|
+
# The newly build target Document.
|
|
125
|
+
def nested_build(attributes, options = {})
|
|
126
|
+
attributes.each do |index, attrs|
|
|
127
|
+
begin
|
|
128
|
+
document = find(index.to_i)
|
|
129
|
+
if options && options[:allow_destroy] && attrs['_destroy']
|
|
130
|
+
@target.delete(document)
|
|
131
|
+
document.destroy
|
|
132
|
+
else
|
|
133
|
+
document.write_attributes(attrs)
|
|
134
|
+
end
|
|
135
|
+
rescue Errors::DocumentNotFound
|
|
136
|
+
build(attrs)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
protected
|
|
142
|
+
# Load the target entries if the parent document is new.
|
|
143
|
+
def load_target
|
|
144
|
+
@target = @target.entries if @parent.new_record?
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def determine_name
|
|
148
|
+
@proxy ||= class << self; self; end
|
|
149
|
+
@proxy.send(:determine_name, @parent, @options)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# The default query used for retrieving the documents from the database.
|
|
153
|
+
# In this case we use the common API between Mongoid, ActiveRecord, and
|
|
154
|
+
# DataMapper so we can do one-to-many relationships with data in other
|
|
155
|
+
# databases.
|
|
156
|
+
#
|
|
157
|
+
# Example:
|
|
158
|
+
#
|
|
159
|
+
# <tt>association.query</tt>
|
|
160
|
+
#
|
|
161
|
+
# Returns:
|
|
162
|
+
#
|
|
163
|
+
# A +Criteria+ if a Mongoid association.
|
|
164
|
+
# An +Array+ of objects if an ActiveRecord association
|
|
165
|
+
# A +Collection+ if a DataMapper association.
|
|
166
|
+
def query
|
|
167
|
+
@query ||= lambda { @klass.all(:conditions => { @foreign_key => @parent.id }) }
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Remove the objects based on conditions.
|
|
171
|
+
def remove(method, conditions)
|
|
172
|
+
selector = { @foreign_key => @parent.id }.merge(conditions || {})
|
|
173
|
+
removed = @klass.send(method, :conditions => selector)
|
|
174
|
+
reset; removed
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Reset the memoized association on the parent. This will execute the
|
|
178
|
+
# database query again.
|
|
179
|
+
#
|
|
180
|
+
# Example:
|
|
181
|
+
#
|
|
182
|
+
# <tt>association.reset</tt>
|
|
183
|
+
#
|
|
184
|
+
# Returns:
|
|
185
|
+
#
|
|
186
|
+
# See #query rdoc for return values.
|
|
187
|
+
def reset
|
|
188
|
+
@parent.send(:reset, @options.name) { query.call }
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
class << self
|
|
192
|
+
# Preferred method for creating the new +ReferencesMany+ association.
|
|
193
|
+
#
|
|
194
|
+
# Options:
|
|
195
|
+
#
|
|
196
|
+
# document: The +Document+ that contains the relationship.
|
|
197
|
+
# options: The association +Options+.
|
|
198
|
+
def instantiate(document, options, target = nil)
|
|
199
|
+
new(document, options, target)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Returns the macro used to create the association.
|
|
203
|
+
def macro
|
|
204
|
+
:references_many
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Perform an update of the relationship of the parent and child. This
|
|
208
|
+
# will assimilate the child +Document+ into the parent's object graph.
|
|
209
|
+
#
|
|
210
|
+
# Options:
|
|
211
|
+
#
|
|
212
|
+
# related: The related object
|
|
213
|
+
# parent: The parent +Document+ to update.
|
|
214
|
+
# options: The association +Options+
|
|
215
|
+
#
|
|
216
|
+
# Example:
|
|
217
|
+
#
|
|
218
|
+
# <tt>RelatesToOne.update(game, person, options)</tt>
|
|
219
|
+
def update(target, document, options)
|
|
220
|
+
name = determine_name(document, options)
|
|
221
|
+
target.each { |child| child.send("#{name}=", document) }
|
|
222
|
+
instantiate(document, options, target)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
protected
|
|
226
|
+
def determine_name(document, options)
|
|
227
|
+
target = document.class
|
|
228
|
+
|
|
229
|
+
if (inverse = options.inverse_of) && inverse.is_a?(Array)
|
|
230
|
+
inverse = [*inverse].detect { |name| target.respond_to?(name) }
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
if !inverse
|
|
234
|
+
association = options.klass.associations.values.detect do |metadata|
|
|
235
|
+
metadata.options.klass == target
|
|
236
|
+
end
|
|
237
|
+
inverse = association.name if association
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
inverse || target.to_s.underscore
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|