Projet

Général

Profil

0003-misc-use-a-single-sql-query-to-get-item-ids-65511.patch

Frédéric Péters, 30 mai 2022 09:53

Télécharger (8,68 ko)

Voir les différences:

Subject: [PATCH 3/4] misc: use a single sql query to get item ids (#65511)

 wcs/formdata.py         |  12 +++--
 wcs/forms/backoffice.py | 108 ++++++++++++++++++++++++++++------------
 2 files changed, 85 insertions(+), 35 deletions(-)
wcs/formdata.py
30 30
from .qommon import _, misc
31 31
from .qommon.evalutils import make_datetime
32 32
from .qommon.publisher import get_cfg
33
from .qommon.storage import Contains, Intersects, Null, StorableObject
33
from .qommon.storage import And, Contains, Intersects, Null, StorableObject
34 34
from .qommon.substitution import CompatibilityNamesDict, Substitutions, invalidate_substitution_cache
35 35
from .qommon.template import Template
36 36

  
......
436 436
            return len(cls.get_actionable_ids(user_roles))
437 437

  
438 438
    @classmethod
439
    def get_actionable_ids(cls, user_roles):
439
    def get_actionable_ids_criteria(cls, user_roles):
440 440
        statuses = ['wf-%s' % x.id for x in cls._formdef.workflow.get_not_endpoint_status()]
441
        return And([Intersects('actions_roles_array', user_roles), Contains('status', statuses)])
442

  
443
    @classmethod
444
    def get_actionable_ids(cls, user_roles):
441 445
        if get_publisher().is_using_postgresql():
442
            criterias = [Intersects('actions_roles_array', user_roles), Contains('status', statuses)]
443
            return cls.keys(criterias)
446
            return cls.keys([cls.get_actionable_ids_criteria(user_roles)])
444 447
        else:
448
            statuses = ['wf-%s' % x.id for x in cls._formdef.workflow.get_not_endpoint_status()]
445 449
            actions_ids = set()
446 450
            for role in user_roles:
447 451
                actions_ids |= set(cls.get_ids_with_indexed_value('actions_roles', str(role)))
wcs/forms/backoffice.py
19 19
from quixote import get_publisher, get_request, get_session, redirect
20 20
from quixote.html import TemplateIO, htmltext
21 21

  
22
from wcs.qommon.storage import Contains, FtsMatch, NotContains, Null, StrictNotEqual
22
from wcs.qommon.storage import Contains, FtsMatch, Intersects, Not, NotContains, Null, StrictNotEqual
23 23
from wcs.roles import logged_users_role
24 24

  
25 25
from ..qommon import _, misc
......
160 160
        criterias=None,
161 161
        anonymise=False,
162 162
    ):
163
        def get_all_except_drafts(**clause_kwargs):
164
            if get_publisher().is_using_postgresql():
165
                return formdata_class.keys(**clause_kwargs)
163
        if get_publisher().is_using_postgresql():
164
            return self.get_listing_item_ids_sql(
165
                selected_filter, selected_filter_operator, query, order_by, user, criterias, anonymise
166
            )
166 167

  
168
        def get_all_except_drafts():
167 169
            item_ids = formdata_class.keys()
168 170
            drafts = formdata_class.get_ids_with_indexed_value('status', 'draft')
169 171
            return [x for x in item_ids if x not in drafts]
170 172

  
171 173
        formdata_class = self.formdef.data_class()
172 174
        # used for postgresql mode only
173
        clause_kwargs = {'clause': criterias + [StrictNotEqual('status', 'draft')]}
174 175
        if selected_filter == 'all':
175 176
            if selected_filter_operator == 'ne':
176 177
                # nothing
177 178
                item_ids = []
178 179
            else:
179 180
                # all except drafts
180
                item_ids = get_all_except_drafts(**clause_kwargs)
181
                item_ids = get_all_except_drafts()
181 182
        elif selected_filter == 'waiting':
182 183
            user_roles = [logged_users_role().id] + user.get_roles()
183 184
            waiting_item_ids = formdata_class.get_actionable_ids(user_roles)
184 185
            if selected_filter_operator == 'ne':
185 186
                # select all ids except drafts
186
                item_ids = get_all_except_drafts(**clause_kwargs)
187
                item_ids = get_all_except_drafts()
187 188
                # exclude waiting ids
188 189
                item_ids = [x for x in item_ids if x not in waiting_item_ids]
189 190
            else:
......
199 200
            else:
200 201
                applied_filters = ['wf-%s' % selected_filter]
201 202

  
202
            if get_publisher().is_using_postgresql():
203
                if selected_filter_operator == 'ne':
204
                    # exclude selected status list
205
                    clause_kwargs['clause'].append(NotContains('status', applied_filters))
206
                else:
207
                    # only selected status list
208
                    clause_kwargs['clause'].append(Contains('status', applied_filters))
209
                item_ids = formdata_class.keys(**clause_kwargs)
210
            else:
211
                filtered_item_ids = []
212
                for status_id in applied_filters:
213
                    filtered_item_ids.extend(
214
                        formdata_class.get_ids_with_indexed_value(
215
                            'status',
216
                            status_id,
217
                        )
203
            filtered_item_ids = []
204
            for status_id in applied_filters:
205
                filtered_item_ids.extend(
206
                    formdata_class.get_ids_with_indexed_value(
207
                        'status',
208
                        status_id,
218 209
                    )
219
                if selected_filter_operator == 'ne':
220
                    # select all ids except drafts
221
                    item_ids = get_all_except_drafts()
222
                    # exclude selected status list
223
                    item_ids = [x for x in item_ids if x not in filtered_item_ids]
224
                else:
225
                    # only selected status list
226
                    item_ids = filtered_item_ids
210
                )
211
            if selected_filter_operator == 'ne':
212
                # select all ids except drafts
213
                item_ids = get_all_except_drafts()
214
                # exclude selected status list
215
                item_ids = [x for x in item_ids if x not in filtered_item_ids]
216
            else:
217
                # only selected status list
218
                item_ids = filtered_item_ids
227 219

  
228 220
        if query:
229 221
            query_ids = formdata_class.get_ids_from_query(query)
......
248 240

  
249 241
        return item_ids
250 242

  
243
    def get_listing_item_ids_sql(
244
        self,
245
        selected_filter,
246
        selected_filter_operator,
247
        query,
248
        order_by,
249
        user,
250
        criterias,
251
        anonymise,
252
    ):
253
        formdata_class = self.formdef.data_class()
254
        criterias = [] or criterias[:]
255
        criterias.append(StrictNotEqual('status', 'draft'))
256
        if selected_filter == 'all':
257
            if selected_filter_operator == 'ne':
258
                # nothing
259
                return []
260
        elif selected_filter == 'waiting':
261
            user_roles = [logged_users_role().id] + user.get_roles()
262
            actionable_criteria = formdata_class.get_actionable_ids_criteria(user_roles)
263
            if selected_filter_operator == 'ne':
264
                criterias.append(Not(actionable_criteria))
265
            else:
266
                criterias.append(actionable_criteria)
267
        else:
268
            # build selected status list
269
            applied_filters = []
270
            if selected_filter == 'pending':
271
                applied_filters = ['wf-%s' % x.id for x in self.formdef.workflow.get_not_endpoint_status()]
272
            elif selected_filter == 'done':
273
                applied_filters = ['wf-%s' % x.id for x in self.formdef.workflow.get_endpoint_status()]
274
            else:
275
                applied_filters = ['wf-%s' % selected_filter]
276

  
277
            if selected_filter_operator == 'ne':
278
                # exclude selected status list
279
                criterias.append(NotContains('status', applied_filters))
280
            else:
281
                # only selected status list
282
                criterias.append(Contains('status', applied_filters))
283

  
284
        if query:
285
            criterias.append(FtsMatch(query))
286

  
287
        if not anonymise:
288
            # as we are in the backoffice, we don't have to care about the
289
            # situation where the user is the submitter, and we limit ourselves
290
            # to consider treating roles.
291
            if not user.is_admin:
292
                user_roles = [str(x) for x in user.get_roles()]
293
                criterias.append(Intersects('concerned_roles_array', user_roles))
294

  
295
        return list(formdata_class.keys(criterias))
296

  
251 297
    def get_listing_items(
252 298
        self,
253 299
        fields=None,
254
-