add descendant_of relation: work in progress
authorKatia Saurfelt <katia.saurfelt@logilab.fr>
Mon, 19 Oct 2009 10:48:23 +0200
changeset 70 2cdf0d3d3977
parent 67 52d02ce68893
child 71 178f11d7f7d7
add descendant_of relation: work in progress
hooks.py
schema.py
test/unittest_classification.py
--- a/hooks.py	Thu Sep 24 12:37:40 2009 +0200
+++ b/hooks.py	Mon Oct 19 10:48:23 2009 +0200
@@ -11,7 +11,7 @@
 from cubicweb.server.hooksmanager import Hook
 from cubicweb.server.pool import PreCommitOperation
 from cubicweb.sobjects.notification import NotificationView
-
+from itertools import chain
 
 class SetIncludedInRelationOp(PreCommitOperation):
     """delay this operation to commit to avoid conflict with a late rql query
@@ -43,6 +43,30 @@
                 raise ValidationError(self.fromeid, {'subkeyword_of': msg})
             parents.add(parent.eid)
 
+class SetDescendantOfKeywordOp(PreCommitOperation):
+    def precommit_event(self):
+        parent = self.parent
+        entity = self.entity
+        for parent in chain([parent], parent.iterparents()):
+            self.session.execute('SET K descendant_of P WHERE K eid %(k)s, '
+                            'P eid %(p)s', {'p':parent.eid, 'k': entity.eid})
+class AfterAddKeyword(Hook):
+    events = ('after_add_entity',)
+    accepts = ('Keyword',)
+
+    def call(self, session, entity):
+        session.execute('SET K descendant_of P WHERE K eid %(k)s, '
+                        'P eid %(p)s', {'p':entity.eid, 'k': entity.eid})
+class AfterModificationKeyword(Hook):
+    """  sets descendant_of relation
+    """
+    events = ('after_add_relation', )
+    accepts = ('subkeyword_of', )
+
+    def call(self, session, fromeid, rtype, toeid):
+        parent = session.entity_from_eid(toeid)
+        entity = session.entity_from_eid(fromeid)
+        SetDescendantOfKeywordOp(session, parent=parent, entity=entity)
 
 class SetIncludedInRelationHook(Hook):
     """sets the included_in relation on a subkeyword if not already set
@@ -58,6 +82,18 @@
         SetIncludedInRelationOp(session, vreg=self.vreg,
                                 fromeid=fromeid, toeid=toeid)
 
+class RemoveDescendantOfRelationHook(Hook):
+    """
+       removes descendant_of relation
+    """
+    events = ('after_delete_relation',)
+    accepts = ('subkeyword_of',)
+
+    def call(self, session, fromeid, rtype, toeid):
+        parent = session.entity_from_eid(toeid)
+        for parent in chain([parent], parent.iterparents()):
+            session.execute('DELETE K descendant_of P WHERE K eid %(k)s, '
+                            'P eid %(p)s', {'p':parent.eid, 'k': fromeid})
 
 class KeywordNotificationView(NotificationView):
     __select__ = implements('Keyword')
--- a/schema.py	Thu Sep 24 12:37:40 2009 +0200
+++ b/schema.py	Mon Oct 19 10:48:23 2009 +0200
@@ -5,7 +5,7 @@
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 from yams.buildobjs import (EntityType, RelationType,
-                            SubjectRelation, String)
+                            SubjectRelation, ObjectRelation, String)
 
 from cubicweb.schema import RQLConstraint, ERQLExpression
 
@@ -24,6 +24,7 @@
     classifies = SubjectRelation('CWEType',
                                  # see relation type docstring
                                  constraints = [RQLConstraint('RDEF to_entity O, RDEF relation_type R, R name "applied_to"')])
+    descendant_of = ObjectRelation('Keyword')
 
 
 class classifies(RelationType):
@@ -48,6 +49,7 @@
                                     description=_('which keyword (if any) this keyword specializes'),
                                     # if no included_in set, it'll be automatically added by a hook
                                     constraints=[RQLConstraint('NOT S included_in CS1 OR EXISTS(S included_in CS2, O included_in CS2)')])
+    descendant_of = SubjectRelation('Keyword')
     included_in = SubjectRelation('Classification', cardinality='1*')
 
 
@@ -57,7 +59,6 @@
     __specializes_schema__ = True
     code = String(required=True, fulltextindexed=True, indexed=True, maxsize=128)
 
-
 class subkeyword_of(RelationType):
     """a keyword can specialize another keyword"""
 
@@ -74,4 +75,3 @@
     """tagged objects"""
     fulltext_container = 'object'
     constraints = [RQLConstraint('S included_in CS, O is ET, CS classifies ET')]
-
--- a/test/unittest_classification.py	Thu Sep 24 12:37:40 2009 +0200
+++ b/test/unittest_classification.py	Mon Oct 19 10:48:23 2009 +0200
@@ -12,12 +12,12 @@
         self.kw2 = self.execute('INSERT Keyword K: K name "kwuser", K included_in C WHERE C name "classif2"')[0][0]
         #self.zone = self.add_entity('Zone', name=u"Paris")
 
-    def test_application_of_bad_keyword_fails(self):
+    def aest_application_of_bad_keyword_fails(self):
         self.assertRaises(ValidationError, self.execute,
                           'SET K applied_to G WHERE G is CWGroup, K name "kwuser"')
 
 
-    def test_creating_a_new_subkeyword_sets_included_in(self):
+    def aest_creating_a_new_subkeyword_sets_included_in(self):
         self.execute('INSERT Keyword SK: SK name "kwgroup2", SK subkeyword_of K '
                      'WHERE K name "kwgroup"')
         self.commit()
@@ -26,12 +26,12 @@
         self.assertEqual(rset[0][0], 'classif1')
 
 
-    def test_cannot_create_subkeyword_from_other_classification(self):
+    def aest_cannot_create_subkeyword_from_other_classification(self):
         self.execute('SET X subkeyword_of Y WHERE X eid %s, Y eid %s' % (self.kw1, self.kw2))
         self.assertRaises(ValidationError, self.commit)
 
 
-    def test_cannot_create_cycles(self):
+    def aest_cannot_create_cycles(self):
         # direct obvious cycle
         self.assertRaises(ValidationError, self.execute,
                           'SET X subkeyword_of Y WHERE X eid %s, Y eid %s' % (self.kw1, self.kw1))
@@ -41,6 +41,21 @@
         self.execute('SET X subkeyword_of Y WHERE X eid %s, Y eid %s' % (self.kw1, kw3))
         self.assertRaises(ValidationError, self.commit)
 
+    def test_descendant_of(self):
+        cl = self.add_entity('Classification', name=u'cl')
+        kw1 = self.add_entity('Keyword', name=u'kw1')
+        kw2 = self.add_entity('Keyword', name=u'kw2')
+        kw3 = self.add_entity('Keyword', name=u'kw3')
+        self.execute('SET X included_in C WHERE X eid %(x)s, C eid %(c)s',
+                         {'c':cl.eid, 'x':kw1.eid } )
+        for pkw, kw in ((kw1, kw2), (kw2, kw3)):
+            self.execute('SET K subkeyword_of P WHERE P eid %(p)s, K eid %(k)s',
+                     {'p': pkw.eid, 'k': kw.eid})
+        self.commit()
+        descendants = kw1.descendant_of
+        print [e for e in self.execute('Any K WHERE K descendant_of P, P eid %(x)s ', {'x':kw1.eid}).entities()]
+        print descendants
+        self.assertEquals(set(descendants), set((kw2,kw3)))
 
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main