Projet

Général

Profil

0001-storage-add-parameter-to-sort-get_ids-results-47878.patch

Frédéric Péters, 16 novembre 2020 20:12

Télécharger (6,86 ko)

Voir les différences:

Subject: [PATCH 1/2] storage: add parameter to sort get_ids results (#47878)

 wcs/qommon/storage.py | 58 ++++++++++++++++++++++++-------------------
 wcs/sql.py            | 33 ++++++++++++------------
 2 files changed, 49 insertions(+), 42 deletions(-)
wcs/qommon/storage.py
329 329
            return len(cls.select(clause))
330 330
        return len(cls.keys())
331 331

  
332
    @classmethod
333
    def sort_results(cls, objects, order_by):
334
        if not order_by:
335
            return objects
336
        order_by = str(order_by)
337
        if order_by[0] == '-':
338
            reverse = True
339
            order_by = order_by[1:]
340
        else:
341
            reverse = False
342
        # only list can be sorted
343
        objects = list(objects)
344
        if order_by == 'id':
345
            key_function = lambda x: lax_int(x.id)
346
        elif order_by == 'name':
347
            # proper collation should be done but it's messy to get working
348
            # on all systems so we go the cheap and almost ok way.
349
            from .misc import simplify
350
            key_function = lambda x: simplify(x.name)
351
        elif order_by.endswith('_time'):
352
            typed_none = time.gmtime(-10**10)  # 1653
353
            key_function = lambda x: getattr(x, order_by) or typed_none
354
        else:
355
            key_function = lambda x: getattr(x, order_by)
356
        objects.sort(key=key_function)
357
        if reverse:
358
            objects.reverse()
359
        return objects
360

  
332 361
    @classmethod
333 362
    def select(cls, clause=None, order_by=None, ignore_errors=False,
334 363
            ignore_migration=False, limit=None, offset=None, iterator=False, **kwargs):
......
341 370
        if clause:
342 371
            clause_function = parse_clause(clause)
343 372
            objects = (x for x in objects if clause_function(x))
344
        if order_by:
345
            order_by = str(order_by)
346
            if order_by[0] == '-':
347
                reverse = True
348
                order_by = order_by[1:]
349
            else:
350
                reverse = False
351
            # only list can be sorted
352
            objects = list(objects)
353
            if order_by == 'id':
354
                key_function = lambda x: lax_int(x.id)
355
            elif order_by == 'name':
356
                # proper collation should be done but it's messy to get working
357
                # on all systems so we go the cheap and almost ok way.
358
                from .misc import simplify
359
                key_function = lambda x: simplify(x.name)
360
            elif order_by.endswith('_time'):
361
                typed_none = time.gmtime(-10**10)  # 1653
362
                key_function = lambda x: getattr(x, order_by) or typed_none
363
            else:
364
                key_function = lambda x: getattr(x, order_by)
365
            objects.sort(key=key_function)
366
            if reverse:
367
                objects.reverse()
373
        objects = cls.sort_results(objects, order_by)
368 374
        if limit or offset:
369 375
            objects = _take(objects, limit, offset)
370 376
        return list(objects)
......
418 424
                                **kwargs)
419 425

  
420 426
    @classmethod
421
    def get_ids(cls, ids, ignore_errors=False, **kwargs):
427
    def get_ids(cls, ids, ignore_errors=False, order_by=None, **kwargs):
422 428
        objects = []
423 429
        for x in ids:
424 430
            obj = cls.get(x, ignore_errors=ignore_errors)
425 431
            if obj is not None:
426 432
                objects.append(obj)
427
        return objects
433
        return cls.sort_results(objects, order_by)
428 434

  
429 435
    @classmethod
430 436
    def get_on_index(cls, id, index, ignore_errors=False, ignore_migration=False):
wcs/sql.py
1189 1189

  
1190 1190
    @classmethod
1191 1191
    @guard_postgres
1192
    def get_ids(cls, ids, ignore_errors=False, keep_order=False, fields=None):
1192
    def get_ids(cls, ids, ignore_errors=False, keep_order=False, fields=None, order_by=None):
1193 1193
        if not ids:
1194 1194
            return []
1195 1195
        tables = [cls._table_name]
......
1232 1232
                                    ' '.join(tables),
1233 1233
                                    cls._table_name,
1234 1234
                                    ','.join([str(x) for x in ids]))
1235
        sql_statement += cls.get_order_by_clause(order_by)
1235 1236
        cur.execute(sql_statement)
1236 1237
        objects = cls.get_objects(cur, extra_fields=extra_fields)
1237 1238
        conn.commit()
......
1263 1264
            return generator
1264 1265
        return list(generator)
1265 1266

  
1267
    @classmethod
1268
    def get_order_by_clause(cls, order_by):
1269
        if not order_by:
1270
            return ''
1271
        # [SEC_ORDER] security note: it is not possible to use
1272
        # prepared statements for ORDER BY clauses, therefore input
1273
        # is controlled beforehand (see misc.get_order_by_or_400).
1274
        if order_by.startswith('-'):
1275
            order_by = order_by[1:]
1276
            return ' ORDER BY %s DESC' % order_by.replace('-', '_')
1277
        else:
1278
            return ' ORDER BY %s' % order_by.replace('-', '_')
1279

  
1266 1280
    @classmethod
1267 1281
    @guard_postgres
1268 1282
    def select_iterator(cls, clause=None, order_by=None, ignore_errors=False,
......
1278 1292
        if where_clauses:
1279 1293
            sql_statement += ' WHERE ' + ' AND '.join(where_clauses)
1280 1294

  
1281
        if order_by:
1282
            # [SEC_ORDER] security note: it is not possible to use
1283
            # prepared statements for ORDER BY clauses, therefore input
1284
            # is controlled beforehand (see misc.get_order_by_or_400).
1285
            if order_by.startswith('-'):
1286
                order_by = order_by[1:]
1287
                sql_statement += ' ORDER BY %s DESC' % order_by.replace('-', '_')
1288
            else:
1289
                sql_statement += ' ORDER BY %s' % order_by.replace('-', '_')
1295
        sql_statement += cls.get_order_by_clause(order_by)
1290 1296

  
1291 1297
        if not func_clause:
1292 1298
            if limit:
......
1467 1473
        assert not func_clause
1468 1474
        if where_clauses:
1469 1475
            sql_statement += ' WHERE ' + ' AND '.join(where_clauses)
1470
        # security note, refer to [SEC_ORDER]
1471
        if order_by.startswith('-'):
1472
            order_by = order_by[1:]
1473
            sql_statement += ' ORDER BY %s DESC' % order_by.replace('-', '_')
1474
        else:
1475
            sql_statement += ' ORDER BY %s' % order_by.replace('-', '_')
1476
        sql_statement += cls.get_order_by_clause(order_by)
1476 1477
        cur.execute(sql_statement, parameters)
1477 1478
        ids = [x[0] for x in cur.fetchall()]
1478 1479
        conn.commit()
1479
-