Module: ActiveFacts::API::ObjectType

Defined in:
lib/activefacts/persistence/object_type.rb

Instance Method Summary collapse

Instance Method Details

#__absorb(prefix, except_role = nil) ⇒ Object

Return an array of the absorbed columns, using prefix for name truncation



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
115
# File 'lib/activefacts/persistence/object_type.rb', line 61

def __absorb(prefix, except_role = nil)
  # also considered a table if the superclass isn't excluded and is (transitively) a table
  if !@is_table && (except_role == superclass || !is_table_subtype)
    if is_entity_type
      if (role = fully_absorbed) && role != except_role
        # If this non-table is fully absorbed into another table (not our caller!)
        # (another table plays its single identifying role), then absorb that role only.
        # counterpart_object_type = role.counterpart_object_type
        # This omission matches the one in columns.rb, see EntityType#reference_columns
        # new_prefix = prefix + [role.name.to_s.split(/_/)]
        debug :persistence, "Reference to #{role.name} (absorbed elsewhere)" do
          role.counterpart_object_type.__absorb(prefix, role.counterpart)
        end
      else
        # Not a table -> all roles are absorbed
        roles.
            values.
            select do |role|
              role.unique && role != except_role && !role.counterpart_unary_has_precedence
            end.
            inject([]) do |columns, role|
          columns += __absorb_role(prefix, role)
        end +
        subtypes.          # Absorb subtype roles too!
          select{|subtype| !subtype.is_table}.    # Don't absorb separate subtypes
          inject([]) do |columns, subtype|
            # Pass self as 2nd param here, not a role, standing for the supertype role
            new_prefix = prefix[0..-2] + [[subtype.basename]]
            debug :persistence, "Absorbed subtype #{subtype.basename}" do
              columns += subtype.__absorb(new_prefix, self)
            end
          end
      end
    else
      [prefix]
    end
  else
    # Create a foreign key to the table
    if is_entity_type
      ir = identifying_role_names.map{|role_name| roles(role_name) }
      debug :persistence, "Reference to #{basename} with #{prefix.inspect}" do
        ic = identifying_role_names.map{|role_name| role_name.to_s.split(/_/)}
        ir.inject([]) do |columns, role|
          columns += __absorb_role(prefix, role)
        end
      end
    else
      # Reference to value type which is a table
      col = prefix.clone
      debug :persistence, "Self-value #{col[-1]}.Value"
      col[-1] += ["Value"]
      col
    end
  end
end

#__absorb_role(prefix, role) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/activefacts/persistence/object_type.rb', line 117

def __absorb_role(prefix, role)
  if prefix.size > 0 and
      (c = role.owner).is_entity_type and
      c.identifying_roles == [role] and
      (irn = c.identifying_role_names).size == 1 and
      (n = irn[0].to_s.split(/_/)).size > 1 and
      (owner = role.owner.basename.snakecase.split(/_/)) and
      n[0...owner.size] == owner
    debug :persistence, "truncating transitive identifying role #{n.inspect}"
    owner.size.times { n.shift }
    new_prefix = prefix + [n]
  elsif (c = role.counterpart_object_type).is_entity_type and
      (irn = c.identifying_role_names).size == 1 and
      #irn[0].to_s.split(/_/)[0] == role.owner.basename.downcase
      irn[0] == role.counterpart.name
    #debug :persistence, "=== #{irn[0].to_s.split(/_/)[0]} elided ==="
    new_prefix = prefix
  elsif (fa_role = fully_absorbed) && fa_role == role
    new_prefix = prefix
  else
    new_prefix = prefix + [role.name.to_s.split(/_/)]
  end
  #debug :persistence, "new_prefix is #{new_prefix*"."}"

  debug :persistence, "Absorbing role #{role.name} as #{new_prefix[prefix.size..-1]*"."}" do
    role.counterpart_object_type.__absorb(new_prefix, role.counterpart)
  end
end

#columnsObject



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/activefacts/persistence/object_type.rb', line 14

def columns
  return @columns if @columns
  debug :persistence, "Calculating columns for #{basename}" do
    @columns = (
      if superclass.is_entity_type
        # REVISIT: Need keys to secondary supertypes as well, but no duplicates.
        debug :persistence, "Separate subtype has a foreign key to its supertype" do
          superclass.__absorb([[superclass.basename]], self)
        end
      else
        []
      end +
      # Then absorb all normal roles:
      roles.values.select do |role|
        role.unique && !role.counterpart_unary_has_precedence
      end.inject([]) do |columns, role|
        rn = role.name.to_s.split(/_/)
        debug :persistence, "Role #{rn*'.'}" do
          columns += role.counterpart_object_type.__absorb([rn], role.counterpart)
        end
      end +
      # And finally all absorbed subtypes:
      subtypes.
        select{|subtype| !subtype.is_table}.    # Don't absorb separate subtypes
        inject([]) do |columns, subtype|
          # Pass self as 2nd param here, not a role, standing for the supertype role
          subtype_name = subtype.basename
          debug :persistence, "Absorbing subtype #{subtype_name}" do
            columns += subtype.__absorb([[subtype_name]], self)
          end
        end
      ).map do |col_names|
        last = nil
        col_names.flatten.map do |name|
          name.downcase.sub(/^[a-z]/){|c| c.upcase}
        end.
        reject do |n|
          # Remove sequential duplicates:
          dup = last == n
          last = n
          dup
        end*"."
      end
  end
end

#is_tableObject



10
11
12
# File 'lib/activefacts/persistence/object_type.rb', line 10

def is_table
  @is_table
end

#is_table_subtypeObject



146
147
148
149
150
151
152
153
154
# File 'lib/activefacts/persistence/object_type.rb', line 146

def is_table_subtype
  return true if is_table
  klass = superclass
  while klass.is_entity_type
    return true if klass.is_table
    klass = klass.superclass
  end
  return false
end

#tableObject



6
7
8
# File 'lib/activefacts/persistence/object_type.rb', line 6

def table
  @is_table = true
end