author | Julien Cristau <julien.cristau@logilab.fr> |
Thu, 08 Jan 2015 12:22:43 +0100 | |
changeset 10146 | 78f541f50369 |
parent 10087 | ed0b076c119b |
child 10187 | 0df931eb08de |
permissions | -rw-r--r-- |
7395
09ffcc04bd21
[rset] close #1683703: rset.get_entity crash on rql query with subquery and aggregat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6915
diff
changeset
|
1 |
# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
5421
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
2 |
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
3 |
# |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
4 |
# This file is part of CubicWeb. |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
5 |
# |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
6 |
# CubicWeb is free software: you can redistribute it and/or modify it under the |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
7 |
# terms of the GNU Lesser General Public License as published by the Free |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
8 |
# Software Foundation, either version 2.1 of the License, or (at your option) |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
9 |
# any later version. |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
10 |
# |
5424
8ecbcbff9777
replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5421
diff
changeset
|
11 |
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT |
5421
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
12 |
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
13 |
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
14 |
# details. |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
15 |
# |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
16 |
# You should have received a copy of the GNU Lesser General Public License along |
8167de96c523
proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5314
diff
changeset
|
17 |
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
5671
3a2063b752f3
[editform] consistent [do]reledit between attributes and relations: check if rdef is hidden in main section of uicfg.afs for both attributes and relations, and in the reledit view, not in doreledit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5667
diff
changeset
|
18 |
"""The `ResultSet` class which is returned as result of an rql query""" |
0 | 19 |
|
20 |
__docformat__ = "restructuredtext en" |
|
21 |
||
10087
ed0b076c119b
[rset] kill the rset._rqlst cache
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
9820
diff
changeset
|
22 |
from warnings import warn |
ed0b076c119b
[rset] kill the rset._rqlst cache
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
9820
diff
changeset
|
23 |
|
0 | 24 |
from logilab.common.decorators import cached, clear_cache, copy_cache |
25 |
||
2792
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
26 |
from rql import nodes, stmts |
0 | 27 |
|
9347
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
28 |
from cubicweb import NotAnEntity, NoResultError, MultipleResultsError |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
29 |
|
0 | 30 |
|
31 |
class ResultSet(object): |
|
5312
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
32 |
"""A result set wraps a RQL query result. This object implements |
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
33 |
partially the list protocol to allow direct use as a list of |
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
34 |
result rows. |
0 | 35 |
|
36 |
:type rowcount: int |
|
5312
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
37 |
:param rowcount: number of rows in the result |
0 | 38 |
|
39 |
:type rows: list |
|
5312
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
40 |
:param rows: list of rows of result |
0 | 41 |
|
42 |
:type description: list |
|
5312
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
43 |
:param description: |
0 | 44 |
result's description, using the same structure as the result itself |
45 |
||
46 |
:type rql: str or unicode |
|
5312
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
47 |
:param rql: the original RQL query string |
0 | 48 |
""" |
5740
46207f491a51
[rset] make rsets picklable (again ?) #1056422
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5671
diff
changeset
|
49 |
|
9281
49a7392bb5b5
[rset] make sure rset.description is always a list
Julien Cristau <julien.cristau@logilab.fr>
parents:
8695
diff
changeset
|
50 |
def __init__(self, results, rql, args=None, description=None, rqlst=None): |
10087
ed0b076c119b
[rset] kill the rset._rqlst cache
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
9820
diff
changeset
|
51 |
if rqlst is not None: |
ed0b076c119b
[rset] kill the rset._rqlst cache
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
9820
diff
changeset
|
52 |
warn('[3.20] rqlst parameter is deprecated', |
ed0b076c119b
[rset] kill the rset._rqlst cache
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
9820
diff
changeset
|
53 |
DeprecationWarning, stacklevel=2) |
0 | 54 |
self.rows = results |
55 |
self.rowcount = results and len(results) or 0 |
|
56 |
# original query and arguments |
|
57 |
self.rql = rql |
|
58 |
self.args = args |
|
59 |
# entity types for each cell (same shape as rows) |
|
60 |
# maybe discarded if specified when the query has been executed |
|
9331
c6f54ed6b60a
[rset] Fix regression with rset copying (closes #3344410)
Julien Cristau <julien.cristau@logilab.fr>
parents:
9281
diff
changeset
|
61 |
if description is None: |
c6f54ed6b60a
[rset] Fix regression with rset copying (closes #3344410)
Julien Cristau <julien.cristau@logilab.fr>
parents:
9281
diff
changeset
|
62 |
self.description = [] |
c6f54ed6b60a
[rset] Fix regression with rset copying (closes #3344410)
Julien Cristau <julien.cristau@logilab.fr>
parents:
9281
diff
changeset
|
63 |
else: |
c6f54ed6b60a
[rset] Fix regression with rset copying (closes #3344410)
Julien Cristau <julien.cristau@logilab.fr>
parents:
9281
diff
changeset
|
64 |
self.description = description |
0 | 65 |
# set to (limit, offset) when a result set is limited using the |
66 |
# .limit method |
|
67 |
self.limited = None |
|
68 |
# set by the cursor which returned this resultset |
|
69 |
self.req = None |
|
1381
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
70 |
# actions cache |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
71 |
self._rsetactions = None |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
72 |
|
0 | 73 |
def __str__(self): |
74 |
if not self.rows: |
|
75 |
return '<empty resultset %s>' % self.rql |
|
76 |
return '<resultset %s (%s rows)>' % (self.rql, len(self.rows)) |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
77 |
|
0 | 78 |
def __repr__(self): |
79 |
if not self.rows: |
|
170
455ff18ef28e
use repr (instead of str) to print rql in __repr__ method of a result set
Stephanie Marcu <stephanie.marcu@logilab.fr>
parents:
0
diff
changeset
|
80 |
return '<empty resultset for %r>' % self.rql |
616
545a7e18c47f
don't display too much rset rows
sylvain.thenault@logilab.fr
parents:
572
diff
changeset
|
81 |
rows = self.rows |
545a7e18c47f
don't display too much rset rows
sylvain.thenault@logilab.fr
parents:
572
diff
changeset
|
82 |
if len(rows) > 10: |
545a7e18c47f
don't display too much rset rows
sylvain.thenault@logilab.fr
parents:
572
diff
changeset
|
83 |
rows = rows[:10] + ['...'] |
5687
3ea39709b50e
[rset] Add a line break the first result in repr of multiple rows rset
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
5679
diff
changeset
|
84 |
if len(rows) > 1: |
3ea39709b50e
[rset] Add a line break the first result in repr of multiple rows rset
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
5679
diff
changeset
|
85 |
# add a line break before first entity if more that one. |
7395
09ffcc04bd21
[rset] close #1683703: rset.get_entity crash on rql query with subquery and aggregat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6915
diff
changeset
|
86 |
pattern = '<resultset %r (%s rows):\n%s>' |
5687
3ea39709b50e
[rset] Add a line break the first result in repr of multiple rows rset
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
5679
diff
changeset
|
87 |
else: |
3ea39709b50e
[rset] Add a line break the first result in repr of multiple rows rset
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
5679
diff
changeset
|
88 |
pattern = '<resultset %r (%s rows): %s>' |
3ea39709b50e
[rset] Add a line break the first result in repr of multiple rows rset
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
5679
diff
changeset
|
89 |
|
0 | 90 |
if not self.description: |
5687
3ea39709b50e
[rset] Add a line break the first result in repr of multiple rows rset
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
5679
diff
changeset
|
91 |
return pattern % (self.rql, len(self.rows), |
616
545a7e18c47f
don't display too much rset rows
sylvain.thenault@logilab.fr
parents:
572
diff
changeset
|
92 |
'\n'.join(str(r) for r in rows)) |
5687
3ea39709b50e
[rset] Add a line break the first result in repr of multiple rows rset
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
5679
diff
changeset
|
93 |
return pattern % (self.rql, len(self.rows), |
616
545a7e18c47f
don't display too much rset rows
sylvain.thenault@logilab.fr
parents:
572
diff
changeset
|
94 |
'\n'.join('%s (%s)' % (r, d) |
545a7e18c47f
don't display too much rset rows
sylvain.thenault@logilab.fr
parents:
572
diff
changeset
|
95 |
for r, d in zip(rows, self.description))) |
0 | 96 |
|
1381
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
97 |
def possible_actions(self, **kwargs): |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
98 |
if self._rsetactions is None: |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
99 |
self._rsetactions = {} |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
100 |
if kwargs: |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
101 |
key = tuple(sorted(kwargs.iteritems())) |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
102 |
else: |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
103 |
key = None |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
104 |
try: |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
105 |
return self._rsetactions[key] |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
106 |
except KeyError: |
4850
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
107 |
actions = self.req.vreg['actions'].poss_visible_objects( |
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2648
diff
changeset
|
108 |
self.req, rset=self, **kwargs) |
1381
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
109 |
self._rsetactions[key] = actions |
6042f1b342bb
consider kwargs in possible_actions
sylvain.thenault@logilab.fr
parents:
616
diff
changeset
|
110 |
return actions |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
111 |
|
0 | 112 |
def __len__(self): |
113 |
"""returns the result set's size""" |
|
114 |
return self.rowcount |
|
115 |
||
116 |
def __getitem__(self, i): |
|
117 |
"""returns the ith element of the result set""" |
|
118 |
return self.rows[i] #ResultSetRow(self.rows[i]) |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
119 |
|
0 | 120 |
def __getslice__(self, i, j): |
121 |
"""returns slice [i:j] of the result set""" |
|
122 |
return self.rows[i:j] |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
123 |
|
0 | 124 |
def __iter__(self): |
125 |
"""Returns an iterator over rows""" |
|
126 |
return iter(self.rows) |
|
127 |
||
128 |
def __add__(self, rset): |
|
129 |
# XXX buggy implementation (.rql and .args attributes at least much |
|
130 |
# probably differ) |
|
131 |
# at least rql could be fixed now that we have union and sub-queries |
|
132 |
# but I tend to think that since we have that, we should not need this |
|
133 |
# method anymore (syt) |
|
134 |
rset = ResultSet(self.rows+rset.rows, self.rql, self.args, |
|
5072
072ae171aeb0
[cleanup] style fixes, add nodes, 0.2 cents refactorings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4951
diff
changeset
|
135 |
self.description + rset.description) |
4850
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
136 |
rset.req = self.req |
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
137 |
return rset |
0 | 138 |
|
3764
034aa14b740a
drop _prepare_copy method from rset in favor of a more generic copy method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3689
diff
changeset
|
139 |
def copy(self, rows=None, descr=None): |
034aa14b740a
drop _prepare_copy method from rset in favor of a more generic copy method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3689
diff
changeset
|
140 |
if rows is None: |
034aa14b740a
drop _prepare_copy method from rset in favor of a more generic copy method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3689
diff
changeset
|
141 |
rows = self.rows[:] |
034aa14b740a
drop _prepare_copy method from rset in favor of a more generic copy method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3689
diff
changeset
|
142 |
descr = self.description[:] |
0 | 143 |
rset = ResultSet(rows, self.rql, self.args, descr) |
4850
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
144 |
rset.req = self.req |
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
145 |
return rset |
0 | 146 |
|
147 |
def transformed_rset(self, transformcb): |
|
148 |
""" the result set according to a given column types |
|
149 |
||
150 |
:type transormcb: callable(row, desc) |
|
151 |
:param transformcb: |
|
152 |
a callable which should take a row and its type description as |
|
153 |
parameters, and return the transformed row and type description. |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
154 |
|
0 | 155 |
|
156 |
:type col: int |
|
157 |
:param col: the column index |
|
158 |
||
159 |
:rtype: `ResultSet` |
|
160 |
""" |
|
161 |
rows, descr = [], [] |
|
3764
034aa14b740a
drop _prepare_copy method from rset in favor of a more generic copy method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3689
diff
changeset
|
162 |
rset = self.copy(rows, descr) |
0 | 163 |
for row, desc in zip(self.rows, self.description): |
164 |
nrow, ndesc = transformcb(row, desc) |
|
165 |
if ndesc: # transformcb returns None for ndesc to skip that row |
|
166 |
rows.append(nrow) |
|
167 |
descr.append(ndesc) |
|
168 |
rset.rowcount = len(rows) |
|
169 |
return rset |
|
170 |
||
171 |
def filtered_rset(self, filtercb, col=0): |
|
172 |
"""filter the result set according to a given filtercb |
|
173 |
||
174 |
:type filtercb: callable(entity) |
|
175 |
:param filtercb: |
|
176 |
a callable which should take an entity as argument and return |
|
177 |
False if it should be skipped, else True |
|
178 |
||
179 |
:type col: int |
|
180 |
:param col: the column index |
|
181 |
||
182 |
:rtype: `ResultSet` |
|
183 |
""" |
|
184 |
rows, descr = [], [] |
|
3764
034aa14b740a
drop _prepare_copy method from rset in favor of a more generic copy method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3689
diff
changeset
|
185 |
rset = self.copy(rows, descr) |
0 | 186 |
for i in xrange(len(self)): |
187 |
if not filtercb(self.get_entity(i, col)): |
|
188 |
continue |
|
189 |
rows.append(self.rows[i]) |
|
190 |
descr.append(self.description[i]) |
|
191 |
rset.rowcount = len(rows) |
|
192 |
return rset |
|
193 |
||
194 |
||
195 |
def sorted_rset(self, keyfunc, reverse=False, col=0): |
|
196 |
"""sorts the result set according to a given keyfunc |
|
197 |
||
198 |
:type keyfunc: callable(entity) |
|
199 |
:param keyfunc: |
|
200 |
a callable which should take an entity as argument and return |
|
201 |
the value used to compare and sort |
|
202 |
||
203 |
:type reverse: bool |
|
204 |
:param reverse: if the result should be reversed |
|
205 |
||
206 |
:type col: int |
|
207 |
:param col: the column index. if col = -1, the whole row are used |
|
208 |
||
209 |
:rtype: `ResultSet` |
|
210 |
""" |
|
211 |
rows, descr = [], [] |
|
3764
034aa14b740a
drop _prepare_copy method from rset in favor of a more generic copy method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3689
diff
changeset
|
212 |
rset = self.copy(rows, descr) |
0 | 213 |
if col >= 0: |
214 |
entities = sorted(enumerate(self.entities(col)), |
|
215 |
key=lambda (i, e): keyfunc(e), reverse=reverse) |
|
216 |
else: |
|
217 |
entities = sorted(enumerate(self), |
|
218 |
key=lambda (i, e): keyfunc(e), reverse=reverse) |
|
1132 | 219 |
for index, _ in entities: |
0 | 220 |
rows.append(self.rows[index]) |
221 |
descr.append(self.description[index]) |
|
222 |
rset.rowcount = len(rows) |
|
223 |
return rset |
|
224 |
||
225 |
def split_rset(self, keyfunc=None, col=0, return_dict=False): |
|
5312
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
226 |
"""splits the result set in multiple result sets according to |
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
227 |
a given key |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
228 |
|
0 | 229 |
:type keyfunc: callable(entity or FinalType) |
230 |
:param keyfunc: |
|
231 |
a callable which should take a value of the rset in argument and |
|
232 |
return the value used to group the value. If not define, raw value |
|
233 |
of the specified columns is used. |
|
234 |
||
235 |
:type col: int |
|
236 |
:param col: the column index. if col = -1, the whole row are used |
|
237 |
||
238 |
:type return_dict: Boolean |
|
239 |
:param return_dict: If true, the function return a mapping |
|
240 |
(key -> rset) instead of a list of rset |
|
241 |
||
242 |
:rtype: List of `ResultSet` or mapping of `ResultSet` |
|
243 |
||
244 |
""" |
|
245 |
result = [] |
|
246 |
mapping = {} |
|
247 |
for idx, line in enumerate(self): |
|
248 |
if col >= 0: |
|
249 |
try: |
|
1132 | 250 |
key = self.get_entity(idx, col) |
0 | 251 |
except NotAnEntity: |
252 |
key = line[col] |
|
253 |
else: |
|
254 |
key = line |
|
255 |
if keyfunc is not None: |
|
256 |
key = keyfunc(key) |
|
257 |
||
258 |
if key not in mapping: |
|
259 |
rows, descr = [], [] |
|
3764
034aa14b740a
drop _prepare_copy method from rset in favor of a more generic copy method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3689
diff
changeset
|
260 |
rset = self.copy(rows, descr) |
0 | 261 |
mapping[key] = rset |
262 |
result.append(rset) |
|
263 |
else: |
|
264 |
rset = mapping[key] |
|
265 |
rset.rows.append(self.rows[idx]) |
|
266 |
rset.description.append(self.description[idx]) |
|
267 |
for rset in result: |
|
268 |
rset.rowcount = len(rset.rows) |
|
269 |
if return_dict: |
|
270 |
return mapping |
|
271 |
else: |
|
272 |
return result |
|
273 |
||
2792
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
274 |
def limited_rql(self): |
5312
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
275 |
"""returns a printable rql for the result set associated to the object, |
2792
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
276 |
with limit/offset correctly set according to maximum page size and |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
277 |
currently displayed page when necessary |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
278 |
""" |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
279 |
# try to get page boundaries from the navigation component |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
280 |
# XXX we should probably not have a ref to this component here (eg in |
4023
eae23c40627a
drop common subpackage
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3998
diff
changeset
|
281 |
# cubicweb) |
4850
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
282 |
nav = self.req.vreg['components'].select_or_none('navigation', self.req, |
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
283 |
rset=self) |
2792
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
284 |
if nav: |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
285 |
start, stop = nav.page_boundaries() |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
286 |
rql = self._limit_offset_rql(stop - start, start) |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
287 |
# result set may have be limited manually in which case navigation won't |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
288 |
# apply |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
289 |
elif self.limited: |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
290 |
rql = self._limit_offset_rql(*self.limited) |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
291 |
# navigation component doesn't apply and rset has not been limited, no |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
292 |
# need to limit query |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
293 |
else: |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
294 |
rql = self.printable_rql() |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
295 |
return rql |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
296 |
|
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
297 |
def _limit_offset_rql(self, limit, offset): |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
298 |
rqlst = self.syntax_tree() |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
299 |
if len(rqlst.children) == 1: |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
300 |
select = rqlst.children[0] |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
301 |
olimit, ooffset = select.limit, select.offset |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
302 |
select.limit, select.offset = limit, offset |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
303 |
rql = rqlst.as_string(kwargs=self.args) |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
304 |
# restore original limit/offset |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
305 |
select.limit, select.offset = olimit, ooffset |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
306 |
else: |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
307 |
newselect = stmts.Select() |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
308 |
newselect.limit = limit |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
309 |
newselect.offset = offset |
4939
349af486f5ed
fix limited_rql w/ UNION query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
310 |
aliases = [nodes.VariableRef(newselect.get_variable(chr(65+i), i)) |
349af486f5ed
fix limited_rql w/ UNION query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
311 |
for i in xrange(len(rqlst.children[0].selection))] |
349af486f5ed
fix limited_rql w/ UNION query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
312 |
for vref in aliases: |
349af486f5ed
fix limited_rql w/ UNION query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
313 |
newselect.append_selected(nodes.VariableRef(vref.variable)) |
2792
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
314 |
newselect.set_with([nodes.SubQuery(aliases, rqlst)], check=False) |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
315 |
newunion = stmts.Union() |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
316 |
newunion.append(newselect) |
4939
349af486f5ed
fix limited_rql w/ UNION query
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
317 |
rql = newunion.as_string(kwargs=self.args) |
2792
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
318 |
rqlst.parent = None |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
319 |
return rql |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
320 |
|
0 | 321 |
def limit(self, limit, offset=0, inplace=False): |
322 |
"""limit the result set to the given number of rows optionaly starting |
|
323 |
from an index different than 0 |
|
324 |
||
325 |
:type limit: int |
|
326 |
:param limit: the maximum number of results |
|
327 |
||
328 |
:type offset: int |
|
329 |
:param offset: the offset index |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
330 |
|
0 | 331 |
:type inplace: bool |
332 |
:param inplace: |
|
333 |
if true, the result set is modified in place, else a new result set |
|
334 |
is returned and the original is left unmodified |
|
335 |
||
336 |
:rtype: `ResultSet` |
|
337 |
""" |
|
338 |
stop = limit+offset |
|
339 |
rows = self.rows[offset:stop] |
|
340 |
descr = self.description[offset:stop] |
|
341 |
if inplace: |
|
342 |
rset = self |
|
343 |
rset.rows, rset.description = rows, descr |
|
344 |
rset.rowcount = len(rows) |
|
345 |
clear_cache(rset, 'description_struct') |
|
346 |
if offset: |
|
347 |
clear_cache(rset, 'get_entity') |
|
348 |
# we also have to fix/remove from the request entity cache entities |
|
349 |
# which get a wrong rset reference by this limit call |
|
350 |
for entity in self.req.cached_entities(): |
|
3379
9192ba07890d
use .cw_rset instead of rset on appobject classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3023
diff
changeset
|
351 |
if entity.cw_rset is self: |
4150
2835482b8daf
don't try to write .row/.col, use new cw_row/cw_col attributes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4023
diff
changeset
|
352 |
if offset <= entity.cw_row < stop: |
2835482b8daf
don't try to write .row/.col, use new cw_row/cw_col attributes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4023
diff
changeset
|
353 |
entity.cw_row = entity.cw_row - offset |
0 | 354 |
else: |
8048
10a0f73d834d
[rset] replace entity cw_rset on .limit(inplace=True) will avoid pb if the entity is still referenced by some other entity relations cache. Closes #2065643
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7595
diff
changeset
|
355 |
entity.cw_rset = entity.as_rset() |
10a0f73d834d
[rset] replace entity cw_rset on .limit(inplace=True) will avoid pb if the entity is still referenced by some other entity relations cache. Closes #2065643
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7595
diff
changeset
|
356 |
entity.cw_row = entity.cw_col = 0 |
0 | 357 |
else: |
3764
034aa14b740a
drop _prepare_copy method from rset in favor of a more generic copy method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3689
diff
changeset
|
358 |
rset = self.copy(rows, descr) |
0 | 359 |
if not offset: |
360 |
# can copy built entity caches |
|
361 |
copy_cache(rset, 'get_entity', self) |
|
362 |
rset.limited = (limit, offset) |
|
363 |
return rset |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
364 |
|
0 | 365 |
def printable_rql(self, encoded=False): |
366 |
"""return the result set's origin rql as a string, with arguments |
|
367 |
substitued |
|
368 |
""" |
|
369 |
encoding = self.req.encoding |
|
370 |
rqlstr = self.syntax_tree().as_string(encoding, self.args) |
|
371 |
# sounds like we get encoded or unicode string due to a bug in as_string |
|
372 |
if not encoded: |
|
373 |
if isinstance(rqlstr, unicode): |
|
374 |
return rqlstr |
|
375 |
return unicode(rqlstr, encoding) |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
376 |
else: |
0 | 377 |
if isinstance(rqlstr, unicode): |
378 |
return rqlstr.encode(encoding) |
|
379 |
return rqlstr |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
380 |
|
0 | 381 |
# client helper methods ################################################### |
382 |
||
383 |
def entities(self, col=0): |
|
384 |
"""iter on entities with eid in the `col` column of the result set""" |
|
385 |
for i in xrange(len(self)): |
|
386 |
# may have None values in case of outer join (or aggregat on eid |
|
387 |
# hacks) |
|
388 |
if self.rows[i][col] is not None: |
|
389 |
yield self.get_entity(i, col) |
|
390 |
||
6857
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
391 |
def iter_rows_with_entities(self): |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
392 |
""" iterates over rows, and for each row |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
393 |
eids are converted to plain entities |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
394 |
""" |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
395 |
for i, row in enumerate(self): |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
396 |
_row = [] |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
397 |
for j, col in enumerate(row): |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
398 |
try: |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
399 |
_row.append(self.get_entity(i, j) if col is not None else col) |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
400 |
except NotAnEntity: |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
401 |
_row.append(col) |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
402 |
yield _row |
8d2062387134
[rset] add utility method to get entities and attributes from any rset
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
6225
diff
changeset
|
403 |
|
2792
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
404 |
def complete_entity(self, row, col=0, skip_bytes=True): |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
405 |
"""short cut to get an completed entity instance for a particular |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
406 |
row (all instance's attributes have been fetched) |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
407 |
""" |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
408 |
entity = self.get_entity(row, col) |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
409 |
entity.complete(skip_bytes=skip_bytes) |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
410 |
return entity |
135580d15d42
rename and move cw.RequestSessionMixIn to cw.req.RequestSessionBase; move some appobjects methods where they actually belong to
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
411 |
|
0 | 412 |
@cached |
4475
37c413a07216
kill most pre 3.2 bw compat code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4427
diff
changeset
|
413 |
def get_entity(self, row, col): |
5312
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
414 |
"""convenience method for query retrieving a single entity, returns a |
0 | 415 |
partially initialized Entity instance. |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
416 |
|
5314
86e5abbebfaf
[doc/book] refresh the autoform section with uicfg content (moved there)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5312
diff
changeset
|
417 |
.. warning:: |
5312
d2dbba898a96
[doc/book] misc on views, docstrings
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
5311
diff
changeset
|
418 |
|
6859
ace0b991e17b
[entity] fix some docstrings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6857
diff
changeset
|
419 |
Due to the cache wrapping this function, you should NEVER give row as |
ace0b991e17b
[entity] fix some docstrings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6857
diff
changeset
|
420 |
a named parameter (i.e. `rset.get_entity(0, 1)` is OK but |
ace0b991e17b
[entity] fix some docstrings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6857
diff
changeset
|
421 |
`rset.get_entity(row=0, col=1)` isn't) |
0 | 422 |
|
423 |
:type row,col: int, int |
|
424 |
:param row,col: |
|
425 |
row and col numbers localizing the entity among the result's table |
|
426 |
||
427 |
:return: the partially initialized `Entity` instance |
|
428 |
""" |
|
429 |
etype = self.description[row][col] |
|
430 |
try: |
|
4850
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
431 |
eschema = self.req.vreg.schema.eschema(etype) |
3689
deb13e88e037
follow yams 0.25 api changes to improve performance
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3625
diff
changeset
|
432 |
if eschema.final: |
0 | 433 |
raise NotAnEntity(etype) |
434 |
except KeyError: |
|
435 |
raise NotAnEntity(etype) |
|
436 |
return self._build_entity(row, col) |
|
437 |
||
9347
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
438 |
def one(self, col=0): |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
439 |
"""Retrieve exactly one entity from the query. |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
440 |
|
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
441 |
If the result set is empty, raises :exc:`NoResultError`. |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
442 |
If the result set has more than one row, raises |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
443 |
:exc:`MultipleResultsError`. |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
444 |
|
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
445 |
:type col: int |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
446 |
:param col: The column localising the entity in the unique row |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
447 |
|
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
448 |
:return: the partially initialized `Entity` instance |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
449 |
""" |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
450 |
if len(self) == 1: |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
451 |
return self.get_entity(0, col) |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
452 |
elif len(self) == 0: |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
453 |
raise NoResultError("No row was found for one()") |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
454 |
else: |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
455 |
raise MultipleResultsError("Multiple rows were found for one()") |
bd841d6ae723
[rset] New method: ResultSet.one()
Christophe de Vienne <cdevienne@gmail.com>
parents:
9331
diff
changeset
|
456 |
|
2647
b0a2e779845c
enable server side entity caching, 25% speedup on codenaf insertion. ALL CW TESTS OK
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2381
diff
changeset
|
457 |
def _build_entity(self, row, col): |
6859
ace0b991e17b
[entity] fix some docstrings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6857
diff
changeset
|
458 |
"""internal method to get a single entity, returns a partially |
ace0b991e17b
[entity] fix some docstrings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6857
diff
changeset
|
459 |
initialized Entity instance. |
0 | 460 |
|
6859
ace0b991e17b
[entity] fix some docstrings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6857
diff
changeset
|
461 |
partially means that only attributes selected in the RQL query will be |
ace0b991e17b
[entity] fix some docstrings
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6857
diff
changeset
|
462 |
directly assigned to the entity. |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
463 |
|
0 | 464 |
:type row,col: int, int |
465 |
:param row,col: |
|
466 |
row and col numbers localizing the entity among the result's table |
|
467 |
||
468 |
:return: the partially initialized `Entity` instance |
|
469 |
""" |
|
470 |
req = self.req |
|
471 |
if req is None: |
|
472 |
raise AssertionError('dont call get_entity with no req on the result set') |
|
473 |
rowvalues = self.rows[row] |
|
474 |
eid = rowvalues[col] |
|
475 |
assert eid is not None |
|
476 |
# return cached entity if exists. This also avoids potential recursion |
|
477 |
# XXX should we consider updating a cached entity with possible |
|
478 |
# new attributes found in this resultset ? |
|
479 |
try: |
|
2648
4ae7d02ce063
F [rset repo cache] set entity.rset when no set on entities retreived from the cache
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2647
diff
changeset
|
480 |
entity = req.entity_cache(eid) |
0 | 481 |
except KeyError: |
482 |
pass |
|
2832
7fb67c54ffb9
[rset] better explanation, refactor try except
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2813
diff
changeset
|
483 |
else: |
3379
9192ba07890d
use .cw_rset instead of rset on appobject classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3023
diff
changeset
|
484 |
if entity.cw_rset is None: |
2832
7fb67c54ffb9
[rset] better explanation, refactor try except
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2813
diff
changeset
|
485 |
# entity has no rset set, this means entity has been created by |
7fb67c54ffb9
[rset] better explanation, refactor try except
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2813
diff
changeset
|
486 |
# the querier (req is a repository session) and so jas no rset |
7fb67c54ffb9
[rset] better explanation, refactor try except
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2813
diff
changeset
|
487 |
# info. Add it. |
7fb67c54ffb9
[rset] better explanation, refactor try except
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2813
diff
changeset
|
488 |
entity.cw_rset = self |
7fb67c54ffb9
[rset] better explanation, refactor try except
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2813
diff
changeset
|
489 |
entity.cw_row = row |
7fb67c54ffb9
[rset] better explanation, refactor try except
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2813
diff
changeset
|
490 |
entity.cw_col = col |
7fb67c54ffb9
[rset] better explanation, refactor try except
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2813
diff
changeset
|
491 |
return entity |
0 | 492 |
# build entity instance |
493 |
etype = self.description[row][col] |
|
4850
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
494 |
entity = self.req.vreg['etypes'].etype_class(etype)(req, rset=self, |
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
495 |
row=row, col=col) |
5557
1a534c596bff
[entity] continue cleanup of Entity/AnyEntity namespace
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5532
diff
changeset
|
496 |
entity.eid = eid |
0 | 497 |
# cache entity |
498 |
req.set_entity_cache(entity) |
|
499 |
# try to complete the entity if there are some additional columns |
|
500 |
if len(rowvalues) > 1: |
|
7285
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
501 |
eschema = entity.e_schema |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
502 |
eid_col, attr_cols, rel_cols = self._rset_structure(eschema, col) |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
503 |
entity.eid = rowvalues[eid_col] |
7968
92303e2ed77a
[rset] use .iteritems() instead of items()
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7595
diff
changeset
|
504 |
for attr, col_idx in attr_cols.iteritems(): |
7285
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
505 |
entity.cw_attr_cache[attr] = rowvalues[col_idx] |
7968
92303e2ed77a
[rset] use .iteritems() instead of items()
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
7595
diff
changeset
|
506 |
for (rtype, role), col_idx in rel_cols.iteritems(): |
7285
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
507 |
value = rowvalues[col_idx] |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
508 |
if value is None: |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
509 |
if role == 'subject': |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
510 |
rql = 'Any Y WHERE X %s Y, X eid %s' |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
511 |
else: |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
512 |
rql = 'Any Y WHERE Y %s X, X eid %s' |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
513 |
rrset = ResultSet([], rql % (rtype, entity.eid)) |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
514 |
rrset.req = req |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
515 |
else: |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
516 |
rrset = self._build_entity(row, col_idx).as_rset() |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
517 |
entity.cw_set_relation_cache(rtype, role, rrset) |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
518 |
return entity |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
519 |
|
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
520 |
@cached |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
521 |
def _rset_structure(self, eschema, entity_col): |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
522 |
eid_col = col = entity_col |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
523 |
rqlst = self.syntax_tree() |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
524 |
attr_cols = {} |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
525 |
rel_cols = {} |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
526 |
if rqlst.TYPE == 'select': |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
527 |
# UNION query, find the subquery from which this entity has been |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
528 |
# found |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
529 |
select, col = rqlst.locate_subquery(entity_col, eschema.type, self.args) |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
530 |
else: |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
531 |
select = rqlst |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
532 |
# take care, due to outer join support, we may find None |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
533 |
# values for non final relation |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
534 |
for i, attr, role in attr_desc_iterator(select, col, entity_col): |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
535 |
if role == 'subject': |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
536 |
rschema = eschema.subjrels[attr] |
3625
f03b55a18c43
fix bug w/ get_entity and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3551
diff
changeset
|
537 |
else: |
7285
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
538 |
rschema = eschema.objrels[attr] |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
539 |
if rschema.final: |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
540 |
if attr == 'eid': |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
541 |
eid_col = i |
0 | 542 |
else: |
7285
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
543 |
attr_cols[attr] = i |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
544 |
else: |
9820
3ad221fe04aa
[entity/rset] replace scary warnings about ambiguous rdefs by XXX in the code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
9780
diff
changeset
|
545 |
# XXX takefirst=True to remove warning triggered by ambiguous relations |
3ad221fe04aa
[entity/rset] replace scary warnings about ambiguous rdefs by XXX in the code
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
9780
diff
changeset
|
546 |
rdef = eschema.rdef(attr, role, takefirst=True) |
0 | 547 |
# only keep value if it can't be multivalued |
3877
7ca53fc72a0a
reldefsecurity branch :
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
3766
diff
changeset
|
548 |
if rdef.role_cardinality(role) in '1?': |
7285
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
549 |
rel_cols[(attr, role)] = i |
39437617f3f0
[optim] cache rset column structures
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
6915
diff
changeset
|
550 |
return eid_col, attr_cols, rel_cols |
0 | 551 |
|
552 |
@cached |
|
553 |
def syntax_tree(self): |
|
10087
ed0b076c119b
[rset] kill the rset._rqlst cache
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
9820
diff
changeset
|
554 |
"""return the syntax tree (:class:`rql.stmts.Union`) for the |
ed0b076c119b
[rset] kill the rset._rqlst cache
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
9820
diff
changeset
|
555 |
originating query. You can expect it to have solutions |
ed0b076c119b
[rset] kill the rset._rqlst cache
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
9820
diff
changeset
|
556 |
computed and it will be properly annotated. |
0 | 557 |
""" |
10087
ed0b076c119b
[rset] kill the rset._rqlst cache
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
9820
diff
changeset
|
558 |
return self.req.vreg.parse(self.req, self.rql, self.args) |
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
559 |
|
0 | 560 |
@cached |
561 |
def column_types(self, col): |
|
562 |
"""return the list of different types in the column with the given col |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
563 |
|
0 | 564 |
:type col: int |
565 |
:param col: the index of the desired column |
|
566 |
||
567 |
:rtype: list |
|
568 |
:return: the different entities type found in the column |
|
569 |
""" |
|
570 |
return frozenset(struc[-1][col] for struc in self.description_struct()) |
|
571 |
||
572 |
@cached |
|
573 |
def description_struct(self): |
|
574 |
"""return a list describing sequence of results with the same |
|
575 |
description, e.g. : |
|
576 |
[[0, 4, ('Bug',)] |
|
577 |
[[0, 4, ('Bug',), [5, 8, ('Story',)] |
|
578 |
[[0, 3, ('Project', 'Version',)]] |
|
579 |
""" |
|
580 |
result = [] |
|
581 |
last = None |
|
582 |
for i, row in enumerate(self.description): |
|
583 |
if row != last: |
|
584 |
if last is not None: |
|
585 |
result[-1][1] = i - 1 |
|
586 |
result.append( [i, None, row] ) |
|
587 |
last = row |
|
588 |
if last is not None: |
|
589 |
result[-1][1] = i |
|
590 |
return result |
|
591 |
||
4427
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
592 |
def _locate_query_params(self, rqlst, row, col): |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
593 |
locate_query_col = col |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
594 |
etype = self.description[row][col] |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
595 |
# final type, find a better one to locate the correct subquery |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
596 |
# (ambiguous if possible) |
4850
bd640b137f50
[refactor] drop rset.vreg attribute, vreg should be accessed through rset.req. Also kill decorate_rset, simply set rset.req where we were calling this method.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4475
diff
changeset
|
597 |
eschema = self.req.vreg.schema.eschema |
4427
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
598 |
if eschema(etype).final: |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
599 |
for select in rqlst.children: |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
600 |
try: |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
601 |
myvar = select.selection[col].variable |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
602 |
except AttributeError: |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
603 |
# not a variable |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
604 |
continue |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
605 |
for i in xrange(len(select.selection)): |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
606 |
if i == col: |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
607 |
continue |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
608 |
coletype = self.description[row][i] |
6196 | 609 |
# None description possible on column resulting from an |
610 |
# outer join |
|
4427
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
611 |
if coletype is None or eschema(coletype).final: |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
612 |
continue |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
613 |
try: |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
614 |
ivar = select.selection[i].variable |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
615 |
except AttributeError: |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
616 |
# not a variable |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
617 |
continue |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
618 |
# check variables don't comes from a subquery or are both |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
619 |
# coming from the same subquery |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
620 |
if getattr(ivar, 'query', None) is getattr(myvar, 'query', None): |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
621 |
etype = coletype |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
622 |
locate_query_col = i |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
623 |
if len(self.column_types(i)) > 1: |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
624 |
return etype, locate_query_col |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
625 |
return etype, locate_query_col |
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
626 |
|
0 | 627 |
@cached |
628 |
def related_entity(self, row, col): |
|
6195
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
629 |
"""given an cell of the result set, try to return a (entity, relation |
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
630 |
name) tuple to which this cell is linked. |
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
631 |
|
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
632 |
This is especially useful when the cell is an attribute of an entity, |
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
633 |
to get the entity to which this attribute belongs to. |
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
634 |
""" |
0 | 635 |
rqlst = self.syntax_tree() |
6195
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
636 |
# UNION query, we've first to find a 'pivot' column to use to get the |
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
637 |
# actual query from which the row is coming |
4427
410c99a917fa
fix rset.related_entity with variables coming from subquery while some others not
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
4252
diff
changeset
|
638 |
etype, locate_query_col = self._locate_query_params(rqlst, row, col) |
6195
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
639 |
# now find the query from which this entity has been found. Returned |
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
640 |
# select node may be a subquery with different column indexes. |
3016
5787d1cc8106
[rset] fix #231354 w/ rql 0.22.3 api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
641 |
select = rqlst.locate_subquery(locate_query_col, etype, self.args)[0] |
6195
a0c4441e6ddf
[rset]Â add test for #1251252, actually fixed in rql; fix docstring and add comments in rset.related_entity to make things clearer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
5752
diff
changeset
|
642 |
# then get the index of root query's col in the subquery |
3016
5787d1cc8106
[rset] fix #231354 w/ rql 0.22.3 api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
643 |
col = rqlst.subquery_selection_index(select, col) |
3766
9e5dc4b1ada4
work around a pb. with subquery_selection_index
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
3764
diff
changeset
|
644 |
if col is None: |
9e5dc4b1ada4
work around a pb. with subquery_selection_index
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
3764
diff
changeset
|
645 |
# XXX unexpected, should fix subquery_selection_index ? |
9e5dc4b1ada4
work around a pb. with subquery_selection_index
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
3764
diff
changeset
|
646 |
return None, None |
0 | 647 |
try: |
648 |
myvar = select.selection[col].variable |
|
649 |
except AttributeError: |
|
572
9849fed789c9
test and fix potential error with None optional relation
sylvain.thenault@logilab.fr
parents:
170
diff
changeset
|
650 |
# not a variable |
0 | 651 |
return None, None |
652 |
rel = myvar.main_relation() |
|
653 |
if rel is not None: |
|
3016
5787d1cc8106
[rset] fix #231354 w/ rql 0.22.3 api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
654 |
index = rel.children[0].root_selection_index() |
572
9849fed789c9
test and fix potential error with None optional relation
sylvain.thenault@logilab.fr
parents:
170
diff
changeset
|
655 |
if index is not None and self.rows[row][index]: |
5667
04cbd80fd5dc
[rset] do not break when rset.related_entity(x,y) is not an entity
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
5532
diff
changeset
|
656 |
try: |
04cbd80fd5dc
[rset] do not break when rset.related_entity(x,y) is not an entity
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
5532
diff
changeset
|
657 |
entity = self.get_entity(row, index) |
04cbd80fd5dc
[rset] do not break when rset.related_entity(x,y) is not an entity
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
5532
diff
changeset
|
658 |
return entity, rel.r_type |
8695
358d8bed9626
[toward-py3k] rewrite to "except AnException as exc:" (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
8087
diff
changeset
|
659 |
except NotAnEntity as exc: |
5667
04cbd80fd5dc
[rset] do not break when rset.related_entity(x,y) is not an entity
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents:
5532
diff
changeset
|
660 |
return None, None |
0 | 661 |
return None, None |
662 |
||
663 |
@cached |
|
664 |
def searched_text(self): |
|
665 |
"""returns the searched text in case of full-text search |
|
666 |
||
667 |
:return: searched text or `None` if the query is not |
|
668 |
a full-text query |
|
669 |
""" |
|
670 |
rqlst = self.syntax_tree() |
|
671 |
for rel in rqlst.iget_nodes(nodes.Relation): |
|
672 |
if rel.r_type == 'has_text': |
|
673 |
__, rhs = rel.get_variable_parts() |
|
674 |
return rhs.eval(self.args) |
|
675 |
return None |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1477
diff
changeset
|
676 |
|
6915
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
677 |
def _get_variable(term): |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
678 |
# XXX rewritten const |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
679 |
# use iget_nodes for (hack) case where we have things like MAX(V) |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
680 |
for vref in term.iget_nodes(nodes.VariableRef): |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
681 |
return vref.variable |
0 | 682 |
|
6915
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
683 |
def attr_desc_iterator(select, selectidx, rootidx): |
0 | 684 |
"""return an iterator on a list of 2-uple (index, attr_relation) |
685 |
localizing attribute relations of the main variable in a result's row |
|
686 |
||
687 |
:type rqlst: rql.stmts.Select |
|
688 |
:param rqlst: the RQL syntax tree to describe |
|
689 |
||
690 |
:return: |
|
691 |
a generator on (index, relation, target) describing column being |
|
692 |
attribute of the main variable |
|
693 |
""" |
|
6915
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
694 |
rootselect = select |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
695 |
while rootselect.parent.parent is not None: |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
696 |
rootselect = rootselect.parent.parent.parent |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
697 |
rootmain = rootselect.selection[selectidx] |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
698 |
rootmainvar = _get_variable(rootmain) |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
699 |
assert rootmainvar |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
700 |
root = rootselect.parent |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
701 |
selectmain = select.selection[selectidx] |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
702 |
for i, term in enumerate(rootselect.selection): |
7395
09ffcc04bd21
[rset] close #1683703: rset.get_entity crash on rql query with subquery and aggregat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6915
diff
changeset
|
703 |
try: |
09ffcc04bd21
[rset] close #1683703: rset.get_entity crash on rql query with subquery and aggregat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6915
diff
changeset
|
704 |
# don't use _get_variable here: if the term isn't a variable |
09ffcc04bd21
[rset] close #1683703: rset.get_entity crash on rql query with subquery and aggregat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6915
diff
changeset
|
705 |
# (function...), we don't want it to be used as an entity attribute |
09ffcc04bd21
[rset] close #1683703: rset.get_entity crash on rql query with subquery and aggregat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6915
diff
changeset
|
706 |
# or relation's value (XXX beside MAX/MIN trick?) |
09ffcc04bd21
[rset] close #1683703: rset.get_entity crash on rql query with subquery and aggregat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6915
diff
changeset
|
707 |
rootvar = term.variable |
09ffcc04bd21
[rset] close #1683703: rset.get_entity crash on rql query with subquery and aggregat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6915
diff
changeset
|
708 |
except AttributeError: |
0 | 709 |
continue |
6915
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
710 |
if rootvar.name == rootmainvar.name: |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
711 |
continue |
8085
51929d531aff
[rset] fix crash while building entity from rset w/ some subquery. Closes #2089055
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
8048
diff
changeset
|
712 |
if select is not rootselect and isinstance(rootvar, nodes.ColumnAlias): |
6915
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
713 |
term = select.selection[root.subquery_selection_index(select, i)] |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
714 |
var = _get_variable(term) |
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
715 |
if var is None: |
0 | 716 |
continue |
717 |
for ref in var.references(): |
|
718 |
rel = ref.relation() |
|
719 |
if rel is None or rel.is_types_restriction(): |
|
720 |
continue |
|
721 |
lhs, rhs = rel.get_variable_parts() |
|
6915
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
722 |
if selectmain.is_equivalent(lhs): |
0 | 723 |
if rhs.is_equivalent(term): |
724 |
yield (i, rel.r_type, 'subject') |
|
6915
99eb71b311e4
[rset] fix entity building for some result set with UNION and subqueries
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
6859
diff
changeset
|
725 |
elif selectmain.is_equivalent(rhs): |
0 | 726 |
if lhs.is_equivalent(term): |
727 |
yield (i, rel.r_type, 'object') |