[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.
--- 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: