class ActiveFacts::Metamodel::Component

Constants

RANK_DISCRIMINATOR
RANK_FOREIGN
RANK_IDENT
RANK_INDICATOR
RANK_INJECTION
RANK_MANDATORY
RANK_MULTIPLE
RANK_NON_MANDATORY
RANK_SCOPING
RANK_SUBTYPE
RANK_SUPER
RANK_SURROGATE

The ranking key of a component indicates its importance to its parent: Ranking assigns a total order, but is computed in groups:

RANK_VALUE

Public Instance Methods

all_role() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2229
def all_role
  []
end
comment() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2241
def comment
  return '' unless parent
  ((c = parent.comment) != '' ? c +' and ' : '') + name
end
data_type(context = DataType::DefaultContext.new) click to toggle source
# File lib/activefacts/metamodel/datatypes.rb, line 201
def data_type context = DataType::DefaultContext.new
  case self
  when Indicator
    context.boolean_type

  when SurrogateKey
    type_name, options = *context.surrogate_type
    options ||= {}
    # Flag but disable auto-assignment for a surrogate that's an FK (assigned elsewhere)
    options[:auto_assign] ||= 'commit'
    options[:auto_assign] = nil if in_foreign_key
    options[:mandatory] = path_mandatory
    [ type_name, options ]

  when ValidFrom, ValueField, Mapping
    # Walk up the entity type identifiers (must be single-part) to a value type:
    vt = self.object_type
    while vt.is_a?(EntityType)
      rr = vt.preferred_identifier.role_sequence.all_role_ref.single
      raise "Can't produce a column for composite #{inspect}" unless rr
      value_constraint = narrow_value_constraint(value_constraint, rr.role.role_value_constraint)
      vt = rr.role.object_type
    end
    raise "A column can only be produced from a ValueType not a #{vt.class.basename}" unless vt.is_a?(ValueType)

    if is_a?(Absorption)
      value_constraint = narrow_value_constraint(value_constraint, child_role.role_value_constraint)
    end

    # Gather up the characteristics from the value supertype hierarchy:
    is_auto_assigned = false
    stype = vt
    begin
      vt = stype
      # REVISIT: Check for length and scale shortening
      length ||= vt.length
      scale ||= vt.scale
      is_auto_assigned ||= vt.is_auto_assigned
      unless parent.parent and parent.foreign_key
        # No need to enforce value constraints that are already enforced by a foreign key
        value_constraint = narrow_value_constraint(value_constraint, vt.value_constraint)
      end
    end while stype = vt.supertype
    auto_assign =
      if is_auto_assigned
        if in_primary_index and !in_foreign_key
          {auto_assign: is_auto_assigned}     # It's auto-assigned here
        else
          {auto_assign: nil}                  # It's auto-assigned elsewhere
        end
      else
        {}                                    # It's not auto-assigned
    end

    [ vt.name,
      (length ? {length: length} : {}).
      merge!(scale ? {scale: scale} : {}).
      merge!(auto_assign).
      merge!({mandatory: path_mandatory}).
      merge!(value_constraint ? {value_constraint: value_constraint} : {})
    ]

  else
    raise "Can't make a column from #{component}"
  end
end
depth() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2199
def depth
  parent ? 1+parent.depth : 0
end
fork_to_new_parent(parent) click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2246
def fork_to_new_parent parent
  @constellation.fork self, guid: :new, parent: parent, injection_annotation: nil
end
in_foreign_key() click to toggle source
# File lib/activefacts/metamodel/datatypes.rb, line 197
def in_foreign_key
  all_foreign_key_field.detect{|fkf| fkf.foreign_key.source_composite == root}
end
in_natural_index() click to toggle source
# File lib/activefacts/metamodel/datatypes.rb, line 192
def in_natural_index
  natural_index = root.natural_index and
  natural_index.all_index_field.detect{|ixf| ixf.component == self}
end
in_primary_index() click to toggle source
# File lib/activefacts/metamodel/datatypes.rb, line 187
def in_primary_index
  primary_index = root.primary_index and
  primary_index.all_index_field.detect{|ixf| ixf.component == self}
end
inspect() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2203
def inspect
  "#{self.class.basename}"
end
is_auto_assigned() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2237
def is_auto_assigned
  false
end
is_in_primary() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2166
def is_in_primary
  !!(root and p = root.primary_index and p.all_index_field.detect{|f| f.component == self})
end
is_mandatory() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2220
def is_mandatory
  parent.is_mandatory
end
leaves() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2212
def leaves
  self
end
narrow_value_constraint(value_constraint, nested_value_constraint) click to toggle source
# File lib/activefacts/metamodel/datatypes.rb, line 268
def narrow_value_constraint(value_constraint, nested_value_constraint)
  # REVISIT: Need to calculate the constrant narrowing
  return nested_value_constraint || value_constraint
end
parent_entity_type() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2170
def parent_entity_type
  parent &&
    parent.object_type.is_a?(EntityType) &&
    parent.object_type
end
path() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2216
def path
  (parent ? parent.path+[self] : [self])
end
path_mandatory() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2224
def path_mandatory
  # REVISIT: is_mandatory &&
  parent.path_mandatory
end
primary_index_components() click to toggle source

REVISIT: This should be a method on Composite, called here as root.primary_index_components

# File lib/activefacts/metamodel/extensions.rb, line 2157
def primary_index_components
  root and
  ix = root.primary_index and                             # Primary index has been decided
  root.primary_index.all_index_field.size > 0 and         # has been populated and
  ix = root.primary_index and
  ixfs = ix.all_index_field.sort_by(&:ordinal) and
  ixfs.map(&:component)
end
rank_key() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2082
def rank_key
  @rank_key ||=
    case self
    when SurrogateKey
      if is_identifying
        [RANK_SURROGATE]  # an injected PK
      elsif injection_annotation
        [RANK_INJECTION, name]
      else
        [RANK_FOREIGN, name]    # an FK
      end

    when Indicator
      if (p = parent_entity_type) and
          p.preferred_identifier and
          (position = p.rank_in_preferred_identifier(role.base_role))
        [RANK_IDENT, position]     # An identifying unary
      else
        [RANK_INDICATOR, name || role.name]             # A non-identifying unary
      end

    when Discriminator
      [RANK_DISCRIMINATOR, name || child_role.name]

    when ValueField
      if injection_annotation
        [RANK_INJECTION, name]
      else
        [RANK_IDENT]
      end

    when Absorption
      if is_type_inheritance
        # We are traversing a type inheritance fact type. Is this object_type the subtype or supertype?
        if is_supertype_absorption
          # What's the rank of this supertype?
          tis = parent_role.object_type.all_type_inheritance_as_subtype.sort_by{|ti| ti.provides_identification ? '' : ti.supertype.name }
          [RANK_SUPER, child_role.fact_type.provides_identification ? 0 : 1+tis.index(parent_role.fact_type)]
        else
          # What's the rank of this subtype?
          tis = parent_role.object_type.all_type_inheritance_as_supertype.sort_by{|ti| ti.subtype.name }
          [RANK_SUBTYPE, tis.index(parent_role.fact_type)]
        end
      elsif (p = parent_entity_type) and (position = p.rank_in_preferred_identifier(child_role.base_role))
        [RANK_IDENT, position]
      elsif injection_annotation
        [RANK_INJECTION, name]
      else
        if parent_role.is_unique
          [parent_role.is_mandatory ? RANK_MANDATORY : RANK_NON_MANDATORY, name || child_role.name]
        else
          [RANK_MULTIPLE, name || child_role.name, parent_role.name]
        end
      end

    when Scoping
      [RANK_SCOPING, name || object_type.name]

    when ValidFrom
      [RANK_INJECTION, name]

    when Mapping
      # bare Mappings are always injected
      if root.mapping.object_type == object_type
        [RANK_IDENT, 0]
      else
        [RANK_INJECTION, name]
      end

    else
      raise "unexpected #{self.class.basename} in Component#rank_key"
    end
end
rank_kind() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2176
def rank_kind
  return "top" unless parent  # E.g. a Mapping that is a Composite
  case rank_key[0]
  when RANK_SURROGATE;    "surrogate"
  when RANK_SUPER;        "supertype"
  when RANK_IDENT;        "existential"
  when RANK_VALUE;        "self-value"
  when RANK_INJECTION;    "injection"
  when RANK_DISCRIMINATOR;"discriminator"
  when RANK_FOREIGN;      "foreignkey"
  when RANK_INDICATOR;    "indicator"
  when RANK_MANDATORY;    "mandatory"
  when RANK_NON_MANDATORY;"optional"
  when RANK_MULTIPLE;     "multiple"
  when RANK_SUBTYPE;      "subtype"
  when RANK_SCOPING;      "scoping"
  end
end
rank_path() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2233
def rank_path
  (parent ? parent.rank_path+[ordinal] : [ordinal])
end
root() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2195
def root
  parent.root
end
show_trace() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2207
def show_trace
  raise "Implemented in subclasses"
  # trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect}#{name ? " (as #{name.inspect})" : ''}"
end
uncache_rank_key() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 2078
def uncache_rank_key
  @rank_key = nil
end