In some methods, like group expand methods, it is not uncommon to transform a domain designed for model A to search records from another model B. In general this transformation requires two operations: - Rename some fields in the domain - Remove leaves from the domain that relate to fields not existing in model B The current function filter_domain_leaf allows to realize this second operation. It currently relies on a recursive implementation with a complexity of order O(n²). This commit introduces a re-writing of the function filter_domain_leaf that: 1. Changes the recursion based implementation to an explicit stack implementation 2. Introduces a field mapping dictionary as argument The explicit stack implementation allows to avoid stack overflow when working with long domains. The complexity order is also improved to O(n) instead of O(n²) which leads to performance gain. For a domain length of ~100 elements, the gain (timewise) is reaching 50%. It is >95% for domain length over 10 000 elements. The field mapping dictionary allows to avoid pre-filtering of domains when using filter_domain_leaf. In cases where it is used, the domain then just has to be browsed once in the filter_domain_leaf function. task-3299357 closes odoo/odoo#120834 Related: odoo/enterprise#40847 Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com>
60 lines
3.2 KiB
Python
60 lines
3.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo.tests.common import TransactionCase
|
|
from odoo.osv.expression import normalize_domain
|
|
from odoo.addons.resource.models import utils
|
|
|
|
|
|
class TestExpression(TransactionCase):
|
|
|
|
def test_filter_domain_leaf(self):
|
|
domains = [
|
|
['|', ('skills', '=', 1), ('admin', '=', True)],
|
|
['|', ('skills', '=', 1), ('admin', '=', True), '|', ('skills', '=', 2), ('admin', '=', True)],
|
|
['|', ('skills', '=', 1), ('skills', '=', 2), '|', ('skills', '=', 2), ('admin', '=', True)],
|
|
['|', '|', ('skills', '=', 1), ('skills', '=', True), '|', ('skills', '=', 2), ('admin', '=', True)],
|
|
['|', '|', ('admin', '=', 1), ('admin', '=', True), '&', ('skills', '=', 2), ('admin', '=', True)],
|
|
['|', '|', '!', ('admin', '=', 1), ('admin', '=', True), '!', '&', '!', ('skills', '=', 2), ('admin', '=', True)],
|
|
['&', '!', ('skills', '=', 2), ('admin', '=', True)],
|
|
[['start_datetime', '<=', '2022-12-17 22:59:59'], ['end_datetime', '>=', '2022-12-10 23:00:00']],
|
|
[('admin', '=', 1), ('admin', '=', 1), '|', ('admin', '=', 1), ('admin', '=', 1), ('skills', '=', 2)]
|
|
]
|
|
fields_to_remove = [['skills'], ['admin', 'skills']]
|
|
expected_results = []
|
|
expected_results.append([
|
|
normalize_domain([('admin', '=', True)]),
|
|
normalize_domain([('admin', '=', True), ('admin', '=', True)]),
|
|
normalize_domain([('admin', '=', True)]),
|
|
normalize_domain([('admin', '=', True)]),
|
|
normalize_domain(['|', '|', ('admin', '=', 1), ('admin', '=', True), ('admin', '=', True)]),
|
|
normalize_domain(['|', '|', '!', ('admin', '=', 1), ('admin', '=', True), '!', ('admin', '=', True)]),
|
|
normalize_domain([('admin', '=', True)]),
|
|
normalize_domain([['start_datetime', '<=', '2022-12-17 22:59:59'], ['end_datetime', '>=', '2022-12-10 23:00:00']]),
|
|
normalize_domain([('admin', '=', 1), ('admin', '=', 1), '|', ('admin', '=', 1), ('admin', '=', 1)])
|
|
])
|
|
expected_results.append([
|
|
normalize_domain([]),
|
|
normalize_domain([]),
|
|
normalize_domain([]),
|
|
normalize_domain([]),
|
|
normalize_domain([]),
|
|
normalize_domain([]),
|
|
normalize_domain([]),
|
|
normalize_domain([['start_datetime', '<=', '2022-12-17 22:59:59'], ['end_datetime', '>=', '2022-12-10 23:00:00']]),
|
|
normalize_domain([])
|
|
])
|
|
for idx, fields in enumerate(fields_to_remove):
|
|
results = [normalize_domain(utils.filter_domain_leaf(dom, lambda field: field not in fields)) for dom in domains]
|
|
self.assertEqual(results, expected_results[idx])
|
|
|
|
# Testing field mapping 1
|
|
self.assertEqual(
|
|
['&', '!', ('field3', '=', False), ('field3', '!=', 'test')],
|
|
normalize_domain(utils.filter_domain_leaf(
|
|
['|', ('field1', 'in', [1, 2]), '!', ('field2', '=', False), ('field3', '!=', 'test')],
|
|
lambda field: field == 'field3',
|
|
field_name_mapping={'field2': 'field3'},
|
|
))
|
|
)
|