class ActiveFacts::RMap::Reference
This class contains the core data structure used in composing a relational schema.
A Reference
is from one ObjectType to another ObjectType, and relates to the from_role and the to_role. When either ObjectType is an objectified fact type, the corresponding role is nil. When the Reference
from_role
is of a unary fact type, there’s no to_role
or to ObjectType. The final kind of Reference
is a self-reference which is added to a ValueType that becomes a table.
When the underlying fact type is a one-to-one (including an inheritance fact type), the Reference
may be flipped.
Each Reference
has a name; an array of names in fact, in case of adjectives, etc. Each Refererence can produce the reading of the underlying fact type.
A Reference
is indexed in the player’s references_from and references_to, and flipping updates those. Finally, a Reference
may be marked as absorbing the whole referenced object, and that can flip too.
Attributes
Public Class Methods
A Reference
is created from a object_type in regard to a role it plays
# File lib/activefacts/rmap/reference.rb, line 45 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 @to_role = role @to = role.fact_type.entity_type # nil unless the unary is objectified elsif (role.fact_type.entity_type == @from) # role is in "from", an objectified fact type @from_role = nil # Phantom role @to_role = role @to = @to_role.object_type else @from_role = role @to = role.fact_type.entity_type # If set, to_role is a phantom unless @to raise "Illegal reference through >binary fact type" if @fact_type.all_role.size >2 @to_role = (role.fact_type.all_role-[role])[0] @to = @to_role.object_type end end end
Public Instance Methods
Return the array of names for the (perhaps implicit) from_role of this Reference
# File lib/activefacts/rmap/reference.rb, line 137 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_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
Is the to object_type fully absorbed through this reference?
# File lib/activefacts/rmap/reference.rb, line 104 def is_absorbing @to && @to.absorbed_via == self end
If this Reference
is from an objectified FactType, there is no from_role
# File lib/activefacts/rmap/reference.rb, line 94 def is_from_objectified_fact @to && !@from_role && @to_role end
Is this Reference
covered by a mandatory constraint (implicitly or explicitly)
# File lib/activefacts/rmap/reference.rb, line 76 def is_mandatory !is_unary && (!@from_role || # All phantom roles of fact types are mandatory @from_role.is_mandatory) end
# File lib/activefacts/rmap/reference.rb, line 157 def is_one_to_one [:one_one, :subtype, :supertype].include?(role_type) end
Is this reference an injected role as a result a ValueType being a table?
# File lib/activefacts/rmap/reference.rb, line 99 def is_self_value !@to && !@to_role end
Is this a simple reference?
# File lib/activefacts/rmap/reference.rb, line 109 def is_simple_reference # It's a simple reference to a thing if that thing is a table, # or is fully absorbed into another table but not via this reference. @to && (@to.is_table or @to.absorbed_via && !is_absorbing) end
If this Reference
is to an objectified FactType, there is no to_role
# File lib/activefacts/rmap/reference.rb, line 88 def is_to_objectified_fact # This case is the only one that cannot be used in the preferred identifier of @from @to && !@to_role && @from_role end
Is this Reference
from a unary Role?
# File lib/activefacts/rmap/reference.rb, line 83 def is_unary @to_role && @to_role.fact_type.all_role.size == 1 end
Create a (non-tabulated) flipped version of this Reference
. Careful not to tabulate it!
# File lib/activefacts/rmap/reference.rb, line 171 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 trace :references, "Mirror #{self.inspect} absorbs #{@to.name}" if @to.absorbed_via == self self end
The reading for the fact type underlying this Reference
# File lib/activefacts/rmap/reference.rb, line 211 def reading is_self_value ? "#{from.name} has value" : @fact_type.reading_preferably_starting_with_role(@from_role).expand end
# File lib/activefacts/rmap/reference.rb, line 184 def reversed clone.mirror end
What type of Role did this Reference
arise from?
# File lib/activefacts/rmap/reference.rb, line 70 def role_type role = @from_role||@to_role role && role.role_type end
Return the array of names for the (perhaps implicit) to_role of this Reference
# File lib/activefacts/rmap/reference.rb, line 116 def to_names(is_prefix = true) case when is_unary 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 @to.name.camelwords when !@to_role # Self-value role of an independent ValueType @from.name.camelwords + ["Value"] when @to_role.role_name # Named role @to_role.role_name.camelwords else # Use the name from the preferred reading role_ref = @to_role.preferred_reference [role_ref.leading_adjective, @to_role.object_type.name, role_ref.trailing_adjective].compact.map{|w| w.camelwords}.flatten.reject{|s| s == ''} end end
# File lib/activefacts/rmap/reference.rb, line 215 def verbalised_path reverse = false return "#{from.name} Value" if is_self_value objectified = fact_type.entity_type f = # Switch to the Link Fact Type if we're traversing an objectification (to_role && to_role.link_fact_type) || (from_role && from_role.link_fact_type) || fact_type start_role = if objectified target = reverse ? to : from [to_role, from_role, f.all_role_in_order[0]].compact.detect{|role| role.object_type == target} else reverse ? to_role : from_role end reading = f.reading_preferably_starting_with_role(start_role) (is_mandatory || is_unary ? '' : 'maybe ') + reading.expand end