1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
"""
QueryChain is a wrapper for sequence of queries.
Features:
* Easy iteration for sequence of queries
* Limit, offset and count which are applied to all queries in the chain
* Smart __getitem__ support
Initialization
^^^^^^^^^^^^^^
QueryChain takes iterable of queries as first argument. Additionally limit and
offset parameters can be given
::
chain = QueryChain([session.query(User), session.query(Article)])
chain = QueryChain(
[session.query(User), session.query(Article)],
limit=4
)
Simple iteration
^^^^^^^^^^^^^^^^
::
chain = QueryChain([session.query(User), session.query(Article)])
for obj in chain:
print obj
Limit and offset
^^^^^^^^^^^^^^^^
Lets say you have 5 blog posts, 5 articles and 5 news items in your
database.
::
chain = QueryChain(
[
session.query(BlogPost),
session.query(Article),
session.query(NewsItem)
],
limit=5
)
list(chain) # all blog posts but not articles and news items
chain = chain.offset(4)
list(chain) # last blog post, and first four articles
Just like with original query object the limit and offset can be chained to
return a new QueryChain.
::
chain = chain.limit(5).offset(7)
Chain slicing
^^^^^^^^^^^^^
::
chain = QueryChain(
[
session.query(BlogPost),
session.query(Article),
session.query(NewsItem)
]
)
chain[3:6] # New QueryChain with offset=3 and limit=6
Count
^^^^^
Let's assume that there are five blog posts, five articles and five news
items in the database, and you have the following query chain::
chain = QueryChain(
[
session.query(BlogPost),
session.query(Article),
session.query(NewsItem)
]
)
You can then get the total number rows returned by the query chain
with :meth:`~QueryChain.count`::
>>> chain.count()
15
"""
from copy import copy
class QueryChain:
"""
QueryChain can be used as a wrapper for sequence of queries.
:param queries: A sequence of SQLAlchemy Query objects
:param limit: Similar to normal query limit this parameter can be used for
limiting the number of results for the whole query chain.
:param offset: Similar to normal query offset this parameter can be used
for offsetting the query chain as a whole.
.. versionadded: 0.26.0
"""
def __init__(self, queries, limit=None, offset=None):
self.queries = queries
self._limit = limit
self._offset = offset
def __iter__(self):
consumed = 0
skipped = 0
for query in self.queries:
query_copy = copy(query)
if self._limit:
query = query.limit(self._limit - consumed)
if self._offset:
query = query.offset(self._offset - skipped)
obj_count = 0
for obj in query:
consumed += 1
obj_count += 1
yield obj
if not obj_count:
skipped += query_copy.count()
else:
skipped += obj_count
def limit(self, value):
return self[:value]
def offset(self, value):
return self[value:]
def count(self):
"""
Return the total number of rows this QueryChain's queries would return.
"""
return sum(q.count() for q in self.queries)
def __getitem__(self, key):
if isinstance(key, slice):
return self.__class__(
queries=self.queries,
limit=key.stop if key.stop is not None else self._limit,
offset=key.start if key.start is not None else self._offset
)
else:
for obj in self[key:1]:
return obj
def __repr__(self):
return '<QueryChain at 0x%x>' % id(self)
|