summaryrefslogtreecommitdiff
path: root/odoo/osv/expression.py
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2020-06-17 16:48:00 +0000
committerRaphael Collet <rco@odoo.com>2020-08-18 13:02:41 +0000
commit0f7f163d2e2bb9cc38f2b037dae6df2eae9466a4 (patch)
treefeacbae81dfd362e6493c41280a80604a215a649 /odoo/osv/expression.py
parent6f87bbbfc8e34b412fe9c129c002269540fa5a30 (diff)
[REF] core: improve the API and implementation of Query
Introduce better methods for introducing tables, join clauses and where clauses to the Query object, and other methods to generate a complete SELECT query. The Query object can also behave as a tuple of ids, where the query is made on demand, and the result is memoized.
Diffstat (limited to 'odoo/osv/expression.py')
-rw-r--r--odoo/osv/expression.py70
1 files changed, 7 insertions, 63 deletions
diff --git a/odoo/osv/expression.py b/odoo/osv/expression.py
index 90dd394537c..e5733164567 100644
--- a/odoo/osv/expression.py
+++ b/odoo/osv/expression.py
@@ -119,7 +119,6 @@ import warnings
import logging
import traceback
from functools import partial
-from zlib import crc32
from datetime import date, datetime, time
import odoo.modules
@@ -339,55 +338,6 @@ def _quote(to_quote):
return to_quote
-def generate_table_alias(src_table_alias, joined_tables=[]):
- """ Generate a standard table alias name. An alias is generated as following:
- - the base is the source table name (that can already be an alias)
- - then, each joined table is added in the alias using a 'link field name'
- that is used to render unique aliases for a given path
- - returns a tuple composed of the alias, and the full table alias to be
- added in a from condition with quoting done
- Examples:
- - src_table_alias='res_users', join_tables=[]:
- alias = ('res_users','"res_users"')
- - src_model='res_users', join_tables=[(res.partner, 'parent_id')]
- alias = ('res_users__parent_id', '"res_partner" as "res_users__parent_id"')
-
- :param model src_table_alias: model source of the alias
- :param list joined_tables: list of tuples
- (dst_model, link_field)
-
- :return tuple: (table_alias, alias statement for from clause with quotes added)
- """
- alias = src_table_alias
- if not joined_tables:
- return '%s' % alias, '%s' % _quote(alias)
- for link in joined_tables:
- alias += '__' + link[1]
- # Use an alternate alias scheme if length exceeds the PostgreSQL limit
- # of 63 characters.
- if len(alias) >= 64:
- # We have to fit a crc32 hash and one underscore
- # into a 63 character alias. The remaining space we can use to add
- # a human readable prefix.
- alias_hash = hex(crc32(alias.encode('utf-8')))[2:]
- ALIAS_PREFIX_LENGTH = 63 - len(alias_hash) - 1
- alias = "%s_%s" % (
- alias[:ALIAS_PREFIX_LENGTH], alias_hash)
- return '%s' % alias, '%s as %s' % (_quote(joined_tables[-1][0]), _quote(alias))
-
-
-def get_alias_from_query(from_query):
- """ :param string from_query: is something like :
- - '"res_partner"' OR
- - '"res_partner" as "res_users__partner_id"''
- """
- from_splitted = from_query.split(' as ')
- if len(from_splitted) > 1:
- return from_splitted[0].replace('"', ''), from_splitted[1].replace('"', '')
- else:
- return from_splitted[0].replace('"', ''), from_splitted[0].replace('"', '')
-
-
def normalize_leaf(element):
""" Change a term's operator to some canonical form, simplifying later
processing. """
@@ -482,7 +432,7 @@ class expression(object):
self.expression = distribute_not(normalize_domain(domain))
# this object handles all the joins
- self.query = Query(['"%s"' % model._table]) if query is None else query
+ self.query = Query(model.env.cr, model._table) if query is None else query
# parse the domain expression
self.parse()
@@ -692,9 +642,8 @@ class expression(object):
elif field.inherited:
parent_model = model.env[field.related_field.model_name]
parent_fname = model._inherits[parent_model._name]
- parent_alias, _ = self.query.add_join(
- (alias, parent_model._table, parent_fname, 'id', parent_fname),
- implicit=False, outer=True,
+ parent_alias = self.query.left_join(
+ alias, parent_fname, parent_model._table, 'id', parent_fname,
)
push(leaf, parent_model, parent_alias)
@@ -719,9 +668,8 @@ class expression(object):
elif len(path) > 1 and field.store and field.type == 'many2one' and field.auto_join:
# res_partner.state_id = res_partner__state_id.id
- coalias, _ = self.query.add_join(
- (alias, comodel._table, path[0], 'id', path[0]),
- implicit=False, outer=True,
+ coalias = self.query.left_join(
+ alias, path[0], comodel._table, 'id', path[0],
)
push((path[1], operator, right), comodel, coalias)
@@ -729,10 +677,7 @@ class expression(object):
# use a subquery bypassing access rules and business logic
domain = [(path[1], operator, right)] + field.get_domain_list(model)
query = comodel.with_context(**field.context)._where_calc(domain)
- subfrom, subwhere, subparams = query.get_sql()
- subquery = 'SELECT "{}"."{}" FROM {} WHERE {}'.format(
- comodel._table, field.inverse_name, subfrom, subwhere,
- )
+ subquery, subparams = query.select('"%s"."%s"' % (comodel._table, field.inverse_name))
push(('id', 'inselect', (subquery, subparams)), model, alias, internal=True)
elif len(path) > 1 and field.store and field.auto_join:
@@ -968,8 +913,7 @@ class expression(object):
[self.result] = result_stack
where_clause, where_params = self.result
- self.query.where_clause.append(where_clause)
- self.query.where_clause_params.extend(where_params)
+ self.query.add_where(where_clause, where_params)
def __leaf_to_sql(self, leaf, model, alias):
left, operator, right = leaf