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