[IMP] core: remove parameter 'extra' from Query.join() and Query.left_join()

Part-of: odoo/odoo#134677
This commit is contained in:
Raphael Collet
2023-09-27 03:01:45 +00:00
parent 66a0cdd637
commit 758780c03b
3 changed files with 52 additions and 70 deletions
+29 -18
View File
@@ -10,7 +10,7 @@ from collections import defaultdict
from odoo import _, api, Command, fields, models, modules, tools
from odoo.exceptions import AccessError
from odoo.osv import expression
from odoo.tools.misc import clean_context, groupby as tools_groupby
from odoo.tools import clean_context, groupby as tools_groupby, SQL
_logger = logging.getLogger(__name__)
_image_dataurl = re.compile(r'(data:image/[a-z]+?);base64,([a-z0-9+/\n]{3,}=*)\n*([\'"])(?: data-filename="([^"]*)")?', re.I)
@@ -294,23 +294,34 @@ class Message(models.Model):
allowed_ids = set()
model_ids = defaultdict(lambda: defaultdict(set))
rel_alias = query.left_join(
self._table, 'id', 'mail_message_res_partner_rel', 'mail_message_id', 'partner_ids',
'{rhs}.res_partner_id = %s', [pid],
)
notif_alias = query.left_join(
self._table, 'id', 'mail_notification', 'mail_message_id', 'notification_ids',
'{rhs}.res_partner_id = %s', [pid],
)
query_str, params = query.select(
f'"{self._table}"."id"',
f'"{self._table}"."model"',
f'"{self._table}"."res_id"',
f'"{self._table}"."author_id"',
f'"{self._table}"."message_type"',
f'COALESCE("{rel_alias}"."res_partner_id", "{notif_alias}"."res_partner_id")',
)
self.env.cr.execute(query_str, params)
rel_alias = query.make_alias(self._table, 'partner_ids')
query.add_join("LEFT JOIN", rel_alias, 'mail_message_res_partner_rel', SQL(
"%s = %s AND %s = %s",
SQL.identifier(self._table, 'id'),
SQL.identifier(rel_alias, 'mail_message_id'),
SQL.identifier(rel_alias, 'res_partner_id'),
pid,
))
notif_alias = query.make_alias(self._table, 'notification_ids')
query.add_join("LEFT JOIN", notif_alias, 'mail_notification', SQL(
"%s = %s AND %s = %s",
SQL.identifier(self._table, 'id'),
SQL.identifier(notif_alias, 'mail_message_id'),
SQL.identifier(notif_alias, 'res_partner_id'),
pid,
))
self.env.cr.execute(query.select(
SQL.identifier(self._table, 'id'),
SQL.identifier(self._table, 'model'),
SQL.identifier(self._table, 'res_id'),
SQL.identifier(self._table, 'author_id'),
SQL.identifier(self._table, 'message_type'),
SQL(
"COALESCE(%s, %s)",
SQL.identifier(rel_alias, 'res_partner_id'),
SQL.identifier(notif_alias, 'res_partner_id'),
),
))
for id_, model, res_id, author_id, message_type, partner_id in self.env.cr.fetchall():
ids.append(id_)
if author_id == pid:
+13 -8
View File
@@ -2780,18 +2780,23 @@ class BaseModel(metaclass=MetaModel):
comodel = self.env[field.comodel_name]
subquery = Query(self.env.cr, comodel._table)
comodel._apply_ir_rules(subquery)
# add the extra join condition only if there is an actual subquery
extra, extra_params = None, ()
if subquery.where_clause:
subquery_str, extra_params = subquery.select()
extra = '"{rhs}"."%s" IN (%s)' % (field.column2, subquery_str)
# LEFT JOIN field_relation ON
# alias.id = field_relation.field_column1
# AND field_relation.field_column2 IN (subquery)
rel_alias = query.left_join(
alias, 'id', field.relation, field.column1, field.name,
extra=extra, extra_params=extra_params,
rel_alias = query.make_alias(alias, field.name)
condition = SQL(
"%s = %s",
SQL.identifier(alias, 'id'),
SQL.identifier(rel_alias, field.column1),
)
if subquery.where_clause:
condition = SQL(
"%s AND %s IN %s",
condition,
SQL.identifier(rel_alias, field.column2),
subquery.subselect(),
)
query.add_join("LEFT JOIN", rel_alias, field.relation, condition)
return '"%s"."%s"' % (rel_alias, field.column2)
elif field.translate and not self.env.context.get('prefetch_langs'):
lang = self.env.lang or 'en_US'
+10 -44
View File
@@ -110,10 +110,11 @@ class Query(object):
self._where_clauses.append(SQL(where_clause, *where_params))
self._ids = None
def join(self, lhs_alias, lhs_column, rhs_table, rhs_column, link, extra=None, extra_params=()):
def join(self, lhs_alias: str, lhs_column: str, rhs_table: str, rhs_column: str, link: str):
"""
Perform a join between a table already present in the current Query object and
another table.
another table. This method is essentially a shortcut for methods :meth:`~.make_alias`
and :meth:`~.add_join`.
:param str lhs_alias: alias of a table already defined in the current Query object.
:param str lhs_column: column of `lhs_alias` to be used for the join's ON condition.
@@ -121,59 +122,24 @@ class Query(object):
:param str rhs_column: column of `rhs_alias` to be used for the join's ON condition.
:param str link: used to generate the alias for the joined table, this string should
represent the relationship (the link) between both tables.
:param str extra: an sql string of a predicate or series of predicates to append to the
join's ON condition, `lhs_alias` and `rhs_alias` can be injected if the string uses
the `lhs` and `rhs` variables with the `str.format` syntax. e.g.::
query.join(..., extra="{lhs}.name != {rhs}.name OR ...", ...)
:param tuple extra_params: a tuple of values to be interpolated into `extra`, this is
done by psycopg2.
Full example:
>>> rhs_alias = query.join(
... "res_users",
... "partner_id",
... "res_partner",
... "id",
... "partner_id", # partner_id is the "link" from res_users to res_partner
... "{lhs}.\"name\" != %s",
... ("Mitchell Admin",),
... )
>>> rhs_alias
res_users_res_partner__partner_id
From the example above, the resulting query would be something like::
SELECT ...
FROM "res_users" AS "res_users"
JOIN "res_partner" AS "res_users_res_partner__partner_id"
ON "res_users"."partner_id" = "res_users_res_partner__partner_id"."id"
AND "res_users"."name" != 'Mitchell Admin'
WHERE ...
"""
return self._join('JOIN', lhs_alias, lhs_column, rhs_table, rhs_column, link, extra, extra_params)
assert lhs_alias in self._tables or lhs_alias in self._joins, "Alias %r not in %s" % (lhs_alias, str(self))
rhs_alias = self.make_alias(lhs_alias, link)
condition = SQL("%s = %s", SQL.identifier(lhs_alias, lhs_column), SQL.identifier(rhs_alias, rhs_column))
self.add_join('JOIN', rhs_alias, rhs_table, condition)
return rhs_alias
def left_join(self, lhs_alias, lhs_column, rhs_table, rhs_column, link, extra=None, extra_params=()):
def left_join(self, lhs_alias: str, lhs_column: str, rhs_table: str, rhs_column: str, link: str):
""" Add a LEFT JOIN to the current table (if necessary), and return the
alias corresponding to ``rhs_table``.
See the documentation of :meth:`join` for a better overview of the
arguments and what they do.
"""
return self._join('LEFT JOIN', lhs_alias, lhs_column, rhs_table, rhs_column, link, extra, extra_params)
def _join(self, kind, lhs_alias, lhs_column, rhs_table, rhs_column, link, extra=None, extra_params=()):
assert lhs_alias in self._tables or lhs_alias in self._joins, "Alias %r not in %s" % (lhs_alias, str(self))
rhs_alias = self.make_alias(lhs_alias, link)
condition = SQL("%s = %s", SQL.identifier(lhs_alias, lhs_column), SQL.identifier(rhs_alias, rhs_column))
if extra:
extra = SQL(extra, *extra_params)
extra = SQL(extra.code.format(lhs=lhs_alias, rhs=rhs_alias), *extra.params)
condition = SQL("%s AND %s", condition, extra)
self.add_join(kind, rhs_alias, rhs_table, condition)
self.add_join('LEFT JOIN', rhs_alias, rhs_table, condition)
return rhs_alias
@property