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, &block) ⇒ 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.
172 173 174 |
# File 'lib/dm-core/associations/relationship.rb', line 172 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.
69 70 71 72 73 |
# File 'lib/dm-core/associations/relationship.rb', line 69 def child_model Class === @child_model ? @child_model : (Class === @parent_model ? @parent_model.find_const(@child_model) : Object.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.
76 77 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 |
# File 'lib/dm-core/associations/relationship.rb', line 76 def get_children(parent, = {}, finder = :all, *args) bind_values = parent_key.get(parent) parent_values = bind_values.dup with_repository(child_model) do |r| parent_identity_map = parent.repository.identity_map(parent_model) child_identity_map = r.identity_map(child_model) query_values = parent_identity_map.keys.flatten query_values.reject! { |k| child_identity_map[[k]] } bind_values = query_values unless query_values.empty? query = child_key.map { |k| [ k, bind_values ] }.to_hash collection = child_model.send(finder, *(args.dup << @query.merge().merge(query))) return collection unless collection.kind_of?(Collection) && collection.any? grouped_collection = Hash.new { |h,k| h[k] = [] } collection.each do |resource| grouped_collection[get_parent(resource, parent)] << 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| 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_values 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_values).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.
127 128 129 130 131 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 |
# File 'lib/dm-core/associations/relationship.rb', line 127 def get_parent(child, parent = nil) child_value = child_key.get(child) return nil unless child_value.nitems == child_value.size with_repository(parent || parent_model) do parent_identity_map = (parent || parent_model).repository.identity_map(parent_model) child_identity_map = child.repository.identity_map(child_model) if parent = parent_identity_map[child_value] return parent end children = child_identity_map.values | [child] 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 |
# File 'lib/dm-core/associations/relationship.rb', line 62 def parent_model Class === @parent_model ? @parent_model : (Class === @child_model ? @child_model.find_const(@parent_model) : Object.find_const(@parent_model)) rescue NameError raise NameError, "Cannot find the parent_model #{@parent_model} for #{@child_model}" end |
#with_repository(object = nil, &block) ⇒ 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.
160 161 162 163 164 165 166 167 168 169 |
# File 'lib/dm-core/associations/relationship.rb', line 160 def with_repository(object = nil, &block) 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) else repository(@repository_name, &block) end end |