Use tables and Model as arguments for sql_column of the Field
This commit is contained in:
@@ -547,7 +547,7 @@ class Payment(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
def order_amount(cls, tables):
|
||||
table, _ = tables[None]
|
||||
context = Transaction().context
|
||||
column = cls.amount.sql_column(table)
|
||||
column = cls.amount.sql_column(tables, cls)
|
||||
if isinstance(context.get('amount_order'), Decimal):
|
||||
return [Abs(column - abs(context['amount_order']))]
|
||||
else:
|
||||
|
||||
@@ -245,7 +245,7 @@ class AccountNumber(DeactivableMixin, sequence_ordered(), ModelSQL, ModelView):
|
||||
Operator = fields.SQL_OPERATORS[operator]
|
||||
result = None
|
||||
for field in (cls.number, cls.number_compact):
|
||||
column = field.sql_column(table)
|
||||
column = field.sql_column(tables, cls)
|
||||
expression = Operator(column, field._domain_value(operator, value))
|
||||
if isinstance(expression, operators.In) and not expression.right:
|
||||
expression = Literal(False)
|
||||
|
||||
@@ -437,7 +437,7 @@ class Subdivision(DeactivableMixin, ModelSQL, ModelView):
|
||||
|
||||
_, op, value = domain
|
||||
Operator = fields.SQL_OPERATORS[op]
|
||||
column = cls.code.sql_column(table)
|
||||
column = cls.code.sql_column(tables, cls)
|
||||
if op.endswith('like'):
|
||||
if op.endswith('ilike') and cls.code.search_unaccented:
|
||||
database = Transaction().database
|
||||
|
||||
@@ -61,8 +61,8 @@ class Move(metaclass=PoolMeta):
|
||||
field = cls.fifo_quantity_available._field
|
||||
Operator = fields.SQL_OPERATORS[operator]
|
||||
column = (
|
||||
cls.quantity.sql_column(table)
|
||||
- cls.fifo_quantity.sql_column(table))
|
||||
cls.quantity.sql_column(tables, cls)
|
||||
- cls.fifo_quantity.sql_column(tables, cls))
|
||||
expression = Operator(column, field._domain_value(operator, value))
|
||||
if isinstance(expression, operators.In) and not expression.right:
|
||||
expression = Literal(False)
|
||||
|
||||
@@ -42,7 +42,7 @@ class Geometry(fields.Field):
|
||||
|
||||
assert operator in GEOGRAPHIC_OPERATORS
|
||||
|
||||
column = self.sql_column(table)
|
||||
column = self.sql_column(tables, Model)
|
||||
|
||||
if operator in {'=', '!='} and value is Null:
|
||||
Operator = SQL_OPERATORS[operator]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
* Use tables and Model as arguments for sql_column of the Field
|
||||
* Add support for basic authentication for user application
|
||||
* Support the conversion of MJML reports to HTML
|
||||
* Allow filtering users to be notified by cron tasks
|
||||
|
||||
@@ -191,9 +191,10 @@ Instance methods:
|
||||
|
||||
Return the SQL expression with cast with the type of the field.
|
||||
|
||||
.. method:: Field.sql_column(table)
|
||||
.. method:: Field.sql_column(tables, Model)
|
||||
|
||||
Return the Column instance based on table.
|
||||
Return the Column or SQL expression instance for the field.
|
||||
:ref:`tables <ref-tables>` could be updated to add new joins.
|
||||
|
||||
.. method:: Field.set_rpc(model)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import string
|
||||
import warnings
|
||||
|
||||
from sql import Expression, Query
|
||||
from sql import Column, Expression, Query
|
||||
from sql.conditionals import Coalesce, NullIf
|
||||
from sql.functions import Trim
|
||||
from sql.operators import Not
|
||||
@@ -143,10 +143,10 @@ class Char(FieldTranslate):
|
||||
language = transaction.language
|
||||
model, join, column = self._get_translation_column(
|
||||
Model, name)
|
||||
column = Coalesce(NullIf(column, ''), self.sql_column(model))
|
||||
column = Coalesce(NullIf(column, ''), Column(model, self.name))
|
||||
else:
|
||||
language = None
|
||||
column = self.sql_column(table)
|
||||
column = self.sql_column(tables, Model)
|
||||
column = self._domain_column(operator, column)
|
||||
|
||||
threshold = context.get(
|
||||
@@ -207,7 +207,7 @@ class Char(FieldTranslate):
|
||||
column = self._get_translation_order(tables, Model, name)
|
||||
else:
|
||||
language = None
|
||||
column = self.sql_column(table)
|
||||
column = self.sql_column(tables, Model)
|
||||
column = self._domain_column('ilike', column)
|
||||
if database.has_similarity():
|
||||
sim_value = unescape_wildcard(value)
|
||||
|
||||
@@ -119,10 +119,9 @@ class Dict(Field):
|
||||
if '.' not in name:
|
||||
return super().convert_domain(domain, tables, Model)
|
||||
database = Transaction().database
|
||||
table, _ = tables[None]
|
||||
name, key = name.split('.', 1)
|
||||
Operator = SQL_OPERATORS[operator]
|
||||
raw_column = self.sql_column(table)
|
||||
raw_column = self.sql_column(tables, Model)
|
||||
column = self._domain_column(operator, raw_column, key)
|
||||
expression = Operator(column, self._domain_value(operator, value))
|
||||
if operator in {'=', '!='}:
|
||||
@@ -171,8 +170,7 @@ class Dict(Field):
|
||||
if not key:
|
||||
return super().convert_order(fname, tables, Model)
|
||||
database = Transaction().database
|
||||
table, _ = tables[None]
|
||||
column = self.sql_column(table)
|
||||
column = self.sql_column(tables, Model)
|
||||
return [database.json_get(column, key)]
|
||||
|
||||
def definition(self, model, language):
|
||||
|
||||
@@ -421,7 +421,8 @@ class Field(object):
|
||||
def sql_cast(self, expression):
|
||||
return Cast(expression, self.sql_type().base)
|
||||
|
||||
def sql_column(self, table):
|
||||
def sql_column(self, tables, Model):
|
||||
table, _ = tables[None]
|
||||
return Column(table, self.name)
|
||||
|
||||
def _domain_column(self, operator, column):
|
||||
@@ -451,7 +452,7 @@ class Field(object):
|
||||
table, _ = tables[None]
|
||||
name, operator, value = domain
|
||||
Operator = SQL_OPERATORS[operator]
|
||||
column = self.sql_column(table)
|
||||
column = self.sql_column(tables, Model)
|
||||
column = self._domain_column(operator, column)
|
||||
expression = Operator(column, self._domain_value(operator, value))
|
||||
if isinstance(expression, operators.In) and not expression.right:
|
||||
@@ -464,8 +465,7 @@ class Field(object):
|
||||
@order_method
|
||||
def convert_order(self, name, tables, Model):
|
||||
"Return a SQL expression to order"
|
||||
table, _ = tables[None]
|
||||
return [self.sql_column(table)]
|
||||
return [self.sql_column(tables, Model)]
|
||||
|
||||
def set_rpc(self, model):
|
||||
for attribute, decorator, result in (
|
||||
@@ -680,7 +680,7 @@ class FieldTranslate(Field):
|
||||
table, _ = tables[None]
|
||||
name, operator, value = domain
|
||||
model, join, column = self._get_translation_column(Model, name)
|
||||
column = Coalesce(NullIf(column, ''), self.sql_column(model))
|
||||
column = Coalesce(NullIf(column, ''), Column(model, self.name))
|
||||
column = self._domain_column(operator, column)
|
||||
Operator = SQL_OPERATORS[operator]
|
||||
assert name == self.name
|
||||
@@ -731,9 +731,9 @@ class FieldTranslate(Field):
|
||||
if not self.translate:
|
||||
return super().convert_order(name, tables, Model)
|
||||
assert name == self.name
|
||||
table, _ = tables[None]
|
||||
column = self._get_translation_order(tables, Model, name)
|
||||
return [Coalesce(NullIf(column, ''), self.sql_column(table))]
|
||||
return [
|
||||
Coalesce(NullIf(column, ''), self.sql_column(tables, Model))]
|
||||
|
||||
def definition(self, model, language):
|
||||
definition = super().definition(model, language)
|
||||
|
||||
@@ -384,14 +384,19 @@ class Many2Many(Field):
|
||||
else:
|
||||
relation = Relation.__table__()
|
||||
history_where = None
|
||||
relation_tables = {
|
||||
None: (relation, None),
|
||||
}
|
||||
origin_field = Relation._fields[self.origin]
|
||||
origin = getattr(Relation, self.origin).sql_column(relation)
|
||||
origin = getattr(Relation, self.origin).sql_column(
|
||||
relation_tables, Relation)
|
||||
origin_where = None
|
||||
if origin_field._type == 'reference':
|
||||
origin_where = origin.like(Model.__name__ + ',%')
|
||||
origin = origin_field.sql_id(origin, Relation)
|
||||
|
||||
target = getattr(Relation, self.target).sql_column(relation)
|
||||
target = getattr(Relation, self.target).sql_column(
|
||||
relation_tables, Relation)
|
||||
if '.' not in name:
|
||||
if operator.endswith('child_of') or operator.endswith('parent_of'):
|
||||
if Target != Model:
|
||||
@@ -481,9 +486,6 @@ class Many2Many(Field):
|
||||
relation_domain,
|
||||
(self.target, 'where', self.filter),
|
||||
]
|
||||
relation_tables = {
|
||||
None: (relation, None),
|
||||
}
|
||||
tables, expression = Relation.search_domain(
|
||||
relation_domain, tables=relation_tables)
|
||||
query_table = convert_from(None, relation_tables)
|
||||
|
||||
@@ -133,7 +133,7 @@ class Many2One(Field):
|
||||
name, operator, ids = domain
|
||||
red_sql = reduce_ids(table.id, (i for i in ids if i is not None))
|
||||
Target = self.get_target()
|
||||
path_column = getattr(Target, self.path).sql_column(table)
|
||||
path_column = getattr(Target, self.path).sql_column(tables, Target)
|
||||
path_column = Coalesce(path_column, '')
|
||||
cursor.execute(*table.select(
|
||||
path_column, where=red_sql,
|
||||
@@ -165,8 +165,8 @@ class Many2One(Field):
|
||||
name, operator, ids = domain
|
||||
red_sql = reduce_ids(table.id, (i for i in ids if i is not None))
|
||||
Target = self.get_target()
|
||||
left = getattr(Target, self.left).sql_column(table)
|
||||
right = getattr(Target, self.right).sql_column(table)
|
||||
left = getattr(Target, self.left).sql_column(tables, Target)
|
||||
right = getattr(Target, self.right).sql_column(tables, Target)
|
||||
cursor.execute(*table.select(
|
||||
left, right, where=red_sql,
|
||||
order_by=[(right - left).asc, left.asc]))
|
||||
@@ -228,7 +228,7 @@ class Many2One(Field):
|
||||
|
||||
table, _ = tables[None]
|
||||
name, operator, value = domain[:3]
|
||||
column = self.sql_column(table)
|
||||
column = self.sql_column(tables, Model)
|
||||
if '.' not in name:
|
||||
if operator.endswith('child_of') or operator.endswith('parent_of'):
|
||||
if Target != Model:
|
||||
@@ -307,7 +307,7 @@ class Many2One(Field):
|
||||
expression = column.in_(query)
|
||||
else:
|
||||
target_domain = [target_domain, rule_domain]
|
||||
target_tables = self._get_target_tables(tables)
|
||||
target_tables = self._get_target_tables(tables, Model)
|
||||
target_table, _ = target_tables[None]
|
||||
_, expression = Target.search_domain(
|
||||
target_domain, tables=target_tables)
|
||||
@@ -338,13 +338,13 @@ class Many2One(Field):
|
||||
|
||||
table, _ = tables[None]
|
||||
if oname == 'id':
|
||||
return [self.sql_column(table)]
|
||||
return [self.sql_column(tables, Model)]
|
||||
|
||||
ofield = Target._fields[oname]
|
||||
target_tables = self._get_target_tables(tables)
|
||||
target_tables = self._get_target_tables(tables, Model)
|
||||
return ofield.convert_order(oexpr, target_tables, Target)
|
||||
|
||||
def _get_target_tables(self, tables):
|
||||
def _get_target_tables(self, tables, Model):
|
||||
Target = self.get_target()
|
||||
table, _ = tables[None]
|
||||
target_tables = tables.get(self.name)
|
||||
@@ -364,7 +364,7 @@ class Many2One(Field):
|
||||
else:
|
||||
target = Target.__table__()
|
||||
history_condition = None
|
||||
condition = target.id == self.sql_column(table)
|
||||
condition = target.id == self.sql_column(tables, Model)
|
||||
if history_condition:
|
||||
condition &= history_condition
|
||||
target_tables = {
|
||||
|
||||
@@ -90,8 +90,7 @@ class MultiSelection(SelectionMixin, Field):
|
||||
if operator not in {'in', 'not in'}:
|
||||
return super().convert_domain(domain, tables, Model)
|
||||
database = Transaction().database
|
||||
table, _ = tables[None]
|
||||
raw_column = self.sql_column(table)
|
||||
raw_column = self.sql_column(tables, Model)
|
||||
if value is None:
|
||||
expression = Literal(False)
|
||||
elif isinstance(value, str):
|
||||
|
||||
@@ -338,8 +338,11 @@ class One2Many(Field):
|
||||
else:
|
||||
target = Target.__table__()
|
||||
history_where = None
|
||||
target_tables = {
|
||||
None: (target, None),
|
||||
}
|
||||
origin_field = Target._fields[self.field]
|
||||
origin = getattr(Target, self.field).sql_column(target)
|
||||
origin = getattr(Target, self.field).sql_column(target_tables, Target)
|
||||
origin_where = None
|
||||
if origin_field._type == 'reference':
|
||||
origin_where = origin.like(Model.__name__ + ',%')
|
||||
@@ -408,9 +411,6 @@ class One2Many(Field):
|
||||
target_domain = [target_domain, rule_domain]
|
||||
if self.filter:
|
||||
target_domain = [target_domain, self.filter]
|
||||
target_tables = {
|
||||
None: (target, None),
|
||||
}
|
||||
tables, expression = Target.search_domain(
|
||||
target_domain, tables=target_tables)
|
||||
query_table = convert_from(None, target_tables)
|
||||
|
||||
@@ -204,10 +204,9 @@ class Reference(SelectionMixin, Field):
|
||||
pool = Pool()
|
||||
name, operator, value, target = domain[:4]
|
||||
Target = pool.get(target)
|
||||
table, _ = tables[None]
|
||||
name, target_name = name.split('.', 1)
|
||||
assert name == self.name
|
||||
column = self.sql_column(table)
|
||||
column = self.sql_column(tables, Model)
|
||||
target_domain = [(target_name,) + tuple(domain[1:3])
|
||||
+ tuple(domain[4:])]
|
||||
if 'active' in Target._fields:
|
||||
|
||||
@@ -146,14 +146,13 @@ class Selection(SelectionMixin, Field):
|
||||
|
||||
@order_method
|
||||
def convert_order(self, name, tables, Model):
|
||||
table, _ = tables[None]
|
||||
selections = Model.fields_get([name])[name]['selection']
|
||||
if not isinstance(selections, (tuple, list)):
|
||||
if not is_instance_method(Model, selections):
|
||||
selections = getattr(Model, selections)()
|
||||
else:
|
||||
selections = []
|
||||
column = self.sql_column(table)
|
||||
column = self.sql_column(tables, Model)
|
||||
if not self.sort:
|
||||
else_ = len(selections) + 1
|
||||
selections = ((k, i) for i, (k, v) in enumerate(selections))
|
||||
|
||||
@@ -54,7 +54,7 @@ class FullText(Field):
|
||||
table, _ = tables[None]
|
||||
name, operator, value = domain
|
||||
assert name == self.name
|
||||
column = self.sql_column(table)
|
||||
column = self.sql_column(tables, Model)
|
||||
column = self._domain_column(operator, column)
|
||||
if operator.endswith('like'):
|
||||
if database.has_search_full_text():
|
||||
@@ -81,8 +81,7 @@ class FullText(Field):
|
||||
|
||||
@order_method
|
||||
def convert_order(self, name, tables, Model):
|
||||
table, _ = tables[None]
|
||||
column = self.sql_column(table)
|
||||
column = self.sql_column(tables, Model)
|
||||
column = self._domain_column('ilike', column)
|
||||
column = self._rank_column(column, name, Model)
|
||||
if column:
|
||||
|
||||
@@ -1192,6 +1192,7 @@ class ModelSQL(ModelStorage):
|
||||
history_clause = (column <= Transaction().context['_datetime'])
|
||||
history_order = (column.desc, Column(table, '__id').desc)
|
||||
history_limit = 1
|
||||
tables = {None: (table, None)}
|
||||
|
||||
columns = {}
|
||||
for f in all_fields:
|
||||
@@ -1200,7 +1201,7 @@ class ModelSQL(ModelStorage):
|
||||
if f in _TABLE_QUERY_COLUMNS and cls._is_table_query():
|
||||
column = _TABLE_QUERY_COLUMNS[f]
|
||||
else:
|
||||
column = field.sql_column(table)
|
||||
column = field.sql_column(tables, cls)
|
||||
columns[f] = column.as_(f)
|
||||
if backend.name == 'sqlite':
|
||||
columns[f].output_name += ' [%s]' % field.sql_type().base
|
||||
@@ -1241,7 +1242,6 @@ class ModelSQL(ModelStorage):
|
||||
if 'id' not in fields_names:
|
||||
columns['id'] = table.id.as_('id')
|
||||
|
||||
tables = {None: (table, None)}
|
||||
if domain:
|
||||
tables, dom_exp = cls.search_domain(
|
||||
domain, active_test=False, tables=tables)
|
||||
@@ -1581,10 +1581,9 @@ class ModelSQL(ModelStorage):
|
||||
|
||||
tree_ids = {}
|
||||
for fname in cls._mptt_fields:
|
||||
field = cls._fields[fname]
|
||||
tree_ids[fname] = []
|
||||
for sub_ids in grouped_slice(ids):
|
||||
where = reduce_ids(field.sql_column(table), sub_ids)
|
||||
where = reduce_ids(Column(table, fname), sub_ids)
|
||||
cursor.execute(*table.select(table.id, where=where))
|
||||
tree_ids[fname] += [x[0] for x in cursor]
|
||||
|
||||
@@ -1841,9 +1840,8 @@ class ModelSQL(ModelStorage):
|
||||
rule_domain, active_test=False, tables=tables)
|
||||
expression &= domain_exp
|
||||
main_table, _ = tables[None]
|
||||
table = convert_from(None, tables)
|
||||
columns = cls.__searched_columns(
|
||||
main_table, eager=not count and not query)
|
||||
tables, eager=not count and not query)
|
||||
|
||||
o_idx = 0
|
||||
for oexpr, otype in order:
|
||||
@@ -1858,6 +1856,7 @@ class ModelSQL(ModelStorage):
|
||||
orderings.extend([otype] * len(forder))
|
||||
done_orderings = True
|
||||
|
||||
table = convert_from(None, tables)
|
||||
union_tables.append(table.select(
|
||||
*columns, where=expression))
|
||||
expression = None
|
||||
@@ -1874,7 +1873,8 @@ class ModelSQL(ModelStorage):
|
||||
return tables, expression, orderings
|
||||
|
||||
@classmethod
|
||||
def __searched_columns(cls, table, *, eager=False, history=False):
|
||||
def __searched_columns(cls, tables, *, eager=False, history=False):
|
||||
table, _ = tables[None]
|
||||
columns = [table.id.as_('id')]
|
||||
if (cls._history and Transaction().context.get('_datetime')
|
||||
and (eager or history)):
|
||||
@@ -1884,7 +1884,7 @@ class ModelSQL(ModelStorage):
|
||||
|
||||
if eager:
|
||||
table_query = cls._is_table_query()
|
||||
columns += [f.sql_column(table).as_(n)
|
||||
columns += [f.sql_column(tables, cls).as_(n)
|
||||
for n, f in sorted(cls._fields.items())
|
||||
if not hasattr(f, 'get')
|
||||
and n != 'id'
|
||||
@@ -1955,16 +1955,20 @@ class ModelSQL(ModelStorage):
|
||||
order_by = cls.__search_order(order, tables)
|
||||
|
||||
# compute it here because __search_order might modify tables
|
||||
table = convert_from(None, tables)
|
||||
if query:
|
||||
columns = [main_table.id.as_('id')]
|
||||
else:
|
||||
columns = cls.__searched_columns(main_table, eager=True)
|
||||
columns = cls.__searched_columns(tables, eager=True)
|
||||
if union_orderings:
|
||||
columns = [
|
||||
Column(main_table, c.output_name).as_(c.output_name)
|
||||
for c in columns]
|
||||
if backend.name == 'sqlite':
|
||||
for column in columns:
|
||||
field = cls._fields.get(column.output_name)
|
||||
if field:
|
||||
column.output_name += ' [%s]' % field.sql_type().base
|
||||
table = convert_from(None, tables)
|
||||
select = table.select(
|
||||
*columns, where=expression, limit=limit, offset=offset,
|
||||
order_by=order_by)
|
||||
|
||||
Reference in New Issue
Block a user