[integrity] keep ordering for schema integrity checks stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 18 May 2010 14:28:44 +0200
branchstable
changeset 5538 752bc67064f2
parent 5537 2889091bd1bf
child 5539 f927e6a322a6
[integrity] keep ordering for schema integrity checks set_operation gained a new containercls argument, so one can choose to use list or set (by default). Use this when registering schema integrity check operation.
entities/test/unittest_wfobjs.py
hooks/integrity.py
server/hook.py
--- a/entities/test/unittest_wfobjs.py	Tue May 18 14:26:19 2010 +0200
+++ b/entities/test/unittest_wfobjs.py	Tue May 18 14:28:44 2010 +0200
@@ -56,7 +56,7 @@
         self.commit()
         wf.add_state(u'foo')
         ex = self.assertRaises(ValidationError, self.commit)
-        self.assertEquals(ex.errors, {'state_of-subject': 'workflow already have a state of that name'})
+        self.assertEquals(ex.errors, {'name-subject': 'workflow already have a state of that name'})
         # no pb if not in the same workflow
         wf2 = add_wf(self, 'Company')
         foo = wf2.add_state(u'foo', initial=True)
--- a/hooks/integrity.py	Tue May 18 14:26:19 2010 +0200
+++ b/hooks/integrity.py	Tue May 18 14:28:44 2010 +0200
@@ -136,10 +136,10 @@
             if rdef.role_cardinality(role) in '1+':
                 if role == 'subject':
                     set_operation(self._cw, '_cwisrel', (eid, rschema.type),
-                                  _CheckSRelationOp)
+                                  _CheckSRelationOp, list)
                 else:
                     set_operation(self._cw, '_cwiorel', (eid, rschema.type),
-                                  _CheckORelationOp)
+                                  _CheckORelationOp, list)
 
     def before_delete_relation(self):
         rtype = self.rtype
@@ -153,10 +153,10 @@
         card = session.schema_rproperty(rtype, eidfrom, eidto, 'cardinality')
         if card[0] in '1+' and not session.deleted_in_transaction(eidfrom):
             set_operation(self._cw, '_cwisrel', (eidfrom, rtype),
-                          _CheckSRelationOp)
+                          _CheckSRelationOp, list)
         if card[1] in '1+' and not session.deleted_in_transaction(eidto):
             set_operation(self._cw, '_cwiorel', (eidto, rtype),
-                          _CheckORelationOp)
+                          _CheckORelationOp, list)
 
 
 class _CheckConstraintsOp(hook.LateOperation):
@@ -205,7 +205,7 @@
         if constraints:
             hook.set_operation(self._cw, 'check_constraints_op',
                                (self.eidfrom, self.rtype, self.eidto, tuple(constraints)),
-                               _CheckConstraintsOp)
+                               _CheckConstraintsOp, list)
 
 
 class CheckAttributeConstraintHook(IntegrityHook):
@@ -226,7 +226,7 @@
                 if constraints:
                     hook.set_operation(self._cw, 'check_constraints_op',
                                        (self.entity.eid, attr, None, tuple(constraints)),
-                                       _CheckConstraintsOp)
+                                       _CheckConstraintsOp, list)
 
 
 class CheckUniqueHook(IntegrityHook):
--- a/server/hook.py	Tue May 18 14:26:19 2010 +0200
+++ b/server/hook.py	Tue May 18 14:28:44 2010 +0200
@@ -473,23 +473,27 @@
 
 set_log_methods(Operation, getLogger('cubicweb.session'))
 
+def _container_add(container, value):
+    {set: set.add, list: list.append}[container.__class__](container, value)
 
-def set_operation(session, datakey, value, opcls, **opkwargs):
+def set_operation(session, datakey, value, opcls, containercls=set, **opkwargs):
     """Search for session.transaction_data[`datakey`] (expected to be a set):
 
     * if found, simply append `value`
 
-    * else, initialize it to set([`value`]) and instantiate the given `opcls`
-      operation class with additional keyword arguments.
+    * else, initialize it to containercls([`value`]) and instantiate the given
+      `opcls` operation class with additional keyword arguments. `containercls`
+      is a set by default. Give `list` if you want to keep arrival ordering.
 
     You should use this instead of creating on operation for each `value`,
     since handling operations becomes coslty on massive data import.
     """
     try:
-        session.transaction_data[datakey].add(value)
+        _container_add(session.transaction_data[datakey], value)
     except KeyError:
         opcls(session, **opkwargs)
-        session.transaction_data[datakey] = set((value,))
+        session.transaction_data[datakey] = containercls()
+        _container_add(session.transaction_data[datakey], value)
 
 
 class LateOperation(Operation):