[FIX] expression.py: avoid using TRUE_DOMAIN/FALSE_DOMAIN
Ensure that expression.OR and expression.AND and some other
expression.py methods do not propagate or rely on TRUE_DOMAIN and
FALSE_DOMAIN that may be muted on some instance.
For example, if we did:
self.search(expression.OR([]))
then in the search method we do something like:
received_domain.append(('res_field', '=', False))
before this commit, FALSE_DOMAIN would be altered for any succeeding code
that try to use it in `[(0, '=', 1), ('res_field', '=', 'False')]`.
Without the changeset, the added test would fail with:
[(1, '=', 1), ('id', '=', 1)] != [(1, '=', 1)]
[(0, '=', 1), ('id', '=', 1)] != [(0, '=', 1)]
[(0, '=', 1), ('id', '=', 1)] != [(0, '=', 1)]
[(1, '=', 1), ('id', '=', 1)] != [(1, '=', 1)]
[(1, '=', 1), ('id', '=', 1)] != [(1, '=', 1)]
note: another commit referenced in #41968 should make the TRUE_DOMAIN
and FALSE_DOMAIN immutable.
related to work on opw-2154448
closes #42107
closes odoo/odoo#42222
X-original-commit: 303ce32e6ccd7432b96ffae545e4a6eced68ae84
Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
This commit is contained in:
@@ -604,6 +604,37 @@ class TestExpression(SavepointCaseWithUserDemo):
|
||||
self.assertNotIn(helene, Company.search([('name','not ilike','Helene')]))
|
||||
self.assertNotIn(helene, Company.search([('name','not ilike','hélène')]))
|
||||
|
||||
def test_pure_function(self):
|
||||
orig_false = expression.FALSE_DOMAIN.copy()
|
||||
orig_true = expression.TRUE_DOMAIN.copy()
|
||||
false = orig_false.copy()
|
||||
true = orig_true.copy()
|
||||
|
||||
domain = expression.AND([])
|
||||
domain += [('id', '=', 1)]
|
||||
domain = expression.AND([])
|
||||
self.assertEqual(domain, orig_true)
|
||||
|
||||
domain = expression.AND([false])
|
||||
domain += [('id', '=', 1)]
|
||||
domain = expression.AND([false])
|
||||
self.assertEqual(domain, orig_false)
|
||||
|
||||
domain = expression.OR([])
|
||||
domain += [('id', '=', 1)]
|
||||
domain = expression.OR([])
|
||||
self.assertEqual(domain, orig_false)
|
||||
|
||||
domain = expression.OR([true])
|
||||
domain += [('id', '=', 1)]
|
||||
domain = expression.OR([true])
|
||||
self.assertEqual(domain, orig_true)
|
||||
|
||||
domain = expression.normalize_domain([])
|
||||
domain += [('id', '=', 1)]
|
||||
domain = expression.normalize_domain([])
|
||||
self.assertEqual(domain, orig_true)
|
||||
|
||||
def test_like_wildcards(self):
|
||||
# check that =like/=ilike expressions are working on an untranslated field
|
||||
Partner = self.env['res.partner']
|
||||
|
||||
@@ -191,7 +191,7 @@ def normalize_domain(domain):
|
||||
"""
|
||||
assert isinstance(domain, (list, tuple)), "Domains to normalize must have a 'domain' form: a list or tuple of domain components"
|
||||
if not domain:
|
||||
return TRUE_DOMAIN
|
||||
return [TRUE_LEAF]
|
||||
result = []
|
||||
expected = 1 # expected number of expressions
|
||||
op_arity = {NOT_OPERATOR: 1, AND_OPERATOR: 2, OR_OPERATOR: 2}
|
||||
@@ -269,12 +269,12 @@ def combine(operator, unit, zero, domains):
|
||||
|
||||
def AND(domains):
|
||||
"""AND([D1,D2,...]) returns a domain representing D1 and D2 and ... """
|
||||
return combine(AND_OPERATOR, TRUE_DOMAIN, FALSE_DOMAIN, domains)
|
||||
return combine(AND_OPERATOR, [TRUE_LEAF], [FALSE_LEAF], domains)
|
||||
|
||||
|
||||
def OR(domains):
|
||||
"""OR([D1,D2,...]) returns a domain representing D1 or D2 or ... """
|
||||
return combine(OR_OPERATOR, FALSE_DOMAIN, TRUE_DOMAIN, domains)
|
||||
return combine(OR_OPERATOR, [FALSE_LEAF], [TRUE_LEAF], domains)
|
||||
|
||||
|
||||
def distribute_not(domain):
|
||||
@@ -752,7 +752,7 @@ class expression(object):
|
||||
either as a range using the parent_path tree lookup field
|
||||
(when available), or as an expanded [(left,in,child_ids)] """
|
||||
if not ids:
|
||||
return FALSE_DOMAIN
|
||||
return [FALSE_LEAF]
|
||||
if left_model._parent_store:
|
||||
doms = OR([
|
||||
[('parent_path', '=like', rec.parent_path + '%')]
|
||||
|
||||
Reference in New Issue
Block a user