[PATCH 14 of 18 seda] [itree / hooks] Keep ordering sequential on child removal

Sylvain Thenault sylvain.thenault at logilab.fr
Mon Dec 11 16:53:46 CET 2017


# HG changeset patch
# User Sylvain Thénault <sylvain.thenault at logilab.fr>
# Date 1513001580 -3600
#      Mon Dec 11 15:13:00 2017 +0100
# Node ID 6860d9ed3e19f3c2f42e851055119c7ad0006aa6
# Parent  c5789035e5683604503063d1bb03138fb128f3a1
[itree / hooks] Keep ordering sequential on child removal

because we have to keep this property in the targeted ordering implementation.

diff --git a/cubicweb_seda/entities/itree.py b/cubicweb_seda/entities/itree.py
--- a/cubicweb_seda/entities/itree.py
+++ b/cubicweb_seda/entities/itree.py
@@ -214,10 +214,23 @@ def move_child_at_index(cnx, parent_eid,
                       'porder': None if reparenting else child.ordering,
                       'p': parent_eid}).rows
     child.cw_set(ordering=order)
 
 
+def prepare_child_removal(child):
+    """Before `child` will be removed or reparented, update its former parent's
+    child to keep their `ordering` attribute sequential.
+
+    This is expected to be called by a hook.
+    """
+    rtype = ETYPE_PARENT_RTYPE[child.cw_etype]
+    child._cw.execute(
+        'SET C ordering CO - 1 WHERE C ordering CO, C ordering > XO, '
+        'X ordering XO, X {rtype} P, C {rtype} P, X eid %(x)s'.format(rtype=rtype),
+        {'x': child.eid}).rows
+
+
 def reparent(entity, new_parent_eid):
     """Move `entity` as a children of `new_parent_eid`.
     """
     rtype = ETYPE_PARENT_RTYPE[entity.cw_etype]
     entity.cw_set(**{rtype: new_parent_eid})
diff --git a/cubicweb_seda/hooks.py b/cubicweb_seda/hooks.py
--- a/cubicweb_seda/hooks.py
+++ b/cubicweb_seda/hooks.py
@@ -25,11 +25,11 @@ from cubicweb import _
 from cubicweb.predicates import is_instance, score_entity
 from cubicweb.server import hook
 
 from .xsd2yams import MULTIPLE_CHILDREN
 from .entities import rule_type_from_etype, diag
-from .entities.itree import next_child_ordering
+from .entities.itree import next_child_ordering, prepare_child_removal
 from .entities.generated import (CHOICE_RTYPE,
                                  CHECK_CARD_ETYPES, CHECK_CHILDREN_CARD_RTYPES)
 
 
 SEDA_PARENT_RTYPES = {}
@@ -519,11 +519,25 @@ class SetOrderingHook(hook.Hook):
 
     def __call__(self):
         eid, parent_eid = self.eidfrom, self.eidto
         ordering = next_child_ordering(self._cw, parent_eid, self.rtype)
         entity = self._cw.entity_from_eid(eid)
-        entity.cw_set(ordering=ordering + 1)
+        entity.cw_set(ordering=ordering)
+
+
+class KeepOrderingSequentielHook(hook.Hook):
+    """Hook to keep `ordering` attribute of sibbling entities sequential when some
+    relation will be removed.
+    """
+    __regid__ = 'seda.ordering.remove'
+    __select__ = hook.Hook.__select__ & hook.match_rtype_sets(
+        {rtype for _, rtype in MULTIPLE_CHILDREN})
+
+    events = ('before_delete_relation',)
+
+    def __call__(self):
+        prepare_child_removal(self._cw.entity_from_eid(self.eidfrom))
 
 
 def registration_callback(vreg):
     from cubicweb.server import ON_COMMIT_ADD_RELATIONS
     from cubicweb_seda import seda_profile_container_def, iter_all_rdefs
diff --git a/test/test_hooks.py b/test/test_hooks.py
--- a/test/test_hooks.py
+++ b/test/test_hooks.py
@@ -304,11 +304,11 @@ class DispatchFileCategoryTC(CubicWebTC)
         self.assertEqual(mime_types, set(expected_mime_types))
         format_ids = set(x.label() for x in bdo.reverse_seda_format_id_from[0].seda_format_id_to)
         self.assertEqual(format_ids, set(expected_format_ids))
 
 
-class SetOrderingHooksTC(CubicWebTC):
+class OrderingHooksTC(CubicWebTC):
 
     def test_first_level_archive_units(self):
         with self.admin_access.cnx() as cnx:
             transfer = cnx.create_entity('SEDAArchiveTransfer', title=u'test profile')
             unit1 = testutils.create_archive_unit(transfer)[0]
@@ -343,9 +343,22 @@ class SetOrderingHooksTC(CubicWebTC):
             self.assertEqual(bdo1.ordering, 1)
             self.assertEqual(bdo2.ordering, 2)
             self.assertEqual(bdo1.reverse_seda_data_object_reference_id[0].ordering, 1)
             self.assertEqual(bdo2.reverse_seda_data_object_reference_id[0].ordering, 2)
 
+    def test_remove_keep_in_sync(self):
+        with self.admin_access.cnx() as cnx:
+            transfer = cnx.create_entity('SEDAArchiveTransfer', title=u'test profile')
+            bdo1 = testutils.create_data_object(transfer)
+            bdo2 = testutils.create_data_object(transfer)
+            cnx.commit()
+
+            bdo1.cw_delete()
+            cnx.commit()
+
+            bdo2.cw_clear_all_caches()
+            self.assertEqual(bdo2.ordering, 1)
+
 
 if __name__ == '__main__':
     import unittest
     unittest.main()


More information about the saem-devel mailing list