From 9473c1dcc94bb1fcd03b7031fbaf5caf6cf97b6f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 05:57:53 +0000 Subject: [PATCH 1/5] Initial plan From 29086eb55c2a58e3c6aa577f25db9acf4c0e6f6a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 06:02:54 +0000 Subject: [PATCH 2/5] Add name_search method implementation and tests Co-authored-by: ecarreras <294235+ecarreras@users.noreply.github.com> --- orm_mongodb.py | 20 ++++++++++++ tests/__init__.py | 79 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/orm_mongodb.py b/orm_mongodb.py index a1695c1..fc5850c 100644 --- a/orm_mongodb.py +++ b/orm_mongodb.py @@ -587,6 +587,26 @@ def name_get(self, cr, user, ids, context=None): result = self.read(cr, user, ids, [self._rec_name]) return [(x['id'], x[self._rec_name]) for x in result] + def name_search(self, cr, user, name='', args=None, operator='ilike', + context=None, limit=100): + if args is None: + args = [] + if not context: + context = {} + + # Build the search domain + search_domain = list(args) + + # Add the name filter if name is provided + if name: + search_domain.append((self._rec_name, operator, name)) + + # Search for matching records + ids = self.search(cr, user, search_domain, limit=limit, context=context) + + # Return results in name_get format + return self.name_get(cr, user, ids, context=context) + def perm_read(self, cr, user, ids, context=None, details=True): if not ids: diff --git a/tests/__init__.py b/tests/__init__.py index 2d7146f..24338a1 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -206,6 +206,85 @@ def test_name_get(self): [(mmt_id, 'Bar')] ) + def test_name_search(self): + self.create_model() + cursor = self.txn.cursor + uid = self.txn.user + mmt_obj = self.openerp.pool.get(MongoModelTest._name) + + # Create test records + mmt_id1 = mmt_obj.create(cursor, uid, { + 'name': 'Apple Product', + 'other_name': 'Product A', + 'boolean_field': True + }) + mmt_id2 = mmt_obj.create(cursor, uid, { + 'name': 'Banana Product', + 'other_name': 'Product B', + 'boolean_field': True + }) + mmt_id3 = mmt_obj.create(cursor, uid, { + 'name': 'Cherry Product', + 'other_name': 'Product C', + 'boolean_field': False + }) + + # Test basic name search with ilike operator (default) + result = mmt_obj.name_search(cursor, uid, 'Apple') + self.assertIn((mmt_id1, 'Apple Product'), result) + self.assertEqual(len(result), 1) + + # Test case-insensitive search + result = mmt_obj.name_search(cursor, uid, 'apple') + self.assertIn((mmt_id1, 'Apple Product'), result) + self.assertEqual(len(result), 1) + + # Test partial match + result = mmt_obj.name_search(cursor, uid, 'Product') + self.assertEqual(len(result), 3) + result_ids = [r[0] for r in result] + self.assertIn(mmt_id1, result_ids) + self.assertIn(mmt_id2, result_ids) + self.assertIn(mmt_id3, result_ids) + + # Test with args (domain filters) + result = mmt_obj.name_search(cursor, uid, 'Product', + args=[('boolean_field', '=', True)]) + self.assertEqual(len(result), 2) + result_ids = [r[0] for r in result] + self.assertIn(mmt_id1, result_ids) + self.assertIn(mmt_id2, result_ids) + self.assertNotIn(mmt_id3, result_ids) + + # Test with empty name (should return all records or filtered by args) + result = mmt_obj.name_search(cursor, uid, '', + args=[('boolean_field', '=', False)]) + self.assertEqual(len(result), 1) + self.assertIn((mmt_id3, 'Cherry Product'), result) + + # Test with limit + result = mmt_obj.name_search(cursor, uid, 'Product', limit=2) + self.assertEqual(len(result), 2) + + # Test with exact match operator + result = mmt_obj.name_search(cursor, uid, 'Apple Product', operator='=') + self.assertEqual(len(result), 1) + self.assertIn((mmt_id1, 'Apple Product'), result) + + # Test with like operator + result = mmt_obj.name_search(cursor, uid, 'Banana%', operator='like') + self.assertEqual(len(result), 1) + self.assertIn((mmt_id2, 'Banana Product'), result) + + # Test with different _rec_name + MongoModelTest._rec_name = 'other_name' + result = mmt_obj.name_search(cursor, uid, 'Product A') + self.assertIn((mmt_id1, 'Product A'), result) + self.assertEqual(len(result), 1) + + # Reset _rec_name to default + MongoModelTest._rec_name = 'name' + def test_boolean(self): self.create_model() cursor = self.txn.cursor From 5396b89e3ad222d57c42e0b2cc43a6571d823719 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 06:05:15 +0000 Subject: [PATCH 3/5] Fix code review issues - proper context handling and test isolation Co-authored-by: ecarreras <294235+ecarreras@users.noreply.github.com> --- orm_mongodb.py | 2 +- tests/__init__.py | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/orm_mongodb.py b/orm_mongodb.py index fc5850c..91069da 100644 --- a/orm_mongodb.py +++ b/orm_mongodb.py @@ -591,7 +591,7 @@ def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100): if args is None: args = [] - if not context: + if context is None: context = {} # Build the search domain diff --git a/tests/__init__.py b/tests/__init__.py index 24338a1..c18882f 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -212,6 +212,9 @@ def test_name_search(self): uid = self.txn.user mmt_obj = self.openerp.pool.get(MongoModelTest._name) + # Save original _rec_name + original_rec_name = MongoModelTest._rec_name + # Create test records mmt_id1 = mmt_obj.create(cursor, uid, { 'name': 'Apple Product', @@ -277,13 +280,14 @@ def test_name_search(self): self.assertIn((mmt_id2, 'Banana Product'), result) # Test with different _rec_name - MongoModelTest._rec_name = 'other_name' - result = mmt_obj.name_search(cursor, uid, 'Product A') - self.assertIn((mmt_id1, 'Product A'), result) - self.assertEqual(len(result), 1) - - # Reset _rec_name to default - MongoModelTest._rec_name = 'name' + try: + MongoModelTest._rec_name = 'other_name' + result = mmt_obj.name_search(cursor, uid, 'Product A') + self.assertIn((mmt_id1, 'Product A'), result) + self.assertEqual(len(result), 1) + finally: + # Always restore original _rec_name + MongoModelTest._rec_name = original_rec_name def test_boolean(self): self.create_model() From 6f03ac354f392d33449fd90c15b01a2525226675 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 09:07:23 +0000 Subject: [PATCH 4/5] Update name_get to match orm implementation with isolation decorator and proper handling Co-authored-by: ecarreras <294235+ecarreras@users.noreply.github.com> --- orm_mongodb.py | 11 +++++++++-- tests/__init__.py | 13 +++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/orm_mongodb.py b/orm_mongodb.py index 91069da..1ea1d53 100644 --- a/orm_mongodb.py +++ b/orm_mongodb.py @@ -583,9 +583,16 @@ def _check_removed_columns(self, cr, log=False): # nothing to check in schema free... pass + @isolation(readonly=True, isolation_level='repeatable_read') def name_get(self, cr, user, ids, context=None): - result = self.read(cr, user, ids, [self._rec_name]) - return [(x['id'], x[self._rec_name]) for x in result] + if not context: + context = {} + if not ids: + return [] + if isinstance(ids, integer_types): + ids = [ids] + return [(r['id'], tools.ustr(r[self._rec_name])) for r in self.read(cr, user, ids, + [self._rec_name], context, load='_classic_write')] def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100): diff --git a/tests/__init__.py b/tests/__init__.py index c18882f..3bfdc42 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -198,6 +198,17 @@ def test_name_get(self): [(mmt_id, 'Foo')] ) + # Test with single id (integer) + result = mmt_obj.name_get(cursor, uid, mmt_id) + self.assertListEqual( + result, + [(mmt_id, 'Foo')] + ) + + # Test with empty ids + result = mmt_obj.name_get(cursor, uid, []) + self.assertListEqual(result, []) + # Changing the rec_name should use other field MongoModelTest._rec_name = 'other_name' result = mmt_obj.name_get(cursor, uid, [mmt_id]) @@ -205,6 +216,8 @@ def test_name_get(self): result, [(mmt_id, 'Bar')] ) + # Reset _rec_name to default + MongoModelTest._rec_name = 'name' def test_name_search(self): self.create_model() From 0399127503561a4315c8d36e59ac1b4f4835841c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 09:18:23 +0000 Subject: [PATCH 5/5] Remove @isolation decorator from name_get method Co-authored-by: ecarreras <294235+ecarreras@users.noreply.github.com> --- orm_mongodb.py | 1 - 1 file changed, 1 deletion(-) diff --git a/orm_mongodb.py b/orm_mongodb.py index 1ea1d53..1fcba5b 100644 --- a/orm_mongodb.py +++ b/orm_mongodb.py @@ -583,7 +583,6 @@ def _check_removed_columns(self, cr, log=False): # nothing to check in schema free... pass - @isolation(readonly=True, isolation_level='repeatable_read') def name_get(self, cr, user, ids, context=None): if not context: context = {}