Class: ActiveFacts::Metamodel::Component

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

Direct Known Subclasses

Discriminator, Indicator, Mapping

Constant Summary collapse

RANK_SURROGATE =

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

0
RANK_SUPER =

Supertypes, with the identifying supertype first, others alphabetical

1
RANK_IDENT =

Identifying components (absorptions, indicator), in order of the identifier

2
RANK_VALUE =

A ValueField

3
RANK_INJECTION =

Injections, in alphabetical order

4
RANK_DISCRIMINATOR =

Discriminator components, in alphabetical order

5
RANK_FOREIGN =

REVISIT: Foreign key components

6
RANK_INDICATOR =

Indicators in alphabetical order

7
RANK_MANDATORY =

Absorption: unique mandatory

8
RANK_NON_MANDATORY =

Absorption: unique optional

9
RANK_MULTIPLE =

Absorption: manifold

10
RANK_SUBTYPE =

Subtypes in alphabetical order

11
RANK_SCOPING =

Scoping in alphabetical order

12

Instance Method Summary collapse

Instance Method Details

#all_roleObject



2180
2181
2182
# File 'lib/activefacts/metamodel/extensions.rb', line 2180

def all_role
  []
end

#commentObject



2192
2193
2194
2195
# File 'lib/activefacts/metamodel/extensions.rb', line 2192

def comment
  return '' unless parent
  ((c = parent.comment) != '' ? c +' and ' : '') + name
end

#data_type(context = DataType::DefaultContext.new) ⇒ Object



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/activefacts/metamodel/datatypes.rb', line 187

def data_type context = DataType::DefaultContext.new
  case self
  when Indicator
    context.boolean_type

  when SurrogateKey
    [ context.surrogate_type,
      {
        auto_assign: ((in_primary_index && !in_foreign_key) ? "commit" : nil),
        mandatory: path_mandatory
      }
    ]

  when ValidFrom
    object_type.name

  when ValueField, Absorption
    # 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} : {})
    ]

  when Injection
    object_type.name
  else
    raise "Can't make a column from #{component}"
  end
end

#depthObject



2150
2151
2152
# File 'lib/activefacts/metamodel/extensions.rb', line 2150

def depth
  parent ? 1+parent.depth : 0
end

#fork_to_new_parent(parent) ⇒ Object



2197
2198
2199
# File 'lib/activefacts/metamodel/extensions.rb', line 2197

def fork_to_new_parent parent
  @constellation.fork self, guid: :new, parent: parent
end

#in_foreign_keyObject



183
184
185
# File 'lib/activefacts/metamodel/datatypes.rb', line 183

def in_foreign_key
  all_foreign_key_field.detect{|fkf| fkf.foreign_key.source_composite == root}
end

#in_primary_indexObject



178
179
180
181
# File 'lib/activefacts/metamodel/datatypes.rb', line 178

def in_primary_index
  primary_index = root.primary_index and
  primary_index.all_index_field.detect{|ixf| ixf.component == self}
end

#inspectObject



2154
2155
2156
# File 'lib/activefacts/metamodel/extensions.rb', line 2154

def inspect
  "#{self.class.basename}"
end

#is_auto_assignedObject



2188
2189
2190
# File 'lib/activefacts/metamodel/extensions.rb', line 2188

def is_auto_assigned
  false
end

#is_mandatoryObject



2171
2172
2173
# File 'lib/activefacts/metamodel/extensions.rb', line 2171

def is_mandatory
  parent.is_mandatory
end

#leavesObject



2163
2164
2165
# File 'lib/activefacts/metamodel/extensions.rb', line 2163

def leaves
  self
end

#narrow_value_constraint(value_constraint, nested_value_constraint) ⇒ Object



258
259
260
261
# File 'lib/activefacts/metamodel/datatypes.rb', line 258

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_typeObject



2121
2122
2123
2124
2125
# File 'lib/activefacts/metamodel/extensions.rb', line 2121

def parent_entity_type
  parent &&
    parent.object_type.is_a?(EntityType) &&
    parent.object_type
end

#pathObject



2167
2168
2169
# File 'lib/activefacts/metamodel/extensions.rb', line 2167

def path
  (parent ? parent.path+[self] : [self])
end

#path_mandatoryObject



2175
2176
2177
2178
# File 'lib/activefacts/metamodel/extensions.rb', line 2175

def path_mandatory
  # REVISIT: is_mandatory &&
  parent.path_mandatory
end

#primary_index_componentsObject

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



2112
2113
2114
2115
2116
2117
2118
2119
# File 'lib/activefacts/metamodel/extensions.rb', line 2112

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_keyObject



2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
# File 'lib/activefacts/metamodel/extensions.rb', line 2050

def rank_key
  @rank_key ||=
    case self
    when SurrogateKey
      if is_identifying
        [RANK_SURROGATE]  # an injected PK
      else
        [RANK_MANDATORY, 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
      [RANK_IDENT]

    when Injection
      [RANK_INJECTION, name]            # REVISIT: Injection not fully elaborated. A different sub-key for ranking may be needed

    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]
      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 Mapping
      [ name ]

    else
      raise "unexpected #{self.class.basename} in Component#rank_key"
    end
end

#rank_kindObject



2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
# File 'lib/activefacts/metamodel/extensions.rb', line 2127

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_pathObject



2184
2185
2186
# File 'lib/activefacts/metamodel/extensions.rb', line 2184

def rank_path
  (parent ? parent.rank_path+[ordinal] : [ordinal])
end

#rootObject



2146
2147
2148
# File 'lib/activefacts/metamodel/extensions.rb', line 2146

def root
  parent.root
end

#show_traceObject



2158
2159
2160
2161
# File 'lib/activefacts/metamodel/extensions.rb', line 2158

def show_trace
  raise "Implemented in subclasses"
  # trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect}#{name ? " (as #{name.inspect})" : ''}"
end

#uncache_rank_keyObject



2046
2047
2048
# File 'lib/activefacts/metamodel/extensions.rb', line 2046

def uncache_rank_key
  @rank_key = nil
end