Merge lp:~wgrant/launchpad/pofile-filter-stormify into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 17369
Proposed branch: lp:~wgrant/launchpad/pofile-filter-stormify
Merge into: lp:launchpad
Diff against target: 357 lines (+126/-141)
1 file modified
lib/lp/translations/model/pofile.py (+126/-141)
To merge this branch: bzr merge lp:~wgrant/launchpad/pofile-filter-stormify
Reviewer Review Type Date Requested Status
Colin Watson (community) code Approve
Review via email: mp+251249@code.launchpad.net

Commit message

Stormify the remaining POTMsgSet filter methods in POFile.

Description of the change

Stormify the remaining POTMsgSet filter methods in POFile. There are no non-cosmetic query changes, but it's much easier to rework the queries to use new denormalised columns.

findPOTMsgSetsContaining is handled separately in https://code.launchpad.net/~wgrant/launchpad/bug-736005-trivialise/+merge/250447.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

I believe that you can remove the _getClausesForPOFileMessages method now too.

review: Approve (code)
Revision history for this message
William Grant (wgrant) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/translations/model/pofile.py'
2--- lib/lp/translations/model/pofile.py 2013-06-20 05:50:00 +0000
3+++ lib/lp/translations/model/pofile.py 2015-02-27 22:28:33 +0000
4@@ -23,6 +23,7 @@
5 )
6 from storm.expr import (
7 And,
8+ Cast,
9 Coalesce,
10 Desc,
11 Exists,
12@@ -267,8 +268,10 @@
13 Orders the result by TranslationTemplateItem.sequence which must
14 be among `origin_tables`.
15 """
16+ if isinstance(query, basestring):
17+ query = SQL(query)
18 results = IMasterStore(POTMsgSet).using(origin_tables).find(
19- POTMsgSet, SQL(query))
20+ POTMsgSet, query)
21 return results.order_by(TranslationTemplateItem.sequence)
22
23 def findPOTMsgSetsContaining(self, text):
24@@ -581,50 +584,42 @@
25 """
26 flag_name = getUtility(ITranslationSideTraitsSet).getForTemplate(
27 self.potemplate).flag_name
28- clause_tables = ['TranslationTemplateItem', 'TranslationMessage']
29- clauses = self._getClausesForPOFileMessages()
30- clauses.append('TranslationMessage.%s IS TRUE' % flag_name)
31- self._appendCompletePluralFormsConditions(clauses)
32+ clause_tables = [TranslationTemplateItem, TranslationMessage]
33+ clauses = self._getStormClausesForPOFileMessages()
34+ clauses.append(getattr(TranslationMessage, flag_name))
35+ clauses.extend(
36+ SQL(clause) for clause in self._getCompletePluralFormsConditions())
37
38 # A message is current in this pofile if:
39 # * it's current (above) AND
40 # * (it's diverged AND non-empty)
41 # OR (it's shared AND non-empty AND no diverged one exists)
42- diverged_translation_clauses = [
43- 'TranslationMessage.potemplate = %s' % sqlvalues(self.potemplate),
44- ]
45- diverged_translation_query = ' AND '.join(
46- diverged_translation_clauses)
47-
48- shared_translation_clauses = [
49- 'TranslationMessage.potemplate IS NULL',
50- '''NOT EXISTS (
51- SELECT * FROM TranslationMessage AS diverged
52- WHERE
53- diverged.potemplate=%(potemplate)s AND
54- diverged.%(flag_name)s IS TRUE AND
55- diverged.language = %(language)s AND
56- diverged.potmsgset=TranslationMessage.potmsgset)''' % (
57- dict(
58- flag_name=flag_name,
59- language=quote(self.language),
60- potemplate=quote(self.potemplate),
61- )
62- ),
63- ]
64- shared_translation_query = ' AND '.join(shared_translation_clauses)
65-
66- translated_query = ('( (' + diverged_translation_query + ') OR ('
67- + shared_translation_query + ') )')
68- clauses.append(translated_query)
69+ diverged_translation_clause = (
70+ TranslationMessage.potemplateID == self.potemplate.id,
71+ )
72+
73+ Diverged = ClassAlias(TranslationMessage, 'Diverged')
74+ shared_translation_clause = And(
75+ TranslationMessage.potemplateID == None,
76+ Not(Exists(Select(
77+ 1,
78+ tables=[Diverged],
79+ where=And(
80+ Diverged.potmsgsetID == TranslationMessage.potmsgsetID,
81+ Diverged.languageID == self.language.id,
82+ getattr(Diverged, flag_name),
83+ Diverged.potemplateID == self.potemplate.id)))))
84+
85+ clauses.append(
86+ Or(diverged_translation_clause, shared_translation_clause))
87 return (clauses, clause_tables)
88
89 def getPOTMsgSetTranslated(self):
90 """See `IPOFile`."""
91 clauses, clause_tables = self._getTranslatedMessagesQuery()
92- clauses.append('TranslationTemplateItem.potmsgset = POTMsgSet.id')
93-
94- query = ' AND '.join(clauses)
95+ query = And(
96+ TranslationTemplateItem.potmsgsetID == POTMsgSet.id,
97+ *clauses)
98 clause_tables.insert(0, POTMsgSet)
99 return self._getOrderedPOTMsgSets(clause_tables, query)
100
101@@ -633,86 +628,82 @@
102 # We get all POTMsgSet.ids with translations, and later
103 # exclude them using a NOT IN subselect.
104 translated_clauses, clause_tables = self._getTranslatedMessagesQuery()
105- translated_clauses.append(
106- 'POTMsgSet.id=TranslationTemplateItem.potmsgset')
107- # Even though this seems silly, Postgres prefers
108- # TranslationTemplateItem index if we add it (and on staging we
109- # get more than a 10x speed improvement: from 8s to 0.7s). We
110- # also need to put it before any other clauses to be actually useful.
111- translated_clauses.insert(0,
112- 'TranslationTemplateItem.potmsgset ='
113- ' TranslationTemplateItem.potmsgset')
114- translated_query = (
115- "(SELECT POTMsgSet.id"
116- " FROM TranslationTemplateItem, TranslationMessage, POTMsgSet"
117- " WHERE " + " AND ".join(translated_clauses) + ")")
118+ translated_query = Select(
119+ POTMsgSet.id,
120+ tables=[TranslationTemplateItem, TranslationMessage, POTMsgSet],
121+ where=And(
122+ # Even though this seems silly, Postgres prefers
123+ # TranslationTemplateItem index if we add it (and on
124+ # staging we get more than a 10x speed improvement: from
125+ # 8s to 0.7s). We also need to put it before any other
126+ # clauses to be actually useful.
127+ TranslationTemplateItem.potmsgsetID ==
128+ TranslationTemplateItem.potmsgsetID,
129+ POTMsgSet.id == TranslationTemplateItem.potmsgsetID,
130+ *translated_clauses))
131 clauses = [
132- 'TranslationTemplateItem.potemplate = %s' % sqlvalues(
133- self.potemplate),
134- 'TranslationTemplateItem.potmsgset = POTMsgSet.id',
135- 'TranslationTemplateItem.sequence > 0',
136+ TranslationTemplateItem.potemplateID == self.potemplate.id,
137+ TranslationTemplateItem.potmsgsetID == POTMsgSet.id,
138+ TranslationTemplateItem.sequence > 0,
139+ Not(TranslationTemplateItem.potmsgsetID.is_in(translated_query)),
140 ]
141- clauses.append(
142- 'TranslationTemplateItem.potmsgset NOT IN (%s)' % (
143- translated_query))
144-
145- query = ' AND '.join(clauses)
146 return self._getOrderedPOTMsgSets(
147- [POTMsgSet, TranslationTemplateItem], query)
148+ [POTMsgSet, TranslationTemplateItem], And(*clauses))
149
150 def getPOTMsgSetWithNewSuggestions(self):
151 """See `IPOFile`."""
152 flag_name = getUtility(ITranslationSideTraitsSet).getForTemplate(
153 self.potemplate).flag_name
154- clauses = self._getClausesForPOFileMessages()
155- msgstr_clause = make_plurals_sql_fragment(
156- "TranslationMessage.msgstr%(form)d IS NOT NULL", "OR")
157+ clauses = self._getStormClausesForPOFileMessages()
158+ msgstr_clause = Or(*(
159+ getattr(TranslationMessage, 'msgstr%d' % form) != None
160+ for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)))
161 clauses.extend([
162- 'TranslationTemplateItem.potmsgset = POTMsgSet.id',
163- 'TranslationMessage.%s IS NOT TRUE' % flag_name,
164- "(%s)" % msgstr_clause,
165+ TranslationTemplateItem.potmsgsetID == POTMsgSet.id,
166+ Not(getattr(TranslationMessage, flag_name)),
167+ msgstr_clause,
168 ])
169
170- diverged_translation_query = (
171- '''(SELECT COALESCE(diverged.date_reviewed, diverged.date_created)
172- FROM TranslationMessage AS diverged
173- WHERE
174- diverged.%(flag_name)s IS TRUE AND
175- diverged.potemplate = %(potemplate)s AND
176- diverged.language = %(language)s AND
177- diverged.potmsgset=POTMsgSet.id)''' % dict(
178- flag_name=flag_name,
179- potemplate=quote(self.potemplate),
180- language=quote(self.language)))
181-
182- shared_translation_query = (
183- '''(SELECT COALESCE(shared.date_reviewed, shared.date_created)
184- FROM TranslationMessage AS shared
185- WHERE
186- shared.%(flag_name)s IS TRUE AND
187- shared.potemplate IS NULL AND
188- shared.language = %(language)s AND
189- shared.potmsgset=POTMsgSet.id)''' % dict(
190- flag_name=flag_name,
191- language=quote(self.language)))
192- beginning_of_time = "TIMESTAMP '1970-01-01 00:00:00'"
193- newer_than_query = (
194- "TranslationMessage.date_created > COALESCE(" +
195- ",".join([diverged_translation_query,
196- shared_translation_query,
197- beginning_of_time]) + ")")
198- clauses.append(newer_than_query)
199+ Diverged = ClassAlias(TranslationMessage, "Diverged")
200+ diverged_translation_query = Select(
201+ Coalesce(Diverged.date_reviewed, Diverged.date_created),
202+ tables=[Diverged],
203+ where=And(
204+ Diverged.potmsgsetID == POTMsgSet.id,
205+ Diverged.languageID == self.language.id,
206+ getattr(Diverged, flag_name),
207+ Diverged.potemplateID == self.potemplate.id))
208+
209+ Shared = ClassAlias(TranslationMessage, "Shared")
210+ shared_translation_query = Select(
211+ Coalesce(Shared.date_reviewed, Shared.date_created),
212+ tables=[Shared],
213+ where=And(
214+ Shared.potmsgsetID == POTMsgSet.id,
215+ Shared.languageID == self.language.id,
216+ getattr(Shared, flag_name),
217+ Shared.potemplateID == None))
218+
219+ beginning_of_time = Cast(u'1970-01-01 00:00:00', 'timestamp')
220+ clauses.append(
221+ TranslationMessage.date_created >
222+ Coalesce(
223+ diverged_translation_query, shared_translation_query,
224+ beginning_of_time))
225
226 # A POT set has "new" suggestions if there is a non current
227 # TranslationMessage newer than the current reviewed one.
228- query = (
229- """POTMsgSet.id IN (SELECT DISTINCT TranslationMessage.potmsgset
230- FROM TranslationMessage, TranslationTemplateItem, POTMsgSet
231- WHERE (%(query)s)) AND
232- POTMsgSet.id=TranslationTemplateItem.potmsgset AND
233- TranslationTemplateItem.potemplate=%(potemplate)s
234- """ % dict(query=' AND '.join(clauses),
235- potemplate=quote(self.potemplate)))
236+ query = And(
237+ POTMsgSet.id.is_in(
238+ Select(
239+ TranslationMessage.potmsgsetID,
240+ tables=[
241+ TranslationMessage, TranslationTemplateItem,
242+ POTMsgSet],
243+ where=And(*clauses),
244+ distinct=True)),
245+ POTMsgSet.id == TranslationTemplateItem.potmsgsetID,
246+ TranslationTemplateItem.potemplateID == self.potemplate.id)
247 return self._getOrderedPOTMsgSets(
248 [POTMsgSet, TranslationTemplateItem], query)
249
250@@ -727,44 +718,39 @@
251 ITranslationSideTraitsSet).getForTemplate(
252 self.potemplate).other_side_traits.flag_name
253 clauses.extend([
254- 'TranslationTemplateItem.potmsgset = POTMsgSet.id',
255- 'TranslationMessage.%s IS FALSE' % other_side_flag_name,
256+ TranslationTemplateItem.potmsgsetID == POTMsgSet.id,
257+ Not(getattr(TranslationMessage, other_side_flag_name)),
258 ])
259
260- imported_no_diverged = (
261- '''NOT EXISTS (
262- SELECT * FROM TranslationMessage AS diverged
263- WHERE
264- diverged.%(flag_name)s IS TRUE AND
265- diverged.id <> imported.id AND
266- diverged.potemplate = %(potemplate)s AND
267- diverged.language = %(language)s AND
268- diverged.potmsgset=TranslationMessage.potmsgset)''' % (
269- dict(
270- flag_name=other_side_flag_name,
271- potemplate=quote(self.potemplate),
272- language=quote(self.language),
273- )))
274+ Imported = ClassAlias(TranslationMessage, 'Imported')
275+ Diverged = ClassAlias(TranslationMessage, 'Diverged')
276+ imported_no_diverged = Not(Exists(
277+ Select(
278+ 1,
279+ tables=[Diverged],
280+ where=And(
281+ Diverged.id != Imported.id,
282+ Diverged.potmsgsetID == TranslationMessage.potmsgsetID,
283+ Diverged.languageID == self.language.id,
284+ getattr(Diverged, other_side_flag_name),
285+ Diverged.potemplateID == self.potemplate.id))))
286 imported_clauses = [
287- 'imported.id <> TranslationMessage.id',
288- 'imported.potmsgset = POTMsgSet.id',
289- 'imported.language = %s' % sqlvalues(self.language),
290- 'imported.%s IS TRUE' % other_side_flag_name,
291- '(imported.potemplate=%s OR ' % sqlvalues(self.potemplate) +
292- ' (imported.potemplate IS NULL AND ' + imported_no_diverged
293- + ' ))',
294+ Imported.id != TranslationMessage.id,
295+ Imported.potmsgsetID == POTMsgSet.id,
296+ Imported.languageID == self.language.id,
297+ getattr(Imported, other_side_flag_name),
298+ Or(
299+ Imported.potemplateID == self.potemplate.id,
300+ And(Imported.potemplateID == None, imported_no_diverged)),
301 ]
302- self._appendCompletePluralFormsConditions(imported_clauses,
303- 'imported')
304- exists_imported_query = (
305- 'EXISTS ('
306- ' SELECT * FROM TranslationMessage AS imported'
307- ' WHERE ' + ' AND '.join(imported_clauses) + ')')
308- clauses.append(exists_imported_query)
309+ imported_clauses.extend(
310+ SQL(clause) for clause in
311+ self._getCompletePluralFormsConditions('imported'))
312+ clauses.append(Exists(Select(
313+ 1, tables=[Imported], where=And(*imported_clauses))))
314
315 clause_tables.insert(0, POTMsgSet)
316- query = ' AND '.join(clauses)
317- return self._getOrderedPOTMsgSets(clause_tables, query)
318+ return self._getOrderedPOTMsgSets(clause_tables, And(*clauses))
319
320 def messageCount(self):
321 """See `IRosettaStats`."""
322@@ -794,16 +780,17 @@
323 self.rosettacount,
324 self.unreviewed_count)
325
326- def _appendCompletePluralFormsConditions(self, query,
327- table_name='TranslationMessage'):
328+ def _getCompletePluralFormsConditions(self,
329+ table_name='TranslationMessage'):
330 """Add conditions to implement ITranslationMessage.is_complete in SQL.
331
332 :param query: A list of AND SQL conditions where the implementation of
333 ITranslationMessage.is_complete will be appended as SQL
334 conditions.
335 """
336- query.append('%(table_name)s.msgstr0 IS NOT NULL' % {
337- 'table_name': table_name})
338+ query = [
339+ '%(table_name)s.msgstr0 IS NOT NULL' % {'table_name': table_name},
340+ ]
341 if self.language.pluralforms > 1:
342 plurals_query = ' AND '.join(
343 '%(table_name)s.msgstr%(plural_form)d IS NOT NULL' % {
344@@ -825,11 +812,9 @@
345 side_traits = getUtility(ITranslationSideTraitsSet).getForTemplate(
346 self.potemplate)
347 complete_plural_clause_this_side = ' AND '.join(
348- self._appendCompletePluralFormsConditions(
349- [], table_name='Current'))
350+ self._getCompletePluralFormsConditions(table_name='Current'))
351 complete_plural_clause_other_side = ' AND '.join(
352- self._appendCompletePluralFormsConditions(
353- [], table_name='Other'))
354+ self._getCompletePluralFormsConditions(table_name='Other'))
355 params = {
356 'potemplate': quote(self.potemplate),
357 'language': quote(self.language),