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, Injection, 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



2229
2230
2231
# File 'lib/activefacts/metamodel/extensions.rb', line 2229

def all_role
  []
end

#commentObject



2241
2242
2243
2244
# 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) ⇒ Object



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
257
258
259
260
261
262
263
264
265
266
# 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

#depthObject



2199
2200
2201
# File 'lib/activefacts/metamodel/extensions.rb', line 2199

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

#fork_to_new_parent(parent) ⇒ Object



2246
2247
2248
# 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_keyObject



197
198
199
# 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_indexObject



192
193
194
195
# 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_indexObject



187
188
189
190
# 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

#inspectObject



2203
2204
2205
# File 'lib/activefacts/metamodel/extensions.rb', line 2203

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

#is_auto_assignedObject



2237
2238
2239
# File 'lib/activefacts/metamodel/extensions.rb', line 2237

def is_auto_assigned
  false
end

#is_in_primaryObject



2166
2167
2168
# 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_mandatoryObject



2220
2221
2222
# File 'lib/activefacts/metamodel/extensions.rb', line 2220

def is_mandatory
  parent.is_mandatory
end

#leavesObject



2212
2213
2214
# File 'lib/activefacts/metamodel/extensions.rb', line 2212

def leaves
  self
end

#narrow_value_constraint(value_constraint, nested_value_constraint) ⇒ Object



268
269
270
271
# 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_typeObject



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

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

#pathObject



2216
2217
2218
# File 'lib/activefacts/metamodel/extensions.rb', line 2216

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

#path_mandatoryObject



2224
2225
2226
2227
# File 'lib/activefacts/metamodel/extensions.rb', line 2224

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



2157
2158
2159
2160
2161
2162
2163
2164
# 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_keyObject



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
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
# 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_kindObject



2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
# 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_pathObject



2233
2234
2235
# File 'lib/activefacts/metamodel/extensions.rb', line 2233

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

#rootObject



2195
2196
2197
# File 'lib/activefacts/metamodel/extensions.rb', line 2195

def root
  parent.root
end

#show_traceObject



2207
2208
2209
2210
# 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_keyObject



2078
2079
2080
# File 'lib/activefacts/metamodel/extensions.rb', line 2078

def uncache_rank_key
  @rank_key = nil
end