# HG changeset patch # User Sylvain Thénault # Date 1492704306 -7200 # Node ID c0ceadfc8aee462eca56d70cfccb7e6925e526c9 # Parent 02b8325720d6ff3ff34100eba88a4c1a23c39bad [rqlrewrite] Enhance detection of need for Exists node We actually want one only if this is not a (`And` / `Or`) binary tree of `Not` or `Exists` nodes, so write a recursive function to tell so. Related to #17074119 diff -r 02b8325720d6 -r c0ceadfc8aee cubicweb/rqlrewrite.py --- a/cubicweb/rqlrewrite.py Fri Apr 21 09:57:04 2017 +0200 +++ b/cubicweb/rqlrewrite.py Thu Apr 20 18:05:06 2017 +0200 @@ -206,6 +206,19 @@ return stinfo['relations'] - stinfo['rhsrelations'] +def need_exists(node): + """Return true if the given node should be wrapped in an `Exists` node. + + This is true when node isn't already an `Exists` or `Not` node, nor a + `And`/`Or` of `Exists` or `Not` nodes. + """ + if isinstance(node, (n.Exists, n.Not)): + return False + if isinstance(node, (n.Or, n.And)): + return need_exists(node.children[0]) or need_exists(node.children[1]) + return True + + class Unsupported(Exception): """raised when an rql expression can't be inserted in some rql query because it create an unresolvable query (eg no solutions found) @@ -474,7 +487,7 @@ self.existingvars = existing def _inserted_root(self, new): - if not isinstance(new, (n.Exists, n.Not)): + if need_exists(new): new = n.Exists(new) return new diff -r 02b8325720d6 -r c0ceadfc8aee cubicweb/test/unittest_rqlrewrite.py --- a/cubicweb/test/unittest_rqlrewrite.py Fri Apr 21 09:57:04 2017 +0200 +++ b/cubicweb/test/unittest_rqlrewrite.py Thu Apr 20 18:05:06 2017 +0200 @@ -528,9 +528,9 @@ self.assertMultiLineEqual( rqlst.as_string(), u'Any P WHERE NOT P require_state S, ' - 'EXISTS(((NOT EXISTS(A require_permission P, A is IN(Card, Note)))' + '((NOT EXISTS(A require_permission P, A is IN(Card, Note)))' ' OR (EXISTS(B require_permission P, B is Card, S name "state1")))' - ' OR (EXISTS(C require_permission P, C is Note, S name "state2"))), ' + ' OR (EXISTS(C require_permission P, C is Note, S name "state2")), ' 'P is CWPermission, S is State') def test_ambiguous_using_is_in_function(self): @@ -543,8 +543,8 @@ self.assertMultiLineEqual( rqlst.as_string(), u'Any P WHERE NOT P require_state S, ' - 'EXISTS((NOT EXISTS(A require_permission P, A is IN(Card, Note))) ' - 'OR (EXISTS(B require_permission P, B is IN(Card, Note), S name "state1"))), ' + '(NOT EXISTS(A require_permission P, A is IN(Card, Note))) ' + 'OR (EXISTS(B require_permission P, B is IN(Card, Note), S name "state1")), ' 'P is CWPermission, S is State') from cubicweb.devtools.testlib import CubicWebTC