[FIX] core: '=like'/'like' doesn't use unaccent anymore
The `=like`/`like` domain operators are accent-insensitive, but still
case-sensitive. This is not really coherent, since `unaccent` is a best
effort to find records from the client, and it is the same idea behind
being case-insensitive. Also, `=like`/`like` cannot be used from the web
client, and we use them in domain to search from the Python side.
Moreover, adding `unaccent` to `=like` can be very inefficient when
searching for a prefix ('prefix%'). In fact, PostgreSQL can use btree
index to find prefix matches, but because we create dy default btree
index without unaccent (when we put
`index=True/'btree'/'btree_not_null'` on the field), PostgreSQL cannot
use this index.
Part-of: odoo/odoo#136007
This commit is contained in:
@@ -728,9 +728,17 @@ class TestExpression(SavepointCaseWithUserDemo):
|
||||
helen = Model.create({'name': 'Hélène'})
|
||||
self.assertEqual(helen, Model.search([('name', 'ilike', 'Helene')]))
|
||||
self.assertEqual(helen, Model.search([('name', 'ilike', 'hélène')]))
|
||||
self.assertEqual(helen, Model.search([('name', '=ilike', 'Hel%')]))
|
||||
self.assertEqual(helen, Model.search([('name', '=ilike', 'hél%')]))
|
||||
self.assertNotIn(helen, Model.search([('name', 'not ilike', 'Helene')]))
|
||||
self.assertNotIn(helen, Model.search([('name', 'not ilike', 'hélène')]))
|
||||
|
||||
# =like and like should be case and accent sensitive
|
||||
self.assertEqual(helen, Model.search([('name', '=like', 'Hél%')]))
|
||||
self.assertNotIn(helen, Model.search([('name', '=like', 'Hel%')]))
|
||||
self.assertEqual(helen, Model.search([('name', 'like', 'élè')]))
|
||||
self.assertNotIn(helen, Model.search([('name', 'like', 'ele')]))
|
||||
|
||||
hermione, nicostratus = Model.create([
|
||||
{'name': 'Hermione', 'parent_id': helen.id},
|
||||
{'name': 'Nicostratus', 'parent_id': helen.id}
|
||||
|
||||
@@ -1036,7 +1036,7 @@ class expression(object):
|
||||
push_result(expr, [right])
|
||||
|
||||
else:
|
||||
if 'like' in operator:
|
||||
if operator in ('like', 'ilike', 'not like', 'not ilike'):
|
||||
right = f'%{pycompat.to_text(right)}%'
|
||||
unaccent = self._unaccent(field)
|
||||
else:
|
||||
@@ -1372,7 +1372,7 @@ class expression(object):
|
||||
expr += f"{_left} {_sql_operator} {_unaccent('%s')} AND "
|
||||
params.append(_right)
|
||||
|
||||
unaccent = self._unaccent(field) if sql_operator.endswith('like') else lambda x: x
|
||||
unaccent = self._unaccent(field) if sql_operator.endswith('ilike') else lambda x: x
|
||||
lang = model.env.lang or 'en_US'
|
||||
if lang == 'en_US':
|
||||
left = unaccent(f""""{alias}"."{field.name}"->>'en_US'""")
|
||||
@@ -1520,7 +1520,7 @@ class expression(object):
|
||||
sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator)
|
||||
cast = '::text' if sql_operator.endswith('like') else ''
|
||||
|
||||
unaccent = self._unaccent(field) if sql_operator.endswith('like') else lambda x: x
|
||||
unaccent = self._unaccent(field) if sql_operator.endswith('ilike') else lambda x: x
|
||||
column = '%s.%s' % (table_alias, _quote(left))
|
||||
query = f'({unaccent(column + cast)} {sql_operator} {unaccent("%s")})'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user