[entity] add a new `cw_linkable_rql` method
authorKatia Saurfelt <katia.saurfelt@logilab.fr>
Mon, 28 Apr 2014 18:11:21 +0200
changeset 9712 6c6cd8c4b256
parent 9711 59616edc20d7
child 9713 1141927b8494
[entity] add a new `cw_linkable_rql` method * the new method returns the entities that are or may be related to the current one by the relation passed as an argument. Closes #3738011.
doc/3.19.rst
entity.py
test/unittest_entity.py
--- a/doc/3.19.rst	Mon Apr 07 12:03:31 2014 +0200
+++ b/doc/3.19.rst	Mon Apr 28 18:11:21 2014 +0200
@@ -159,6 +159,10 @@
   are encouraged to write an actual controller (e.g. using ``ajaxfunc``)
   instead of storing a closure in the session data.
 
+* A new ``entity.cw_linkable_rql`` method provides the rql to fetch all entities
+  that are already or may be related to the current entity using the given
+  relation.
+
 
 Deprecated Code Drops
 ----------------------
--- a/entity.py	Mon Apr 07 12:03:31 2014 +0200
+++ b/entity.py	Mon Apr 28 18:11:21 2014 +0200
@@ -1074,6 +1074,25 @@
 
     # generic vocabulary methods ##############################################
 
+    def cw_linkable_rql(self, rtype, targettype, role, ordermethod=None,
+                        vocabconstraints=True, lt_infos={}, limit=None):
+        """build a rql to fetch targettype entities either related or unrelated
+        to this entity using (rtype, role) relation.
+
+        Consider relation permissions so that returned entities may be actually
+        linked by `rtype`.
+
+        `lt_infos` are supplementary informations, usually coming from __linkto
+        parameter, that can help further restricting the results in case current
+        entity is not yet created. It is a dict describing entities the current
+        entity will be linked to, which keys are (rtype, role) tuples and values
+        are a list of eids.
+        """
+        return self._cw_compute_linkable_rql(rtype, targettype, role, ordermethod=None,
+                                             vocabconstraints=vocabconstraints,
+                                             lt_infos=lt_infos, limit=limit,
+                                             unrelated_only=False)
+
     def cw_unrelated_rql(self, rtype, targettype, role, ordermethod=None,
                          vocabconstraints=True, lt_infos={}, limit=None):
         """build a rql to fetch `targettype` entities unrelated to this entity
@@ -1088,6 +1107,21 @@
         entity will be linked to, which keys are (rtype, role) tuples and values
         are a list of eids.
         """
+        return self._cw_compute_linkable_rql(rtype, targettype, role, ordermethod=None,
+                                             vocabconstraints=vocabconstraints,
+                                             lt_infos=lt_infos, limit=limit,
+                                             unrelated_only=True)
+
+    def _cw_compute_linkable_rql(self, rtype, targettype, role, ordermethod=None,
+                                 vocabconstraints=True, lt_infos={}, limit=None,
+                                 unrelated_only=False):
+        """build a rql to fetch `targettype` entities that may be related to
+        this entity using the (rtype, role) relation.
+
+        By default (unrelated_only=False), this includes the already linked
+        entities as well as the unrelated ones. If `unrelated_only` is True, the
+        rql filters out the already related entities.
+        """
         ordermethod = ordermethod or 'fetch_unrelated_order'
         rschema = self._cw.vreg.schema.rschema(rtype)
         rdef = rschema.role_rdef(self.e_schema, targettype, role)
@@ -1116,7 +1150,7 @@
             else:
                 rel = make_relation(searchedvar, rtype, (variable,), VariableRef)
             select.add_restriction(Not(rel))
-        elif self.has_eid():
+        elif self.has_eid() and unrelated_only:
             # elif we have an eid, we don't want a target entity which is
             # already linked to ourself through this relation
             rel = make_relation(subjvar, rtype, (objvar,), VariableRef)
--- a/test/unittest_entity.py	Mon Apr 07 12:03:31 2014 +0200
+++ b/test/unittest_entity.py	Mon Apr 28 18:11:21 2014 +0200
@@ -371,6 +371,13 @@
             clear_cache(self.schema['EmailAddress'], 'get_rqlexprs')
             self.schema['EmailAddress'].permissions['read'] = rperms
 
+    def test_cw_linkable_rql(self):
+        with self.admin_access.web_request() as req:
+            email = req.execute('INSERT EmailAddress X: X address "hop"').get_entity(0, 0)
+            rql = email.cw_linkable_rql('use_email', 'CWUser', 'object')[0]
+            self.assertEqual(rql, 'Any S,AA,AB,AC,AD ORDERBY AA '
+                             'WHERE O eid %(x)s, S is_instance_of CWUser, '
+                             'S login AA, S firstname AB, S surname AC, S modification_date AD')
 
     def test_unrelated_rql_security_nonexistant(self):
         with self.new_access('anon').web_request() as req: