Skip to content

Commit 016bed1

Browse files
committed
Reorder signal emitting when adding/updating items in DB Editor
We must emit items_added and items_updated before we wake up fetch parents. Otherwise relationship_graph cache is not updated and we may fail to find added relationships when duplicating items. Re #3325
1 parent 32ef085 commit 016bed1

3 files changed

Lines changed: 45 additions & 5 deletions

File tree

spinetoolbox/cache_graphs.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ def maybe_invalidate_caches_after_fetch(self, item_type: ItemType, db_map: Datab
4747

4848

4949
class SuperclassGraphBase(GraphBase):
50-
INVALIDATING_ITEM_TYPES: ClassVar[set[str]] = {"entity_class", "superclass_subclass"}
51-
5250
def is_any_id_reachable(self, db_map: DatabaseMapping, source_id: TempId, target_ids: set[TempId]) -> bool:
5351
if db_map not in self._graphs:
5452
self._graphs[db_map] = self._build_graph(db_map)
@@ -67,6 +65,8 @@ def _build_graph(db_map: DatabaseMapping) -> nx.DiGraph:
6765

6866

6967
class RelationshipClassGraph(SuperclassGraphBase):
68+
INVALIDATING_ITEM_TYPES: ClassVar[set[str]] = {"entity_class", "superclass_subclass"}
69+
7070
@staticmethod
7171
def _build_graph(db_map: DatabaseMapping) -> nx.DiGraph:
7272
graph = _build_graph(db_map, "entity_class", "dimension_id_list")
@@ -78,6 +78,8 @@ def _build_graph(db_map: DatabaseMapping) -> nx.DiGraph:
7878

7979

8080
class RelationshipGraph(SuperclassGraphBase):
81+
INVALIDATING_ITEM_TYPES: ClassVar[set[str]] = {"entity", "entity_class", "superclass_subclass"}
82+
8183
@staticmethod
8284
def _build_graph(db_map: DatabaseMapping) -> nx.DiGraph:
8385
return _build_graph(db_map, "entity", "element_id_list")

spinetoolbox/spine_db_worker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,10 @@ def add_update_items(self, item_type, orig_items, check):
268268
added, updated, errors = self._db_map.add_update_items(item_type, *orig_items, check=check)
269269
if errors:
270270
self._db_mngr.error_msg.emit({self._db_map: errors})
271-
self._db_mngr.update_icons(self._db_map, item_type, added + updated)
272-
self._wake_up_parents(item_type, added)
273271
self._db_mngr.items_added.emit(item_type, {self._db_map: added})
274272
self._db_mngr.items_updated.emit(item_type, {self._db_map: updated})
273+
self._db_mngr.update_icons(self._db_map, item_type, added + updated)
274+
self._wake_up_parents(item_type, added)
275275
return added, updated
276276

277277
@busy_effect

tests/spine_db_editor/widgets/test_custom_qtreeview.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"""Unit tests for DB editor's custom ``QTreeView`` classes."""
1414

1515
from unittest import mock
16-
from PySide6.QtCore import QItemSelection, QItemSelectionModel, Qt
16+
from PySide6.QtCore import QItemSelection, QItemSelectionModel, QModelIndex, Qt
1717
from PySide6.QtWidgets import QApplication
1818
import pytest
1919
from spinedb_api import (
@@ -734,6 +734,44 @@ def test_removing_element_removes_corresponding_entity(self, entity_tree_model,
734734
assert len(data) == 4
735735
assert {i.name for i in data} == {"object_11", "object_12", "object_22", "object_11__object_22"}
736736

737+
def test_duplicate_element(self, entity_tree_model, db_mngr, db_map, db_editor):
738+
o11_id = db_map.entity(entity_class_name="object_class_1", name="object_11")["id"]
739+
r1_id = db_map.entity(entity_class_name="relationship_class", entity_byname=("object_11", "object_21"))["id"]
740+
assert db_mngr.relationship_graph.is_any_id_reachable(db_map, r1_id, {o11_id})
741+
view = db_editor.ui.treeView_entity
742+
model = entity_tree_model
743+
root_index = model.index(0, 0)
744+
model.fetchMore(root_index)
745+
while model.rowCount(root_index) != 3:
746+
QApplication.processEvents()
747+
class_index = model.index(0, 0, root_index)
748+
assert class_index.data() == "object_class_1"
749+
model.fetchMore(class_index)
750+
while model.rowCount(class_index) != 2:
751+
QApplication.processEvents()
752+
object_index = model.index(0, 0, class_index)
753+
assert object_index.data() == "object_11"
754+
view.selectionModel().setCurrentIndex(object_index, QItemSelectionModel.SelectionFlag.ClearAndSelect)
755+
view._context_item = model.item_from_index(object_index)
756+
view.duplicate_entity()
757+
QApplication.processEvents()
758+
root_index = model.index(0, 0)
759+
model.fetchMore(root_index)
760+
while model.rowCount(root_index) != 3:
761+
QApplication.processEvents()
762+
class_index = model.index(0, 0, root_index)
763+
assert class_index.data() == "object_class_1"
764+
model.fetchMore(class_index)
765+
while model.rowCount(class_index) != 3:
766+
QApplication.processEvents()
767+
object_index = model.index(1, 0, class_index)
768+
assert object_index.data() == "object_11 (1)"
769+
model.fetchMore(object_index)
770+
while model.rowCount(object_index) != 2:
771+
QApplication.processEvents()
772+
assert model.index(0, 0, object_index).data() == "٭ ǀ object_21"
773+
assert model.index(1, 0, object_index).data() == "٭ ǀ object_22"
774+
737775
@staticmethod
738776
def _rename_class(class_name, db_editor):
739777
view = db_editor.ui.treeView_entity

0 commit comments

Comments
 (0)