lib/activefacts/persistence/columns.rb in activefacts-1.0.2 vs lib/activefacts/persistence/columns.rb in activefacts-1.1.0

- old
+ new

@@ -76,32 +76,32 @@ !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 - debug :columns, "Skipping #{ref}, identifies non-initial object" + 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? - debug :columns, "Skipping supertype #{ref}" + trace :columns, "Skipping supertype #{ref}" next a end - debug :columns, "Eliding supertype in #{ref}" + 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 - debug :columns, "truncating repeated #{last_names.last} in #{names[0]}" + 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 - debug :columns, "truncating repeated name in #{names.inspect}" + 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 @@ -111,11 +111,11 @@ # (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 - debug :columns, "truncating transitive identifying role #{names.inspect}" + 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 @@ -175,14 +175,22 @@ 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.is_mandatory ? "" : "maybe ") + - (ref.fact_type && ref.fact_type.entity_type ? ref.fact_type.entity_type.name+" is where " : "") + - ref.reading - end * " and " + # REVISIT: Some contraction would be nice here + objectification = ref.fact_type && ref.fact_type.entity_type + involves = '' + if objectification && ref == @references.last + objectification = nil if ref.fact_type.all_role.size == 1 # Disregard the objectification of a trailing unary + involves = ref.to_role.link_fact_type.default_reading[ref.fact_type.entity_type.name.size..-1] + end + (objectification ? objectification.name + ' (in which ' : '') + + (ref.is_mandatory || ref.is_unary ? '' : 'maybe ') + + ref.reading + + (objectification ? ')'+involves : '') + end.compact * " and " end def to_s #:nodoc: "#{@references[0].from.name} column #{name('.')}" end @@ -192,12 +200,38 @@ def columns(excluded_supertypes) #:nodoc: kind = "" cols = if is_unary kind = "unary " - [Column.new()] + - ((@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 + + (is_from_objectified_fact && first_mandatory_column ? [] : [Column.new()]) + # The unary itself, unless its objectified +=end + + [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) @@ -208,13 +242,13 @@ cols.each do |c| c.prepend self end - debug :columns, "Columns from #{kind}#{self}" do + trace :columns, "Columns from #{kind}#{self}" do cols.each {|c| - debug :columns, "#{c}" + trace :columns, "#{c}" } end end end end @@ -237,11 +271,11 @@ # The ValueType class is defined in the metamodel; full documentation is not generated. # This section shows the features relevant to relational Persistence. class ValueType < DomainObjectType # The identifier_columns for a ValueType can only ever be the self-value role that was injected def identifier_columns - debug :columns, "Identifier Columns for #{name}" do + trace :columns, "Identifier Columns for #{name}" do raise "Illegal call to identifier_columns for absorbed ValueType #{name}" unless is_table if isr = injected_surrogate_role columns.select{|column| column.references[0].from_role == isr } else columns.select{|column| column.references[0] == self_value_reference} @@ -250,11 +284,11 @@ end # When creating a foreign key to this ValueType, what columns must we include? # This must be a fresh copy, because the columns will have References prepended def reference_columns(excluded_supertypes) #:nodoc: - debug :columns, "Reference Columns for #{name}" do + trace :columns, "Reference Columns for #{name}" do if is_table if isr = injected_surrogate_role ref_from = references_from.detect{|ref| ref.from_role == isr} [ActiveFacts::Persistence::Column.new(ref_from)] else @@ -268,18 +302,18 @@ # When absorbing this ValueType, what columns must be absorbed? # This must be a fresh copy, because the columns will have References prepended. def all_columns(excluded_supertypes) #:nodoc: columns = [] - debug :columns, "All Columns for #{name}" do + trace :columns, "All Columns for #{name}" do if is_table self_value_reference else columns << ActiveFacts::Persistence::Column.new end references_from.each do |ref| - debug :columns, "Columns absorbed via #{ref}" do + trace :columns, "Columns absorbed via #{ref}" do columns += ref.columns({}) end end end columns @@ -295,11 +329,11 @@ # The EntityType class is defined in the metamodel; full documentation is not generated. # This section shows the features relevant to relational Persistence. class EntityType < DomainObjectType # The identifier_columns for an EntityType are the columns that result from the identifying roles def identifier_columns - debug :columns, "Identifier Columns for #{name}" do + trace :columns, "Identifier Columns for #{name}" do if absorbed_via and # If this is a subtype that has its own identification, use that. (all_type_inheritance_as_subtype.size == 0 || all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification }) return absorbed_via.from.identifier_columns @@ -314,20 +348,21 @@ end # 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 def reference_columns(excluded_supertypes) #:nodoc: - debug :columns, "Reference Columns for #{name}" do + 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, ans also in object_type.rb - debug :columns, "Skipping #{absorbed_via}" - #rc.each{|col| col.prepend(absorbed_via)} + # 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| @@ -342,11 +377,11 @@ end # When absorbing this EntityType, what columns must be absorbed? # This must be a fresh copy, because the columns will have References prepended. def all_columns(excluded_supertypes) #:nodoc: - debug :columns, "All Columns for #{name}" do + 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: @@ -355,14 +390,14 @@ 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| - debug :columns, "Columns absorbed via #{ref}" do + trace :columns, "Columns absorbed via #{ref}" do if (ref.role_type == :supertype) if excluded_supertypes[ref.to] - debug :columns, "Exclude #{ref.to.name}, we already inherited it" + trace :columns, "Exclude #{ref.to.name}, we already inherited it" next end next if (ref.to.absorbed_via != ref) excluded_supertypes[ref.to] = true @@ -390,23 +425,23 @@ def populate_all_columns #:nodoc: # REVISIT: Is now a good time to apply schema transforms or should this be more explicit? finish_schema - debug :columns, "Populating all columns" do + trace :columns, "Populating all columns" do all_object_type.each do |object_type| next if !object_type.is_table - debug :columns, "Populating columns for table #{object_type.name}" do + trace :columns, "Populating columns for table #{object_type.name}" do object_type.populate_columns end end end - debug :columns, "Finished columns" do + trace :columns, "Finished columns" do all_object_type.each do |object_type| next if !object_type.is_table - debug :columns, "Finished columns for table #{object_type.name}" do + trace :columns, "Finished columns for table #{object_type.name}" do object_type.columns.each do |column| - debug :columns, "#{column}" + trace :columns, "#{column}" end end end end end