~ubuntu-branches/ubuntu/saucy/nova/saucy-proposed

« back to all changes in this revision

Viewing changes to nova/common/sqlalchemyutils.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Chuck Short, Adam Gandelman
  • Date: 2013-02-22 09:27:29 UTC
  • mfrom: (1.1.68)
  • Revision ID: package-import@ubuntu.com-20130222092729-nn3gt8rf97uvts77
Tags: 2013.1.g3-0ubuntu1
[ Chuck Short ]
* New usptream release. 
* debian/patches/debian/patches/fix-ubuntu-tests.patch: Refreshed.
* debian/nova-baremetal.logrotate: Fix logfile path.
* debian/control, debian/nova-spiceproxy.{install, logrotate, upstart}:
  Add spice html5 proxy support.
* debian/nova-novncproxy.upstart: Start on runlevel [2345]
* debian/rules: Call testr directly since run_tests.sh -N gives weird return
  value when tests pass.
* debian/pyddist-overrides: Add websockify.
* debian/nova-common.postinst: Removed config file conversion, since
  the option is no longer available. (LP: #1110567)
* debian/control: Add python-pyasn1 as a dependency.
* debian/control: Add python-oslo-config as a dependency.
* debian/control: Suggest sysfsutils, sg3-utils, multipath-tools for fibre
  channel support.

[ Adam Gandelman ]
* debian/control: Fix typo (websocikfy -> websockify).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
 
 
3
 
# Copyright 2010 United States Government as represented by the
4
 
# Administrator of the National Aeronautics and Space Administration.
5
 
# Copyright 2010-2011 OpenStack LLC.
6
 
# Copyright 2012 Justin Santa Barbara
7
 
# All Rights Reserved.
8
 
#
9
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
10
 
#    not use this file except in compliance with the License. You may obtain
11
 
#    a copy of the License at
12
 
#
13
 
#         http://www.apache.org/licenses/LICENSE-2.0
14
 
#
15
 
#    Unless required by applicable law or agreed to in writing, software
16
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18
 
#    License for the specific language governing permissions and limitations
19
 
#    under the License.
20
 
 
21
 
"""Implementation of paginate query."""
22
 
 
23
 
import sqlalchemy
24
 
 
25
 
from nova import exception
26
 
from nova.openstack.common import log as logging
27
 
 
28
 
 
29
 
LOG = logging.getLogger(__name__)
30
 
 
31
 
 
32
 
# copy from glance/db/sqlalchemy/api.py
33
 
def paginate_query(query, model, limit, sort_keys, marker=None,
34
 
                   sort_dir=None, sort_dirs=None):
35
 
    """Returns a query with sorting / pagination criteria added.
36
 
 
37
 
    Pagination works by requiring a unique sort_key, specified by sort_keys.
38
 
    (If sort_keys is not unique, then we risk looping through values.)
39
 
    We use the last row in the previous page as the 'marker' for pagination.
40
 
    So we must return values that follow the passed marker in the order.
41
 
    With a single-valued sort_key, this would be easy: sort_key > X.
42
 
    With a compound-values sort_key, (k1, k2, k3) we must do this to repeat
43
 
    the lexicographical ordering:
44
 
    (k1 > X1) or (k1 == X1 && k2 > X2) or (k1 == X1 && k2 == X2 && k3 > X3)
45
 
 
46
 
    We also have to cope with different sort_directions.
47
 
 
48
 
    Typically, the id of the last row is used as the client-facing pagination
49
 
    marker, then the actual marker object must be fetched from the db and
50
 
    passed in to us as marker.
51
 
 
52
 
    :param query: the query object to which we should add paging/sorting
53
 
    :param model: the ORM model class
54
 
    :param limit: maximum number of items to return
55
 
    :param sort_keys: array of attributes by which results should be sorted
56
 
    :param marker: the last item of the previous page; we returns the next
57
 
                    results after this value.
58
 
    :param sort_dir: direction in which results should be sorted (asc, desc)
59
 
    :param sort_dirs: per-column array of sort_dirs, corresponding to sort_keys
60
 
 
61
 
    :rtype: sqlalchemy.orm.query.Query
62
 
    :return: The query with sorting/pagination added.
63
 
    """
64
 
 
65
 
    if 'id' not in sort_keys:
66
 
        # TODO(justinsb): If this ever gives a false-positive, check
67
 
        # the actual primary key, rather than assuming its id
68
 
        LOG.warn(_('Id not in sort_keys; is sort_keys unique?'))
69
 
 
70
 
    assert(not (sort_dir and sort_dirs))
71
 
 
72
 
    # Default the sort direction to ascending
73
 
    if sort_dirs is None and sort_dir is None:
74
 
        sort_dir = 'asc'
75
 
 
76
 
    # Ensure a per-column sort direction
77
 
    if sort_dirs is None:
78
 
        sort_dirs = [sort_dir for _sort_key in sort_keys]
79
 
 
80
 
    assert(len(sort_dirs) == len(sort_keys))
81
 
 
82
 
    # Add sorting
83
 
    for current_sort_key, current_sort_dir in zip(sort_keys, sort_dirs):
84
 
        sort_dir_func = {
85
 
            'asc': sqlalchemy.asc,
86
 
            'desc': sqlalchemy.desc,
87
 
        }[current_sort_dir]
88
 
 
89
 
        try:
90
 
            sort_key_attr = getattr(model, current_sort_key)
91
 
        except AttributeError:
92
 
            raise exception.InvalidSortKey()
93
 
        query = query.order_by(sort_dir_func(sort_key_attr))
94
 
 
95
 
    # Add pagination
96
 
    if marker is not None:
97
 
        marker_values = []
98
 
        for sort_key in sort_keys:
99
 
            v = getattr(marker, sort_key)
100
 
            marker_values.append(v)
101
 
 
102
 
        # Build up an array of sort criteria as in the docstring
103
 
        criteria_list = []
104
 
        for i in xrange(0, len(sort_keys)):
105
 
            crit_attrs = []
106
 
            for j in xrange(0, i):
107
 
                model_attr = getattr(model, sort_keys[j])
108
 
                crit_attrs.append((model_attr == marker_values[j]))
109
 
 
110
 
            model_attr = getattr(model, sort_keys[i])
111
 
            if sort_dirs[i] == 'desc':
112
 
                crit_attrs.append((model_attr < marker_values[i]))
113
 
            elif sort_dirs[i] == 'asc':
114
 
                crit_attrs.append((model_attr > marker_values[i]))
115
 
            else:
116
 
                raise ValueError(_("Unknown sort direction, "
117
 
                                   "must be 'desc' or 'asc'"))
118
 
 
119
 
            criteria = sqlalchemy.sql.and_(*crit_attrs)
120
 
            criteria_list.append(criteria)
121
 
 
122
 
        f = sqlalchemy.sql.or_(*criteria_list)
123
 
        query = query.filter(f)
124
 
 
125
 
    if limit is not None:
126
 
        query = query.limit(limit)
127
 
 
128
 
    return query