Associations::OneToMany::Relationship
Returns a set of keys that identify the target model
@return [DataMapper::PropertySet]
a set of properties that identify the target model
@api semipublic
# File lib/dm-core/associations/many_to_many.rb, line 15 15: def child_key 16: return @child_key if defined?(@child_key) 17: 18: repository_name = child_repository_name || parent_repository_name 19: properties = child_model.properties(repository_name) 20: 21: @child_key = if @child_properties 22: child_key = properties.values_at(*@child_properties) 23: properties.class.new(child_key).freeze 24: else 25: properties.key 26: end 27: end
Eager load the collection using the source as a base
@param [Resource, Collection] source
the source to query with
@param [Query, Hash] other_query
optional query to restrict the collection
@return [ManyToMany::Collection]
the loaded collection for the source
@api private
# File lib/dm-core/associations/many_to_many.rb, line 158 158: def eager_load(source, other_query = nil) 159: # FIXME: enable SEL for m:m relationships 160: source.model.all(query_for(source, other_query)) 161: end
Initialize the chain for “many to many” relationships
@api public
# File lib/dm-core/associations/many_to_many.rb, line 130 130: def finalize 131: through 132: via 133: end
@api semipublic
# File lib/dm-core/associations/many_to_many.rb, line 110 110: def links 111: return @links if defined?(@links) 112: 113: @links = [] 114: links = [ through, via ] 115: 116: while relationship = links.shift 117: if relationship.respond_to?(:links) 118: links.unshift(*relationship.links) 119: else 120: @links << relationship 121: end 122: end 123: 124: @links.freeze 125: end
@api private
# File lib/dm-core/associations/many_to_many.rb, line 141 141: def query 142: # TODO: consider making this a query_for method, so that ManyToMany::Relationship#query only 143: # returns the query supplied in the definition 144: @many_to_many_query ||= super.merge(:links => links).freeze 145: end
@api private
# File lib/dm-core/associations/many_to_many.rb, line 136 136: def source_scope(source) 137: { through.inverse => source } 138: end
Intermediate association for through model relationships
Example: for :bugs association in
class Software::Engineer
include DataMapper::Resource has n, :missing_tests has n, :bugs, :through => :missing_tests
end
through is :missing_tests
TODO: document a case when through option is a model and not an association name
@api semipublic
# File lib/dm-core/associations/many_to_many.rb, line 51 51: def through 52: return @through if defined?(@through) 53: 54: @through = options[:through] 55: 56: if @through.kind_of?(Associations::Relationship) 57: return @through 58: end 59: 60: model = source_model 61: repository_name = source_repository_name 62: relationships = model.relationships(repository_name) 63: name = through_relationship_name 64: 65: @through = relationships[name] || 66: DataMapper.repository(repository_name) do 67: model.has(min..max, name, through_model, one_to_many_options) 68: end 69: 70: @through.child_key 71: 72: @through 73: end
@api semipublic
# File lib/dm-core/associations/many_to_many.rb, line 76 76: def via 77: return @via if defined?(@via) 78: 79: @via = options[:via] 80: 81: if @via.kind_of?(Associations::Relationship) 82: return @via 83: end 84: 85: name = self.name 86: through = self.through 87: repository_name = through.relative_target_repository_name 88: through_model = through.target_model 89: relationships = through_model.relationships(repository_name) 90: singular_name = DataMapper::Inflector.singularize(name.to_s).to_sym 91: 92: @via = relationships[@via] || 93: relationships[name] || 94: relationships[singular_name] 95: 96: @via ||= if anonymous_through_model? 97: DataMapper.repository(repository_name) do 98: through_model.belongs_to(singular_name, target_model, many_to_one_options) 99: end 100: else 101: raise UnknownRelationshipError, "No relationships named #{name} or #{singular_name} in #{through_model}" 102: end 103: 104: @via.child_key 105: 106: @via 107: end
Check if the :through association uses an anonymous model
An anonymous model means that DataMapper creates the model in-memory, and sets the relationships to join the source and the target model.
@return [Boolean]
true if the through model is anonymous
@api private
# File lib/dm-core/associations/many_to_many.rb, line 222 222: def anonymous_through_model? 223: options[:through] == Resource 224: end
Returns collection class used by this type of relationship
@api private
# File lib/dm-core/associations/many_to_many.rb, line 313 313: def collection_class 314: ManyToMany::Collection 315: end
Returns the inverse relationship class
@api private
# File lib/dm-core/associations/many_to_many.rb, line 274 274: def inverse_class 275: self.class 276: end
@api private
# File lib/dm-core/associations/many_to_many.rb, line 279 279: def invert 280: inverse_class.new(inverse_name, parent_model, child_model, inverted_options) 281: end
@api private
# File lib/dm-core/associations/many_to_many.rb, line 284 284: def inverted_options 285: links = self.links.dup 286: through = links.pop.inverse 287: 288: links.reverse_each do |relationship| 289: inverse = relationship.inverse 290: 291: through = self.class.new( 292: inverse.name, 293: inverse.child_model, 294: inverse.parent_model, 295: inverse.options.merge(:through => through) 296: ) 297: end 298: 299: options = self.options 300: 301: DataMapper::Ext::Hash.only(options, *OPTIONS - [ :min, :max ]).update( 302: :through => through, 303: :child_key => options[:parent_key], 304: :parent_key => options[:child_key], 305: :inverse => self 306: ) 307: end
@api semipublic
# File lib/dm-core/associations/many_to_many.rb, line 261 261: def many_to_one_options 262: { :parent_key => target_key.map { |property| property.name } } 263: end
@api private
# File lib/dm-core/associations/many_to_many.rb, line 227 227: def nearest_relationship 228: return @nearest_relationship if defined?(@nearest_relationship) 229: 230: nearest_relationship = self 231: 232: while nearest_relationship.respond_to?(:through) 233: nearest_relationship = nearest_relationship.through 234: end 235: 236: @nearest_relationship = nearest_relationship 237: end
@api semipublic
# File lib/dm-core/associations/many_to_many.rb, line 266 266: def one_to_many_options 267: { :parent_key => source_key.map { |property| property.name } } 268: end
all properties added to the anonymous through model are keys
# File lib/dm-core/associations/many_to_many.rb, line 174 174: def property(name, type, options = {}) 175: options[:key] = true 176: options.delete(:index) 177: super 178: end
@api private
# File lib/dm-core/associations/many_to_many.rb, line 166 166: def through_model 167: namespace, name = through_model_namespace_name 168: 169: if namespace.const_defined?(name) 170: namespace.const_get(name) 171: else 172: Model.new(name, namespace) do 173: # all properties added to the anonymous through model are keys 174: def property(name, type, options = {}) 175: options[:key] = true 176: options.delete(:index) 177: super 178: end 179: end 180: end 181: end
@api private
# File lib/dm-core/associations/many_to_many.rb, line 184 184: def through_model_namespace_name 185: target_parts = target_model.base_model.name.split('::') 186: source_parts = source_model.base_model.name.split('::') 187: 188: name = [ target_parts.pop, source_parts.pop ].sort.join 189: 190: namespace = Object 191: 192: # find the common namespace between the target_model and source_model 193: target_parts.zip(source_parts) do |target_part, source_part| 194: break if target_part != source_part 195: namespace = namespace.const_get(target_part) 196: end 197: 198: return namespace, name 199: end
@api private
# File lib/dm-core/associations/many_to_many.rb, line 202 202: def through_relationship_name 203: if anonymous_through_model? 204: namespace = through_model_namespace_name.first 205: relationship_name = DataMapper::Inflector.underscore(through_model.name.sub(/\A#{namespace.name}::/, '')).tr('/', '_') 206: DataMapper::Inflector.pluralize(relationship_name).to_sym 207: else 208: options[:through] 209: end 210: end
@api private
# File lib/dm-core/associations/many_to_many.rb, line 250 250: def valid_source?(source) 251: relationship = nearest_relationship 252: source_key = relationship.source_key 253: target_key = relationship.target_key 254: 255: source.kind_of?(source_model) && 256: target_key.valid?(source_key.get(source)) 257: end
@api private
# File lib/dm-core/associations/many_to_many.rb, line 240 240: def valid_target?(target) 241: relationship = via 242: source_key = relationship.source_key 243: target_key = relationship.target_key 244: 245: target.kind_of?(target_model) && 246: source_key.valid?(target_key.get(target)) 247: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.