[server] change order of entities table modification vs entity creation/deletion
authorJulien Cristau <julien.cristau@logilab.fr>
Fri, 16 Jan 2015 14:30:55 +0100
changeset 10203 1443fe643a38
parent 10202 aaabcb64f77f
child 10204 f8ccae1e271d
[server] change order of entities table modification vs entity creation/deletion In order to have a foreign key referencing the entities table, the insertion into entities must happen first, and the deletion must happen last. For the deletion case, this means we need to: 1. delete all relations (cascade) 2. delete the entities themselves 3. delete the corresponding lines from the entities table This means the _delete_info{,_multi} methods can't keep doing 1 and 3. Thankfully the "public" delete_info method appears to be unused, so drop it. Related to #4846892.
server/repository.py
server/sources/native.py
server/test/unittest_repository.py
--- a/server/repository.py	Thu Jan 15 17:06:16 2015 +0100
+++ b/server/repository.py	Fri Jan 16 14:30:55 2015 +0100
@@ -1074,48 +1074,9 @@
         hook.CleanupNewEidsCacheOp.get_instance(session).add_data(entity.eid)
         self.system_source.add_info(session, entity, source, extid)
 
-    def delete_info(self, session, entity, sourceuri):
-        """called by external source when some entity known by the system source
-        has been deleted in the external source
-        """
-        # mark eid as being deleted in session info and setup cache update
-        # operation
-        hook.CleanupDeletedEidsCacheOp.get_instance(session).add_data(entity.eid)
-        self._delete_info(session, entity, sourceuri)
-
-    def _delete_info(self, session, entity, sourceuri):
-        """delete system information on deletion of an entity:
-
-        * delete all remaining relations from/to this entity
-        * call delete info on the system source
-        """
-        pendingrtypes = session.transaction_data.get('pendingrtypes', ())
-        # delete remaining relations: if user can delete the entity, he can
-        # delete all its relations without security checking
-        with session.security_enabled(read=False, write=False):
-            eid = entity.eid
-            for rschema, _, role in entity.e_schema.relation_definitions():
-                rtype = rschema.type
-                if rtype in schema.VIRTUAL_RTYPES or rtype in pendingrtypes:
-                    continue
-                if role == 'subject':
-                    # don't skip inlined relation so they are regularly
-                    # deleted and so hooks are correctly called
-                    rql = 'DELETE X %s Y WHERE X eid %%(x)s' % rtype
-                else:
-                    rql = 'DELETE Y %s X WHERE X eid %%(x)s' % rtype
-                try:
-                    session.execute(rql, {'x': eid}, build_descr=False)
-                except Exception:
-                    if self.config.mode == 'test':
-                        raise
-                    self.exception('error while cascading delete for entity %s '
-                                   'from %s. RQL: %s', entity, sourceuri, rql)
-        self.system_source.delete_info_multi(session, [entity])
-
-    def _delete_info_multi(self, session, entities):
-        """same as _delete_info but accepts a list of entities with
-        the same etype and belinging to the same source.
+    def _delete_cascade_multi(self, session, entities):
+        """same as _delete_cascade but accepts a list of entities with
+        the same etype and belonging to the same source.
         """
         pendingrtypes = session.transaction_data.get('pendingrtypes', ())
         # delete remaining relations: if user can delete the entity, he can
@@ -1146,7 +1107,6 @@
                         raise
                     self.exception('error while cascading delete for entity %s. RQL: %s',
                                    entities, rql)
-        self.system_source.delete_info_multi(session, entities)
 
     def init_entity_caches(self, cnx, entity, source):
         """add entity to connection entities cache and repo's extid cache.
@@ -1184,13 +1144,13 @@
         edited.set_defaults()
         if cnx.is_hook_category_activated('integrity'):
             edited.check(creation=True)
+        self.add_info(cnx, entity, source, extid)
         try:
             source.add_entity(cnx, entity)
         except UniqueTogetherError as exc:
             userhdlr = cnx.vreg['adapters'].select(
                 'IUserFriendlyError', cnx, entity=entity, exc=exc)
             userhdlr.raise_user_exception()
-        self.add_info(cnx, entity, source, extid)
         edited.saved = entity._cw_is_saved = True
         # trigger after_add_entity after after_add_relation
         self.hm.call_hooks('after_add_entity', cnx, entity=entity)
@@ -1305,8 +1265,9 @@
             if server.DEBUG & server.DBG_REPO:
                 print 'DELETE entities', etype, [entity.eid for entity in entities]
             self.hm.call_hooks('before_delete_entity', cnx, entities=entities)
-            self._delete_info_multi(cnx, entities)
+            self._delete_cascade_multi(cnx, entities)
             source.delete_entities(cnx, entities)
+            source.delete_info_multi(cnx, entities)
             self.hm.call_hooks('after_delete_entity', cnx, entities=entities)
         # don't clear cache here, it is done in a hook on commit
 
--- a/server/sources/native.py	Thu Jan 15 17:06:16 2015 +0100
+++ b/server/sources/native.py	Fri Jan 16 14:30:55 2015 +0100
@@ -1182,10 +1182,10 @@
         self.repo.hm.call_hooks('before_add_entity', cnx, entity=entity)
         # restore the entity
         action.changes['cw_eid'] = eid
+        # restore record in entities (will update fti if needed)
+        self.add_info(cnx, entity, self, None)
         sql = self.sqlgen.insert(SQL_PREFIX + etype, action.changes)
         self.doexec(cnx, sql, action.changes)
-        # restore record in entities (will update fti if needed)
-        self.add_info(cnx, entity, self, None)
         self.repo.hm.call_hooks('after_add_entity', cnx, entity=entity)
         return errors
 
--- a/server/test/unittest_repository.py	Thu Jan 15 17:06:16 2015 +0100
+++ b/server/test/unittest_repository.py	Fri Jan 16 14:30:55 2015 +0100
@@ -692,7 +692,8 @@
                 cu = cnx.system_sql('SELECT * FROM entities WHERE eid = -1')
                 data = cu.fetchall()
                 self.assertEqual(tuplify(data), [(-1, 'Personne', 'system', None)])
-                self.repo.delete_info(cnx, entity, 'system')
+                self.repo._delete_cascade_multi(cnx, [entity])
+                self.repo.system_source.delete_info_multi(cnx, [entity])
                 #self.repo.commit()
                 cu = cnx.system_sql('SELECT * FROM entities WHERE eid = -1')
                 data = cu.fetchall()