class ActiveFacts::RMap::Column

Public Class Methods

name(refs, separator = "") click to toggle source
# File lib/activefacts/rmap/columns.rb, line 69
def self.name(refs, separator = "")
  last_names = []
  name_array = nil
  trace :columns, "Building column name from #{refs.inspect}" do
    names = refs.
      inject([]) do |a, ref|

        # Skip any object after the first which is identified by this reference
        if ref != refs[0] and
            !ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) and
            ref.to and
            ref.to.is_a?(ActiveFacts::Metamodel::EntityType) and
            (role_ref = ref.to.preferred_identifier.role_sequence.all_role_ref.single) and
            role_ref.role == ref.from_role
          trace :columns, "Skipping #{ref}, identifies non-initial object"
          next a
        end

        names = ref.to_names(ref != refs.last)

        # When traversing type inheritances, keep the subtype name, not the supertype names as well:
        if a.size > 0 && ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
          if ref.to != ref.fact_type.subtype  # Did we already have the subtype?
            trace :columns, "Skipping supertype #{ref}"
            next a
          end
          trace :columns, "Eliding supertype in #{ref}"
          last_names.size.times { a.pop }   # Remove the last names added
        elsif last_names.last && last_names.last == names[0][0...last_names.last.size] 
          # When Xyz is followed by XyzID, truncate that to just ID
          trace :columns, "truncating repeated #{last_names.last} in #{names[0]}"
          names[0] = names[0][last_names.last.size..-1]
          names.shift if names[0] == ''
        elsif last_names.last == names[0]
          # Same, but where an underscore split up the words
          trace :columns, "truncating repeated name in #{names.inspect}"
          names.shift
        end

        # If the reference is to the single identifying role of the object_type making the reference,
        # strip the object_type name from the start of the reference role
        if a.size > 0 and
            (et = ref.from).is_a?(ActiveFacts::Metamodel::EntityType) and
            # This instead of the next 2 would apply to all identifying roles, but breaks some examples:
            # (role_ref = et.preferred_identifier.role_sequence.all_role_ref.detect{|rr| rr.role == ref.to_role}) and
            (role_ref = et.preferred_identifier.role_sequence.all_role_ref.single) and
            role_ref.role == ref.to_role and
            names[0][0...et.name.size].downcase == et.name.downcase

          trace :columns, "truncating transitive identifying role #{names.inspect}"
          names[0] = names[0][et.name.size..-1]
          names.shift if names[0] == ""
        end

        last_names = names

        a += names
        a
      end.elide_repeated_subsequences { |a, b|
        if a.is_a?(Array)
          a.map{|e| e.downcase} == b.map{|e| e.downcase}
        else
          a.downcase == b.downcase
        end
      }

    name_array = names.map{|n| n.sub(/^[a-z]/){|s| s.upcase}}
    trace :columns, "column name is #{name_array*'.'}"
  end
  separator ? name_array * separator : name_array
end

Public Instance Methods

absorption_level() click to toggle source

How many of the initial references are involved in full absorption of an EntityType into this column’s table

# File lib/activefacts/rmap/columns.rb, line 43
def absorption_level
  l = 0
  @references.detect do |ref|
    l += 1 if ref.is_absorbing
    false
  end
  l
end
absorption_references() click to toggle source

All references up to and including the first non-absorbing reference

# File lib/activefacts/rmap/columns.rb, line 33
def absorption_references
  @references.inject([]) do |array, ref|
    array << ref
    # puts "Column #{name} spans #{ref}, #{ref.is_absorbing ? "" : "not "} absorbing (#{ref.to.name} absorbs via #{ref.to.absorbed_via.inspect})"
    break array unless ref.is_absorbing
    array
  end
end
comment() click to toggle source

The comment is the readings from the References expressed as a series of steps (not a full verbalisation)

# File lib/activefacts/rmap/columns.rb, line 182
def comment
  @references.map do |ref|
    ref.verbalised_path
  end.compact * " and "
end
is_auto_assigned() click to toggle source

This column is auto-assigned if it’s an auto-assigned value type and is not a foreign key

# File lib/activefacts/rmap/columns.rb, line 149
def is_auto_assigned
  last_table_ref = references.reverse.detect{|r| r.from && r.from.is_table}
  (to = references[-1].to) &&
    to.is_auto_assigned &&
    references[0].from.identifier_columns.size == 1 &&
    references[0].from == last_table_ref.from
end
is_mandatory() click to toggle source

Is this column mandatory or nullable?

# File lib/activefacts/rmap/columns.rb, line 142
def is_mandatory
  # Uncomment the following line for CWA unaries (not nullable, just T/F)
  # @references[-1].is_unary ||
    !@references.detect{|ref| !ref.is_mandatory || ref.is_unary }
end
name(separator = "") click to toggle source

A Column name is a sequence of names (derived from the to_roles of the References) appended by a separator string (pass nil to get the original array of names) The names to use is derived from the to_names of each Reference, modified by these rules:

  • A reference after the first one which is not a TypeInheritance but where the from object plays the sole role in the preferred identifier of the to entity is ignored,

  • A reference (after a name has been retained) which is a TypeInheritance retains the names of the subtype,

  • If the names retained so far end in XYZ and the to_names start with XYZ, remove the duplication

  • If we have retained the name of an entity, and this reference is the sole identifying role of an entity, and the identifying object has a name that is prefixed by the name of the object it identifies, remove the prefix and use just the suffix.

# File lib/activefacts/rmap/columns.rb, line 65
def name(separator = "")
  self.class.name(@references, separator)
end
references() click to toggle source

A Column is created from a path through an array of References to a ValueType

# File lib/activefacts/rmap/columns.rb, line 28
def references
  @references ||= []
end
type() click to toggle source

What’s the underlying SQL data type of this column?

# File lib/activefacts/rmap/columns.rb, line 158
def type
  params = {}
  constraints = []
  return ["BIT", params, constraints] if references[-1].is_unary   # It's a unary

  # Add a role value constraint
  # REVISIT: Can add join-role-value-constraints here, if we ever provide a way to define them
  if references[-1].to_role && references[-1].to_role.role_value_constraint
    constraints << references[-1].to_role.base_role.role_value_constraint
  end

  vt = references[-1].is_self_value ? references[-1].from : references[-1].to
  begin
    params[:length] ||= vt.length if vt.length.to_i != 0
    params[:scale] ||= vt.scale if vt.scale.to_i != 0
    constraints << vt.value_constraint if vt.value_constraint
    last_vt = vt
    vt = vt.supertype
  end while vt
  params[:underlying_type] = last_vt
  return [last_vt.name, params, constraints]
end