Beispiel #1
0
    def commit(self):
        """ Commit side effects. """
        for orig_role in self.corr:
            ref_roles = orig_role.player.ref_roles
            new_role = self.corr[orig_role]

            if orig_role in ref_roles and new_role not in ref_roles:
                ref_roles.append(new_role)

        FactType.commit(self)
Beispiel #2
0
 def test_rename(self):
     """ Confirm items with same name added to set get renamed. """
     _set = ModelElementSet()
     _set.add(ObjectType(name="Item"))
     _set.add(FactType(name="Item"))
     _set.add(FactType(name="Item"))
     self.assertEqual(_set.count(), 3)
     self.assertIsInstance(_set.get("Item"), ObjectType)
     self.assertIsInstance(_set.get("Item2"), FactType)
     self.assertIsInstance(_set.get("Item3"), FactType)
Beispiel #3
0
    def test_display_nonempty(self):
        """ Test Display of non-empty model. """
        model = Model()
        model.object_types.add(ObjectType(name="O1"))
        model.fact_types.add(FactType(name="F1"))
        model.fact_types.add(FactType(name="F2"))
        model.constraints.add(Constraint(name="C1"))
        model.display()

        output = sys.stdout.getvalue().strip()
        self.assertEqual(output, "Object Types:\n    O1\nFact Types:\n    F1\n    F2\nConstraints:\n    C1")
Beispiel #4
0
    def test_add_remove_fact_type(self):
        """ Test adding and removing a fact type from the model. """
        model = Model()
        fact = FactType(name="F1")
        fact.add_role(player=ObjectType(name="O1"))
        model.add(fact)

        self.assertEquals(model.fact_types.count(), 1)
        self.assertEquals(model.fact_types.get("F1"), fact)

        with self.assertRaises(NotImplementedError):
            model.remove(fact)

        # I decided for now to just raise a NotImplementedError for rollback,
        # since I'm not sure what the right behavior should be.
        """
Beispiel #5
0
    def __init__(self, root_player=None, *args, **kwargs):
        super(AbsorptionFactType, self).__init__(*args, **kwargs)

        #: Role played by the identified object type
        self.root_role = FactType.add_role(self, root_player)

        #: Original fact type name for each role
        self.fact_type_names = {}
Beispiel #6
0
    def _materialize_join(self, suffix, role_seq):
        """ Materialize a join path.  Returns a triple consisting of the 
            join fact type (which is *not* added to the model), a list of 
            roles on the join fact type corresponding to *role_seq*, and 
            a corresponding LogiQL rule. 
        """
        JoinFact = FactType(name="JoinFact_" + suffix)
        name = {
        }  # Mapping of roles from *role_seq* to their name in *JoinFact*
        projected = [
        ]  # List of roles in *JoinFact* corresponding to *role_seq*

        # Create dictionary FROM covered roles TO name and add roles to JoinFact
        #
        # IMPORTANT: We add covered roles to the join fact type before
        # adding any other roles from the join path to ensure that the covered
        # roles appear in the same order as in the constraint's "covered" list.
        for role in role_seq:
            name[role] = "{0}_{1}".format(role.fact_type.name, role.name)
            new_role = JoinFact.add_role(role.player, name[role])
            projected.append(new_role)

        # Add remaining roles in join path to join fact type
        for fact_type in role_seq.join_path.fact_types:
            for role in fact_type.roles:
                if role not in name:
                    name[role] = "{0}_{1}".format(fact_type.name, role.name)
                    JoinFact.add_role(role.player, name[role])

        # Generate role equality constraint for each join
        joins = [
            "{0} = {1}".format(name[role1], name[role2])
            for role1, role2 in role_seq.join_path.joins
        ]

        # Create IDB rule for join fact type
        # See https://developer.logicblox.com/content/docs4/core-reference/webhelp/rules.html
        head = pred_with_args(JoinFact, default="{0}", local=True)
        tail = []
        for fact_type in role_seq.join_path.fact_types:
            args = ', '.join([name[role] for role in fact_type.roles])
            tail.append("{0}({1})".format(pred_name(fact_type), args))
        rule = "{0} <- {1}.\n\n".format(head, ', '.join(tail + joins))

        return JoinFact, projected, rule
Beispiel #7
0
    def test_commit_and_rollback(self):
        """ Test committing and rolling back constraints on a model. """
        model = Model()

        obj1 = ObjectType(name="O1")
        obj2 = ObjectType(name="O2")

        fact = FactType(name="F1")
        role1 = fact.add_role(player=obj1, name="R1")
        role2 = fact.add_role(player=obj2, name="R2")

        cons1 = Constraint.MandatoryConstraint(name="M1", covers=[role1])
        cons2 = Constraint.UniquenessConstraint(name="U1",
                                                covers=[role1, role2])
        cons3 = Constraint.ValueConstraint(name="V1", covers=[obj1])

        for element in [obj1, obj2, fact, cons1, cons2, cons3]:
            model.add(element)

        self.assertEquals(model.constraints.get("M1").covers, [role1])
        self.assertEquals(model.constraints.get("U1").covers, [role1, role2])
        self.assertEquals(model.constraints.get("V1").covers, [obj1])

        self.assertEquals(role1.covered_by, [cons1, cons2])
        self.assertEquals(role2.covered_by, [cons2])
        self.assertEquals(obj1.covered_by, [cons3])

        model.remove(cons2)
        model.remove(cons3)

        self.assertEquals(model.constraints.get("M1"), cons1)
        self.assertEquals(model.constraints.get("U1"), None)
        self.assertEquals(model.constraints.get("V1"), None)

        self.assertEquals(role1.covered_by, [cons1])
        self.assertEquals(role2.covered_by, [])
        self.assertEquals(obj1.covered_by, [])

        # Test that additional rollback has no effect
        model.remove(cons3)
        self.assertEquals(model.constraints.get("M1"), cons1)
        self.assertEquals(model.constraints.get("V1"), None)
        self.assertEquals(obj1.covered_by, [])
Beispiel #8
0
    def test_commit_rollback_iuc(self):
        """ Test commit and rollback of internal uniqueness constraints."""
        obj1 = EntityType(name="O1")
        obj2 = EntityType(name="V1")

        fact1 = FactType(name="F1")
        role1 = fact1.add_role(player=obj1)
        role2 = fact1.add_role(player=obj2)
        fact1.commit()

        fact2 = FactType(name="F2")
        role3 = fact2.add_role(player=obj1)
        fact2.commit()

        cons1 = Constraint.UniquenessConstraint(covers=[role1],
                                                identifier_for=None)
        cons2 = Constraint.UniquenessConstraint(covers=[role2],
                                                identifier_for=obj1)

        self.assertEquals(role1.covered_by, [])
        self.assertEquals(role2.covered_by, [])

        self.assertEquals(obj1.identifying_constraint, None)
        self.assertEquals(obj1.ref_roles, [])
        self.assertItemsEqual(obj1.roles, [role1, role3])

        cons1.commit()
        cons2.commit()

        self.assertEquals(role1.covered_by, [cons1])
        self.assertEquals(role2.covered_by, [cons2])
        self.assertEquals(obj1.identifying_constraint, cons2)
        self.assertEquals(obj1.ref_roles, [role1])

        cons1.rollback()
        cons2.rollback()

        self.assertEquals(role1.covered_by, [])
        self.assertEquals(role2.covered_by, [])
        self.assertEquals(obj1.identifying_constraint, None)
        self.assertEquals(obj1.ref_roles, [])
Beispiel #9
0
    def test_duplicate_role_name(self):
        """ Test that a new name is generated for a role if the role name is
            already present on the fact type. """
        fact_type = FactType(name="Test")
        fact_type.add_role(ObjectType(name="Person"), name="R1")
        fact_type.add_role(ObjectType(name="Dog"), name="R1")

        names = [role.name for role in fact_type.roles]

        self.assertEquals(names, ["R1", "Dog"])
Beispiel #10
0
    def test_get_elements(self):
        """ Test get() method. """
        model = Model()
        obj = ObjectType(name="O1")
        cons = Constraint(name="O1")
        fact = FactType(name="F1")
    
        model.add(obj)
        model.add(cons)
        model.add(fact)

        self.assertEquals(model.get("ObjectTypes.O1"), obj)
        self.assertEquals(model.get("Constraints.O1"), cons)
        self.assertEquals(model.get("FactTypes.F1"), fact)
        self.assertEquals(model.get("ObjectTypes."), None)
        self.assertEquals(model.get("F1"), None)       
Beispiel #11
0
    def test_compatible_roles_via_subtype(self):
        """ Test case where join is OK because one role player is a subtype of
            the other role player. """
        obj1 = ObjectType(name="A")
        obj2 = ObjectType(name="B")
        obj3 = ObjectType(name="C")

        fact1 = FactType("AIsB")
        fact1.add_role(obj1)
        fact1.add_role(obj2)

        fact2 = FactType("BIsC")
        fact2.add_role(obj2)
        fact2.add_role(obj3)

        join1 = (fact1.roles[0], fact2.roles[0])
        join2 = (fact2.roles[0], fact1.roles[0])

        join_path = JoinPath()

        # At this point there is no subtype relation from obj1 to obj2, so the
        # join fails
        with self.assertRaises(JoinPathException) as ex:
            join_path.add_join(*join1)

        msg = "join roles must be played by compatible object types"
        self.assertEquals(ex.exception.message, msg)

        with self.assertRaises(JoinPathException) as ex:
            join_path.add_join(*join2)

        msg = "join roles must be played by compatible object types"
        self.assertEquals(ex.exception.message, msg)

        # Create a subtype relation so the join succeeds.
        cons = SubtypeConstraint(obj1, obj2)
        cons.commit()

        join_path.add_join(*join1)
        self.assertEquals(join_path.joins, [join1])

        # Reset the join path and try the join in the opposite direction
        join_path = JoinPath()
        join_path.add_join(*join2)
        self.assertEquals(join_path.joins, [join2])
Beispiel #12
0
    def setUp(self):
        self.obj1 = ObjectType(name="A")
        self.obj2 = ObjectType(name="B")
        self.obj3 = ObjectType(name="C")

        self.fact1 = FactType(name="AHasB")
        self.fact1.add_role(self.obj1)
        self.fact1.add_role(self.obj2)

        self.fact2 = FactType(name="BHasC")
        self.fact2.add_role(self.obj2)
        self.fact2.add_role(self.obj3)

        self.fact3 = FactType(name="ALikesA")
        self.fact3.add_role(self.obj1)
        self.fact3.add_role(self.obj1)

        self.fact4 = FactType(name="ALikesB")
        self.fact4.add_role(self.obj1)
        self.fact4.add_role(self.obj2)
Beispiel #13
0
    def test_add_role(self):
        """ Confirm we can add a role to the fact type. """
        obj1 = ObjectType(name="Person")
        obj2 = ObjectType(name="School")

        fact_type = FactType(name="PersonAttendsSchoolWithPersonAndPerson")

        role1 = fact_type.add_role(obj1)
        role2 = fact_type.add_role(obj2)
        role3 = fact_type.add_role(obj1)
        role4 = fact_type.add_role(obj1)

        self.assertEquals(fact_type.arity(), 4)

        self.assertIs(role1.fact_type, fact_type)
        self.assertIs(role1.player, obj1)
        self.assertEquals(role1.name, "Person")

        self.assertIs(role2.fact_type, fact_type)
        self.assertIs(role2.player, obj2)
        self.assertEquals(role2.name, "School")

        self.assertIs(role3.fact_type, fact_type)
        self.assertIs(role3.player, obj1)
        self.assertEquals(role3.name, "Person2")

        self.assertIs(role4.fact_type, fact_type)
        self.assertIs(role4.player, obj1)
        self.assertEquals(role4.name, "Person3")

        self.assertItemsEqual(obj1.roles, [])
        self.assertItemsEqual(obj2.roles, [])

        fact_type.commit()

        self.assertItemsEqual(obj1.roles, [role1, role3, role4])
        self.assertItemsEqual(obj2.roles, [role2])
Beispiel #14
0
    def test_commit_and_rollback_affect_on_role_unique(self):
        """ Test affect of commit and rollback on role.unique """
        fact = FactType("AHasB")
        fact.add_role(ObjectType("A"))
        fact.add_role(ObjectType("B"))
        fact.commit()

        role = fact.roles[0]
        self.assertFalse(role.unique)

        # Unique after covered by a simple IUC
        uniq1 = Constraint.UniquenessConstraint(covers=[role])
        uniq1.commit()
        self.assertTrue(role.unique)

        # No longer unique after rollback
        uniq1.rollback()
        self.assertFalse(role.unique)

        # Not unique after covered by spanning IUC
        uniq2 = Constraint.UniquenessConstraint(covers=[role, fact.roles[1]])
        uniq2.commit()
        self.assertFalse(role.unique)

        # Unique again, covered by simple IUC
        uniq1.commit()
        self.assertTrue(role.unique)

        # Cover by a second simple IUC
        uniq3 = Constraint.UniquenessConstraint(covers=[role])
        uniq3.commit()

        # Still unique after rollback, because it's still covered by a simple IUC
        uniq1.rollback()
        self.assertTrue(role.unique)

        # No longer unique: not covered by any simple IUCs.
        uniq3.rollback()
        self.assertFalse(role.unique)
Beispiel #15
0
 def setUp(self):
     self.object_type1 = ObjectType(name="Object Type 1")
     self.fact_type1 = FactType(name="Fact Type 1")
     self.constraint1 = Constraint(name="Constraint 1")
Beispiel #16
0
    def test_commit_rollback_euc(self):
        """ Test commit and rollback of external uniqueness constraint."""
        obj1 = EntityType(name="O1")
        obj2 = EntityType(name="V1")
        obj3 = EntityType(name="V2")

        fact1 = FactType(name="F1")
        role11 = fact1.add_role(player=obj1)
        role12 = fact1.add_role(player=obj2)
        fact1.commit()

        fact2 = FactType(name="F2")
        role21 = fact2.add_role(player=obj1)
        role23 = fact2.add_role(player=obj3)
        fact2.commit()

        fact3 = FactType(name="F3")
        role31 = fact3.add_role(player=obj1)
        fact3.commit()

        cons = Constraint.UniquenessConstraint(covers=[role12, role23],
                                               identifier_for=obj1)

        self.assertEquals(obj1.identifying_constraint, None)
        self.assertEquals(obj1.ref_roles, [])
        self.assertItemsEqual(obj1.roles, [role11, role21, role31])

        cons.commit()

        self.assertEquals(obj1.identifying_constraint, cons)
        self.assertItemsEqual(obj1.ref_roles, [role11, role21])

        cons.rollback()

        self.assertEquals(obj1.identifying_constraint, None)
        self.assertEquals(obj1.ref_roles, [])
Beispiel #17
0
class TestJoinPath(TestCase):
    """ Unit tests for the JoinPath class. """
    def setUp(self):
        self.obj1 = ObjectType(name="A")
        self.obj2 = ObjectType(name="B")
        self.obj3 = ObjectType(name="C")

        self.fact1 = FactType(name="AHasB")
        self.fact1.add_role(self.obj1)
        self.fact1.add_role(self.obj2)

        self.fact2 = FactType(name="BHasC")
        self.fact2.add_role(self.obj2)
        self.fact2.add_role(self.obj3)

        self.fact3 = FactType(name="ALikesA")
        self.fact3.add_role(self.obj1)
        self.fact3.add_role(self.obj1)

        self.fact4 = FactType(name="ALikesB")
        self.fact4.add_role(self.obj1)
        self.fact4.add_role(self.obj2)

    def test_incompatible_roles(self):
        """ Test an attempt to join fact types on incompatible roles."""
        join_path = JoinPath()

        with self.assertRaises(JoinPathException) as ex:
            join_path.add_join(self.fact1.roles[0], self.fact2.roles[0])

        msg = "join roles must be played by compatible object types"
        self.assertEquals(ex.exception.message, msg)

    def test_compatible_roles_via_subtype(self):
        """ Test case where join is OK because one role player is a subtype of
            the other role player. """
        obj1 = ObjectType(name="A")
        obj2 = ObjectType(name="B")
        obj3 = ObjectType(name="C")

        fact1 = FactType("AIsB")
        fact1.add_role(obj1)
        fact1.add_role(obj2)

        fact2 = FactType("BIsC")
        fact2.add_role(obj2)
        fact2.add_role(obj3)

        join1 = (fact1.roles[0], fact2.roles[0])
        join2 = (fact2.roles[0], fact1.roles[0])

        join_path = JoinPath()

        # At this point there is no subtype relation from obj1 to obj2, so the
        # join fails
        with self.assertRaises(JoinPathException) as ex:
            join_path.add_join(*join1)

        msg = "join roles must be played by compatible object types"
        self.assertEquals(ex.exception.message, msg)

        with self.assertRaises(JoinPathException) as ex:
            join_path.add_join(*join2)

        msg = "join roles must be played by compatible object types"
        self.assertEquals(ex.exception.message, msg)

        # Create a subtype relation so the join succeeds.
        cons = SubtypeConstraint(obj1, obj2)
        cons.commit()

        join_path.add_join(*join1)
        self.assertEquals(join_path.joins, [join1])

        # Reset the join path and try the join in the opposite direction
        join_path = JoinPath()
        join_path.add_join(*join2)
        self.assertEquals(join_path.joins, [join2])

    def test_disconnected(self):
        """ Test that the first join role must be on a fact type already on
            the path. """
        join_path = JoinPath()
        join_path.add_join(self.fact1.roles[1], self.fact2.roles[0])

        with self.assertRaises(JoinPathException) as ex:
            join_path.add_join(self.fact3.roles[1], self.fact4.roles[0])

        msg = "first join role must already be on the join path"
        self.assertEquals(ex.exception.message, msg)

    def test_cycle_1(self):
        """ Test that a self-join is rejected. """
        join_path = JoinPath()

        with self.assertRaises(JoinPathException) as ex:
            join_path.add_join(self.fact3.roles[0], self.fact3.roles[1])

        msg = "join would create a cycle in the join path"
        self.assertEquals(ex.exception.message, msg)

    def test_cycle_2(self):
        """ Test that a join to a fact type already in the path is rejected. """
        join_path = JoinPath()

        join_path.add_join(self.fact1.roles[1], self.fact2.roles[0])

        with self.assertRaises(JoinPathException) as ex:
            join_path.add_join(self.fact2.roles[0], self.fact1.roles[1])

        msg = "join would create a cycle in the join path"
        self.assertEquals(ex.exception.message, msg)

    def test_valid_join(self):
        """ Test that a valid join path is stored as expected. """
        join_path = JoinPath()

        join_path.add_join(self.fact1.roles[1], self.fact2.roles[0])
        join_path.add_join(self.fact1.roles[0], self.fact4.roles[0])
        join_path.add_join(self.fact4.roles[0], self.fact3.roles[1])

        self.assertEquals(join_path.fact_types,
                          [self.fact1, self.fact2, self.fact4, self.fact3])
        self.assertEquals(join_path.joins,
                          [(self.fact1.roles[1], self.fact2.roles[0]),
                           (self.fact1.roles[0], self.fact4.roles[0]),
                           (self.fact4.roles[0], self.fact3.roles[1])])