Class: ActiveFacts::Metamodel::Composite

Inherits:
Object
  • Object
show all
Defined in:
lib/activefacts/metamodel/metamodel.rb,
lib/activefacts/metamodel/extensions.rb,
lib/activefacts/metamodel/validate/composition.rb

Instance Method Summary collapse

Instance Method Details

#all_foreign_key_as_target_compositeObject



1703
1704
1705
1706
1707
# File 'lib/activefacts/metamodel/extensions.rb', line 1703

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_indexObject



1651
1652
1653
1654
1655
# File 'lib/activefacts/metamodel/extensions.rb', line 1651

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_rankObject

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



1697
1698
1699
1700
1701
# File 'lib/activefacts/metamodel/extensions.rb', line 1697

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| ixf.component.rank_path}.compact }
end

#inspectObject



1647
1648
1649
# File 'lib/activefacts/metamodel/extensions.rb', line 1647

def inspect
  "Composite #{mapping.inspect}"
end

#show_traceObject



1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
# File 'lib/activefacts/metamodel/extensions.rb', line 1657

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.absorption.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.absorption.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) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 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) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 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?(Indicator) || index_field.component.object_type.is_a?(ValueType)
      report.call(access_path, "#{index_field.inspect} must be within its composite") unless index_field.component.root == self
    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