[MERGE] sync w/ latest trunk
authorOlivier Dony <odo@openerp.com>
Wed, 21 Sep 2011 16:21:28 +0000 (18:21 +0200)
committerOlivier Dony <odo@openerp.com>
Wed, 21 Sep 2011 16:21:28 +0000 (18:21 +0200)
bzr revid: odo@openerp.com-20110921162128-22sp59cn4xv983q5

1  2 
openerp/addons/base/test/test_osv_expression.yml
openerp/modules/db.py
openerp/modules/registry.py
openerp/osv/expression.py
openerp/osv/orm.py

          norm_domain = ['&','&','&'] + domain
          assert norm_domain == expression.normalize(domain), "Non-normalized domains should be properly normalized"
  -
 +    Unaccent. Create a company with an accent in its name.
 +-
 +    !record {model: res.company, id: ymltest_unaccent_company}:
 +        name: Hélène
 +-
 +    Test the unaccent-enabled 'ilike'.
 +-
 +    !python {model: res.company}: |
 +        if self.pool.has_unaccent:
 +            ids = self.search(cr, uid, [('name','ilike','Helene')], {})
 +            assert ids == [ref('ymltest_unaccent_company')]
 +            ids = self.search(cr, uid, [('name','ilike','hélène')], {})
 +            assert ids == [ref('ymltest_unaccent_company')]
 +            ids = self.search(cr, uid, [('name','not ilike','Helene')], {})
 +            assert ref('ymltest_unaccent_company') not in ids
 +            ids = self.search(cr, uid, [('name','not ilike','hélène')], {})
 +            assert ref('ymltest_unaccent_company') not in ids
++-
+     Check that =like/=ilike expressions are working with an untranslated field.
+ -
+     !python {model: res.partner }: |
+         all_ids = self.search(cr, uid, [('name', '=like', 'Ax')])
+         assert len(all_ids) == 1, "It should have 1 record !"
+         all_ids = self.search(cr, uid, [('name', '=ilike', 'Ax')])
+         assert len(all_ids) == 2, "It should have 2 records !"
+ -
+     Check that =like/=ilike expressions are working with a translated field.
+ -
+     !python {model: res.country }: |
+         all_ids = self.search(cr, uid, [('name', '=like', 'Ind')])
+         assert len(all_ids) == 3, "It should have 3 records !"
+         all_ids = self.search(cr, uid, [('name', '=ilike', 'Ind')])
+         assert len(all_ids) == 3, "It should have 3 records !"
Simple merge
  """ Models registries.
  
  """
+ import threading
  
 +import logging
 +
  import openerp.sql_db
  import openerp.osv.orm
 -
 +import openerp.modules.db
 +import openerp.tools.config
  
  class Registry(object):
      """ Model registry for a particular database.
@@@ -383,42 -196,31 +383,42 @@@ class expression(object)
          while i + 1<len(self.__exp):
              i += 1
              e = self.__exp[i]
 -            if self._is_operator(e) or e == self.__DUMMY_LEAF:
 +            if is_operator(e) or e == TRUE_LEAF or e == FALSE_LEAF:
                  continue
 +
 +            # check if the expression is valid
 +            if not is_leaf(e):
 +                raise ValueError('Bad domain expression: %r, %r is not a valid term.' % (exp, e))
 +
 +            # normalize the leaf's operator
 +            e = normalize_leaf(*e)
 +            self.__exp[i] = e
              left, operator, right = e
 -            operator = operator.lower()
 -            working_table = table
 -            main_table = table
 +
 +            working_table = table # The table containing the field (the name provided in the left operand)
              fargs = left.split('.', 1)
 +
 +            # If the field is _inherits'd, search for the working_table,
 +            # and extract the field.
              if fargs[0] in table._inherit_fields:
                  while True:
 -                    field = main_table._columns.get(fargs[0], False)
 +                    field = working_table._columns.get(fargs[0])
                      if field:
 -                        working_table = main_table
                          self.__field_tables[i] = working_table
                          break
 -                    working_table = main_table.pool.get(main_table._inherit_fields[fargs[0]][0])
 -                    if working_table not in self.__all_tables:
 -                        self.__joins.append('%s."%s"=%s."%s"' % (working_table._table, 'id', main_table._table, main_table._inherits[working_table._name]))
 -                        self.__all_tables.add(working_table)
 -                    main_table = working_table
 +                    next_table = working_table.pool.get(working_table._inherit_fields[fargs[0]][0])
 +                    if next_table not in self.__all_tables:
-                         self.__joins.append('%s.%s=%s.%s' % (next_table._table, 'id', working_table._table, working_table._inherits[next_table._name]))
++                        self.__joins.append('%s."%s"=%s."%s"' % (next_table._table, 'id', working_table._table, working_table._inherits[next_table._name]))
 +                        self.__all_tables.add(next_table)
 +                    working_table = next_table
 +            # Or (try to) directly extract the field.
 +            else:
 +                field = working_table._columns.get(fargs[0])
  
 -            field = working_table._columns.get(fargs[0], False)
              if not field:
                  if left == 'id' and operator == 'child_of':
 -                    ids2 = child_of_right_to_ids(right)
 -                    dom = _rec_get(ids2, working_table)
 +                    ids2 = child_of_right_to_ids(right, table)
 +                    dom = child_of_domain(left, ids2, working_table)
                      self.__exp = self.__exp[:i] + dom + self.__exp[i+1:]
                  continue
  
                      self.__exp[i] = tuple(self.__exp[i])
  
                  if field.translate:
+                     operator = {'=like':'like','=ilike':'ilike'}.get(operator,operator)
                      if operator in ('like', 'ilike', 'not like', 'not ilike'):
                          right = '%%%s%%' % right
 -                        
 -                    query1 = '( SELECT res_id'          \
 +
-                     operator = operator == '=like' and 'like' or operator
 +                    subselect = '( SELECT res_id'          \
                               '    FROM ir_translation'  \
                               '   WHERE name = %s'       \
                               '     AND lang = %s'       \
                                right,
                               ]
  
 -                    self.__exp[i] = ('id', 'inselect', (query1, query2))
 -        return self
 +                    self.__exp[i] = ('id', 'inselect', (subselect, params))
  
      def __leaf_to_sql(self, leaf, table):
 -        if leaf == self.__DUMMY_LEAF:
 -            return ('(1=1)', [])
          left, operator, right = leaf
  
 -        if operator == 'inselect':
 +        if leaf == TRUE_LEAF:
 +            query = 'TRUE'
 +            params = []
 +
 +        elif leaf == FALSE_LEAF:
 +            query = 'FALSE'
 +            params = []
 +
 +        elif operator == 'inselect':
-             query = '(%s.%s in (%s))' % (table._table, left, right[0])
+             query = '(%s."%s" in (%s))' % (table._table, left, right[0])
              params = right[1]
 +
          elif operator in ['in', 'not in']:
 -            params = right and right[:] or []
 -            len_before = len(params)
 -            for i in range(len_before)[::-1]:
 -                if params[i] == False:
 -                    del params[i]
 -
 -            len_after = len(params)
 -            check_nulls = len_after != len_before
 -            query = '(1=0)'
 -
 -            if len_after:
 -                if left == 'id':
 -                    instr = ','.join(['%s'] * len_after)
 -                else:
 -                    instr = ','.join([table._columns[left]._symbol_set[0]] * len_after)
 -                query = '(%s."%s" %s (%s))' % (table._table, left, operator, instr)
 -            else:
 -                # the case for [field, 'in', []] or [left, 'not in', []]
 +            # Two cases: right is a boolean or a list. The boolean case is an
 +            # abuse and handled for backward compatibility.
 +            if isinstance(right, bool):
 +                _logger.warning("The domain term '%s' should use the '=' or '!=' operator." % (leaf,))
                  if operator == 'in':
 -                    query = '(%s."%s" IS NULL)' % (table._table, left)
 +                    r = 'NOT NULL' if right else 'NULL'
                  else:
 -                    query = '(%s."%s" IS NOT NULL)' % (table._table, left)
 -            if check_nulls:
 -                query = '(%s OR %s."%s" IS NULL)' % (query, table._table, left)
 -        else:
 +                    r = 'NULL' if right else 'NOT NULL'
-                 query = '(%s.%s IS %s)' % (table._table, left, r)
++                query = '(%s."%s" IS %s)' % (table._table, left, r)
 +                params = []
 +            elif isinstance(right, (list, tuple)):
 +                params = right[:]
 +                check_nulls = False
 +                for i in range(len(params))[::-1]:
 +                    if params[i] == False:
 +                        check_nulls = True
 +                        del params[i]
 +
 +                if params:
 +                    if left == 'id':
 +                        instr = ','.join(['%s'] * len(params))
 +                    else:
 +                        instr = ','.join([table._columns[left]._symbol_set[0]] * len(params))
-                     query = '(%s.%s %s (%s))' % (table._table, left, operator, instr)
++                    query = '(%s."%s" %s (%s))' % (table._table, left, operator, instr)
 +                else:
 +                    # The case for (left, 'in', []) or (left, 'not in', []).
 +                    query = 'FALSE' if operator == 'in' else 'TRUE'
 +
 +                if check_nulls and operator == 'in':
-                     query = '(%s OR %s.%s IS NULL)' % (query, table._table, left)
++                    query = '(%s OR %s."%s" IS NULL)' % (query, table._table, left)
 +                elif not check_nulls and operator == 'not in':
-                     query = '(%s OR %s.%s IS NULL)' % (query, table._table, left)
++                    query = '(%s OR %s."%s" IS NULL)' % (query, table._table, left)
 +                elif check_nulls and operator == 'not in':
-                     query = '(%s AND %s.%s IS NOT NULL)' % (query, table._table, left) # needed only for TRUE.
++                    query = '(%s AND %s."%s" IS NOT NULL)' % (query, table._table, left) # needed only for TRUE.
 +            else: # Must not happen.
 +                pass
 +
 +        elif right == False and (left in table._columns) and table._columns[left]._type=="boolean" and (operator == '='):
-             query = '(%s.%s IS NULL or %s.%s = false )' % (table._table, left, table._table, left)
++            query = '(%s."%s" IS NULL or %s."%s" = false )' % (table._table, left, table._table, left)
              params = []
  
 -            if right == False and (leaf[0] in table._columns)  and table._columns[leaf[0]]._type=="boolean"  and (operator == '='):
 -                query = '(%s."%s" IS NULL or %s."%s" = false )' % (table._table, left,table._table, left)
 -            elif (((right == False) and (type(right)==bool)) or (right is None)) and (operator == '='):
 -                query = '%s."%s" IS NULL ' % (table._table, left)
 -            elif right == False and (leaf[0] in table._columns)  and table._columns[leaf[0]]._type=="boolean"  and (operator in ['<>', '!=']):
 -                query = '(%s."%s" IS NOT NULL and %s."%s" != false)' % (table._table, left,table._table, left)
 -            elif (((right == False) and (type(right)==bool)) or right is None) and (operator in ['<>', '!=']):
 -                query = '%s."%s" IS NOT NULL' % (table._table, left)
 -            elif (operator == '=?'):
 -                op = '='
 -                if (right is False or right is None):
 -                    return ( 'TRUE',[])
 -                if left in table._columns:
 -                        format = table._columns[left]._symbol_set[0]
 -                        query = '(%s."%s" %s %s)' % (table._table, left, op, format)
 -                        params = table._columns[left]._symbol_set[1](right)
 -                else:
 -                        query = "(%s.\"%s\" %s '%%s')" % (table._table, left, op)
 -                        params = right
 +        elif (right is False or right is None) and (operator == '='):
-             query = '%s.%s IS NULL ' % (table._table, left)
++            query = '%s."%s" IS NULL ' % (table._table, left)
 +            params = []
 +
 +        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 = []
 +
 +        elif (right is False 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 = []
  
 +        elif (operator == '=?'):
 +            if (right is False or right is None):
 +                query = 'TRUE'
 +                params = []
 +            elif left in table._columns:
 +                format = table._columns[left]._symbol_set[0]
-                 query = '(%s.%s = %s)' % (table._table, left, format)
++                query = '(%s."%s" = %s)' % (table._table, left, format)
 +                params = table._columns[left]._symbol_set[1](right)
              else:
-                 query = "(%s.%s = '%%s')" % (table._table, left)
 -                if left == 'id':
 -                    query = '%s.id %s %%s' % (table._table, operator)
 -                    params = right
++                query = "(%s.\"%s\" = '%%s')" % (table._table, left)
 +                params = right
 +
 +        elif left == 'id':
 +            query = '%s.id %s %%s' % (table._table, operator)
 +            params = right
 +
 +        else:
 +            like = operator in ('like', 'ilike', 'not like', 'not ilike')
 +
 +            op = {'=like':'like','=ilike':'ilike'}.get(operator, operator)
 +            if left in table._columns:
 +                format = like and '%s' or table._columns[left]._symbol_set[0]
 +                if self.has_unaccent and op in ('ilike', 'not ilike'):
-                     query = '(unaccent(%s.%s) %s unaccent(%s))' % (table._table, left, op, format)
++                    query = '(unaccent(%s."%s") %s unaccent(%s))' % (table._table, left, op, format)
                  else:
-                     query = '(%s.%s %s %s)' % (table._table, left, op, format)
 -                    operator = {'=like':'like','=ilike':'ilike'}.get(operator,operator)
 -                    like = operator in ('like', 'ilike', 'not like', 'not ilike')
 -                    
 -                    op = {'=like':'like','=ilike':'ilike'}.get(operator,operator)
 -                    if left in table._columns:
 -                        format = like and '%s' or table._columns[left]._symbol_set[0]
 -                        query = '(%s."%s" %s %s)' % (table._table, left, op, format)
 -                    else:
 -                        query = "(%s.\"%s\" %s '%s')" % (table._table, left, op, right)
 -
 -                    add_null = False
 -                    if like:
 -                        if isinstance(right, str):
 -                            str_utf8 = right
 -                        elif isinstance(right, unicode):
 -                            str_utf8 = right.encode('utf-8')
 -                        else:
 -                            str_utf8 = str(right)
 -                        params = '%%%s%%' % str_utf8
 -                        add_null = not str_utf8
 -                    elif left in table._columns:
 -                        params = table._columns[left]._symbol_set[1](right)
++                    query = '(%s."%s" %s %s)' % (table._table, left, op, format)
 +            else:
 +                if self.has_unaccent and op in ('ilike', 'not ilike'):
-                     query = "(unaccent(%s.%s) %s unaccent('%s'))" % (table._table, left, op, right)
++                    query = "(unaccent(%s.\"%s\") %s unaccent('%s'))" % (table._table, left, op, right)
 +                else:
-                     query = "(%s.%s %s '%s')" % (table._table, left, op, right)
++                    query = "(%s.\"%s\" %s '%s')" % (table._table, left, op, right)
 +
 +            add_null = False
 +            if like:
 +                if isinstance(right, str):
 +                    str_utf8 = right
 +                elif isinstance(right, unicode):
 +                    str_utf8 = right.encode('utf-8')
 +                else:
 +                    str_utf8 = str(right)
 +                params = '%%%s%%' % str_utf8
 +                add_null = not str_utf8
 +            elif left in table._columns:
 +                params = table._columns[left]._symbol_set[1](right)
  
 -                    if add_null:
 -                        query = '(%s OR \"%s\" IS NULL)' % (query, left)
 +            if add_null:
-                 query = '(%s OR %s.%s IS NULL)' % (query, table._table, left)
++                query = '(%s OR %s."%s" IS NULL)' % (query, table._table, left)
  
          if isinstance(params, basestring):
              params = [params]
Simple merge