class ActiveFacts::Compositions::Relational::Candidate

A candidate is a Mapping of an object type which may become a Composition (a table, in relational-speak)

Attributes

full_absorption[RW]
is_table[R]
is_tentative[R]
mapping[R]

Public Class Methods

new(compositor, mapping) click to toggle source
# File lib/activefacts/compositions/relational.rb, line 847
def initialize compositor, mapping
  @compositor = compositor
  @mapping = mapping
end

Public Instance Methods

assign_default(composition) click to toggle source
# File lib/activefacts/compositions/relational.rb, line 898
def assign_default composition
  o = object_type
  if o.is_separate
    trace :relational_defaults, "#{o.name} is a table because it's declared independent or separate"
    definitely_table
    return
  end

  case o
  when MM::ValueType
    if o.is_auto_assigned
      trace :relational_defaults, "#{o.name} is not a table because it is auto assigned"
      definitely_not_table
    elsif references_from.size > 0
      trace :relational_defaults, "#{o.name} is a table because it has references to absorb"
      definitely_table
    else
      trace :relational_defaults, "#{o.name} is not a table because it will be absorbed wherever needed"
      definitely_not_table
    end

  when MM::EntityType
    if references_to.empty? and
        !references_from.detect do |absorption|   # detect whether anything can absorb this entity type
          absorption.is_a?(MM::Mapping) && absorption.parent_role.is_unique && absorption.child_role.is_unique
        end
      trace :relational_defaults, "#{o.name} is a table because it has nothing to absorb it"
      definitely_table
      return
    end
    if !o.supertypes.empty?
      # We know that this entity type is not a separate or partitioned subtype, so a supertype that can absorb us does
      identifying_fact_type = o.all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification}
      if identifying_fact_type
        fact_type = identifying_fact_type
      else
        if o.all_type_inheritance_as_subtype.size > 1
          trace :relational_defaults, "REVISIT: #{o.name} cannot be absorbed into a supertype that doesn't also absorb all our other supertypes (or is absorbed into one of its supertypes that does)"
        end
        fact_type = o.all_type_inheritance_as_subtype.to_a[0]
      end

      absorbing_ref = mapping.all_member.detect{|m| m.is_a?(MM::Absorption) && m.child_role.fact_type == fact_type}

      absorbing_ref = absorbing_ref.flip! if absorbing_ref.reverse_mapping   # We were forward, but the other end must be
      absorbing_ref = absorbing_ref.forward_mapping
      self.full_absorption =
        o.constellation.FullAbsorption(composition: composition, mapping: absorbing_ref, object_type: o)
      trace :relational_defaults, "Supertype #{fact_type.supertype_role.name} fully absorbs subtype #{o.name} via #{absorbing_ref.inspect}"
      definitely_not_table
      return
    end # subtype

    # If the preferred_identifier consists of a ValueType that's auto-assigned ON COMMIT (like an SQL sequence),
    # that can only happen in one table, which controls the sequence.
    auto_assigned_identifying_role_player = nil
    pi_role_refs = o.preferred_identifier.role_sequence.all_role_ref
    if pi_role_refs.size == 1 and
        rr = pi_role_refs.single and
        (v = rr.role.object_type).is_a?(MM::ValueType) and
        v.is_auto_assigned == 'commit'
      auto_assigned_identifying_role_player = v
    end
    if (@compositor.options['single_sequence'] || references_to.size > 1) and auto_assigned_identifying_role_player   # Can be absorbed in more than one place
      trace :relational_defaults, "#{o.name} must be a table to support its auto-assigned identifier #{auto_assigned_identifying_role_player.name}"
      definitely_table
      return
    end

    trace :relational_defaults, "#{o.name} is initially presumed to be a table"
    probably_table

  end   # case
end
definitely_not_table() click to toggle source
# File lib/activefacts/compositions/relational.rb, line 880
def definitely_not_table
  @is_tentative = @is_table = false
end
definitely_table() click to toggle source
# File lib/activefacts/compositions/relational.rb, line 884
def definitely_table
  @is_tentative = false
  @is_table = true
end
has_references() click to toggle source
# File lib/activefacts/compositions/relational.rb, line 876
def has_references
  @mapping.all_member.select{|m| m.is_a?(MM::Absorption) }
end
object_type() click to toggle source
# File lib/activefacts/compositions/relational.rb, line 852
def object_type
  @mapping.object_type
end
probably_not_table() click to toggle source
# File lib/activefacts/compositions/relational.rb, line 889
def probably_not_table
  @is_tentative = true
  @is_table = false
end
probably_table() click to toggle source
# File lib/activefacts/compositions/relational.rb, line 894
def probably_table
  @is_tentative = @is_table = true
end
references_from() click to toggle source

References from us are things we can own (non-Mappings) or have a unique forward absorption for

# File lib/activefacts/compositions/relational.rb, line 857
def references_from
  @mapping.all_member.select do |m|
    !m.is_a?(MM::Absorption) or
    !m.forward_mapping && m.parent_role.is_unique  # A forward absorption has no forward absorption
  end
end
Also aliased as: rf
references_to() click to toggle source

References to us are reverse absorptions where the forward absorption can absorb us

# File lib/activefacts/compositions/relational.rb, line 866
def references_to
  # REVISIT: If some other object has a Mapping to us, that should be in this list
  @mapping.all_member.select do |m|
    m.is_a?(MM::Absorption) and
    f = m.forward_mapping and    # This Absorption has a forward counterpart, so must be reverse
    f.parent_role.is_unique
  end
end
Also aliased as: rt
rf()
Alias for: references_from
rt()
Alias for: references_to