def sort_query(query, table, sort_keys, sort_dir=None, sort_dirs=None): if 'id' not in sort_keys: # TODO(justinsb): If this ever gives a false-positive, check # the actual primary key, rather than assuming its id LOG.warning(_LW('Id not in sort_keys; is sort_keys unique?')) assert (not (sort_dir and sort_dirs)) # Default the sort direction to ascending if sort_dirs is None and sort_dir is None: sort_dir = 'asc' # Ensure a per-column sort direction if sort_dirs is None: sort_dirs = [sort_dir for _sort_key in sort_keys] assert (len(sort_dirs) == len(sort_keys)) for current_sort_key, current_sort_dir in \ six.moves.zip(sort_keys, sort_dirs): try: sort_dir_func = { 'asc': sqlalchemy.asc, 'desc': sqlalchemy.desc, }[current_sort_dir] except KeyError: raise ValueError( _("Unknown sort direction, " "must be 'desc' or 'asc'")) try: sort_key_attr = getattr(table.c, current_sort_key) except AttributeError: raise utils.InvalidSortKey() query = query.order_by(sort_dir_func(sort_key_attr)) return query, sort_dirs
def paginate_query(query, table, limit, sort_keys, marker=None, sort_dir=None, sort_dirs=None): if 'id' not in sort_keys: # TODO(justinsb): If this ever gives a false-positive, check # the actual primary key, rather than assuming its id LOG.warning(_LW('Id not in sort_keys; is sort_keys unique?')) assert (not (sort_dir and sort_dirs)) # Default the sort direction to ascending if sort_dirs is None and sort_dir is None: sort_dir = 'asc' # Ensure a per-column sort direction if sort_dirs is None: sort_dirs = [sort_dir for _sort_key in sort_keys] assert (len(sort_dirs) == len(sort_keys)) # Add sorting for current_sort_key, current_sort_dir in zip(sort_keys, sort_dirs): try: sort_dir_func = { 'asc': sqlalchemy.asc, 'desc': sqlalchemy.desc, }[current_sort_dir] except KeyError: raise ValueError( _("Unknown sort direction, " "must be 'desc' or 'asc'")) try: sort_key_attr = getattr(table.c, current_sort_key) except AttributeError: raise utils.InvalidSortKey() query = query.order_by(sort_dir_func(sort_key_attr)) # Add pagination if marker is not None: marker_values = [] for sort_key in sort_keys: v = marker[sort_key] marker_values.append(v) # Build up an array of sort criteria as in the docstring criteria_list = [] for i in range(len(sort_keys)): crit_attrs = [] for j in range(i): table_attr = getattr(table.c, sort_keys[j]) crit_attrs.append((table_attr == marker_values[j])) table_attr = getattr(table.c, sort_keys[i]) if sort_dirs[i] == 'desc': crit_attrs.append((table_attr < marker_values[i])) else: crit_attrs.append((table_attr > marker_values[i])) criteria = sqlalchemy.sql.and_(*crit_attrs) criteria_list.append(criteria) f = sqlalchemy.sql.or_(*criteria_list) query = query.where(f) if limit is not None: query = query.limit(limit) return query