From 6251434cb9be97a3569dfe9767ccc0932ab49e37 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Thu, 11 Aug 2011 13:01:18 +0200 Subject: [PATCH] [IMP] unaccent: support for the postgres unaccent contrib module. OpenERP is now able to use the SQL unaccent() function when available, and when the server is run with the --unaccent flag. bzr revid: vmt@openerp.com-20110811110118-cyx2l6c3wk58083p --- .../addons/base/test/test_osv_expression.yml | 19 ++++++- openerp/modules/registry.py | 10 +++- openerp/osv/expression.py | 52 ++++++++++++++++++- openerp/tools/config.py | 4 +- 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/openerp/addons/base/test/test_osv_expression.yml b/openerp/addons/base/test/test_osv_expression.yml index 6ff02fb45f6..68d78df9baf 100644 --- a/openerp/addons/base/test/test_osv_expression.yml +++ b/openerp/addons/base/test/test_osv_expression.yml @@ -435,6 +435,23 @@ domain = [('x','in',['y','z']),('a.v','=','e'),'|','|',('a','=','b'),'!',('c','>','d'),('e','!=','f'),('g','=','h')] 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 diff --git a/openerp/modules/registry.py b/openerp/modules/registry.py index bc80a7bc354..735bf68cfdc 100644 --- a/openerp/modules/registry.py +++ b/openerp/modules/registry.py @@ -23,10 +23,12 @@ """ +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. @@ -46,7 +48,11 @@ class Registry(object): self.db = openerp.sql_db.db_connect(db_name) cr = self.db.cursor() - self.has_unaccent = openerp.modules.db.has_unaccent(cr) + has_unaccent = openerp.modules.db.has_unaccent(cr) + if openerp.tools.config['unaccent'] and not has_unaccent: + logger = logging.getLogger('unaccent') + logger.warning("The option --unaccent was given but no unaccent() function was found in database.") + self.has_unaccent = openerp.tools.config['unaccent'] and has_unaccent cr.close() def do_parent_store(self, cr): diff --git a/openerp/osv/expression.py b/openerp/osv/expression.py index ca1360288ff..983dbb36181 100644 --- a/openerp/osv/expression.py +++ b/openerp/osv/expression.py @@ -72,6 +72,47 @@ That is, a domain could be a valid operand. But this is not the case. A domain is really limited to a two-level nature, and can not takes a recursive form: a domain is not a valid second-level operand. +Unaccent - Accent-insensitive search + +OpenERP will use the SQL function 'unaccent' when available for the 'ilike' and +'not ilike' operators. Normally the 'unaccent' function is obtained from the +PostgreSQL 'unaccent' contrib module[0]. The steps to install the module might +differ on specific PostgreSQL versions. We give here some instruction for +PostgreSQL 9.x on a Ubuntu system. + +Ubuntu doesn't come yet with PostgreSQL 9.x, so an alternive package source +is used. We use Martin Pitt's PPA available at ppa:pitti/postgresql[1]. See +[2] for instructions. Basically: + + > sudo add-apt-repository ppa:pitti/postgresql + > sudo apt-get update + +Once the package list is up-to-date, you have to install PostgreSQL 9.0 and +its contrib modules. + + > sudo apt-get install postgresql-9.0 postgresql-contrib-9.0 + +When you want to enable unaccent on some database: + + > psql9 -f /usr/share/postgresql/9.0/contrib/unaccent.sql + +Here 'psql9' is an alias for the newly installed PostgreSQL 9.0 tool, together +with the correct port if necessary (for instance if PostgreSQL 8.4 is running +on 5432). (Other aliases can be used for createdb and dropdb.) + + > alias psql9='/usr/lib/postgresql/9.0/bin/psql -p 5433' + +You can check unaccent is working: + + > psql9 -c"select unaccent('hélène')" + +Finally, to instruct OpenERP to really use the unaccent function, you have to +start the server specifying the --unaccent flag. + +[0] http://developer.postgresql.org/pgdocs/postgres/unaccent.html +[1] https://launchpad.net/~pitti/+archive/postgresql +[2] https://launchpad.net/+help/soyuz/ppa-sources-list.html + """ import logging @@ -82,6 +123,7 @@ import openerp.modules #.apidoc title: Domain Expressions +# Domain operators. NOT_OPERATOR = '!' OR_OPERATOR = '|' AND_OPERATOR = '&' @@ -678,9 +720,15 @@ class expression(object): 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) + if self.has_unaccent and op in ('ilike', 'not ilike'): + query = '(unaccent(%s.%s) %s unaccent(%s))' % (table._table, left, op, format) + else: + query = '(%s.%s %s %s)' % (table._table, left, op, format) else: - query = "(%s.%s %s '%s')" % (table._table, left, op, right) + if self.has_unaccent and op in ('ilike', 'not ilike'): + query = "(unaccent(%s.%s) %s unaccent('%s'))" % (table._table, left, op, right) + else: + query = "(%s.%s %s '%s')" % (table._table, left, op, right) add_null = False if like: diff --git a/openerp/tools/config.py b/openerp/tools/config.py index b09ef040cea..f7335bcf0c5 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -250,7 +250,7 @@ class configmanager(object): "osv_memory tables. This is a decimal value expressed in hours, " "and the default is 1 hour.", type="float") - group.add_option("--unaccent", dest="unaccent", my_default=False, + group.add_option("--unaccent", dest="unaccent", my_default=False, action="store_true", help="Use the unaccent function provided by the database when available.") parser.add_option_group(group) @@ -337,7 +337,7 @@ class configmanager(object): 'stop_after_init', 'logrotate', 'without_demo', 'netrpc', 'xmlrpc', 'syslog', 'list_db', 'xmlrpcs', 'test_file', 'test_disable', 'test_commit', 'test_report_directory', - 'osv_memory_count_limit', 'osv_memory_age_limit', + 'osv_memory_count_limit', 'osv_memory_age_limit', 'unaccent', ] for arg in keys: