# for consistency. This list doesn't contain '<>' as it is simpified to '!='
# by the normalize_operator() function (so later part of the code deals with
# only one representation).
-# An internal (i.e. not available to the user) 'inselect' operator is also
-# used. In this case its right operand has the form (subselect, params).
+# Internals (i.e. not available to the user) 'inselect' and 'not inselect'
+# operators are also used. In this case its right operand has the form (subselect, params).
TERM_OPERATORS = ('=', '!=', '<=', '<', '>', '>=', '=?', '=like', '=ilike',
'like', 'not like', 'ilike', 'not ilike', 'in', 'not in',
'child_of')
"""
INTERNAL_OPS = TERM_OPERATORS + ('<>',)
if internal:
- INTERNAL_OPS += ('inselect',)
+ INTERNAL_OPS += ('inselect', 'not inselect')
return (isinstance(element, tuple) or isinstance(element, list)) \
and len(element) == 3 \
and element[1] in INTERNAL_OPS \
else:
if field._type == 'datetime' and right and len(right) == 10:
- if operator in ('>', '>='):
+ if operator in ('>', '>=', '='):
right += ' 00:00:00'
elif operator in ('<', '<='):
right += ' 23:59:59'
push(create_substitution_leaf(leaf, (left, operator, right), working_model))
- elif field.translate:
+ elif field.translate and right:
need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike')
sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator)
if need_wildcard:
right = '%%%s%%' % right
+ inselect_operator = 'inselect'
+ if sql_operator in NEGATIVE_TERM_OPERATORS:
+ # negate operator (fix lp:1071710)
+ sql_operator = sql_operator[4:] if sql_operator[:3] == 'not' else '='
+ inselect_operator = 'not inselect'
+
subselect = '( SELECT res_id' \
' FROM ir_translation' \
' WHERE name = %s' \
' AND type = %s'
instr = ' %s'
#Covering in,not in operators with operands (%s,%s) ,etc.
- if sql_operator in ['in', 'not in']:
+ if sql_operator == 'in':
instr = ','.join(['%s'] * len(right))
subselect += ' AND value ' + sql_operator + ' ' + " (" + instr + ")" \
') UNION (' \
right,
right,
]
- push(create_substitution_leaf(leaf, ('id', 'inselect', (subselect, params)), working_model))
+ push(create_substitution_leaf(leaf, ('id', inselect_operator, (subselect, params)), working_model))
else:
push_result(leaf)
left, operator, right = leaf
# final sanity checks - should never fail
- assert operator in (TERM_OPERATORS + ('inselect',)), \
+ assert operator in (TERM_OPERATORS + ('inselect', 'not inselect')), \
"Invalid operator %r in domain term %r" % (operator, leaf)
assert leaf in (TRUE_LEAF, FALSE_LEAF) or left in model._all_columns \
or left in MAGIC_COLUMNS, "Invalid field %r in domain term %r" % (left, leaf)
query = '(%s."%s" in (%s))' % (table_alias, left, right[0])
params = right[1]
+ elif operator == 'not inselect':
+ query = '(%s."%s" not in (%s))' % (table_alias, left, right[0])
+ params = right[1]
+
elif operator in ['in', 'not in']:
# Two cases: right is a boolean or a list. The boolean case is an
# abuse and handled for backward compatibility.
if left == 'id':
instr = ','.join(['%s'] * len(params))
else:
- instr = ','.join([model._columns[left]._symbol_set[0]] * len(params))
+ ss = model._columns[left]._symbol_set
+ instr = ','.join([ss[0]] * len(params))
+ params = map(ss[1], params)
query = '(%s."%s" %s (%s))' % (table_alias, left, operator, instr)
else:
# The case for (left, 'in', []) or (left, 'not in', []).