From d4e3b605ef5f5cd0959d0df2e82676de55ac7d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Thu, 21 Jan 2016 10:48:32 +0100 Subject: [PATCH] Add 'where' operator to xxx2many issue4507 review12951002 --- CHANGELOG | 1 + doc/topics/domain.rst | 16 ++++++++++++++++ trytond/const.py | 2 ++ trytond/model/fields/many2many.py | 24 ++++++++++++++++++------ trytond/model/fields/one2many.py | 12 ++++++++++-- trytond/tests/test_fields.py | 18 ++++++++++++++++++ 6 files changed, 65 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 07ddc3af1f..c599950e06 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add 'where' operator for xxx2many fields * Strip and unquote double-quote from Postgresql schema in search_path * Move webdav into a separate module * Don't read historized user when evaluating record rules as it could lead to diff --git a/doc/topics/domain.rst b/doc/topics/domain.rst index d3eebc14b0..dac185f78d 100644 --- a/doc/topics/domain.rst +++ b/doc/topics/domain.rst @@ -238,3 +238,19 @@ pattern, unless otherwise noted:: Is a parent child comparison operator. it is the negation of this `parent_of`_ operator. + +``แบhere`` +--------- + + Is a :class:`trytond.model.fields.One2Many` / + :class:`trytond.model.fields.Many2Many` domain operator. It returns true + for every row of the target model that match the domain specified as + ````. + +``not where`` +------------- + + Is a :class:`trytond.model.fields.One2Many` / + :class:`trytond.model.fields.Many2Many` domain operator. It returns true + for every row of the target model that does not match the domain specified + as ````. diff --git a/trytond/const.py b/trytond/const.py index 15e51156c2..07a56ec99c 100644 --- a/trytond/const.py +++ b/trytond/const.py @@ -1,6 +1,8 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. OPERATORS = ( + 'where', + 'not where', 'child_of', 'not child_of', 'parent_of', diff --git a/trytond/model/fields/many2many.py b/trytond/model/fields/many2many.py index 422501ee15..58514e4937 100644 --- a/trytond/model/fields/many2many.py +++ b/trytond/model/fields/many2many.py @@ -286,6 +286,7 @@ class Many2Many(Field): transaction = Transaction() table, _ = tables[None] name, operator, value = domain[:3] + assert operator not in {'where', 'not where'} or '.' not in name if Relation._history and transaction.context.get('_datetime'): relation = Relation.__table_history__() @@ -361,11 +362,18 @@ class Many2Many(Field): else: _, target_name = name.split('.', 1) - relation_domain = [('%s.%s' % (self.target, target_name),) - + tuple(domain[1:])] - if origin_field._type == 'reference': - relation_domain.append( - (self.origin, 'like', Model.__name__ + ',%')) + if operator not in {'where', 'not where'}: + relation_domain = [('%s.%s' % (self.target, target_name),) + + tuple(domain[1:])] + if origin_field._type == 'reference': + relation_domain.append( + (self.origin, 'like', Model.__name__ + ',%')) + else: + relation_domain = [] + for clause in value: + relation_domain.append( + ('%s.%s' % (self.target, clause[0]),) + + tuple(clause[1:])) rule_domain = Rule.domain_get(Relation.__name__, mode='read') if rule_domain: relation_domain = [relation_domain, rule_domain] @@ -376,4 +384,8 @@ class Many2Many(Field): relation_domain, tables=relation_tables) query_table = convert_from(None, relation_tables) query = query_table.select(origin, where=expression) - return table.id.in_(query) + expression = table.id.in_(query) + + if operator == 'not where': + expression = ~expression + return expression diff --git a/trytond/model/fields/one2many.py b/trytond/model/fields/one2many.py index d2c1a432a7..a94b720cc3 100644 --- a/trytond/model/fields/one2many.py +++ b/trytond/model/fields/one2many.py @@ -231,6 +231,7 @@ class One2Many(Field): transaction = Transaction() table, _ = tables[None] name, operator, value = domain[:3] + assert operator not in {'where', 'not where'} or '.' not in name if Target._history and transaction.context.get('_datetime'): target = Target.__table_history__() @@ -268,7 +269,10 @@ class One2Many(Field): target_name = 'id' else: _, target_name = name.split('.', 1) - target_domain = [(target_name,) + tuple(domain[1:])] + if operator not in {'where', 'not where'}: + target_domain = [(target_name,) + tuple(domain[1:])] + else: + target_domain = value if origin_field._type == 'reference': target_domain.append( (self.field, 'like', Model.__name__ + ',%')) @@ -282,4 +286,8 @@ class One2Many(Field): target_domain, tables=target_tables) query_table = convert_from(None, target_tables) query = query_table.select(origin, where=expression) - return table.id.in_(query) + expression = table.id.in_(query) + + if operator == 'not where': + expression = ~expression + return expression diff --git a/trytond/tests/test_fields.py b/trytond/tests/test_fields.py index abe0a0e10f..ba3e638098 100644 --- a/trytond/tests/test_fields.py +++ b/trytond/tests/test_fields.py @@ -2363,6 +2363,15 @@ class FieldsTestCase(unittest.TestCase): ]) self.assertEqual(one2manys, []) + one2manys = one2many.search([ + ('targets', 'where', [('name', '=', 'target1')]), + ]) + self.assertEqual(one2manys, [one2many1]) + one2manys = one2many.search([ + ('targets', 'not where', [('name', '=', 'target1')]), + ]) + self.assertEqual(one2manys, []) + one2many2, = one2many.create([{ 'name': 'origin2', }]) @@ -2557,6 +2566,15 @@ class FieldsTestCase(unittest.TestCase): ]) self.assertEqual(many2manys, []) + many2manys = many2many.search([ + ('targets', 'where', [('name', '=', 'target1')]), + ]) + self.assertEqual(many2manys, [many2many1]) + many2manys = many2many.search([ + ('targets', 'not where', [('name', '=', 'target1')]), + ]) + self.assertEqual(many2manys, []) + many2many2, = many2many.create([{ 'name': 'origin2', }])