diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 82bab896fbf..29f81f97928 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -819,6 +819,8 @@ def load_modules(db, force_demo=False, status=None, update_module=False): report = tools.assertion_report() # NOTE: Try to also load the modules that have been marked as uninstallable previously... STATES_TO_LOAD = ['installed', 'to upgrade', 'uninstallable'] + if 'base' in tools.config['update']: + cr.execute("update ir_module_module set state=%s where name=%s", ('to upgrade', 'base')) graph = create_graph(cr, ['base'], force) if not graph: logger.notifyChannel('init', netsvc.LOG_CRITICAL, 'module base cannot be loaded! (hint: verify addons-path)') diff --git a/bin/addons/base/__openerp__.py b/bin/addons/base/__openerp__.py index eefaf9f4442..bb419fc90d3 100644 --- a/bin/addons/base/__openerp__.py +++ b/bin/addons/base/__openerp__.py @@ -89,6 +89,7 @@ 'test/base_test.yml', 'test/test_context.xml', 'test/bug_lp541545.xml', + 'test/test_osv_expression.yml', ], 'installable': True, 'active': True, diff --git a/bin/addons/base/test/test_osv_expression.yml b/bin/addons/base/test/test_osv_expression.yml index 71488597579..4916fe06203 100644 --- a/bin/addons/base/test/test_osv_expression.yml +++ b/bin/addons/base/test/test_osv_expression.yml @@ -43,4 +43,71 @@ - Filtering on invalid value across x2many relationship should return an empty set - - !assert {model: res.partner, search: "[('address.city','=','foo')]", count: 0, string: "Searching for address.city = foo should give empty results"} \ No newline at end of file + !assert {model: res.partner, search: "[('address.city','=','foo')]", count: 0, string: "Searching for address.city = foo should give empty results"} +- + Check if many2one works with empty search list +- + !assert {model: res.partner, search: "[('company_id','in', [])]", count: 0, string: "Searching for company_id in [] should be empty!" } +- + For the sake of the following tests, I will create a second company +- + !record {model: res.company, id: ymltest_company2}: + name: Acme 2 +- + And create a few partners with that company or no company +- + !python {model: res.partner }: | + for r in range(4): + self.create(cr, uid, { 'name': 'P of Acme %d' % r, + 'company_id': ref('ymltest_company2') }) + for r in range(4): + self.create(cr, uid, { 'name': 'P of All %d' % r, + 'company_id': False }) +- + Check if many2one works with negative empty list +- + !python {model: res.partner }: | + all_ids = self.search(cr, uid, []) + all_ids.sort() + res_ids = self.search(cr, uid,['|',('company_id','not in', []), ('company_id','=',False)]) + res_ids.sort() + assert all_ids == res_ids, "not in [] fails" +- + Check that many2one will pick the correct records with a list +- + !python {model: res.partner }: | + res_ids = self.search(cr, uid, [('company_id', 'in', [False,])]) + assert len(res_ids) >= 4, "We created 4 partners w/company, why find %d? %r" % \ + (len(res_ids), res_ids) +- + Check that many2one will exclude the correct records with a list +- + !python {model: res.partner }: | + # assuming that the default company is #1 + res_ids = self.search(cr, uid, [('company_id', 'not in', [1])]) + assert len(res_ids) >= 4, "We should have found 4 records at least, only have %d! %r" % \ + (len(res_ids), res_ids) +- + Check that we exclude the correct records, + False +- + !python {model: res.partner }: | + # assuming that the default company is #1 + res_ids = self.search(cr, uid, ['|', ('company_id', 'not in', [1]), ('company_id', '=', False)]) + assert len(res_ids) >= 8, "We should have found 8 records at least, only have %d! %r" % \ + (len(res_ids), res_ids) +- + Check that multi-level expressions also work +- + !python {model: res.partner }: | + res_ids = self.search(cr, uid, [('company_id.partner_id', 'in', [])]) + assert res_ids == [], "Searching an empty set should return empty result, not %r" % res_ids +- + Check that multi-level expressions with negative op work +- + !python {model: res.partner }: | + all_ids = self.search(cr, uid, [('company_id', '!=', False)]) + all_ids.sort() + res_ids = self.search(cr, uid, [('company_id.partner_id', 'not in', [])]) + res_ids.sort() + assert res_ids == all_ids, "Searching against empty set failed, returns %r" % res_ids + diff --git a/bin/osv/expression.py b/bin/osv/expression.py index dddd11af569..7608e963e7a 100644 --- a/bin/osv/expression.py +++ b/bin/osv/expression.py @@ -143,13 +143,19 @@ class expression(object): if len(fargs) > 1: if field._type == 'many2one': right = field_obj.search(cr, uid, [(fargs[1], operator, right)], context=context) - self.__exp[i] = (fargs[0], 'in', right) + if right == []: + self.__exp[i] = ( 'id', '=', 0 ) + else: + self.__exp[i] = (fargs[0], 'in', right) # Making search easier when there is a left operand as field.o2m or field.m2m if field._type in ['many2many','one2many']: right = field_obj.search(cr, uid, [(fargs[1], operator, right)], context=context) right1 = table.search(cr, uid, [(fargs[0],'in', right)], context=context) - self.__exp[i] = ('id', 'in', right1) - + if right1 == []: + self.__exp[i] = ( 'id', '=', 0 ) + else: + self.__exp[i] = ('id', 'in', right1) + if not isinstance(field,fields.property): continue @@ -313,6 +319,13 @@ class expression(object): if not isinstance(ele, basestring): m2o_str = False break + elif right == []: + m2o_str = False + if operator in ('not in', '!=', '<>'): + # (many2one not in []) should return all records + self.__exp[i] = self.__DUMMY_LEAF + else: + self.__exp[i] = ('id','=',0) else: new_op = '=' if operator in ['not like','not ilike','not in','<>','!=']: