Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy_utils/query_chain.py: 27%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

37 statements  

1""" 

2QueryChain is a wrapper for sequence of queries. 

3 

4 

5Features: 

6 

7 * Easy iteration for sequence of queries 

8 * Limit, offset and count which are applied to all queries in the chain 

9 * Smart __getitem__ support 

10 

11 

12Initialization 

13^^^^^^^^^^^^^^ 

14 

15QueryChain takes iterable of queries as first argument. Additionally limit and 

16offset parameters can be given 

17 

18:: 

19 

20 chain = QueryChain([session.query(User), session.query(Article)]) 

21 

22 chain = QueryChain( 

23 [session.query(User), session.query(Article)], 

24 limit=4 

25 ) 

26 

27 

28Simple iteration 

29^^^^^^^^^^^^^^^^ 

30:: 

31 

32 chain = QueryChain([session.query(User), session.query(Article)]) 

33 

34 for obj in chain: 

35 print obj 

36 

37 

38Limit and offset 

39^^^^^^^^^^^^^^^^ 

40 

41Lets say you have 5 blog posts, 5 articles and 5 news items in your 

42database. 

43 

44:: 

45 

46 chain = QueryChain( 

47 [ 

48 session.query(BlogPost), 

49 session.query(Article), 

50 session.query(NewsItem) 

51 ], 

52 limit=5 

53 ) 

54 

55 list(chain) # all blog posts but not articles and news items 

56 

57 

58 chain = chain.offset(4) 

59 list(chain) # last blog post, and first four articles 

60 

61 

62Just like with original query object the limit and offset can be chained to 

63return a new QueryChain. 

64 

65:: 

66 

67 chain = chain.limit(5).offset(7) 

68 

69 

70Chain slicing 

71^^^^^^^^^^^^^ 

72 

73:: 

74 

75 chain = QueryChain( 

76 [ 

77 session.query(BlogPost), 

78 session.query(Article), 

79 session.query(NewsItem) 

80 ] 

81 ) 

82 

83 chain[3:6] # New QueryChain with offset=3 and limit=6 

84 

85 

86Count 

87^^^^^ 

88 

89Let's assume that there are five blog posts, five articles and five news 

90items in the database, and you have the following query chain:: 

91 

92 chain = QueryChain( 

93 [ 

94 session.query(BlogPost), 

95 session.query(Article), 

96 session.query(NewsItem) 

97 ] 

98 ) 

99 

100You can then get the total number rows returned by the query chain 

101with :meth:`~QueryChain.count`:: 

102 

103 >>> chain.count() 

104 15 

105 

106 

107""" 

108 

109from copy import copy 

110 

111 

112class QueryChain: 

113 """ 

114 QueryChain can be used as a wrapper for sequence of queries. 

115 

116 :param queries: A sequence of SQLAlchemy Query objects 

117 :param limit: Similar to normal query limit this parameter can be used for 

118 limiting the number of results for the whole query chain. 

119 :param offset: Similar to normal query offset this parameter can be used 

120 for offsetting the query chain as a whole. 

121 

122 .. versionadded: 0.26.0 

123 """ 

124 

125 def __init__(self, queries, limit=None, offset=None): 

126 self.queries = queries 

127 self._limit = limit 

128 self._offset = offset 

129 

130 def __iter__(self): 

131 consumed = 0 

132 skipped = 0 

133 for query in self.queries: 

134 query_copy = copy(query) 

135 if self._limit: 

136 query = query.limit(self._limit - consumed) 

137 if self._offset: 

138 query = query.offset(self._offset - skipped) 

139 

140 obj_count = 0 

141 for obj in query: 

142 consumed += 1 

143 obj_count += 1 

144 yield obj 

145 

146 if not obj_count: 

147 skipped += query_copy.count() 

148 else: 

149 skipped += obj_count 

150 

151 def limit(self, value): 

152 return self[:value] 

153 

154 def offset(self, value): 

155 return self[value:] 

156 

157 def count(self): 

158 """ 

159 Return the total number of rows this QueryChain's queries would return. 

160 """ 

161 return sum(q.count() for q in self.queries) 

162 

163 def __getitem__(self, key): 

164 if isinstance(key, slice): 

165 return self.__class__( 

166 queries=self.queries, 

167 limit=key.stop if key.stop is not None else self._limit, 

168 offset=key.start if key.start is not None else self._offset, 

169 ) 

170 else: 

171 for obj in self[key:1]: 

172 return obj 

173 

174 def __repr__(self): 

175 return '<QueryChain at 0x%x>' % id(self)