[IMP] core: improve search count with a limit
The new feature (search count with limit) introduced by https://github.com/odoo/odoo/pull/95589 lacks of test and code readability: - Add tests to check the result and query generate - Increase the readability of SQL/python code. - Change a little bit the SQL request generate: in the subquery, change `SELECT 1 FROM...` into `SELECT FROM` which avoid extra work in the postgreSQL side. task-2761165 closes odoo/odoo#95641 Signed-off-by: Raphael Collet <rco@odoo.com>
This commit is contained in:
@@ -1144,12 +1144,25 @@ class TestQueries(TransactionCase):
|
||||
Model.search([('name', 'like', 'foo')])
|
||||
|
||||
with self.assertQueries(['''
|
||||
SELECT count(*)
|
||||
SELECT COUNT(*)
|
||||
FROM "res_partner"
|
||||
WHERE (("res_partner"."active" = %s) AND ("res_partner"."name"::text LIKE %s))
|
||||
''']):
|
||||
Model.search_count([('name', 'like', 'foo')])
|
||||
|
||||
def test_count_limit(self):
|
||||
Model = self.env['res.partner']
|
||||
Model.search([('name', 'like', 'foo')])
|
||||
|
||||
with self.assertQueries(['''
|
||||
SELECT COUNT(*) FROM (
|
||||
SELECT FROM "res_partner"
|
||||
WHERE (("res_partner"."active" = %s) AND ("res_partner"."name"::text LIKE %s))
|
||||
LIMIT 1
|
||||
) t
|
||||
''']):
|
||||
Model.search_count([('name', 'like', 'foo')], limit=1)
|
||||
|
||||
def test_translated_field(self):
|
||||
self.env['res.lang']._activate_lang('fr_FR')
|
||||
Model = self.env['res.partner.title'].with_context(lang='fr_FR')
|
||||
|
||||
@@ -192,3 +192,18 @@ class test_search(TransactionCase):
|
||||
})
|
||||
cc_search = model_bank.search([('name', '=', 'Crédit Communal')])
|
||||
self.assertNotIn(bank_credit_communal, cc_search, "Search for inactive record with x_active set to True has failed")
|
||||
|
||||
def test_21_search_count(self):
|
||||
Partner = self.env['res.partner']
|
||||
count_partner_before = Partner.search_count([])
|
||||
partners = Partner.create([
|
||||
{'name': 'abc'},
|
||||
{'name': 'zer'},
|
||||
{'name': 'christope'},
|
||||
{'name': 'runbot'},
|
||||
])
|
||||
self.assertEqual(len(partners) + count_partner_before, Partner.search_count([]))
|
||||
self.assertEqual(len(partners) + count_partner_before, Partner.search([], count=True))
|
||||
|
||||
self.assertEqual(3, Partner.search_count([], limit=3))
|
||||
self.assertEqual(3, Partner.search([], count=True, limit=3))
|
||||
|
||||
+13
-5
@@ -1872,6 +1872,10 @@ class BaseModel(metaclass=MetaModel):
|
||||
|
||||
Returns the number of records in the current model matching :ref:`the
|
||||
provided domain <reference/orm/domains>`.
|
||||
|
||||
:param domain: :ref:`A search domain <reference/orm/domains>`. Use an empty
|
||||
list to match all records.
|
||||
:param limit: maximum number of record to count (upperbound) (default: all)
|
||||
"""
|
||||
res = self.search(domain, limit=limit, count=True)
|
||||
return res if isinstance(res, int) else len(res)
|
||||
@@ -4888,14 +4892,18 @@ class BaseModel(metaclass=MetaModel):
|
||||
query.limit = limit
|
||||
|
||||
if count:
|
||||
# Ignore order, limit and offset when just counting, they don't make sense and could
|
||||
# Ignore order and offset when just counting, they don't make sense and could
|
||||
# hurt performance
|
||||
query_str, params = query.select(limit and "1" or "count(*)")
|
||||
if limit:
|
||||
query_str = "select count(*) from (" + query_str + ") t"
|
||||
# Special case to avoid counting every record in DB (which can be really slow).
|
||||
# The result will be between 0 and limit.
|
||||
query_str, params = query.select("") # generates a `SELECT FROM` (faster)
|
||||
query_str = f"SELECT COUNT(*) FROM ({query_str}) t"
|
||||
else:
|
||||
query_str, params = query.select("COUNT(*)")
|
||||
|
||||
self._cr.execute(query_str, params)
|
||||
res = self._cr.fetchone()
|
||||
return res[0]
|
||||
return self._cr.fetchone()[0]
|
||||
|
||||
query.order = self._generate_order_by(order, query).replace('ORDER BY ', '')
|
||||
query.offset = offset
|
||||
|
||||
Reference in New Issue
Block a user