Merge lp:~lifeless/launchpad/prejoin into lp:launchpad
- prejoin
- Merge into devel
Proposed by
Robert Collins
Status: | Merged |
---|---|
Approved by: | Robert Collins |
Approved revision: | no longer in the source branch. |
Merged at revision: | 11956 |
Proposed branch: | lp:~lifeless/launchpad/prejoin |
Merge into: | lp:launchpad |
Diff against target: |
455 lines (+30/-259) 7 files modified
lib/lp/code/model/branch.py (+6/-3) lib/lp/registry/model/product.py (+4/-2) lib/lp/services/database/configure.zcml (+0/-4) lib/lp/services/database/prejoin.py (+0/-118) lib/lp/services/database/tests/test_prejoin.py (+0/-118) lib/lp/translations/model/potemplate.py (+7/-3) lib/lp/translations/model/translationgroup.py (+13/-11) |
To merge this branch: | bzr merge lp:~lifeless/launchpad/prejoin |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jonathan Lange (community) | Approve | ||
Review via email: mp+39720@code.launchpad.net |
Commit message
Replace lp.services.
Description of the change
Delete unused code.
To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote : | # |
Bah, my grep was not powerful enough. Theres at least 'a' user. Will investigate.
Revision history for this message
Robert Collins (lifeless) wrote : | # |
The 'extra' logic was used in one call site - to return a slice. We can, if we want, add it to DRS eventually - but for now lambda x:x[slice(0,3)] should do the job.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/code/model/branch.py' | |||
2 | --- lib/lp/code/model/branch.py 2010-11-18 16:34:35 +0000 | |||
3 | +++ lib/lp/code/model/branch.py 2010-11-19 22:50:20 +0000 | |||
4 | @@ -10,6 +10,7 @@ | |||
5 | 10 | ] | 10 | ] |
6 | 11 | 11 | ||
7 | 12 | from datetime import datetime | 12 | from datetime import datetime |
8 | 13 | import operator | ||
9 | 13 | import simplejson | 14 | import simplejson |
10 | 14 | 15 | ||
11 | 15 | from bzrlib import urlutils | 16 | from bzrlib import urlutils |
12 | @@ -58,6 +59,9 @@ | |||
13 | 58 | sqlvalues, | 59 | sqlvalues, |
14 | 59 | ) | 60 | ) |
15 | 60 | from canonical.launchpad import _ | 61 | from canonical.launchpad import _ |
16 | 62 | from canonical.launchpad.components.decoratedresultset import ( | ||
17 | 63 | DecoratedResultSet, | ||
18 | 64 | ) | ||
19 | 61 | from canonical.launchpad.interfaces.launchpad import ( | 65 | from canonical.launchpad.interfaces.launchpad import ( |
20 | 62 | ILaunchpadCelebrities, | 66 | ILaunchpadCelebrities, |
21 | 63 | IPrivacy, | 67 | IPrivacy, |
22 | @@ -129,7 +133,6 @@ | |||
23 | 129 | validate_person, | 133 | validate_person, |
24 | 130 | validate_public_person, | 134 | validate_public_person, |
25 | 131 | ) | 135 | ) |
26 | 132 | from lp.services.database.prejoin import prejoin | ||
27 | 133 | from lp.services.job.interfaces.job import JobStatus | 136 | from lp.services.job.interfaces.job import JobStatus |
28 | 134 | from lp.services.job.model.job import Job | 137 | from lp.services.job.model.job import Job |
29 | 135 | from lp.services.mail.notificationrecipientset import NotificationRecipientSet | 138 | from lp.services.mail.notificationrecipientset import NotificationRecipientSet |
30 | @@ -283,7 +286,7 @@ | |||
31 | 283 | Revision.id == BranchRevision.revision_id, | 286 | Revision.id == BranchRevision.revision_id, |
32 | 284 | BranchRevision.sequence != None) | 287 | BranchRevision.sequence != None) |
33 | 285 | result = result.order_by(Desc(BranchRevision.sequence)) | 288 | result = result.order_by(Desc(BranchRevision.sequence)) |
35 | 286 | return prejoin(result, return_slice=slice(0, 1)) | 289 | return DecoratedResultSet(result, operator.itemgetter(0)) |
36 | 287 | 290 | ||
37 | 288 | subscriptions = SQLMultipleJoin( | 291 | subscriptions = SQLMultipleJoin( |
38 | 289 | 'BranchSubscription', joinColumn='branch', orderBy='id') | 292 | 'BranchSubscription', joinColumn='branch', orderBy='id') |
39 | @@ -593,7 +596,7 @@ | |||
40 | 593 | Revision.revision_date > timestamp) | 596 | Revision.revision_date > timestamp) |
41 | 594 | result = result.order_by(Desc(BranchRevision.sequence)) | 597 | result = result.order_by(Desc(BranchRevision.sequence)) |
42 | 595 | # Return BranchRevision but prejoin Revision as well. | 598 | # Return BranchRevision but prejoin Revision as well. |
44 | 596 | return prejoin(result, slice(0, 1)) | 599 | return DecoratedResultSet(result, operator.itemgetter(0)) |
45 | 597 | 600 | ||
46 | 598 | def canBeDeleted(self): | 601 | def canBeDeleted(self): |
47 | 599 | """See `IBranch`.""" | 602 | """See `IBranch`.""" |
48 | 600 | 603 | ||
49 | === modified file 'lib/lp/registry/model/product.py' | |||
50 | --- lib/lp/registry/model/product.py 2010-11-08 01:08:15 +0000 | |||
51 | +++ lib/lp/registry/model/product.py 2010-11-19 22:50:20 +0000 | |||
52 | @@ -55,6 +55,9 @@ | |||
53 | 55 | SQLBase, | 55 | SQLBase, |
54 | 56 | sqlvalues, | 56 | sqlvalues, |
55 | 57 | ) | 57 | ) |
56 | 58 | from canonical.launchpad.components.decoratedresultset import ( | ||
57 | 59 | DecoratedResultSet, | ||
58 | 60 | ) | ||
59 | 58 | from canonical.launchpad.interfaces.launchpad import ( | 61 | from canonical.launchpad.interfaces.launchpad import ( |
60 | 59 | IHasIcon, | 62 | IHasIcon, |
61 | 60 | IHasLogo, | 63 | IHasLogo, |
62 | @@ -157,7 +160,6 @@ | |||
63 | 157 | from lp.registry.model.structuralsubscription import ( | 160 | from lp.registry.model.structuralsubscription import ( |
64 | 158 | StructuralSubscriptionTargetMixin, | 161 | StructuralSubscriptionTargetMixin, |
65 | 159 | ) | 162 | ) |
66 | 160 | from lp.services.database.prejoin import prejoin | ||
67 | 161 | from lp.services.propertycache import ( | 163 | from lp.services.propertycache import ( |
68 | 162 | cachedproperty, | 164 | cachedproperty, |
69 | 163 | get_property_cache, | 165 | get_property_cache, |
70 | @@ -1576,7 +1578,7 @@ | |||
71 | 1576 | 1578 | ||
72 | 1577 | # We only want Product - the other tables are just to populate | 1579 | # We only want Product - the other tables are just to populate |
73 | 1578 | # the cache. | 1580 | # the cache. |
75 | 1579 | return prejoin(results) | 1581 | return DecoratedResultSet(results, operator.itemgetter(0)) |
76 | 1580 | 1582 | ||
77 | 1581 | def featuredTranslatables(self, maximumproducts=8): | 1583 | def featuredTranslatables(self, maximumproducts=8): |
78 | 1582 | """See `IProductSet`""" | 1584 | """See `IProductSet`""" |
79 | 1583 | 1585 | ||
80 | === modified file 'lib/lp/services/database/configure.zcml' | |||
81 | --- lib/lp/services/database/configure.zcml 2010-03-11 15:57:43 +0000 | |||
82 | +++ lib/lp/services/database/configure.zcml 2010-11-19 22:50:20 +0000 | |||
83 | @@ -8,10 +8,6 @@ | |||
84 | 8 | xmlns:i18n="http://namespaces.zope.org/i18n" | 8 | xmlns:i18n="http://namespaces.zope.org/i18n" |
85 | 9 | i18n_domain="launchpad"> | 9 | i18n_domain="launchpad"> |
86 | 10 | 10 | ||
87 | 11 | <class class="lp.services.database.prejoin.PrejoinResultSet"> | ||
88 | 12 | <allow interface="storm.zope.interfaces.IResultSet" /> | ||
89 | 13 | <allow attributes="__getslice__" /> | ||
90 | 14 | </class> | ||
91 | 15 | <class class="storm.references.BoundIndirectReferenceSet"> | 11 | <class class="storm.references.BoundIndirectReferenceSet"> |
92 | 16 | <allow attributes="add remove clear" /> | 12 | <allow attributes="add remove clear" /> |
93 | 17 | </class> | 13 | </class> |
94 | 18 | 14 | ||
95 | === removed file 'lib/lp/services/database/prejoin.py' | |||
96 | --- lib/lp/services/database/prejoin.py 2010-09-07 04:53:35 +0000 | |||
97 | +++ lib/lp/services/database/prejoin.py 1970-01-01 00:00:00 +0000 | |||
98 | @@ -1,118 +0,0 @@ | |||
99 | 1 | # Copyright 2009 Canonical Ltd. This software is licensed under the | ||
100 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
101 | 3 | |||
102 | 4 | """Prejoin for Storm. | ||
103 | 5 | |||
104 | 6 | XXX bug=632150 This is duplicated with DecoratedResultSet. please use that. | ||
105 | 7 | RBC 20100907. | ||
106 | 8 | """ | ||
107 | 9 | |||
108 | 10 | __metaclass__ = type | ||
109 | 11 | __all__ = ['prejoin'] | ||
110 | 12 | |||
111 | 13 | from lazr.delegates import delegates | ||
112 | 14 | from storm.zope.interfaces import IResultSet | ||
113 | 15 | |||
114 | 16 | |||
115 | 17 | class PrejoinResultSet: | ||
116 | 18 | """Prejoin support. | ||
117 | 19 | |||
118 | 20 | Wrap a ResultSet, trimming unwanted items. The unwanted items | ||
119 | 21 | are still pulled from the database and populate the Storm caches. | ||
120 | 22 | |||
121 | 23 | This is a temporary solution, as as count() performs an unnecessary | ||
122 | 24 | join making it slower and __contains__() is not implemented at all. | ||
123 | 25 | The preferred solution is support in Storm core, so we can just do | ||
124 | 26 | something like: | ||
125 | 27 | |||
126 | 28 | # Select Product, but prejoin the owner as well. | ||
127 | 29 | >>> join = store.find((Product, Person), Product.name == name) | ||
128 | 30 | >>> results = prejoin(join, slice(0, 1)) | ||
129 | 31 | """ | ||
130 | 32 | delegates(IResultSet, context='result_set') | ||
131 | 33 | |||
132 | 34 | def __init__(self, result_set, return_slice=slice(0, 1)): | ||
133 | 35 | self.result_set = result_set | ||
134 | 36 | self.return_slice = return_slice | ||
135 | 37 | |||
136 | 38 | def _chain(self, result_set): | ||
137 | 39 | return PrejoinResultSet(result_set, self.return_slice) | ||
138 | 40 | |||
139 | 41 | def _chomp(self, row): | ||
140 | 42 | if row is None: | ||
141 | 43 | return None | ||
142 | 44 | elems = row[self.return_slice] | ||
143 | 45 | if len(elems) == 1: | ||
144 | 46 | return elems[0] | ||
145 | 47 | else: | ||
146 | 48 | return elems | ||
147 | 49 | |||
148 | 50 | def copy(self): | ||
149 | 51 | """See `IResultSet`.""" | ||
150 | 52 | return self._chain(self.result_set.copy()) | ||
151 | 53 | |||
152 | 54 | def config(self, distinct=None, offset=None, limit=None): | ||
153 | 55 | """See `IResultSet`.""" | ||
154 | 56 | self.result_set.config(distinct, offset, limit) | ||
155 | 57 | return self | ||
156 | 58 | |||
157 | 59 | def order_by(self, *args): | ||
158 | 60 | """See `IResultSet`.""" | ||
159 | 61 | return self._chain(self.result_set.order_by(*args)) | ||
160 | 62 | |||
161 | 63 | def difference(self, *args, **kw): | ||
162 | 64 | """See `IResultSet`.""" | ||
163 | 65 | raise NotImplementedError("difference") | ||
164 | 66 | |||
165 | 67 | def group_by(self, *args, **kw): | ||
166 | 68 | """See `IResultSet`.""" | ||
167 | 69 | raise NotImplementedError("group_by") | ||
168 | 70 | |||
169 | 71 | def having(self, *args, **kw): | ||
170 | 72 | """See `IResultSet`.""" | ||
171 | 73 | raise NotImplementedError("having") | ||
172 | 74 | |||
173 | 75 | def intersection(self, *args, **kw): | ||
174 | 76 | """See `IResultSet`.""" | ||
175 | 77 | raise NotImplementedError("intersection") | ||
176 | 78 | |||
177 | 79 | def union(self, *args, **kw): | ||
178 | 80 | """See `IResultSet`.""" | ||
179 | 81 | raise NotImplementedError("union") | ||
180 | 82 | |||
181 | 83 | def __iter__(self): | ||
182 | 84 | """See `IResultSet`.""" | ||
183 | 85 | return (self._chomp(row) for row in self.result_set) | ||
184 | 86 | |||
185 | 87 | def __getitem__(self, index): | ||
186 | 88 | """See `IResultSet`.""" | ||
187 | 89 | if isinstance(index, slice): | ||
188 | 90 | return self._chain(self.result_set[index]) | ||
189 | 91 | else: | ||
190 | 92 | return self._chomp(self.result_set[index]) | ||
191 | 93 | |||
192 | 94 | def __contains__(self, item): | ||
193 | 95 | """See `IResultSet`.""" | ||
194 | 96 | raise NotImplementedError("__contains__") | ||
195 | 97 | |||
196 | 98 | def any(self): | ||
197 | 99 | """See `IResultSet`.""" | ||
198 | 100 | return self._chomp(self.result_set.any()) | ||
199 | 101 | |||
200 | 102 | def first(self): | ||
201 | 103 | """See `IResultSet`.""" | ||
202 | 104 | return self._chomp(self.result_set.first()) | ||
203 | 105 | |||
204 | 106 | def last(self): | ||
205 | 107 | """See `IResultSet`.""" | ||
206 | 108 | return self._chomp(self.result_set.last()) | ||
207 | 109 | |||
208 | 110 | def one(self): | ||
209 | 111 | """See `IResultSet`.""" | ||
210 | 112 | return self._chomp(self.result_set.one()) | ||
211 | 113 | |||
212 | 114 | def cached(self): | ||
213 | 115 | """See `IResultSet`.""" | ||
214 | 116 | raise NotImplementedError("cached") | ||
215 | 117 | |||
216 | 118 | prejoin = PrejoinResultSet | ||
217 | 119 | 0 | ||
218 | === removed file 'lib/lp/services/database/tests/test_prejoin.py' | |||
219 | --- lib/lp/services/database/tests/test_prejoin.py 2010-10-20 20:51:26 +0000 | |||
220 | +++ lib/lp/services/database/tests/test_prejoin.py 1970-01-01 00:00:00 +0000 | |||
221 | @@ -1,118 +0,0 @@ | |||
222 | 1 | # Copyright 2009 Canonical Ltd. This software is licensed under the | ||
223 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
224 | 3 | |||
225 | 4 | """prejoin module tests.""" | ||
226 | 5 | |||
227 | 6 | __metaclass__ = type | ||
228 | 7 | __all__ = [] | ||
229 | 8 | |||
230 | 9 | import unittest | ||
231 | 10 | |||
232 | 11 | from canonical.launchpad.interfaces.lpstorm import IMasterStore | ||
233 | 12 | from canonical.testing.layers import LaunchpadZopelessLayer | ||
234 | 13 | from lp.registry.model.person import Person | ||
235 | 14 | from lp.registry.model.product import Product | ||
236 | 15 | from lp.services.database.prejoin import ( | ||
237 | 16 | prejoin, | ||
238 | 17 | PrejoinResultSet, | ||
239 | 18 | ) | ||
240 | 19 | from lp.testing import TestCase | ||
241 | 20 | |||
242 | 21 | |||
243 | 22 | class PrejoinTestCase(TestCase): | ||
244 | 23 | layer = LaunchpadZopelessLayer | ||
245 | 24 | |||
246 | 25 | def setUp(self): | ||
247 | 26 | super(PrejoinTestCase, self).setUp() | ||
248 | 27 | self.store = IMasterStore(Product) | ||
249 | 28 | |||
250 | 29 | # All products | ||
251 | 30 | self.standard_result = self.store.find(Product).order_by(Product.name) | ||
252 | 31 | |||
253 | 32 | # All products, with owner and preferred email address prejoined. | ||
254 | 33 | # Note that because some Product owners have multiple email | ||
255 | 34 | # addresses, this query returns more results. prejoin needs | ||
256 | 35 | # to hide this from callsites. | ||
257 | 36 | self.unwrapped_result = self.store.find( | ||
258 | 37 | (Product, Person), | ||
259 | 38 | Product._ownerID == Person.id).order_by(Product.name) | ||
260 | 39 | self.prejoin_result = prejoin(self.unwrapped_result) | ||
261 | 40 | |||
262 | 41 | def verify(self, prejoined, normal): | ||
263 | 42 | # Ensure our prejoined result really is a PrejoinResultSet. | ||
264 | 43 | # One of our methods might not be sticky, and we have ended up | ||
265 | 44 | # with a normal Storm ResultSet. | ||
266 | 45 | self.assertTrue( | ||
267 | 46 | isinstance(prejoined, PrejoinResultSet), | ||
268 | 47 | "Expected a PrejoinResultSet, got %s" % repr(prejoined)) | ||
269 | 48 | |||
270 | 49 | # Confirm the two result sets return identical results. | ||
271 | 50 | self.assertEqual(list(normal), list(prejoined)) | ||
272 | 51 | |||
273 | 52 | def test_count(self): | ||
274 | 53 | self.assertEqual( | ||
275 | 54 | self.standard_result.count(), | ||
276 | 55 | self.prejoin_result.count()) | ||
277 | 56 | |||
278 | 57 | def test_copy(self): | ||
279 | 58 | copy = self.prejoin_result.copy() | ||
280 | 59 | self.verify(copy, self.standard_result) | ||
281 | 60 | |||
282 | 61 | def test_config(self): | ||
283 | 62 | self.prejoin_result.config(offset=3, limit=2) | ||
284 | 63 | self.standard_result.config(offset=3, limit=2) | ||
285 | 64 | self.verify(self.prejoin_result, self.standard_result) | ||
286 | 65 | |||
287 | 66 | def test_config_returnvalue(self): | ||
288 | 67 | prejoin_rv = self.prejoin_result.config(offset=3, limit=2) | ||
289 | 68 | standard_rv = self.standard_result.config(offset=3, limit=2) | ||
290 | 69 | self.verify(prejoin_rv, standard_rv) | ||
291 | 70 | |||
292 | 71 | def test_order_by(self): | ||
293 | 72 | self.verify( | ||
294 | 73 | self.prejoin_result.order_by(Product.id), | ||
295 | 74 | self.standard_result.order_by(Product.id)) | ||
296 | 75 | |||
297 | 76 | def test_slice(self): | ||
298 | 77 | self.verify( | ||
299 | 78 | self.prejoin_result[4:6], | ||
300 | 79 | self.standard_result[4:6]) | ||
301 | 80 | |||
302 | 81 | def test_any(self): | ||
303 | 82 | self.assertIn(self.prejoin_result.any(), self.standard_result) | ||
304 | 83 | |||
305 | 84 | def test_first(self): | ||
306 | 85 | self.assertEqual( | ||
307 | 86 | self.standard_result.first(), self.prejoin_result.first()) | ||
308 | 87 | |||
309 | 88 | def test_one(self): | ||
310 | 89 | standard_result = self.store.find(Product, Product.name == 'firefox') | ||
311 | 90 | prejoin_result = prejoin(self.store.find( | ||
312 | 91 | (Product, Person), | ||
313 | 92 | Person.id == Product._ownerID, | ||
314 | 93 | Product.name == 'firefox')) | ||
315 | 94 | self.assertEqual(standard_result.one(), prejoin_result.one()) | ||
316 | 95 | |||
317 | 96 | def test_one_empty(self): | ||
318 | 97 | # For an empty result (None), one returns None, too. | ||
319 | 98 | name = "none-existent-name" | ||
320 | 99 | prejoin_result = prejoin(self.store.find( | ||
321 | 100 | (Product, Person), | ||
322 | 101 | Person.id == Product._ownerID, | ||
323 | 102 | Product.name == name)) | ||
324 | 103 | self.assertIs(None, prejoin_result.one()) | ||
325 | 104 | |||
326 | 105 | def test_cache_populated(self): | ||
327 | 106 | # Load a row. | ||
328 | 107 | product = self.prejoin_result.first() | ||
329 | 108 | |||
330 | 109 | # Destroy our data, without telling Storm. This way we can | ||
331 | 110 | # tell if we are accessing an object from the cache, or if it | ||
332 | 111 | # was retrieved from the database. | ||
333 | 112 | self.store.execute("UPDATE Person SET displayname='foo'") | ||
334 | 113 | |||
335 | 114 | self.failIfEqual('foo', product.owner.displayname) | ||
336 | 115 | |||
337 | 116 | |||
338 | 117 | def test_suite(): | ||
339 | 118 | return unittest.TestLoader().loadTestsFromName(__name__) | ||
340 | 119 | 0 | ||
341 | === modified file 'lib/lp/translations/model/potemplate.py' | |||
342 | --- lib/lp/translations/model/potemplate.py 2010-11-11 06:16:33 +0000 | |||
343 | +++ lib/lp/translations/model/potemplate.py 2010-11-19 22:50:20 +0000 | |||
344 | @@ -17,6 +17,7 @@ | |||
345 | 17 | 17 | ||
346 | 18 | import datetime | 18 | import datetime |
347 | 19 | import logging | 19 | import logging |
348 | 20 | import operator | ||
349 | 20 | import os | 21 | import os |
350 | 21 | import re | 22 | import re |
351 | 22 | 23 | ||
352 | @@ -56,6 +57,9 @@ | |||
353 | 56 | sqlvalues, | 57 | sqlvalues, |
354 | 57 | ) | 58 | ) |
355 | 58 | from canonical.launchpad import helpers | 59 | from canonical.launchpad import helpers |
356 | 60 | from canonical.launchpad.components.decoratedresultset import ( | ||
357 | 61 | DecoratedResultSet, | ||
358 | 62 | ) | ||
359 | 59 | from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities | 63 | from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
360 | 60 | from canonical.launchpad.interfaces.lpstorm import ( | 64 | from canonical.launchpad.interfaces.lpstorm import ( |
361 | 61 | IMasterStore, | 65 | IMasterStore, |
362 | @@ -65,7 +69,6 @@ | |||
363 | 65 | from lp.registry.interfaces.person import validate_public_person | 69 | from lp.registry.interfaces.person import validate_public_person |
364 | 66 | from lp.registry.model.sourcepackagename import SourcePackageName | 70 | from lp.registry.model.sourcepackagename import SourcePackageName |
365 | 67 | from lp.services.database.collection import Collection | 71 | from lp.services.database.collection import Collection |
366 | 68 | from lp.services.database.prejoin import prejoin | ||
367 | 69 | from lp.services.propertycache import cachedproperty | 72 | from lp.services.propertycache import cachedproperty |
368 | 70 | from lp.services.worlddata.model.language import Language | 73 | from lp.services.worlddata.model.language import Language |
369 | 71 | from lp.translations.enums import RosettaImportStatus | 74 | from lp.translations.enums import RosettaImportStatus |
370 | @@ -1066,10 +1069,11 @@ | |||
371 | 1066 | else: | 1069 | else: |
372 | 1067 | store = Store.of(self.distroseries) | 1070 | store = Store.of(self.distroseries) |
373 | 1068 | if do_prejoin: | 1071 | if do_prejoin: |
375 | 1069 | query = prejoin(store.find( | 1072 | query = DecoratedResultSet(store.find( |
376 | 1070 | (POTemplate, SourcePackageName), | 1073 | (POTemplate, SourcePackageName), |
377 | 1071 | (POTemplate.sourcepackagenameID == | 1074 | (POTemplate.sourcepackagenameID == |
379 | 1072 | SourcePackageName.id), condition)) | 1075 | SourcePackageName.id), condition), |
380 | 1076 | operator.itemgetter(0)) | ||
381 | 1073 | else: | 1077 | else: |
382 | 1074 | query = store.find(POTemplate, condition) | 1078 | query = store.find(POTemplate, condition) |
383 | 1075 | 1079 | ||
384 | 1076 | 1080 | ||
385 | === modified file 'lib/lp/translations/model/translationgroup.py' | |||
386 | --- lib/lp/translations/model/translationgroup.py 2010-09-03 10:59:24 +0000 | |||
387 | +++ lib/lp/translations/model/translationgroup.py 2010-11-19 22:50:20 +0000 | |||
388 | @@ -9,6 +9,8 @@ | |||
389 | 9 | 'TranslationGroupSet', | 9 | 'TranslationGroupSet', |
390 | 10 | ] | 10 | ] |
391 | 11 | 11 | ||
392 | 12 | import operator | ||
393 | 13 | |||
394 | 12 | from sqlobject import ( | 14 | from sqlobject import ( |
395 | 13 | ForeignKey, | 15 | ForeignKey, |
396 | 14 | SQLMultipleJoin, | 16 | SQLMultipleJoin, |
397 | @@ -26,6 +28,9 @@ | |||
398 | 26 | from canonical.database.constants import DEFAULT | 28 | from canonical.database.constants import DEFAULT |
399 | 27 | from canonical.database.datetimecol import UtcDateTimeCol | 29 | from canonical.database.datetimecol import UtcDateTimeCol |
400 | 28 | from canonical.database.sqlbase import SQLBase | 30 | from canonical.database.sqlbase import SQLBase |
401 | 31 | from canonical.launchpad.components.decoratedresultset import ( | ||
402 | 32 | DecoratedResultSet, | ||
403 | 33 | ) | ||
404 | 29 | from canonical.launchpad.database.librarian import ( | 34 | from canonical.launchpad.database.librarian import ( |
405 | 30 | LibraryFileAlias, | 35 | LibraryFileAlias, |
406 | 31 | LibraryFileContent, | 36 | LibraryFileContent, |
407 | @@ -41,7 +46,6 @@ | |||
408 | 41 | ) | 46 | ) |
409 | 42 | from lp.registry.model.projectgroup import ProjectGroup | 47 | from lp.registry.model.projectgroup import ProjectGroup |
410 | 43 | from lp.registry.model.teammembership import TeamParticipation | 48 | from lp.registry.model.teammembership import TeamParticipation |
411 | 44 | from lp.services.database.prejoin import prejoin | ||
412 | 45 | from lp.services.worlddata.model.language import Language | 49 | from lp.services.worlddata.model.language import Language |
413 | 46 | from lp.translations.interfaces.translationgroup import ( | 50 | from lp.translations.interfaces.translationgroup import ( |
414 | 47 | ITranslationGroup, | 51 | ITranslationGroup, |
415 | @@ -171,10 +175,9 @@ | |||
416 | 171 | Translator.translationgroup == self, | 175 | Translator.translationgroup == self, |
417 | 172 | Language.id == Translator.languageID, | 176 | Language.id == Translator.languageID, |
418 | 173 | Person.id == Translator.translatorID) | 177 | Person.id == Translator.translatorID) |
423 | 174 | 178 | translator_data = translator_data.order_by(Language.englishname) | |
424 | 175 | return prejoin( | 179 | mapper = lambda row:row[slice(0,3)] |
425 | 176 | translator_data.order_by(Language.englishname), | 180 | return DecoratedResultSet(translator_data, mapper) |
422 | 177 | slice(0, 3)) | ||
426 | 178 | 181 | ||
427 | 179 | def fetchProjectsForDisplay(self): | 182 | def fetchProjectsForDisplay(self): |
428 | 180 | """See `ITranslationGroup`.""" | 183 | """See `ITranslationGroup`.""" |
429 | @@ -218,10 +221,9 @@ | |||
430 | 218 | project_data = ISlaveStore(ProjectGroup).using(*using).find( | 221 | project_data = ISlaveStore(ProjectGroup).using(*using).find( |
431 | 219 | tables, | 222 | tables, |
432 | 220 | ProjectGroup.translationgroupID == self.id, | 223 | ProjectGroup.translationgroupID == self.id, |
434 | 221 | ProjectGroup.active == True) | 224 | ProjectGroup.active == True).order_by(ProjectGroup.displayname) |
435 | 222 | 225 | ||
438 | 223 | return prejoin( | 226 | return DecoratedResultSet(project_data, operator.itemgetter(0)) |
437 | 224 | project_data.order_by(ProjectGroup.displayname), slice(0, 1)) | ||
439 | 225 | 227 | ||
440 | 226 | def fetchDistrosForDisplay(self): | 228 | def fetchDistrosForDisplay(self): |
441 | 227 | """See `ITranslationGroup`.""" | 229 | """See `ITranslationGroup`.""" |
442 | @@ -239,10 +241,10 @@ | |||
443 | 239 | LibraryFileContent, | 241 | LibraryFileContent, |
444 | 240 | ) | 242 | ) |
445 | 241 | distro_data = ISlaveStore(Distribution).using(*using).find( | 243 | distro_data = ISlaveStore(Distribution).using(*using).find( |
447 | 242 | tables, Distribution.translationgroupID == self.id) | 244 | tables, Distribution.translationgroupID == self.id).order_by( |
448 | 245 | Distribution.displayname) | ||
449 | 243 | 246 | ||
452 | 244 | return prejoin( | 247 | return DecoratedResultSet(distro_data, operator.itemgetter(0)) |
451 | 245 | distro_data.order_by(Distribution.displayname), slice(0, 1)) | ||
453 | 246 | 248 | ||
454 | 247 | 249 | ||
455 | 248 | class TranslationGroupSet: | 250 | class TranslationGroupSet: |
I guess this isn't actually used anywhere, so my one qualm – that this is not a duplicate of DecoratedResultSet but instead a near-duplicate with extra logic – is not valid.