Module: ActiveFacts::Metamodel

Defined in:
lib/activefacts/persistence/index.rb,
lib/activefacts/persistence/tables.rb,
lib/activefacts/persistence/columns.rb,
lib/activefacts/vocabulary/metamodel.rb,
lib/activefacts/persistence/reference.rb,
lib/activefacts/vocabulary/extensions.rb,
lib/activefacts/vocabulary/verbaliser.rb,
lib/activefacts/persistence/foreignkey.rb

Overview

:nodoc:

Defined Under Namespace

Classes: Adjective, Agent, AgentName, Agreement, AllowedRange, Assimilation, Bound, Coefficient, Concept, Constraint, ConstraintId, ConstraintShape, ContextAccordingTo, ContextAgreedBy, ContextNote, ContextNoteId, ContextNoteKind, Date, Denominator, Derivation, Diagram, Discussion, DisplayRoleNamesSetting, Enforcement, EnforcementCode, EntityType, EphemeraURL, Exponent, Fact, FactId, FactType, FactTypeId, FactTypeShape, Frequency, ImplicitBooleanValueType, ImplicitFactType, Instance, InstanceId, Join, JoinId, JoinNode, JoinRole, JoinStep, Length, Literal, ModelNoteShape, Name, Numerator, ObjectTypeShape, ObjectifiedFactTypeNameShape, Offset, Ordinal, ParamValue, Parameter, Population, Position, PresenceConstraint, Pronoun, Reading, ReadingShape, RingConstraint, RingConstraintShape, RingType, Role, RoleDisplay, RoleNameShape, RoleRef, RoleSequence, RoleSequenceId, RoleValue, RotationSetting, Scale, SetComparisonConstraint, SetComparisonRoles, SetConstraint, SetEqualityConstraint, SetExclusionConstraint, Shape, ShapeId, Subscript, SubsetConstraint, Text, TypeInheritance, Unit, UnitId, Value, ValueConstraint, ValueConstraintShape, ValueRange, ValueType, Verbaliser, Vocabulary, X, Y

Class Method Summary collapse

Class Method Details

.join_roles_over(roles, options = :both) ⇒ Object

Some joins must be over the proximate roles, some over the counterpart roles. Return the common superclass of the appropriate roles, and the actual roles



690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
# File 'lib/activefacts/vocabulary/extensions.rb', line 690

def self.join_roles_over roles, options = :both   # Or :proximate, :counterpart
  # If we can stay inside this objectified FT, there's no join:
  roles = Array(roles)  # To be safe, in case we get a role collection proxy
  return nil if roles.size == 1 or
    options != :counterpart && roles.map{|role| role.fact_type}.uniq.size == 1
  proximate_sups, counterpart_sups, obj_sups, counterpart_roles, objectification_roles =
    *roles.inject(nil) do |d_c_o, role|
      concept = role.concept
      fact_type = role.fact_type

      proximate_role_supertypes = concept.supertypes_transitive

      # A role in an objectified fact type may indicate either the objectification or the counterpart player.
      # This could be ambiguous. Figure out both and prefer the counterpart over the objectification.
      counterpart_role_supertypes =
        if fact_type.all_role.size > 2
          possible_roles = fact_type.all_role.select{|r| d_c_o && d_c_o[1].include?(r.concept) }
          if possible_roles.size == 1 # Only one candidate matches the types of the possible join nodes
            counterpart_role = possible_roles[0]
            d_c_o[1]  # No change
          else
            # puts "#{constraint_type} #{name}: Awkward, try counterpart-role join on a >2ary '#{fact_type.default_reading}'"
            # Try all roles; hopefully we don't have two roles with a matching candidate here:
            # Find which role is compatible with the existing supertypes, if any
            if d_c_o
              st = nil
              counterpart_role =
                fact_type.all_role.detect{|r| ((st = r.concept.supertypes_transitive) & d_c_o[1]).size > 0}
              st
            else
              counterpart_role = nil  # This can't work, we don't have any basis for a decision (must be objectification)
              []
            end
            #fact_type.all_role.map{|r| r.concept.supertypes_transitive}.flatten.uniq
          end
        else
          # Get the supertypes of the counterpart role (care with unaries):
          ftr = role.fact_type.all_role.to_a
          (counterpart_role = ftr[0] == role ? ftr[-1] : ftr[0]).concept.supertypes_transitive
        end

      if fact_type.entity_type
        objectification_role_supertypes =
          fact_type.entity_type.supertypes_transitive+concept.supertypes_transitive
        objectification_role = role.implicit_fact_type.all_role.single # Find the phantom role here
      else
        objectification_role_supertypes = counterpart_role_supertypes
        objectification_role = counterpart_role
      end

      if !d_c_o
        d_c_o = [proximate_role_supertypes, counterpart_role_supertypes, objectification_role_supertypes, [counterpart_role], [objectification_role]]
        #puts "role player supertypes starts #{d_c_o.map{|dco| dco.map(&:name).inspect}*' or '}"
      else
        #puts "continues #{[proximate_role_supertypes, counterpart_role_supertypes, objectification_role_supertypes]map{|dco| dco.map(&:name).inspect}*' or '}"
        d_c_o[0] &= proximate_role_supertypes
        d_c_o[1] &= counterpart_role_supertypes
        d_c_o[2] &= objectification_role_supertypes
        d_c_o[3] << (counterpart_role || objectification_role)
        d_c_o[4] << (objectification_role || counterpart_role)
      end
      d_c_o
    end # inject

  # Discount a subtype join over an object type that's not a player here,
  # if we can use an objectification join to an object type that is:
  if counterpart_sups.size > 0 && obj_sups.size > 0 && counterpart_sups[0] != obj_sups[0]
    debug :join, "ambiguous join, could be over #{counterpart_sups[0].name} or #{obj_sups[0].name}"
    if !roles.detect{|r| r.concept == counterpart_sups[0]} and roles.detect{|r| r.concept == obj_sups[0]}
      debug :join, "discounting #{counterpart_sups[0].name} in favour of direct objectification"
      counterpart_sups = []
    end
  end

  # Choose the first entry in the first non-empty supertypes list:
  if options != :counterpart && proximate_sups[0]
    [ proximate_sups[0], roles ]
  elsif !counterpart_sups.empty?
    [ counterpart_sups[0], counterpart_roles ]
  else
    [ obj_sups[0], objectification_roles ]
  end
end