From ccfd86602136ca262bfdd12f7ce702689b18e553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 16 Oct 2019 21:31:25 +0200 Subject: [PATCH] Always use search method on translations This ensure to have always the same order when selecting the record out of many duplicates (which can happen as there is no unique constraint since r 426276806f60). issue8705 review260271002 --- trytond/ir/translation.py | 80 +++++++++++++++------------------- trytond/tests/test_modelsql.py | 24 ++++++++++ 2 files changed, 58 insertions(+), 46 deletions(-) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index dc2f61ebdf..3f666e8a21 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -11,7 +11,6 @@ import polib from sql import Column, Null, Literal from sql.functions import Substring, Position from sql.conditionals import Case -from sql.operators import Or, And from sql.aggregate import Max from genshi.filters.i18n import extract as genshi_extract @@ -24,7 +23,7 @@ from trytond.tools.string_ import LazyString from ..model import ModelView, ModelSQL, fields from ..wizard import Wizard, StateView, StateTransition, StateAction, \ Button -from ..tools import file_open, reduce_ids, grouped_slice, cursor_dict +from ..tools import file_open, grouped_slice, cursor_dict from ..pyson import PYSONEncoder, Eval from ..transaction import Transaction from ..pool import Pool @@ -346,27 +345,20 @@ class Translation(ModelSQL, ModelView): translations.update( cls.get_ids(name, ttype, parent_lang, to_fetch)) - transaction = Transaction() - cursor = transaction.connection.cursor() - table = cls.__table__() - fuzzy_sql = table.fuzzy == False if Transaction().context.get('fuzzy_translation', False): - fuzzy_sql = None - in_max = transaction.database.IN_MAX // 7 - for sub_to_fetch in grouped_slice(to_fetch, in_max): - red_sql = reduce_ids(table.res_id, sub_to_fetch) - where = And(((table.lang == lang), - (table.type == ttype), - (table.name == name), - (table.value != ''), - (table.value != Null), - red_sql, - )) - if fuzzy_sql: - where &= fuzzy_sql - cursor.execute(*table.select(table.res_id, table.value, - where=where)) - translations.update(cursor) + fuzzy_clause = [] + else: + fuzzy_clause = [('fuzzy', '=', False)] + for sub_to_fetch in grouped_slice(to_fetch): + for translation in cls.search([ + ('lang', '=', lang), + ('type', '=', ttype), + ('name', '=', name), + ('value', '!=', ''), + ('value', '!=', None), + ('res_id', 'in', list(sub_to_fetch)), + ] + fuzzy_clause): + translations[translation.res_id] = translation.value # Don't store fuzzy translation in cache if not Transaction().context.get('fuzzy_translation', False): for res_id in to_fetch: @@ -526,10 +518,8 @@ class Translation(ModelSQL, ModelView): res = {} parent_args = [] parent_langs = [] - clause = [] + clauses = [] transaction = Transaction() - cursor = transaction.connection.cursor() - table = cls.__table__() if len(args) > transaction.database.IN_MAX: for sub_args in grouped_slice(args): res.update(cls.get_sources(list(sub_args))) @@ -552,17 +542,18 @@ class Translation(ModelSQL, ModelView): parent_args.append((name, ttype, parent_lang, source)) parent_langs.append(lang) res[(name, ttype, lang, source)] = None - where = And(((table.lang == lang), - (table.type == ttype), - (table.name == name), - (table.value != ''), - (table.value != Null), - (table.fuzzy == False), - (table.res_id == -1), - )) + clause = [ + ('lang', '=', lang), + ('type', '=', ttype), + ('name', '=', name), + ('value', '!=', ''), + ('value', '!=', None), + ('fuzzy', '=', False), + ('res_id', '=', -1), + ] if source is not None: - where &= table.src == source - clause.append(where) + clause.append(('src', '=', source)) + clauses.append(clause) # Get parent transactions if parent_args: @@ -572,17 +563,14 @@ class Translation(ModelSQL, ModelView): res[(name, ttype, lang, source)] = parent_src[ (name, ttype, parent_lang, source)] - if clause: - in_max = transaction.database.IN_MAX // 7 - for sub_clause in grouped_slice(clause, in_max): - cursor.execute(*table.select( - table.lang, table.type, table.name, table.src, - table.value, - where=Or(list(sub_clause)))) - for lang, ttype, name, source, value in cursor.fetchall(): - if (name, ttype, lang, source) not in args: - source = None - res[(name, ttype, lang, source)] = value + in_max = transaction.database.IN_MAX // 7 + for sub_clause in grouped_slice(clauses, in_max): + for translation in cls.search(['OR'] + list(sub_clause)): + key = (translation.name, translation.type, + translation.name, translation.name, translation.src) + if key not in args: + key = key[:-1] + (None,) + res[key] = translation.value for key in to_cache: cls._translation_cache.set(key, res[key]) return res diff --git a/trytond/tests/test_modelsql.py b/trytond/tests/test_modelsql.py index a487b3be44..18c72238cd 100644 --- a/trytond/tests/test_modelsql.py +++ b/trytond/tests/test_modelsql.py @@ -701,6 +701,30 @@ class ModelSQLTranslationTestCase(unittest.TestCase): self.assertEqual(record.name, "Foo") self.assertEqual(other.name, "Bar") + @with_transaction() + def test_read_last_translation(self): + "Test read last translation record" + pool = Pool() + Model = pool.get('test.modelsql.translation') + Translation = pool.get('ir.translation') + + with Transaction().set_context(language=self.default_language): + record, = Model.create([{'name': "Foo"}]) + with Transaction().set_context(language=self.other_language): + Model.write([record], {'name': "Bar"}) + other = Model(record.id) + + translation, = Translation.search([ + ('lang', '=', self.other_language), + ('name', '=', 'test.modelsql.translation,name'), + ('type', '=', 'model'), + ('res_id', '=', record.id), + ]) + Translation.copy([translation], default={'value': "Baz"}) + + self.assertEqual(record.name, "Foo") + self.assertEqual(other.name, "Baz") + def suite(): suite_ = unittest.TestSuite()