Class: ActiveFacts::Metamodel::EntityType

Inherits:
DomainObjectType
  • Object
show all
Defined in:
lib/activefacts/rmap/columns.rb,
lib/activefacts/rmap/index.rb,
lib/activefacts/rmap/tables.rb,
lib/activefacts/rmap/reference.rb

Overview

The EntityType class is defined in the metamodel; full documentation is not generated. This section shows the features relevant to relational mapping.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#absorbed_mirrorObject

:nodoc:



53
54
55
# File 'lib/activefacts/rmap/tables.rb', line 53

def absorbed_mirror
  @absorbed_mirror
end

#absorbed_viaObject

A Reference from an entity type that fully absorbs this one



52
53
54
# File 'lib/activefacts/rmap/tables.rb', line 52

def absorbed_via
  @absorbed_via
end

Instance Method Details

#all_columns(excluded_supertypes) ⇒ Object

When absorbing this EntityType, what columns must be absorbed? This must be a fresh copy, because the columns will have References prepended.



379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'lib/activefacts/rmap/columns.rb', line 379

def all_columns(excluded_supertypes)    #:nodoc:
  trace :columns, "All Columns for #{name}" do
    columns = []
    sups = supertypes
    pi_roles = preferred_identifier.role_sequence.all_role_ref.map{|rr| rr.role}
    references_from.sort_by do |ref|
      # Put supertypes first, in order, then PI roles, non-subtype references by name, then subtypes by name:
      next [0, p] if p = sups.index(ref.to)
      if !ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
        next [1, p] if p = pi_roles.index(ref.to_role)
        next [2, ref.to_names]
      end
      [3, ref.to_names]
    end.each do |ref|
      trace :columns, "Columns absorbed via #{ref}" do
        if (ref.role_type == :supertype)
          if excluded_supertypes[ref.to]
            trace :columns, "Exclude #{ref.to.name}, we already inherited it"
            next
          end

          next if (ref.to.absorbed_via != ref)
          excluded_supertypes[ref.to] = true
          columns += ref.columns(excluded_supertypes)
        else
          columns += ref.columns({})
        end
      end
    end
    columns
  end
end

#identifier_columnsObject

The identifier_columns for an EntityType are the columns that result from the identifying roles



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'lib/activefacts/rmap/columns.rb', line 331

def identifier_columns
  trace :columns, "Identifier Columns for #{name}" do
    if absorbed_via and
      # If this is a subtype that has its own identification, use that instead
      (all_type_inheritance_as_subtype.size == 0 ||
        all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
      return absorbed_via.from.identifier_columns
    end

    preferred_identifier.role_sequence.all_role_ref.map do |role_ref|
      ref = references_from.detect {|ref| ref.to_role == role_ref.role}

      columns.select{|column| column.references[0] == ref}
    end.flatten
  end
end

#is_auto_assignedObject

:nodoc:



55
56
57
# File 'lib/activefacts/rmap/tables.rb', line 55

def is_auto_assigned  #:nodoc:
  false
end

#is_tableObject

Returns true if this EntityType is a table



60
61
62
63
64
65
66
67
68
69
70
71
72
73
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
# File 'lib/activefacts/rmap/tables.rb', line 60

def is_table
  return @is_table if @is_table != nil  # We already make a guess or decision

  @tentative = false

  # Always a table if marked so
  if is_separate
    trace :absorption, "EntityType #{name} is declared independent or separate"
    return @is_table = true
  end

  # Always a table if nowhere else to go, and has no one-to-ones that might flip:
  if references_to.empty? and
      !references_from.detect{|ref| ref.role_type == :one_one }
    trace :absorption, "EntityType #{name} is presumed independent as it has nowhere to go"
    return @is_table = true
  end

  # Subtypes may be partitioned or separate, in which case they're definitely tables.
  # Otherwise, if their identification is inherited from a supertype, they're definitely absorbed.
  # If they have separate identification, it might absorb them.
  if (!supertypes.empty?)
    as_ti = all_supertype_inheritance.detect{|ti| ti.assimilation}
    @is_table = as_ti != nil
    if @is_table
      trace :absorption, "EntityType #{name} is #{as_ti.assimilation} from supertype #{as_ti.supertype}"
    else
      identifying_fact_type = preferred_identifier.role_sequence.all_role_ref.to_a[0].role.fact_type
      if identifying_fact_type.is_a?(TypeInheritance)
        trace :absorption, "EntityType #{name} is absorbed into supertype #{supertypes[0].name}"
        @is_table = false
      else
        # Possibly absorbed, we'll have to see how that pans out
        @tentative = true
      end
    end
    return @is_table
  end

  # If the preferred_identifier includes an auto_assigned ValueType
  # and this object is absorbed in more than one place, we need a table
  # to manage the auto-assignment.
  if references_to.size > 1 and
    preferred_identifier.role_sequence.all_role_ref.detect {|rr|
      next false unless rr.role.object_type.is_a? ValueType
      rr.role.object_type.is_auto_assigned
    }
    trace :absorption, "#{name} has an auto-assigned counter in its ID, so must be a table"
    @tentative = false
    return @is_table = true
  end

  @tentative = true
  @is_table = true
end

#populate_referencesObject

:nodoc:



392
393
394
395
396
397
398
399
400
# File 'lib/activefacts/rmap/reference.rb', line 392

def populate_references          #:nodoc:
  if fact_type && fact_type.all_role.size > 1
    # NOT: fact_type.all_role.each do |role|  # Place roles in the preferred order instead:
    fact_type.preferred_reading.role_sequence.all_role_ref.map(&:role).each do |role|
      populate_reference role     # Objectified fact role, handled specially
    end
  end
  super
end

#reference_columns(excluded_supertypes) ⇒ Object

When creating a foreign key to this EntityType, what columns must we include (the identifier columns)? This must be a fresh copy, because the columns will have References prepended



350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/activefacts/rmap/columns.rb', line 350

def reference_columns(excluded_supertypes)    #:nodoc:
  trace :columns, "Reference Columns for #{name}" do

    if absorbed_via and
      # If this is not a subtype, or is a subtype that has its own identification, use the id.
      (all_type_inheritance_as_subtype.size == 0 ||
        all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
      rc = absorbed_via.from.reference_columns(excluded_supertypes)
      # The absorbed_via reference gets skipped here, and also in object_type.rb
      trace :columns, "Skipping #{absorbed_via}"
      absorbed_mirror ||= absorbed_via.reversed
      rc.each{|col| col.prepend(absorbed_mirror)}
      return rc
    end

    # REVISIT: Should have built preferred_identifier_references
    preferred_identifier.role_sequence.all_role_ref.map do |role_ref|
      # REVISIT: Should index references by to_role:
      ref = references_from.detect {|ref| ref.to_role == role_ref.role}

      raise "reference for role #{role_ref.describe} not found on #{name} in #{references_from.size} references:\n\t#{references_from.map(&:to_s)*"\n\t"}" unless ref

      ref.columns({})
    end.flatten
  end
end

#self_indexObject



87
88
89
# File 'lib/activefacts/rmap/index.rb', line 87

def self_index
  nil
end