diff --git a/sandbox/grist/column.py b/sandbox/grist/column.py index 4b28011c..d2a12b30 100644 --- a/sandbox/grist/column.py +++ b/sandbox/grist/column.py @@ -330,7 +330,7 @@ class BaseReferenceColumn(BaseColumn): # self._data may include values for non-existent rows; it works here because those values are # falsy, which makes them ignored by self._update_references). for row_id, value in enumerate(self._data): - if isinstance(value, int): + if self.type_obj.is_right_type(value): self._update_references(row_id, None, value) def sample_value(self): diff --git a/sandbox/grist/test_reflist_rel.py b/sandbox/grist/test_reflist_rel.py new file mode 100644 index 00000000..aa498034 --- /dev/null +++ b/sandbox/grist/test_reflist_rel.py @@ -0,0 +1,102 @@ +""" +This test replicates a bug involving a column conversion after a table rename in the presence of +a RefList. A RefList column type today only appears as a result of detaching a summary table. +""" +import logger +import test_engine +from test_engine import Table, Column + +log = logger.Logger(__name__, logger.INFO) + +class TestRefListRelation(test_engine.EngineTestCase): + def test_ref_list_relation(self): + # Create two tables, the second referring to the first using a RefList and a Ref column. + self.apply_user_action(["AddTable", "TableA", [ + {"id": "ColA", "type": "Text"} + ]]) + self.apply_user_action(["AddTable", "TableB", [ + {"id": "ColB", "type": "Text"}, + {"id": "group", "type": "RefList:TableA", "isFormula": True, + "formula": "TableA.lookupRecords(ColA=$ColB)"}, + {"id": "ref", "type": "Ref:TableA", "isFormula": True, + "formula": "TableA.lookupOne(ColA=$ColB)"}, + ]]) + + # Populate the tables with some data. + self.apply_user_action(["BulkAddRecord", "TableA", [None]*4, + {"ColA": ["a", "b", "c", "d"]}]) + self.apply_user_action(["BulkAddRecord", "TableB", [None]*3, + {"ColB": ["d", "b", "a"]}]) + + # Rename the second table. This causes some Column objects to be re-created and copied from + # the previous table instance. This logic had a bug. + self.apply_user_action(["RenameTable", "TableB", "TableC"]) + + # Let's see what we've set up here. + self.assertTables([ + Table(1, "TableA", 1, 0, columns=[ + Column(1, "manualSort", "ManualSortPos", False, "", 0), + Column(2, "ColA", "Text", False, "", 0), + ]), + Table(2, "TableC", 2, 0, columns=[ + Column(3, "manualSort", "ManualSortPos", False, "", 0), + Column(4, "ColB", "Text", False, "", 0), + Column(5, "group", "RefList:TableA", True, "TableA.lookupRecords(ColA=$ColB)", 0), + Column(6, "ref", "Ref:TableA", True, "TableA.lookupOne(ColA=$ColB)", 0), + ]), + ]) + self.assertTableData('TableA', cols="subset", data=[ + [ "id", "ColA"], + [ 1, "a", ], + [ 2, "b", ], + [ 3, "c", ], + [ 4, "d", ], + ]) + self.assertTableData('TableC', cols="subset", data=[ + [ "id", "ColB", "group", "ref" ], + [ 1, "d", [4], 4 ], + [ 2, "b", [2], 2 ], + [ 3, "a", [1], 1 ], + ]) + + # Now when the logic was buggy, this sequence of action, as emitted by a user-initiated column + # conversion, triggered an internal exception. Ensure it no longer happens. + self.apply_user_action( + ['AddColumn', 'TableC', 'gristHelper_Transform', { + "type": 'Ref:TableA', "isFormula": True, + "formula": "grist.Reference.typeConvert($ColB, TableA, 'ColA')", "visibleCol": 2, + }]) + self.apply_user_action( + ['SetDisplayFormula', 'TableC', None, 7, '$gristHelper_Transform.ColA']) + self.apply_user_action( + ['CopyFromColumn', 'TableC', 'gristHelper_Transform', 'ColB', '{"widget":"Reference"}']) + self.apply_user_action( + ['RemoveColumn', 'TableC', 'gristHelper_Transform']) + + # Check what we have now. + self.assertTables([ + Table(1, "TableA", 1, 0, columns=[ + Column(1, "manualSort", "ManualSortPos", False, "", 0), + Column(2, "ColA", "Text", False, "", 0), + ]), + Table(2, "TableC", 2, 0, columns=[ + Column(3, "manualSort", "ManualSortPos", False, "", 0), + Column(4, "ColB", "Ref:TableA", False, "", 0), + Column(5, "group", "RefList:TableA", True, "TableA.lookupRecords(ColA=$ColB)", 0), + Column(6, "ref", "Ref:TableA", True, "TableA.lookupOne(ColA=$ColB)", 0), + Column(9, "gristHelper_Display2", "Any", True, "$ColB.ColA", 0), + ]), + ]) + self.assertTableData('TableA', cols="subset", data=[ + [ "id", "ColA"], + [ 1, "a", ], + [ 2, "b", ], + [ 3, "c", ], + [ 4, "d", ], + ]) + self.assertTableData('TableC', cols="subset", data=[ + [ "id", "ColB", "gristHelper_Display2", "group", "ref" ], + [ 1, 4, "d", [], 0 ], + [ 2, 2, "b", [], 0 ], + [ 3, 1, "a", [], 0 ], + ])