fix rset.related_entity with variables coming from subquery while some others not
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 02 Feb 2010 16:19:48 +0100
changeset 4427 410c99a917fa
parent 4419 1f777d13a76b
child 4428 03614b377ecd
fix rset.related_entity with variables coming from subquery while some others not
rset.py
test/unittest_rset.py
--- a/rset.py	Mon Feb 01 19:11:14 2010 +0100
+++ b/rset.py	Tue Feb 02 16:19:48 2010 +0100
@@ -530,26 +530,45 @@
             result[-1][1] = i
         return result
 
+    def _locate_query_params(self, rqlst, row, col):
+        locate_query_col = col
+        etype = self.description[row][col]
+        # final type, find a better one to locate the correct subquery
+        # (ambiguous if possible)
+        eschema = self.vreg.schema.eschema
+        if eschema(etype).final:
+            for select in rqlst.children:
+                try:
+                    myvar = select.selection[col].variable
+                except AttributeError:
+                    # not a variable
+                    continue
+                for i in xrange(len(select.selection)):
+                    if i == col:
+                        continue
+                    coletype = self.description[row][i]
+                    # None description possible on column resulting from an outer join
+                    if coletype is None or eschema(coletype).final:
+                        continue
+                    try:
+                        ivar = select.selection[i].variable
+                    except AttributeError:
+                        # not a variable
+                        continue
+                    # check variables don't comes from a subquery or are both
+                    # coming from the same subquery
+                    if getattr(ivar, 'query', None) is getattr(myvar, 'query', None):
+                        etype = coletype
+                        locate_query_col = i
+                        if len(self.column_types(i)) > 1:
+                            return etype, locate_query_col
+        return etype, locate_query_col
+
     @cached
     def related_entity(self, row, col):
         """try to get the related entity to extract format information if any"""
-        locate_query_col = col
         rqlst = self.syntax_tree()
-        etype = self.description[row][col]
-        if self.vreg.schema.eschema(etype).final:
-            # final type, find a better one to locate the correct subquery
-            # (ambiguous if possible)
-            for i in xrange(len(rqlst.children[0].selection)):
-                if i == col:
-                    continue
-                coletype = self.description[row][i]
-                if coletype is None:
-                    continue
-                if not self.vreg.schema.eschema(coletype).final:
-                    etype = coletype
-                    locate_query_col = i
-                    if len(self.column_types(i)) > 1:
-                        break
+        etype, locate_query_col = self._locate_query_params(rqlst, row, col)
         # UNION query, find the subquery from which this entity has been found
         select = rqlst.locate_subquery(locate_query_col, etype, self.args)[0]
         col = rqlst.subquery_selection_index(select, col)
--- a/test/unittest_rset.py	Mon Feb 01 19:11:14 2010 +0100
+++ b/test/unittest_rset.py	Tue Feb 02 16:19:48 2010 +0100
@@ -345,6 +345,14 @@
         self.assertEquals(entity.eid, e.eid)
         self.assertEquals(rtype, 'title')
 
+    def test_related_entity_trap_subquery(self):
+        req = self.request()
+        req.create_entity('Bookmark', title=u'test bookmark', path=u'')
+        self.execute('SET B bookmarked_by U WHERE U login "admin"')
+        rset = self.execute('Any B,T,L WHERE B bookmarked_by U, U login L '
+                            'WITH B,T BEING (Any B,T WHERE B is Bookmark, B title T)')
+        rset.related_entity(0, 2)
+
     def test_entities(self):
         rset = self.execute('Any U,G WHERE U in_group G')
         # make sure we have at least one element