lib/activefacts/rmap/columns.rb in activefacts-rmap-1.8.1 vs lib/activefacts/rmap/columns.rb in activefacts-rmap-1.8.2

- old
+ new

@@ -66,73 +66,77 @@ self.class.name(@references, separator) end def self.name(refs, separator = "") last_names = [] - names = refs. - inject([]) do |a, ref| + 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 + # 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) + 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 + # 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 - 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 + # 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 + 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 + 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 - } + 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}} + 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 # Is this column mandatory or nullable? def is_mandatory @@ -161,25 +165,25 @@ 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 + 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 + last_vt = vt vt = vt.supertype end while vt - params[:underlying_type] = last_vt + params[:underlying_type] = last_vt return [last_vt.name, params, constraints] end # The comment is the readings from the References expressed as a series of steps (not a full verbalisation) def comment @references.map do |ref| - ref.verbalised_path + ref.verbalised_path end.compact * " and " end def to_s #:nodoc: "#{@references[0].from.name} column #{name('.')}" @@ -190,38 +194,38 @@ def columns(excluded_supertypes) #:nodoc: kind = "" cols = if is_unary kind = "unary " - objectified_unary_columns = - ((@to && @to.fact_type) ? @to.all_columns(excluded_supertypes) : []) + objectified_unary_columns = + ((@to && @to.fact_type) ? @to.all_columns(excluded_supertypes) : []) =begin - # This code omits the unary if it's objectified and that plays a mandatory role - first_mandatory_column = nil - if (@to && @to.fact_type) - trace :unary_col, "Deciding whether to skip unary column for #{inspect}" do - first_mandatory_column = - objectified_unary_columns.detect do |col| # Detect a mandatory column for the unary - trace :unary_col, "checking column #{col.name}" do - !col.references.detect do |ref| - trace :unary_col, "#{ref} is mandatory=#{ref.is_mandatory.inspect}" - !ref.is_mandatory - end - end - end - if is_from_objectified_fact && first_mandatory_column - trace :unary_col, "Skipping unary column for #{inspect} because #{first_mandatory_column.name} is mandatory" - end - end - end + # This code omits the unary if it's objectified and that plays a mandatory role + first_mandatory_column = nil + if (@to && @to.fact_type) + trace :unary_col, "Deciding whether to skip unary column for #{inspect}" do + first_mandatory_column = + objectified_unary_columns.detect do |col| # Detect a mandatory column for the unary + trace :unary_col, "checking column #{col.name}" do + !col.references.detect do |ref| + trace :unary_col, "#{ref} is mandatory=#{ref.is_mandatory.inspect}" + !ref.is_mandatory + end + end + end + if is_from_objectified_fact && first_mandatory_column + trace :unary_col, "Skipping unary column for #{inspect} because #{first_mandatory_column.name} is mandatory" + end + end + end - (is_from_objectified_fact && first_mandatory_column ? [] : [Column.new()]) + # The unary itself, unless its objectified + (is_from_objectified_fact && first_mandatory_column ? [] : [Column.new()]) + # The unary itself, unless its objectified =end - [Column.new()] + # The unary itself - objectified_unary_columns + [Column.new()] + # The unary itself + objectified_unary_columns elsif is_self_value kind = "self-role " [Column.new()] elsif is_simple_reference @to.reference_columns(excluded_supertypes) @@ -256,11 +260,11 @@ @columns = all_columns({}) end def wipe_columns - @columns = nil + @columns = nil end end # The ValueType class is defined in the metamodel; full documentation is not generated. # This section shows the features relevant to relational mapping. @@ -325,10 +329,10 @@ class EntityType < DomainObjectType # The identifier_columns for an EntityType are the columns that result from the identifying roles 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. + # 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