[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.
--- 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')