rset.py
changeset 2792 135580d15d42
parent 2650 18aec79ec3a3
child 2813 0cf6c8005bf6
equal deleted inserted replaced
2791:7ef2b08fbe28 2792:135580d15d42
     7 """
     7 """
     8 __docformat__ = "restructuredtext en"
     8 __docformat__ = "restructuredtext en"
     9 
     9 
    10 from logilab.common.decorators import cached, clear_cache, copy_cache
    10 from logilab.common.decorators import cached, clear_cache, copy_cache
    11 
    11 
    12 from rql import nodes
    12 from rql import nodes, stmts
    13 
    13 
    14 from cubicweb import NotAnEntity
    14 from cubicweb import NotAnEntity
    15 
    15 
    16 
    16 
    17 class ResultSet(object):
    17 class ResultSet(object):
   238                 result.append(rset)
   238                 result.append(rset)
   239             else:
   239             else:
   240                 rset = mapping[key]
   240                 rset = mapping[key]
   241             rset.rows.append(self.rows[idx])
   241             rset.rows.append(self.rows[idx])
   242             rset.description.append(self.description[idx])
   242             rset.description.append(self.description[idx])
   243 
       
   244 
       
   245         for rset in result:
   243         for rset in result:
   246             rset.rowcount = len(rset.rows)
   244             rset.rowcount = len(rset.rows)
   247         if return_dict:
   245         if return_dict:
   248             return mapping
   246             return mapping
   249         else:
   247         else:
   250             return result
   248             return result
       
   249 
       
   250     def limited_rql(self):
       
   251         """return a printable rql for the result set associated to the object,
       
   252         with limit/offset correctly set according to maximum page size and
       
   253         currently displayed page when necessary
       
   254         """
       
   255         # try to get page boundaries from the navigation component
       
   256         # XXX we should probably not have a ref to this component here (eg in
       
   257         #     cubicweb.common)
       
   258         nav = self.vreg['components'].select_or_none('navigation', self.req,
       
   259                                                      rset=self)
       
   260         if nav:
       
   261             start, stop = nav.page_boundaries()
       
   262             rql = self._limit_offset_rql(stop - start, start)
       
   263         # result set may have be limited manually in which case navigation won't
       
   264         # apply
       
   265         elif self.limited:
       
   266             rql = self._limit_offset_rql(*self.limited)
       
   267         # navigation component doesn't apply and rset has not been limited, no
       
   268         # need to limit query
       
   269         else:
       
   270             rql = self.printable_rql()
       
   271         return rql
       
   272 
       
   273     def _limit_offset_rql(self, limit, offset):
       
   274         rqlst = self.syntax_tree()
       
   275         if len(rqlst.children) == 1:
       
   276             select = rqlst.children[0]
       
   277             olimit, ooffset = select.limit, select.offset
       
   278             select.limit, select.offset = limit, offset
       
   279             rql = rqlst.as_string(kwargs=self.args)
       
   280             # restore original limit/offset
       
   281             select.limit, select.offset = olimit, ooffset
       
   282         else:
       
   283             newselect = stmts.Select()
       
   284             newselect.limit = limit
       
   285             newselect.offset = offset
       
   286             aliases = [nodes.VariableRef(newselect.get_variable(vref.name, i))
       
   287                        for i, vref in enumerate(rqlst.selection)]
       
   288             newselect.set_with([nodes.SubQuery(aliases, rqlst)], check=False)
       
   289             newunion = stmts.Union()
       
   290             newunion.append(newselect)
       
   291             rql = rqlst.as_string(kwargs=self.args)
       
   292             rqlst.parent = None
       
   293         return rql
   251 
   294 
   252     def limit(self, limit, offset=0, inplace=False):
   295     def limit(self, limit, offset=0, inplace=False):
   253         """limit the result set to the given number of rows optionaly starting
   296         """limit the result set to the given number of rows optionaly starting
   254         from an index different than 0
   297         from an index different than 0
   255 
   298 
   315         for i in xrange(len(self)):
   358         for i in xrange(len(self)):
   316             # may have None values in case of outer join (or aggregat on eid
   359             # may have None values in case of outer join (or aggregat on eid
   317             # hacks)
   360             # hacks)
   318             if self.rows[i][col] is not None:
   361             if self.rows[i][col] is not None:
   319                 yield self.get_entity(i, col)
   362                 yield self.get_entity(i, col)
       
   363 
       
   364     def complete_entity(self, row, col=0, skip_bytes=True):
       
   365         """short cut to get an completed entity instance for a particular
       
   366         row (all instance's attributes have been fetched)
       
   367         """
       
   368         entity = self.get_entity(row, col)
       
   369         entity.complete(skip_bytes=skip_bytes)
       
   370         return entity
   320 
   371 
   321     @cached
   372     @cached
   322     def get_entity(self, row, col=None):
   373     def get_entity(self, row, col=None):
   323         """special method for query retreiving a single entity, returns a
   374         """special method for query retreiving a single entity, returns a
   324         partially initialized Entity instance.
   375         partially initialized Entity instance.