[entity] Entity.related(): add a targettypes argument (closes #2957313)
authorAurelien Campeas
Thu, 11 Jul 2013 13:32:27 +0200
changeset 9293 723e2c586ea3
parent 9292 4b3e657d17ab
child 9294 769b8867f8ce
[entity] Entity.related(): add a targettypes argument (closes #2957313) This allows to restrict the entity types returned by the method (passed to cw_related_rql). When such an argument is given, no caching happens.
entity.py
test/data/schema.py
test/unittest_entity.py
--- a/entity.py	Wed Aug 28 12:14:20 2013 +0200
+++ b/entity.py	Thu Jul 11 13:32:27 2013 +0200
@@ -969,7 +969,7 @@
             return value
 
     def related(self, rtype, role='subject', limit=None, entities=False, # XXX .cw_related
-                safe=False):
+                safe=False, targettypes=None):
         """returns a resultset of related entities
 
         :param rtype:
@@ -983,10 +983,13 @@
         :param safe:
           if True, an empty rset/list of entities will be returned in case of
           :exc:`Unauthorized`, else (the default), the exception is propagated
+        :param targettypes:
+          a tuple of target entity types to restrict the query
         """
         rtype = str(rtype)
-        if limit is None:
-            # we cannot do much wrt cache on limited queries
+        # Caching restricted/limited results is best avoided.
+        cacheable = limit is None and targettypes is None
+        if cacheable:
             cache_key = '%s_%s' % (rtype, role)
             if cache_key in self._cw_related_cache:
                 return self._cw_related_cache[cache_key][entities]
@@ -994,7 +997,7 @@
             if entities:
                 return []
             return self._cw.empty_rset()
-        rql = self.cw_related_rql(rtype, role, limit=limit)
+        rql = self.cw_related_rql(rtype, role, limit=limit, targettypes=targettypes)
         try:
             rset = self._cw.execute(rql, {'x': self.eid})
         except Unauthorized:
@@ -1002,9 +1005,9 @@
                 raise
             rset = self._cw.empty_rset()
         if entities:
-            if limit is None:
+            if cacheable:
                 self.cw_set_relation_cache(rtype, role, rset)
-                return self.related(rtype, role, limit, entities)
+                return self.related(rtype, role, entities=entities)
             return list(rset.entities())
         else:
             return rset
--- a/test/data/schema.py	Wed Aug 28 12:14:20 2013 +0200
+++ b/test/data/schema.py	Thu Jul 11 13:32:27 2013 +0200
@@ -41,7 +41,7 @@
                                   constraints=[RQLConstraint('NOT EXISTS(O contrat_exclusif S)')])
     dirige = SubjectRelation('Societe', cardinality='??',
                              constraints=[RQLConstraint('S actionnaire O')])
-    associe = SubjectRelation('Personne', cardinality='1*',
+    associe = SubjectRelation('Personne', cardinality='?*',
                               constraints=[RQLConstraint('S actionnaire SOC, O actionnaire SOC')])
 
 class Ami(EntityType):
--- a/test/unittest_entity.py	Wed Aug 28 12:14:20 2013 +0200
+++ b/test/unittest_entity.py	Thu Jul 11 13:32:27 2013 +0200
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -132,6 +132,12 @@
         self.assertEqual(sorted(user._cw_related_cache), ['in_group_subject', 'primary_email_subject'])
         for group in groups:
             self.assertFalse('in_group_subject' in group._cw_related_cache, list(group._cw_related_cache))
+        user.cw_clear_all_caches()
+        user.related('in_group', entities=True)
+        self.assertIn('in_group_subject', user._cw_related_cache)
+        user.cw_clear_all_caches()
+        user.related('in_group', targettypes=('CWGroup',), entities=True)
+        self.assertNotIn('in_group_subject', user._cw_related_cache)
 
     def test_related_limit(self):
         req = self.request()
@@ -145,6 +151,18 @@
         self.assertEqual(len(p.related('tags', 'object', entities=True, limit=2)), 2)
         self.assertEqual(len(p.related('tags', 'object', entities=True)), 4)
 
+    def test_related_targettypes(self):
+        req = self.request()
+        p = req.create_entity('Personne', nom=u'Loxodonta', prenom=u'Babar')
+        n = req.create_entity('Note', type=u'scratch', ecrit_par=p)
+        t = req.create_entity('Tag', name=u'a tag', tags=(p, n))
+        self.commit()
+        req = self.request()
+        t = req.entity_from_eid(t.eid)
+        self.assertEqual(2, t.related('tags').rowcount)
+        self.assertEqual(1, t.related('tags', targettypes=('Personne',)).rowcount)
+        self.assertEqual(1, t.related('tags', targettypes=('Note',)).rowcount)
+
     def test_cw_instantiate_relation(self):
         req = self.request()
         p1 = req.create_entity('Personne', nom=u'di')