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)
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)
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")
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. """
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 = {}
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
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, [])
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, [])
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"])
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)
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 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_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])
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)
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")
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, [])
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])])