mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Two way reference polish
Summary: - Fixing BulkRemoveRecord bug - Rewriting copy on the `delete reverse column` dialog - Rewriting text on the `reassign reference dialog` - Adding tooltip that explains why 2-way references are not enabled for formula columns Test Plan: Added tests Reviewers: georgegevoian Reviewed By: georgegevoian Subscribers: paulfitz Differential Revision: https://phab.getgrist.com/D4355
This commit is contained in:
@@ -20,6 +20,9 @@ Bob = 2
|
||||
Penny = 3
|
||||
EmptyList = None
|
||||
|
||||
def uniqueReferences(rec):
|
||||
return rec.reverseCol and rec.reverseCol.type.startswith('Ref:')
|
||||
|
||||
class TestTwoWayReferences(test_engine.EngineTestCase):
|
||||
|
||||
def get_col_rec(self, tableId, colId):
|
||||
@@ -319,6 +322,16 @@ class TestTwoWayReferences(test_engine.EngineTestCase):
|
||||
# Add a pet named Rex with Bob as owner
|
||||
self.apply_user_action(["AddRecord", "Pets", 1, {"Name": "Rex", "Owner": Bob}])
|
||||
|
||||
self.assertTableData("Owners", cols="subset", data=[
|
||||
["id", "Name"],
|
||||
[Alice, "Alice"],
|
||||
[Bob, "Bob"],
|
||||
])
|
||||
self.assertTableData("Pets", cols="subset", data=[
|
||||
["id", "Name", "Owner"],
|
||||
[Rex, "Rex", Bob],
|
||||
])
|
||||
|
||||
|
||||
def test_uniques(self):
|
||||
self.load_pets()
|
||||
@@ -1192,9 +1205,78 @@ class TestTwoWayReferences(test_engine.EngineTestCase):
|
||||
[Rex, "Rex", Alice],
|
||||
])
|
||||
|
||||
def test_back_loop(self):
|
||||
"""
|
||||
Test that updating reverse column doesn't cause infinite loop.
|
||||
"""
|
||||
|
||||
def uniqueReferences(rec):
|
||||
return rec.reverseCol and rec.reverseCol.type.startswith('Ref:')
|
||||
# Load pets sample.
|
||||
self.load_pets()
|
||||
|
||||
# Add reverse column for Owner.
|
||||
self.apply_user_action(["AddReverseColumn", 'Pets', 'Owner'])
|
||||
|
||||
# Convert Pets to Ref:Owners.
|
||||
self.apply_user_action(["ModifyColumn", "Owners", "Pets", {"type": "Ref:Pets"}])
|
||||
|
||||
# Check the data.
|
||||
self.assertTableData("Pets", cols="subset", data=[
|
||||
["id", "Name", "Owner"],
|
||||
[1, "Rex", Bob],
|
||||
])
|
||||
|
||||
self.assertTableData("Owners", cols="subset", data=[
|
||||
["id", "Name", "Pets"],
|
||||
[1, "Alice", Empty],
|
||||
[2, "Bob", Rex],
|
||||
])
|
||||
|
||||
# Now move Rex to Alice using Pets table.
|
||||
self.apply_user_action(["UpdateRecord", "Pets", Rex, {"Owner": Alice}])
|
||||
|
||||
|
||||
def test_remove_in_bulk(self):
|
||||
"""
|
||||
Test that we can remove many rows at the same time. PReviously it ended up in an error,
|
||||
as the reverse column was trying to update the removed row.
|
||||
"""
|
||||
|
||||
# Load pets sample.
|
||||
self.load_pets()
|
||||
|
||||
# Add another dog.
|
||||
self.apply_user_action(["AddRecord", "Pets", Pluto, {"Name": "Pluto"}])
|
||||
|
||||
# Add reverse column for Owner.
|
||||
self.apply_user_action(["AddReverseColumn", 'Pets', 'Owner'])
|
||||
|
||||
# Add Pluto to Bob.
|
||||
self.apply_user_action(["UpdateRecord", "Pets", Pluto, {"Owner": Alice}])
|
||||
|
||||
# Test the data.
|
||||
self.assertTableData("Pets", cols="subset", data=[
|
||||
["id", "Name", "Owner"],
|
||||
[Rex, "Rex", Bob],
|
||||
[Pluto, "Pluto", Alice],
|
||||
])
|
||||
self.assertTableData("Owners", cols="subset", data=[
|
||||
["id", "Name", "Pets"],
|
||||
[1, "Alice", [Pluto]],
|
||||
[2, "Bob", [Rex]],
|
||||
])
|
||||
|
||||
# Now remove both dogs.
|
||||
self.apply_user_action(["BulkRemoveRecord", "Pets", [Rex, Pluto]])
|
||||
|
||||
# Make sure we see the data.
|
||||
self.assertTableData("Pets", cols="subset", data=[
|
||||
["id", "Name", "Owner"],
|
||||
])
|
||||
self.assertTableData("Owners", cols="subset", data=[
|
||||
["id", "Name", "Pets"],
|
||||
[1, "Alice", EmptyList],
|
||||
[2, "Bob", EmptyList],
|
||||
])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1164,13 +1164,19 @@ class UserActions(object):
|
||||
continue
|
||||
updates = ref_col.get_updates_for_removed_target_rows(row_id_set)
|
||||
if updates:
|
||||
# Previously we sent this as a docaction. Now we do a proper useraction with all the
|
||||
# processing that involves, e.g. triggering two-way-reference updates, and also all the
|
||||
# metadata checks and updates.
|
||||
self._BulkUpdateRecord_decoded(ref_col.table_id,
|
||||
[row_id for (row_id, value) in updates],
|
||||
{ ref_col.col_id: [value for (row_id, value) in updates] }
|
||||
)
|
||||
table_id = ref_col.table_id
|
||||
rows = [row_id for (row_id, value) in updates]
|
||||
columns = {ref_col.col_id: [value for (row_id, value) in updates]}
|
||||
if ref_col.table_id.startswith('_grist_'):
|
||||
# Previously we sent this as a docaction. Now we do a proper useraction with all the
|
||||
# processing that involves, e.g. triggering two-way-reference updates, and also all the
|
||||
# metadata checks and updates.
|
||||
self._BulkUpdateRecord_decoded(table_id, rows, columns)
|
||||
else:
|
||||
# But for normal user tables (with two-way references), we must still use the docaction,
|
||||
# otherwise we'd invoke two-way update logic, and the reverse column would try to update
|
||||
# rows that we just deleted.
|
||||
self._do_doc_action(actions.BulkUpdateRecord(table_id, rows, columns))
|
||||
|
||||
@useraction
|
||||
def RemoveRecord(self, table_id, row_id):
|
||||
|
||||
Reference in New Issue
Block a user