Class: DataMapper::Associations::ManyToMany::Relationship

Inherits:
OneToMany::Relationship show all
Extended by:
Chainable
Defined in:
lib/dm-core/associations/many_to_many.rb

Constant Summary collapse

OPTIONS =
superclass::OPTIONS.dup << :through << :via

Instance Attribute Summary

Attributes inherited from Relationship

#child_repository_name, #instance_variable_name, #max, #min, #name, #options, #parent_repository_name

Instance Method Summary collapse

Methods included from Chainable

chainable, extendable

Methods inherited from OneToMany::Relationship

#collection_for, #get, #inherited_by, #set

Methods inherited from Relationship

#==, #child_model, #child_model?, #child_model_name, #eql?, #get, #get!, #inverse, #loaded?, #parent_key, #parent_model, #parent_model?, #parent_model_name, #query_for, #relative_target_repository_name, #relative_target_repository_name_for, #set, #set!, #valid?

Instance Method Details

#child_keyDataMapper::PropertySet Also known as: target_key

Returns a set of keys that identify the target model

Returns:

  • a set of properties that identify the target model

API:

  • semipublic



15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/dm-core/associations/many_to_many.rb', line 15

def child_key
  return @child_key if defined?(@child_key)

  repository_name = child_repository_name || parent_repository_name
  properties      = child_model.properties(repository_name)

  @child_key = if @child_properties
    child_key = properties.values_at(*@child_properties)
    properties.class.new(child_key).freeze
  else
    properties.key
  end
end

#eager_load(source, other_query = nil) ⇒ ManyToMany::Collection

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.

Eager load the collection using the source as a base

Parameters:

  • the source to query with

  • (defaults to: nil)

    optional query to restrict the collection

Returns:

  • the loaded collection for the source

API:

  • private



148
149
150
151
# File 'lib/dm-core/associations/many_to_many.rb', line 148

def eager_load(source, other_query = nil)
  # FIXME: enable SEL for m:m relationships
  source.model.all(query_for(source, other_query))
end

TODO: document

API:

  • semipublic



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/dm-core/associations/many_to_many.rb', line 106

def links
  return @links if defined?(@links)

  @links = []
  links  = [ through, via ]

  while relationship = links.shift
    if relationship.respond_to?(:links)
      links.unshift(*relationship.links)
    else
      @links << relationship
    end
  end

  @links.freeze
end

#queryObject

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.

TODO: document

API:

  • private



131
132
133
134
135
# File 'lib/dm-core/associations/many_to_many.rb', line 131

def query
  # TODO: consider making this a query_for method, so that ManyToMany::Relationship#query only
  # returns the query supplied in the definition
  @many_to_many_query ||= super.merge(:links => links).freeze
end

#source_scope(source) ⇒ 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.

TODO: document

API:

  • private



125
126
127
# File 'lib/dm-core/associations/many_to_many.rb', line 125

def source_scope(source)
  { through.inverse => source }
end

#throughObject

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



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/dm-core/associations/many_to_many.rb', line 52

def through
  return @through if defined?(@through)

  if options[:through].kind_of?(Associations::Relationship)
    return @through = options[:through]
  end

  repository_name = source_repository_name
  relationships   = source_model.relationships(repository_name)
  name            = through_relationship_name

  @through = relationships[name] ||
    DataMapper.repository(repository_name) do
      source_model.has(min..max, name, through_model, one_to_many_options)
    end

  @through.child_key

  @through
end

#viaObject

TODO: document

API:

  • semipublic



75
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
# File 'lib/dm-core/associations/many_to_many.rb', line 75

def via
  return @via if defined?(@via)

  if options[:via].kind_of?(Associations::Relationship)
    return @via = options[:via]
  end

  repository_name = through.relative_target_repository_name
  through_model   = through.target_model
  relationships   = through_model.relationships(repository_name)
  singular_name   = name.to_s.singularize.to_sym

  @via = relationships[options[:via]] ||
    relationships[name]               ||
    relationships[singular_name]

  @via ||= if anonymous_through_model?
    DataMapper.repository(repository_name) do
      through_model.belongs_to(singular_name, target_model, many_to_one_options)
    end
  else
    raise UnknownRelationshipError, "No relationships named #{name} or #{singular_name} in #{through_model}"
  end

  @via.child_key

  @via
end