[entity vocabulary] fix unrelated rql generation to skip rql constraints that don't make sense
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 31 Mar 2011 15:23:50 +0200
changeset 7153 7df83a6d17c0
parent 7152 39c1ffc7d93f
child 7154 5e2f93b88d86
[entity vocabulary] fix unrelated rql generation to skip rql constraints that don't make sense
entity.py
test/data/schema.py
test/unittest_entity.py
--- a/entity.py	Thu Mar 31 15:23:46 2011 +0200
+++ b/entity.py	Thu Mar 31 15:23:50 2011 +0200
@@ -165,6 +165,7 @@
         selection = [mainvar]
         orderby = []
         # start from 26 to avoid possible conflicts with X
+        # XXX not enough to be sure it'll be no conflicts
         varmaker = rqlvar_maker(index=26)
         cls._fetch_restrictions(mainvar, varmaker, fetchattrs, selection,
                                 orderby, restrictions, user, ordermethod)
@@ -768,29 +769,38 @@
         else:
             searchedvar, evar = 'S', 'O'
             objtype, subjtype = self.e_schema, targettype
+        rdef = rtype.role_rdef(self.e_schema, targettype, role)
         if self.has_eid():
-            restriction = ['NOT S %s O' % rtype, '%s eid %%(x)s' % evar]
+            restriction = ['NOT S %s O' % rtype]
+            if rdef.role_cardinality(role) not in '?1':
+                # if cardinality in '1?', don't add restriction on eid
+                restriction.append('%s eid %%(x)s' % evar)
             args = {'x': self.eid}
             if role == 'subject':
                 securitycheck_args = {'fromeid': self.eid}
             else:
                 securitycheck_args = {'toeid': self.eid}
         else:
-            restriction = []
+            if rdef.role_cardinality(role) in '?1':
+                restriction = ['NOT S %s O' % rtype]
+            else:
+                restriction = []
             args = {}
             securitycheck_args = {}
-        rdef = rtype.role_rdef(self.e_schema, targettype, role)
         insertsecurity = (rdef.has_local_role('add') and not
                           rdef.has_perm(self._cw, 'add', **securitycheck_args))
         # XXX consider constraint.mainvars to check if constraint apply
         if vocabconstraints:
             # RQLConstraint is a subclass for RQLVocabularyConstraint, so they
             # will be included as well
-            restriction += [cstr.expression for cstr in rdef.constraints
-                            if isinstance(cstr, RQLVocabularyConstraint)]
+            cstrcls = RQLVocabularyConstraint
         else:
-            restriction += [cstr.expression for cstr in rdef.constraints
-                            if isinstance(cstr, RQLConstraint)]
+            cstrcls = RQLConstraint
+        for cstr in rdef.constraints:
+            if isinstance(cstr, RQLVocabularyConstraint) and searchedvar in cstr.mainvars:
+                if not self.has_eid() and evar in cstr.mainvars:
+                    continue
+                restriction.append(cstr.expression)
         etypecls = self._cw.vreg['etypes'].etype_class(targettype)
         rql = etypecls.fetch_rql(self._cw.user, restriction,
                                  mainvar=searchedvar, ordermethod=ordermethod)
--- a/test/data/schema.py	Thu Mar 31 15:23:46 2011 +0200
+++ b/test/data/schema.py	Thu Mar 31 15:23:50 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -15,13 +15,11 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""
-
-"""
 
 from yams.buildobjs import (EntityType, String, SubjectRelation,
                             RelationDefinition)
-from cubicweb.schema import  WorkflowableEntityType
+from cubicweb.schema import (WorkflowableEntityType,
+                             RQLConstraint, RQLVocabularyConstraint)
 
 class Personne(EntityType):
     nom = String(required=True)
@@ -29,7 +27,11 @@
     type = String()
     travaille = SubjectRelation('Societe')
     evaluee = SubjectRelation(('Note', 'Personne'))
-    connait = SubjectRelation('Personne', symmetric=True)
+    connait = SubjectRelation(
+        'Personne', symmetric=True,
+        constraints=[
+            RQLConstraint('NOT S identity O'),
+            RQLVocabularyConstraint('NOT (S connait P, P nom "toto")')])
 
 class Societe(EntityType):
     nom = String()
--- a/test/unittest_entity.py	Thu Mar 31 15:23:46 2011 +0200
+++ b/test/unittest_entity.py	Thu Mar 31 15:23:50 2011 +0200
@@ -274,6 +274,33 @@
                           'WHERE S is CWUser, S login AA, S firstname AB, S surname AC, S modification_date AD, '
                           'A eid %(B)s, EXISTS(S identity A, NOT A in_group C, C name "guests", C is CWGroup)')
 
+    def test_unrelated_rql_constraints_creation_subject(self):
+        person = self.vreg['etypes'].etype_class('Personne')(self.request())
+        rql = person.cw_unrelated_rql('connait', 'Personne', 'subject')[0]
+        self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC WHERE '
+                         'O is Personne, O nom AA, O prenom AB, O modification_date AC')
+
+    def test_unrelated_rql_constraints_creation_object(self):
+        person = self.vreg['etypes'].etype_class('Personne')(self.request())
+        rql = person.cw_unrelated_rql('connait', 'Personne', 'object')[0]
+        self.assertEqual(rql, 'Any S,AA,AB,AC ORDERBY AC DESC WHERE '
+                         'NOT (S connait P, P nom "toto"), S is Personne, S nom AA, '
+                         'S prenom AB, S modification_date AC')
+
+    def test_unrelated_rql_constraints_edition_subject(self):
+        person = self.request().create_entity('Personne', nom=u'sylvain')
+        rql = person.cw_unrelated_rql('connait', 'Personne', 'subject')[0]
+        self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC WHERE '
+                         'NOT S connait O, S eid %(x)s, NOT S identity O, O is Personne, '
+                         'O nom AA, O prenom AB, O modification_date AC')
+
+    def test_unrelated_rql_constraints_edition_object(self):
+        person = self.request().create_entity('Personne', nom=u'sylvain')
+        rql = person.cw_unrelated_rql('connait', 'Personne', 'object')[0]
+        self.assertEqual(rql, 'Any S,AA,AB,AC ORDERBY AC DESC WHERE '
+                         'NOT S connait O, O eid %(x)s, NOT S identity O, NOT (S connait P, '
+                         'P nom "toto"), S is Personne, S nom AA, S prenom AB, S modification_date AC')
+
     def test_unrelated_base(self):
         req = self.request()
         p = req.create_entity('Personne', nom=u'di mascio', prenom=u'adrien')