class ActiveFacts::RMap::Column
Public Class Methods
# File lib/activefacts/rmap/columns.rb, line 69 def self.name(refs, separator = "") last_names = [] name_array = nil trace :columns, "Building column name from #{refs.inspect}" do names = refs. inject([]) do |a, ref| # Skip any object after the first which is identified by this reference if ref != refs[0] and !ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) and ref.to and ref.to.is_a?(ActiveFacts::Metamodel::EntityType) and (role_ref = ref.to.preferred_identifier.role_sequence.all_role_ref.single) and role_ref.role == ref.from_role trace :columns, "Skipping #{ref}, identifies non-initial object" next a end names = ref.to_names(ref != refs.last) # When traversing type inheritances, keep the subtype name, not the supertype names as well: if a.size > 0 && ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) if ref.to != ref.fact_type.subtype # Did we already have the subtype? trace :columns, "Skipping supertype #{ref}" next a end trace :columns, "Eliding supertype in #{ref}" last_names.size.times { a.pop } # Remove the last names added elsif last_names.last && last_names.last == names[0][0...last_names.last.size] # When Xyz is followed by XyzID, truncate that to just ID trace :columns, "truncating repeated #{last_names.last} in #{names[0]}" names[0] = names[0][last_names.last.size..-1] names.shift if names[0] == '' elsif last_names.last == names[0] # Same, but where an underscore split up the words trace :columns, "truncating repeated name in #{names.inspect}" names.shift end # If the reference is to the single identifying role of the object_type making the reference, # strip the object_type name from the start of the reference role if a.size > 0 and (et = ref.from).is_a?(ActiveFacts::Metamodel::EntityType) and # This instead of the next 2 would apply to all identifying roles, but breaks some examples: # (role_ref = et.preferred_identifier.role_sequence.all_role_ref.detect{|rr| rr.role == ref.to_role}) and (role_ref = et.preferred_identifier.role_sequence.all_role_ref.single) and role_ref.role == ref.to_role and names[0][0...et.name.size].downcase == et.name.downcase trace :columns, "truncating transitive identifying role #{names.inspect}" names[0] = names[0][et.name.size..-1] names.shift if names[0] == "" end last_names = names a += names a end.elide_repeated_subsequences { |a, b| if a.is_a?(Array) a.map{|e| e.downcase} == b.map{|e| e.downcase} else a.downcase == b.downcase end } name_array = names.map{|n| n.sub(/^[a-z]/){|s| s.upcase}} trace :columns, "column name is #{name_array*'.'}" end separator ? name_array * separator : name_array end
Public Instance Methods
How many of the initial references are involved in full absorption of an EntityType into this column’s table
# File lib/activefacts/rmap/columns.rb, line 43 def absorption_level l = 0 @references.detect do |ref| l += 1 if ref.is_absorbing false end l end
All references up to and including the first non-absorbing reference
# File lib/activefacts/rmap/columns.rb, line 33 def absorption_references @references.inject([]) do |array, ref| array << ref # puts "Column #{name} spans #{ref}, #{ref.is_absorbing ? "" : "not "} absorbing (#{ref.to.name} absorbs via #{ref.to.absorbed_via.inspect})" break array unless ref.is_absorbing array end end
The comment is the readings from the References expressed as a series of steps (not a full verbalisation)
# File lib/activefacts/rmap/columns.rb, line 182 def comment @references.map do |ref| ref.verbalised_path end.compact * " and " end
This column is auto-assigned if it’s an auto-assigned value type and is not a foreign key
# File lib/activefacts/rmap/columns.rb, line 149 def is_auto_assigned last_table_ref = references.reverse.detect{|r| r.from && r.from.is_table} (to = references[-1].to) && to.is_auto_assigned && references[0].from.identifier_columns.size == 1 && references[0].from == last_table_ref.from end
Is this column mandatory or nullable?
# File lib/activefacts/rmap/columns.rb, line 142 def is_mandatory # Uncomment the following line for CWA unaries (not nullable, just T/F) # @references[-1].is_unary || !@references.detect{|ref| !ref.is_mandatory || ref.is_unary } end
A Column
name is a sequence of names (derived from the to_roles of the References) appended by a separator string (pass nil to get the original array of names) The names to use is derived from the to_names of each Reference
, modified by these rules:
-
A reference after the first one which is not a TypeInheritance but where the from object plays the sole role in the preferred identifier of the to entity is ignored,
-
A reference (after a name has been retained) which is a TypeInheritance retains the names of the subtype,
-
If the names retained so far end in XYZ and the to_names start with XYZ, remove the duplication
-
If we have retained the name of an entity, and this reference is the sole identifying role of an entity, and the identifying object has a name that is prefixed by the name of the object it identifies, remove the prefix and use just the suffix.
# File lib/activefacts/rmap/columns.rb, line 65 def name(separator = "") self.class.name(@references, separator) end
A Column
is created from a path through an array of References to a ValueType
# File lib/activefacts/rmap/columns.rb, line 28 def references @references ||= [] end
What’s the underlying SQL data type of this column?
# File lib/activefacts/rmap/columns.rb, line 158 def type params = {} constraints = [] return ["BIT", params, constraints] if references[-1].is_unary # It's a unary # Add a role value constraint # REVISIT: Can add join-role-value-constraints here, if we ever provide a way to define them if references[-1].to_role && references[-1].to_role.role_value_constraint constraints << references[-1].to_role.base_role.role_value_constraint end vt = references[-1].is_self_value ? references[-1].from : references[-1].to begin params[:length] ||= vt.length if vt.length.to_i != 0 params[:scale] ||= vt.scale if vt.scale.to_i != 0 constraints << vt.value_constraint if vt.value_constraint last_vt = vt vt = vt.supertype end while vt params[:underlying_type] = last_vt return [last_vt.name, params, constraints] end