Class: DataMapper::Associations::Relationship
- Inherits:
-
Object
- Object
- DataMapper::Associations::Relationship
- Includes:
- DataMapper::Assertions
- Defined in:
- lib/dm-core/associations/relationship.rb
Direct Known Subclasses
Constant Summary collapse
- OPTIONS =
[ :class_name, :child_key, :parent_key, :min, :max, :through ]
Instance Attribute Summary collapse
- #name ⇒ Object readonly private
- #options ⇒ Object readonly private
- #query ⇒ Object readonly private
Instance Method Summary collapse
- #attach_parent(child, parent) ⇒ Object private
- #child_key ⇒ Object private
- #child_model ⇒ Object private
- #get_children(parent, options = {}, finder = :all, *args) ⇒ Object private
- #get_parent(child, parent = nil) ⇒ Object private
- #parent_key ⇒ Object private
- #parent_model ⇒ Object private
- #with_repository(object = nil) ⇒ Object private
Methods included from DataMapper::Assertions
Instance Attribute Details
#name ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
9 10 11 |
# File 'lib/dm-core/associations/relationship.rb', line 9 def name @name end |
#options ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
9 10 11 |
# File 'lib/dm-core/associations/relationship.rb', line 9 def @options end |
#query ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
9 10 11 |
# File 'lib/dm-core/associations/relationship.rb', line 9 def query @query end |
Instance Method Details
#attach_parent(child, parent) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
178 179 180 |
# File 'lib/dm-core/associations/relationship.rb', line 178 def attach_parent(child, parent) child_key.set(child, parent && parent_key.get(parent)) end |
#child_key ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/dm-core/associations/relationship.rb', line 12 def child_key @child_key ||= begin child_key = nil child_model.repository.scope do |r| model_properties = child_model.properties(r.name) child_key = parent_key.zip(@child_properties || []).map do |parent_property,property_name| # TODO: use something similar to DM::NamingConventions to determine the property name parent_name = Extlib::Inflection.underscore(Extlib::Inflection.demodulize(parent_model.base_model.name)) property_name ||= "#{parent_name}_#{parent_property.name}".to_sym if model_properties.has_property?(property_name) model_properties[property_name] else = {} [ :length, :precision, :scale ].each do |option| [option] = parent_property.send(option) end # NOTE: hack to make each many to many child_key a true key, # until I can figure out a better place for this check if child_model.respond_to?(:many_to_many) [:key] = true end child_model.property(property_name, parent_property.primitive, ) end end end PropertySet.new(child_key) end end |
#child_model ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
70 71 72 73 74 75 |
# File 'lib/dm-core/associations/relationship.rb', line 70 def child_model return @child_model if model_defined?(@child_model) @child_model = @parent_model.find_const(@child_model) rescue NameError raise NameError, "Cannot find the child_model #{@child_model} for #{@parent_model}" end |
#get_children(parent, options = {}, finder = :all, *args) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/dm-core/associations/relationship.rb', line 78 def get_children(parent, = {}, finder = :all, *args) parent_value = parent_key.get(parent) bind_values = [ parent_value ] with_repository(child_model) do |r| parent_identity_map = parent.repository.identity_map(parent_model) query_values = parent_identity_map.keys bind_values = query_values unless query_values.empty? query = child_key.zip(bind_values.transpose).to_hash collection = child_model.send(finder, *(args.dup << @query.merge().merge(query))) return collection unless collection.kind_of?(Collection) && collection.any? grouped_collection = {} collection.each do |resource| child_value = child_key.get(resource) parent_obj = parent_identity_map[child_value] grouped_collection[parent_obj] ||= [] grouped_collection[parent_obj] << resource end association_accessor = "#{self.name}_association" ret = nil grouped_collection.each do |parent, children| association = parent.send(association_accessor) query = collection.query.dup query.conditions.map! do |operator, property, bind_value| property = property.property if property.class == DataMapper::Query::Path if operator != :raw && child_key.has_property?(property.name) bind_value = *children.map { |child| property.get(child) }.uniq end [ operator, property, bind_value ] end parents_children = Collection.new(query) children.each { |child| parents_children.send(:add, child) } if parent_key.get(parent) == parent_value ret = parents_children else association.instance_variable_set(:@children, parents_children) end end ret || child_model.send(finder, *(args.dup << @query.merge().merge(child_key.zip([ parent_value ]).to_hash))) end end |
#get_parent(child, parent = nil) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/dm-core/associations/relationship.rb', line 132 def get_parent(child, parent = nil) child_value = child_key.get(child) return nil if child_value.any? { |v| v.nil? } with_repository(parent || parent_model) do parent_identity_map = (parent || parent_model).repository.identity_map(parent_model.base_model) child_identity_map = child.repository.identity_map(child_model.base_model) if parent = parent_identity_map[child_value] return parent end children = child_identity_map.values children << child unless child_identity_map[child.key] bind_values = children.map { |c| child_key.get(c) }.uniq query_values = bind_values.reject { |k| parent_identity_map[k] } bind_values = query_values unless query_values.empty? query = parent_key.zip(bind_values.transpose).to_hash association_accessor = "#{self.name}_association" collection = parent_model.send(:all, query) unless collection.empty? collection.send(:lazy_load) children.each do |c| c.send(association_accessor).instance_variable_set(:@parent, collection.get(*child_key.get(c))) end child.send(association_accessor).instance_variable_get(:@parent) end end end |
#parent_key ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/dm-core/associations/relationship.rb', line 47 def parent_key @parent_key ||= begin parent_key = nil parent_model.repository.scope do |r| parent_key = if @parent_properties parent_model.properties(r.name).slice(*@parent_properties) else parent_model.key end end PropertySet.new(parent_key) end end |
#parent_model ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
62 63 64 65 66 67 |
# File 'lib/dm-core/associations/relationship.rb', line 62 def parent_model return @parent_model if model_defined?(@parent_model) @parent_model = @child_model.find_const(@parent_model) rescue NameError raise NameError, "Cannot find the parent_model #{@parent_model} for #{@child_model}" end |
#with_repository(object = nil) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
166 167 168 169 170 171 172 173 174 175 |
# File 'lib/dm-core/associations/relationship.rb', line 166 def with_repository(object = nil) other_model = object.model == child_model ? parent_model : child_model if object.respond_to?(:model) other_model = object == child_model ? parent_model : child_model if object.kind_of?(DataMapper::Resource) if other_model && other_model.repository == object.repository && object.repository.name != @repository_name object.repository.scope { |block_args| yield(*block_args) } else repository(@repository_name) { |block_args| yield(*block_args) } end end |