lib/activefacts/persistence/reference.rb in activefacts-0.8.16 vs lib/activefacts/persistence/reference.rb in activefacts-0.8.18

- old
+ new

@@ -37,13 +37,15 @@ # class Reference attr_reader :from, :to # A "from" instance is related to one "to" instance attr_reader :from_role, :to_role # For objectified facts, one role will be nil (a phantom) attr_reader :fact_type + attr_accessor :fk_jump # True if this reference links a table to another in an FK (between absorbed references) # A Reference is created from a object_type in regard to a role it plays def initialize(from, role) + @fk_jump = false @from = from return unless role # All done if it's a self-value reference for a ValueType @fact_type = role.fact_type if @fact_type.all_role.size == 1 # @from_role is nil for a unary @@ -71,11 +73,10 @@ end # Is this Reference covered by a mandatory constraint (implicitly or explicitly) def is_mandatory !@from_role || # All phantom roles of fact types are mandatory - is_unary || # Unary fact types become booleans, which must be true or false @from_role.is_mandatory end # Is this Reference from a unary Role? def is_unary @@ -109,14 +110,14 @@ # or is fully absorbed into another table but not via this reference. @to && (@to.is_table or @to.absorbed_via && !is_absorbing) end # Return the array of names for the (perhaps implicit) *to_role* of this Reference - def to_names + def to_names(is_prefix = true) case when is_unary - if @to && @to.fact_type + if @to && @to.fact_type && is_prefix @to.name.camelwords else @to_role.fact_type.preferred_reading.text.gsub(/\{[0-9]\}/,'').strip.camelwords end when @to && !@to_role # @to is an objectified fact type so @to_role is a phantom @@ -132,44 +133,56 @@ end # Return the array of names for the (perhaps implicit) *from_role* of this Reference def from_names case + when @from && !@from_role # @from is an objectified fact type so @from_role is a phantom + @from.name.camelwords when is_unary if @from && @from.fact_type @from.name.camelwords else @from_role.fact_type.preferred_reading.text.gsub(/\{[0-9]\}/,'').strip.camelwords end - when @from && !@from_role # @from is an objectified fact type so @from_role is a phantom - @from.name.camelwords when !@from_role # Self-value role of an independent ValueType @from.name.camelwords + ["Value"] when @from_role.role_name # Named role @from_role.role_name.camelwords else # Use the name from the preferred reading role_ref = @from_role.preferred_reference [role_ref.leading_adjective, @from_role.object_type.name, role_ref.trailing_adjective].compact.map{|w| w.camelwords}.flatten.reject{|s| s == ''} end end + def is_one_to_one + [:one_one, :subtype, :supertype].include?(role_type) + end + # For a one-to-one (or a subtyping fact type), reverse the direction. def flip #:nodoc: - raise "Illegal flip of #{self}" unless @to and [:one_one, :subtype, :supertype].include?(role_type) + raise "Illegal flip of #{self}" unless @to and is_one_to_one detabulate + mirror + tabulate + end + # Create a (non-tabulated) flipped version of this Reference. Careful not to tabulate it! + def mirror if @to.absorbed_via == self @to.absorbed_via = nil @from.absorbed_via = self end # Flip the reference @to, @from = @from, @to @to_role, @from_role = @from_role, @to_role + self + end - tabulate + def reversed + clone.mirror end def tabulate #:nodoc: # Add to @to and @from's reference lists @from.references_from << self @@ -186,11 +199,12 @@ debug :references, "Dropping #{to_s}" self end def to_s #:nodoc: - "reference from #{@from.name}#{@to ? " to #{@to.name}" : ""}" + (@fact_type ? " in '#{@fact_type.default_reading}'" : "") + ref_type = fk_jump ? "jumping to" : (is_absorbing ? "absorbing" : "to") + "reference from #{@from.name}#{@to ? " #{ref_type} #{@to.name}" : ""}" + (@fact_type ? " in '#{@fact_type.default_reading}'" : "") end # The reading for the fact type underlying this Reference def reading is_self_value ? "#{from.name} has value" : @fact_type.default_reading @@ -256,12 +270,12 @@ end def populate_references #:nodoc: all_role.each do |role| # It's possible that this role is in an implicit or derived fact type. Skip it if so. - next if role.fact_type.is_a?(ImplicitFactType) or - role.fact_type.preferred_reading.role_sequence.all_role_ref.to_a[0].join_role + next if role.fact_type.is_a?(LinkFactType) or + role.fact_type.preferred_reading.role_sequence.all_role_ref.to_a[0].play populate_reference role end end @@ -294,11 +308,10 @@ debug :references, "supertype #{name} absorbs subtype #{r.to.name}" r.tabulate end when :subtype # This object is a supertype, which can absorb the subtype unless that's independent - raise hell unless role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) if role.fact_type.assimilation ActiveFacts::Persistence::Reference.new(self, role).tabulate # If partitioned, the supertype is absorbed into *each* subtype; a reference to the supertype needs to know which else # debug :references, "subtype #{name} is absorbed into #{role.fact_type.supertype.name}" @@ -349,11 +362,11 @@ raise "Role #{role.object_type.name} in '#{role.fact_type.default_reading}' lacks a uniqueness constraint" end end end - class EntityType < ObjectType + class EntityType < DomainObjectType 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 @@ -365,25 +378,26 @@ class Vocabulary def populate_all_references #:nodoc: debug :references, "Populating all object_type references" do all_object_type.each do |object_type| - object_type.clear_references - object_type.is_table = nil # Undecided; force an attempt to decide - object_type.tentative = true # Uncertain - end - all_object_type.each do |object_type| debug :references, "Populating references for #{object_type.name}" do object_type.populate_references end end end - debug :references, "Finished object_type references" do - all_object_type.each do |object_type| - next unless object_type.references_from.size > 0 - debug :references, "#{object_type.name}:" do - object_type.references_from.each do |ref| - debug :references, "#{ref}" + show_all_references + end + + def show_all_references + if debug :references + debug :references, "Finished object_type references" do + all_object_type.each do |object_type| + next unless object_type.references_from.size > 0 + debug :references, "#{object_type.name}:" do + object_type.references_from.each do |ref| + debug :references, "#{ref}" + end end end end end end