[REF]: expression: simplified <> into != in a pre-step,

put some warnings (which might get boring, we will see).

bzr revid: vmt@openerp.com-20110809174814-4uja94uo2spzcvm5
This commit is contained in:
Vo Minh Thu 2011-08-09 19:48:14 +02:00
parent 091e9989d5
commit 187dc4c199
1 changed files with 26 additions and 16 deletions

View File

@ -20,6 +20,8 @@
# #
############################################################################## ##############################################################################
import logging
from openerp.tools import flatten, reverse_enumerate from openerp.tools import flatten, reverse_enumerate
import fields import fields
@ -29,8 +31,8 @@ NOT_OPERATOR = '!'
OR_OPERATOR = '|' OR_OPERATOR = '|'
AND_OPERATOR = '&' AND_OPERATOR = '&'
OPS = ('=', '!=', '<>', '<=', '<', '>', '>=', '=?', '=like', '=ilike', 'like', 'not like', 'ilike', 'not ilike', 'in', 'not in', 'child_of') OPS = ('=', '!=', '<=', '<', '>', '>=', '=?', '=like', '=ilike', 'like', 'not like', 'ilike', 'not ilike', 'in', 'not in', 'child_of')
NEGATIVE_OPS = ('!=', '<>', 'not like', 'not ilike', 'not in') NEGATIVE_OPS = ('!=', 'not like', 'not ilike', 'not in')
TRUE_LEAF = (1, '=', 1) TRUE_LEAF = (1, '=', 1)
FALSE_LEAF = (0, '=', 1) FALSE_LEAF = (0, '=', 1)
@ -38,6 +40,8 @@ FALSE_LEAF = (0, '=', 1)
TRUE_DOMAIN = [TRUE_LEAF] TRUE_DOMAIN = [TRUE_LEAF]
FALSE_DOMAIN = [FALSE_LEAF] FALSE_DOMAIN = [FALSE_LEAF]
_logger = logging.getLogger('expression')
def normalize(domain): def normalize(domain):
"""Returns a normalized version of ``domain_expr``, where all implicit '&' operators """Returns a normalized version of ``domain_expr``, where all implicit '&' operators
have been made explicit. One property of normalized domain expressions is that they have been made explicit. One property of normalized domain expressions is that they
@ -110,6 +114,12 @@ def is_leaf(element, internal=False):
and (((not internal) and element[1] in OPS) \ and (((not internal) and element[1] in OPS) \
or (internal and element[1] in INTERNAL_OPS)) or (internal and element[1] in INTERNAL_OPS))
def normalize_operator(operator):
operator = operator.lower()
if operator == '<>':
operator = '!='
return operator
def select_from_where(cr, s, f, w, ids, op): def select_from_where(cr, s, f, w, ids, op):
# todo: merge into parent query as sub-query # todo: merge into parent query as sub-query
res = [] res = []
@ -201,7 +211,7 @@ class expression(object):
if is_operator(e) or e == TRUE_LEAF or e == FALSE_LEAF: if is_operator(e) or e == TRUE_LEAF or e == FALSE_LEAF:
continue continue
left, operator, right = e left, operator, right = e
operator = operator.lower() operator = normalize_operator(operator)
working_table = table # The table containing the field (the name provided in the left operand) working_table = table # The table containing the field (the name provided in the left operand)
fargs = left.split('.', 1) fargs = left.split('.', 1)
@ -348,11 +358,10 @@ class expression(object):
elif field._type == 'many2one': elif field._type == 'many2one':
if operator == 'child_of': if operator == 'child_of':
ids2 = child_of_right_to_ids(right, 'ilike', field_obj)
if field._obj != working_table._name: if field._obj != working_table._name:
ids2 = child_of_right_to_ids(right, 'ilike', field_obj)
dom = child_of_domain(left, ids2, field_obj, prefix=field._obj) dom = child_of_domain(left, ids2, field_obj, prefix=field._obj)
else: else:
ids2 = child_of_right_to_ids(right, 'ilike', field_obj)
dom = child_of_domain('id', ids2, working_table, parent=left) dom = child_of_domain('id', ids2, working_table, parent=left)
self.__exp = self.__exp[:i] + dom + self.__exp[i+1:] self.__exp = self.__exp[:i] + dom + self.__exp[i+1:]
else: else:
@ -364,12 +373,12 @@ class expression(object):
#Special treatment to ill-formed domains #Special treatment to ill-formed domains
operator = ( operator in ['<','>','<=','>='] ) and 'in' or operator operator = ( operator in ['<','>','<=','>='] ) and 'in' or operator
dict_op = {'not in':'!=','in':'=','=':'in','!=':'not in','<>':'not in'} dict_op = {'not in':'!=','in':'=','=':'in','!=':'not in'}
if isinstance(right, tuple): if isinstance(right, tuple):
right = list(right) right = list(right)
if (not isinstance(right, list)) and operator in ['not in','in']: if (not isinstance(right, list)) and operator in ['not in','in']:
operator = dict_op[operator] operator = dict_op[operator]
elif isinstance(right, list) and operator in ['<>','!=','=']: #for domain (FIELD,'=',['value1','value2']) elif isinstance(right, list) and operator in ['!=','=']: #for domain (FIELD,'=',['value1','value2'])
operator = dict_op[operator] operator = dict_op[operator]
res_ids = [x[0] for x in field_obj.name_search(cr, uid, right, [], operator, limit=None, context=c)] res_ids = [x[0] for x in field_obj.name_search(cr, uid, right, [], operator, limit=None, context=c)]
if not res_ids: if not res_ids:
@ -390,14 +399,14 @@ class expression(object):
if m2o_str: if m2o_str:
self.__exp[i] = _get_expression(field_obj, cr, uid, left, right, operator, context=context) self.__exp[i] = _get_expression(field_obj, cr, uid, left, right, operator, context=context)
elif right == []: elif right == []:
if operator in ('not in', '!=', '<>'): if operator not in ('in', 'not in'):
# (many2one not in []) should return all records _logger.warning("The domain term '%s' should use a set operator ('in' or 'not in')." % (self.__exp[i]),)
self.__exp[i] = TRUE_LEAF # (many2one not in []) returns all records, (many2one in []) returns no record at all.
else: self.__exp[i] = TRUE_LEAF if operator in NEGATIVE_OPS else FALSE_LEAF
self.__exp[i] = FALSE_LEAF else: # right is False
else: if operator not in ('=', '!='):
_logger.warning("The domain term '%s' should use the '=' or '!=' operator." % (self.__exp[i],))
new_op = '!=' if operator in NEGATIVE_OPS else '=' new_op = '!=' if operator in NEGATIVE_OPS else '='
#Is it ok to put 'left' and not 'id' ?
self.__exp[i] = (left, new_op, False) self.__exp[i] = (left, new_op, False)
else: else:
@ -452,6 +461,7 @@ class expression(object):
def __leaf_to_sql(self, leaf, table): def __leaf_to_sql(self, leaf, table):
left, operator, right = leaf left, operator, right = leaf
operator = normalize_operator(operator)
if leaf == TRUE_LEAF: if leaf == TRUE_LEAF:
query = 'TRUE' query = 'TRUE'
@ -501,11 +511,11 @@ class expression(object):
query = '%s.%s IS NULL ' % (table._table, left) query = '%s.%s IS NULL ' % (table._table, left)
params = [] params = []
elif right == False and (left in table._columns) and table._columns[left]._type=="boolean" and (operator in ['<>', '!=']): elif right == False and (left in table._columns) and table._columns[left]._type=="boolean" and (operator == '!='):
query = '(%s.%s IS NOT NULL and %s.%s != false)' % (table._table, left, table._table, left) query = '(%s.%s IS NOT NULL and %s.%s != false)' % (table._table, left, table._table, left)
params = [] params = []
elif (((right == False) and (type(right)==bool)) or right is None) and (operator in ['<>', '!=']): elif (((right == False) and (type(right)==bool)) or right is None) and (operator == '!='):
query = '%s.%s IS NOT NULL' % (table._table, left) query = '%s.%s IS NOT NULL' % (table._table, left)
params = [] params = []