Class: ActiveFacts::Metamodel::Mapping

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

Direct Known Subclasses

Absorption, Scoping, ValidFrom, ValueField

Constant Summary

Constants inherited from Component

Component::RANK_DISCRIMINATOR, Component::RANK_FOREIGN, Component::RANK_IDENT, Component::RANK_INDICATOR, Component::RANK_INJECTION, Component::RANK_MANDATORY, Component::RANK_MULTIPLE, Component::RANK_NON_MANDATORY, Component::RANK_SCOPING, Component::RANK_SUBTYPE, Component::RANK_SUPER, Component::RANK_SURROGATE, Component::RANK_VALUE

Instance Method Summary collapse

Methods inherited from Component

#all_role, #comment, #data_type, #depth, #fork_to_new_parent, #in_foreign_key, #in_natural_index, #in_primary_index, #is_in_primary, #leaves, #narrow_value_constraint, #parent_entity_type, #path, #primary_index_components, #rank_key, #rank_kind, #rank_path, #uncache_rank_key

Instance Method Details

#all_leafObject



1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
# File 'lib/activefacts/metamodel/extensions.rb', line 1822

def all_leaf
  re_rank
  all_member.sort_by(&:ordinal).flat_map do |member|
    if member.is_a?(Mapping) && member.all_member.size > 0
      member.all_leaf
    else
      member
    end
  end
end

#inspectObject



1785
1786
1787
# File 'lib/activefacts/metamodel/extensions.rb', line 1785

def inspect
  "#{self.class.basename} (#{rank_kind})#{parent ? " in #{parent.name}" :''} of #{name && name != '' ? name : '<anonymous>'}"
end

#inspect_reasonObject



1781
1782
1783
# File 'lib/activefacts/metamodel/extensions.rb', line 1781

def inspect_reason
  "#{parent.name} contains mapping of #{name}"
end

#is_auto_assignedObject



1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
# File 'lib/activefacts/metamodel/extensions.rb', line 1841

def is_auto_assigned
  # It's auto-assigned if it's an auto-assigned value type and it's in its root's primary_index and is not a foreign key field
  if root and
      (a = object_type.is_auto_assigned) and
      (root.primary_index.all_index_field.detect{|ixf| ixf.component == self}) and
      (!all_foreign_key_field.detect{|fkf| fkf.foreign_key.source_composite == self.root})
    a
  else
    nil
  end
end

#is_mandatoryObject



1833
1834
1835
# File 'lib/activefacts/metamodel/extensions.rb', line 1833

def is_mandatory
  true
end

#is_partitioned_hereObject



1853
1854
1855
# File 'lib/activefacts/metamodel/extensions.rb', line 1853

def is_partitioned_here
  false # Must be an absorption to be partitioned here
end

#is_type_inheritanceObject



1802
1803
1804
# File 'lib/activefacts/metamodel/extensions.rb', line 1802

def is_type_inheritance
  false
end

#path_mandatoryObject



1837
1838
1839
# File 'lib/activefacts/metamodel/extensions.rb', line 1837

def path_mandatory
  !parent || parent.path_mandatory
end

#re_rankObject

Recompute a contiguous member ranking fron zero, based on current membership:



1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
# File 'lib/activefacts/metamodel/extensions.rb', line 1807

def re_rank
  all_member.each(&:uncache_rank_key)
  next_rank = 0
  all_member.
  sort_by(&:rank_key).
  each do |member|
    member.ordinal = next_rank
    next_rank += 1
  end
end

#rootObject



1818
1819
1820
# File 'lib/activefacts/metamodel/extensions.rb', line 1818

def root
  composite || parent && parent.root
end

#show_traceObject



1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
# File 'lib/activefacts/metamodel/extensions.rb', line 1789

def show_trace
  trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect}" do
    yield if block_given?
    if m = all_member.detect{|m| !m.ordinal}
      trace :composition, "WARNING: show_trace needed to re_rank #{name} because of unranked #{m.inspect}"
      re_rank
    end
    all_member.sort_by{|member| [member.ordinal, member.name]}.each do |member|
      member.show_trace
    end
  end
end

#validate_members(&report) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/activefacts/metamodel/validate/composition.rb', line 74

def validate_members &report
  # Names (except of subtype/supertype absorption) must be unique:
  names = all_member.
    reject{|m| m.is_a?(Absorption) && m.parent_role.fact_type.is_a?(TypeInheritance)}.
    map(&:name).
    compact
  duplicate_names = names.select{|name| names.count(name) > 1}.uniq
  report.call(self, "Contains duplicated names #{duplicate_names.map(&:inspect)*', '}") unless duplicate_names.empty?

  all_member.each do |member|
    trace :composition_validator?, "Validating #{member.inspect}" do
      report.call(member, "Requires a name") unless Absorption === member && member.flattens or member.name && !member.name.empty?
      case member
      when Absorption
        p = member.parent_role
        c = member.child_role
        report.call(member, "Roles should belong to the same fact type, but instead we have #{p.name} in #{p.fact_type.default_reading} and #{c.name} in #{c.fact_type.default_reading}") unless p.fact_type == c.fact_type
        report.call(member, "Object type #{member.object_type.name} should play the child role #{c.name}") unless member.object_type == c.object_type
        report.call(member, "Parent mapping object type #{object_type.name} should play the parent role #{p.name}") unless object_type == p.object_type

        member.validate_nesting &report if member.all_nesting.size > 0
        member.validate_members &report

      when Scoping
        report.call(member, "REVISIT: Unexpected and unchecked Scoping")

      when ValueField
        # Nothing to check here

      when SurrogateKey
        # Nothing to check here

      when ValidFrom
        # Nothing to check here

      when Mapping
        member.validate_reverse &report

      when Indicator
        report.call(member, "Indicator requires a Role") unless member.role

      when Discriminator
        report.call(member, "Discriminator requires at least one Discriminated Role") if member.all_discriminated_role.empty?
        member.all_discriminated_role.each do |role|
          report.call(member, "Discriminated Role #{role.name} is not played by parent object type #{object_type.name}") unless role.object_type == object_type
        end
        # REVISIT: Discriminated Roles must have distinct values matching the type of the Role
      end
    end
  end
end

#validate_reverse(&report) ⇒ Object



126
127
128
129
130
131
# File 'lib/activefacts/metamodel/validate/composition.rb', line 126

def validate_reverse &report
  reverse = forward_mapping || reverse_mapping
  return unless reverse
  report.call(self, "Opposite absorption's child role #{reverse.child_role.name} should match parent role #{parent_role.name}") unless reverse.child_role == parent_role
  report.call(self, "Opposite absorption's parent role #{reverse.parent_role.name} should match child role #{child_role.name}") unless reverse.parent_role == child_role
end