class ActiveFacts::Metamodel::Composite

Public Instance Methods

all_foreign_key_as_target_composite() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 1708
def all_foreign_key_as_target_composite
  all_access_path.
  select{|ap| ap.is_a?(ForeignKey)}.
  sort_by{|ap| ap.all_foreign_key_field.map(&:inspect) }
end
all_index() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 1656
def all_index
  all_access_path.
  select{|ap| ap.is_a?(Index)}.
  sort_by{|ap| [ap.composite_as_primary_index ? 0 : 1] + Array(ap.name)+ap.all_index_field.map(&:inspect) }  # REVISIT: Fix hack for stable ordering
end
all_indices_by_rank() click to toggle source

Provide a stable ordering for indices, based on the ordering of columns by rank:

# File lib/activefacts/metamodel/extensions.rb, line 1702
def all_indices_by_rank
  all_access_path.
  reject{|ap| ap.is_a?(ActiveFacts::Metamodel::ForeignKey)}.
  sort_by{|ap| ap.all_index_field.to_a.flat_map{|ixf| (c = ixf.component) ? c.rank_path : 0}.compact }
end
inspect() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 1652
def inspect
  "Composite #{mapping.inspect}"
end
show_trace() click to toggle source
# File lib/activefacts/metamodel/extensions.rb, line 1662
def show_trace
  trace :composition, inspect do
    trace :composition?, "Columns" do
      mapping.show_trace
    end

    indices = all_index
    unless indices.empty?
      trace :composition, "Indices" do
        indices.each do |ap|
          ap.show_trace
        end
      end
    end

    inbound = all_access_path.
      select{|ap| ap.is_a?(ForeignKey)}.
      sort_by{|fk| [fk.source_composite.mapping.name, fk.mapping.inspect]+fk.all_foreign_key_field.map(&:inspect)+fk.all_index_field.map(&:inspect) }
    unless inbound.empty?
      trace :composition, "Foreign keys inbound" do
        inbound.each do |fk|
          fk.show_trace
        end
      end
    end

    outbound =
      all_foreign_key_as_source_composite.
      sort_by{|fk| [fk.source_composite.mapping.name, fk.mapping.inspect]+fk.all_index_field.map(&:inspect)+fk.all_foreign_key_field.map(&:inspect) }
    unless outbound.empty?
      trace :composition, "Foreign keys outbound" do
        outbound.each do |fk|
          fk.show_trace
        end
      end
    end
  end
end
validate(&report) click to toggle source
# File lib/activefacts/metamodel/validate/composition.rb, line 29
def validate &report
  trace :composition_validator?, "Validating #{inspect}" do
    report.call(self, "Has no Mapping") unless mapping
    report.call(self, "Mapping is not a mapping") unless mapping.class == Mapping
    report.call(mapping, "Has no ObjectType") unless mapping.object_type
    report.call(mapping, "Has no Name") unless mapping.name
    report.call(mapping, "Should not have an Ordinal rank") if mapping.ordinal
    report.call(mapping, "Should not have a parent mapping") if mapping.parent
    report.call(mapping, "Should be the root of its mapping") if mapping.root != self

    mapping.validate_members &report
    validate_access_paths &report
  end
end
validate_access_paths(&report) click to toggle source
# File lib/activefacts/metamodel/validate/composition.rb, line 44
def validate_access_paths &report
  all_access_path.each do |access_path|
    report.call(access_path, "Must contain at least one IndexField") unless access_path.all_index_field.size > 0
    access_path.all_index_field.each do |index_field|
      report.call(access_path, "#{index_field.inspect} must be an Indicator or played by a ValueType") unless !index_field.component.is_a?(Mapping) || index_field.component.object_type.is_a?(ValueType)
      report.call(access_path, "#{index_field.inspect} must have a component") unless index_field.component
      if index_field.component
        report.call(access_path, "#{index_field.inspect} must be within its composite") unless index_field.component.root == self
      end
    end
    if ForeignKey === access_path
      if access_path.all_index_field.size == access_path.all_foreign_key_field.size
        access_path.all_index_field.to_a.zip(access_path.all_foreign_key_field.to_a).each do |index_field, foreign_key_field|
          report.call(access_path, "Column #{foreign_key_field.component.column_name}(#{foreign_key_field.component.class.basename}) does not match #{index_field.component.column_name}(#{index_field.component.class.basename})") unless index_field.component.class == foreign_key_field.component.class
          unless index_field.component.class == foreign_key_field.component.class
            report.call(access_path, "#{index_field.inspect} must have component type matching #{foreign_key_field.inspect}")
          else
            report.call(access_path, "#{index_field.inspect} must have matching target type") unless !index_field.component.is_a?(Absorption) or index_field.component.object_type == foreign_key_field.component.object_type
          end
          report.call(access_path, "#{foreign_key_field.inspect} must be within the source composite") unless foreign_key_field.component.root == access_path.source_composite
        end
      else
        report.call(access_path, "has #{access_path.all_index_field.size} index fields but #{access_path.all_foreign_key_field.size} ForeignKeyField")
      end
    end
  end
end