diff --git a/trytond/CHANGELOG b/trytond/CHANGELOG index cde4d6963c0..9e67117403d 100644 --- a/trytond/CHANGELOG +++ b/trytond/CHANGELOG @@ -1,3 +1,4 @@ +* Use JSONB to store MultiSelection field on PostgreSQL * Use multiple jobs to dump and restore a test database * Support database cache as template for tests diff --git a/trytond/trytond/backend/postgresql/table.py b/trytond/trytond/backend/postgresql/table.py index 8f387705d62..361556b9f60 100644 --- a/trytond/trytond/backend/postgresql/table.py +++ b/trytond/trytond/backend/postgresql/table.py @@ -329,6 +329,7 @@ def add_comment(): if base_type != typname: if (typname, base_type) in [ ('varchar', 'text'), + ('varchar', 'jsonb'), ('text', 'varchar'), ('text', 'jsonb'), ('date', 'timestamp'), diff --git a/trytond/trytond/model/fields/multiselection.py b/trytond/trytond/model/fields/multiselection.py index c34b21de530..fa86be2984d 100644 --- a/trytond/trytond/model/fields/multiselection.py +++ b/trytond/trytond/model/fields/multiselection.py @@ -18,7 +18,7 @@ class MultiSelection(SelectionMixin, Field): "Define a multi-selection field." _type = 'multiselection' - _sql_type = 'VARCHAR' + _sql_type = 'JSON' _py_type = tuple def __init__(self, selection, string='', sort=True, translate=True, diff --git a/trytond/trytond/tests/field_multiselection.py b/trytond/trytond/tests/field_multiselection.py index bbb9f4e21cc..d2ccf0ad57c 100644 --- a/trytond/trytond/tests/field_multiselection.py +++ b/trytond/trytond/tests/field_multiselection.py @@ -38,8 +38,21 @@ class MultiSelectionRequired(ModelSQL): [('foo', "Foo"), ('bar', "Bar")], "Selects", required=True) +class MultiSelectionText(ModelSQL): + "MultiSelection TEXT" + __name__ = 'test.multi_selection_text' + + selects = fields.MultiSelection([ + ('foo', "Foo"), + ('bar', "Bar"), + ('foobar', "FooBar"), + ], "Selections") + selects._sql_type = 'TEXT' + + def register(module): Pool.register( MultiSelection, MultiSelectionRequired, + MultiSelectionText, module=module, type_='model') diff --git a/trytond/trytond/tests/test_field_multiselection.py b/trytond/trytond/tests/test_field_multiselection.py index 881d59ecdac..c839a9eedc5 100644 --- a/trytond/trytond/tests/test_field_multiselection.py +++ b/trytond/trytond/tests/test_field_multiselection.py @@ -358,29 +358,48 @@ def test_read_string_dynamic_selection(self): self.assertEqual(bar_read['dyn_selects:string'], ["Bar", "Baz"]) self.assertEqual(null_read['dyn_selects:string'], []) + @with_transaction() + def test_create_text(self): + "Test creating multiselection with text" + Selection = Pool().get('test.multi_selection_text') -@unittest.skipIf( - backend.name != 'postgresql', 'jsonb only supported by postgresql') -class FieldMultiSelectionJSONBTestCase(FieldMultiSelectionTestCase): + selection, selection_none = Selection.create([{ + 'selects': ['foo', 'bar'], + }, { + 'selects': None, + }]) - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.setup_model() + self.assertEqual(selection.selects, ('bar', 'foo')) + self.assertEqual(selection_none.selects, ()) + + @with_transaction() + def test_write_text(self): + "Test write selection with text" + Selection = Pool().get('test.multi_selection_text') + selection, = Selection.create([{ + 'selects': ['foo'], + }]) + + Selection.write([selection], { + 'selects': ['foo', 'bar'], + }) + + self.assertEqual(selection.selects, ('bar', 'foo')) - @classmethod @with_transaction() - def setup_model(cls): - connection = Transaction().connection - if backend.Database().get_version(connection) < (9, 2): - return - pool = Pool() - for model in ['test.multi_selection', 'test.multi_selection_required']: - Model = pool.get(model) - cursor = connection.cursor() - for name, field in Model._fields.items(): - if field._type == 'multiselection': - cursor.execute('ALTER TABLE "%s" ' - 'ALTER COLUMN %s TYPE json USING %s::json' % ( - Model._table, name, name)) - Transaction().commit() + def test_search_equals_text(self): + "Test search selection equals" + Selection = Pool().get('test.multi_selection_text') + selection, = Selection.create([{ + 'selects': ['bar', 'foo'], + }]) + + foo_bar = Selection.search([ + ('selects', '=', ['foo', 'bar']), + ]) + foo = Selection.search([ + ('selects', '=', ['foo']), + ]) + + self.assertEqual(foo_bar, [selection]) + self.assertEqual(foo, [])