[sources] reorganize abstract source code, drop no more used cleanup_entities_info and _cleanup_system_relations methods
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 07 Feb 2011 15:13:05 +0100
changeset 6943 406a41c25e13
parent 6942 18bdddd3740f
child 6944 0cf10429ad39
[sources] reorganize abstract source code, drop no more used cleanup_entities_info and _cleanup_system_relations methods
server/msplanner.py
server/sources/__init__.py
server/sources/ldapuser.py
server/test/unittest_msplanner.py
--- a/server/msplanner.py	Mon Feb 07 15:13:05 2011 +0100
+++ b/server/msplanner.py	Mon Feb 07 15:13:05 2011 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
--- a/server/sources/__init__.py	Mon Feb 07 15:13:05 2011 +0100
+++ b/server/sources/__init__.py	Mon Feb 07 15:13:05 2011 +0100
@@ -19,10 +19,10 @@
 
 __docformat__ = "restructuredtext en"
 
+import itertools
 from os.path import join, splitext
 from datetime import datetime, timedelta
 from logging import getLogger
-import itertools
 
 from cubicweb import set_log_methods, server
 from cubicweb.schema import VIRTUAL_RTYPES
@@ -113,41 +113,6 @@
         self.public_config = source_config.copy()
         self.remove_sensitive_information(self.public_config)
 
-    def init_creating(self):
-        """method called by the repository once ready to create a new instance"""
-        pass
-
-    def init(self, activated, session=None):
-        """method called by the repository once ready to handle request.
-        `activated` is a boolean flag telling if the source is activated or not.
-        """
-        pass
-
-    def backup(self, backupfile, confirm):
-        """method called to create a backup of source's data"""
-        pass
-
-    def restore(self, backupfile, confirm, drop):
-        """method called to restore a backup of source's data"""
-        pass
-
-    def close_pool_connections(self):
-        for pool in self.repo.pools:
-            pool._cursors.pop(self.uri, None)
-            pool.source_cnxs[self.uri][1].close()
-
-    def open_pool_connections(self):
-        for pool in self.repo.pools:
-            pool.source_cnxs[self.uri] = (self, self.get_connection())
-
-    def reset_caches(self):
-        """method called during test to reset potential source caches"""
-        pass
-
-    def clear_eid_cache(self, eid, etype):
-        """clear potential caches for the given eid"""
-        pass
-
     def __repr__(self):
         return '<%s source %s @%#x>' % (self.uri, self.eid, id(self))
 
@@ -163,10 +128,87 @@
             return -1
         return cmp(self.uri, other.uri)
 
+    def backup(self, backupfile, confirm):
+        """method called to create a backup of source's data"""
+        pass
+
+    def restore(self, backupfile, confirm, drop):
+        """method called to restore a backup of source's data"""
+        pass
+
+    # source initialization / finalization #####################################
+
     def set_schema(self, schema):
         """set the instance'schema"""
         self.schema = schema
 
+    def init_creating(self):
+        """method called by the repository once ready to create a new instance"""
+        pass
+
+    def init(self, activated, session=None):
+        """method called by the repository once ready to handle request.
+        `activated` is a boolean flag telling if the source is activated or not.
+        """
+        pass
+
+    PUBLIC_KEYS = ('type', 'uri')
+    def remove_sensitive_information(self, sourcedef):
+        """remove sensitive information such as login / password from source
+        definition
+        """
+        for key in sourcedef.keys():
+            if not key in self.PUBLIC_KEYS:
+                sourcedef.pop(key)
+
+    # connections handling #####################################################
+
+    def get_connection(self):
+        """open and return a connection to the source"""
+        raise NotImplementedError()
+
+    def check_connection(self, cnx):
+        """Check connection validity, return None if the connection is still
+        valid else a new connection (called when the pool using the given
+        connection is being attached to a session). Do nothing by default.
+        """
+        pass
+
+    def close_pool_connections(self):
+        for pool in self.repo.pools:
+            pool._cursors.pop(self.uri, None)
+            pool.source_cnxs[self.uri][1].close()
+
+    def open_pool_connections(self):
+        for pool in self.repo.pools:
+            pool.source_cnxs[self.uri] = (self, self.get_connection())
+
+    def pool_reset(self, cnx):
+        """the pool using the given connection is being reseted from its current
+        attached session
+
+        do nothing by default
+        """
+        pass
+
+    # cache handling ###########################################################
+
+    def reset_caches(self):
+        """method called during test to reset potential source caches"""
+        pass
+
+    def clear_eid_cache(self, eid, etype):
+        """clear potential caches for the given eid"""
+        pass
+
+    # external source api ######################################################
+
+    def eid2extid(self, eid, session=None):
+        return self.repo.eid2extid(self, eid, session)
+
+    def extid2eid(self, value, etype, session=None, **kwargs):
+        return self.repo.extid2eid(self, value, etype, session, **kwargs)
+
     def support_entity(self, etype, write=False):
         """return true if the given entity's type is handled by this adapter
         if write is true, return true only if it's a RW support
@@ -221,98 +263,26 @@
             return rtype in self.cross_relations
         return rtype not in self.dont_cross_relations
 
-    def eid2extid(self, eid, session=None):
-        return self.repo.eid2extid(self, eid, session)
-
-    def extid2eid(self, value, etype, session=None, **kwargs):
-        return self.repo.extid2eid(self, value, etype, session, **kwargs)
+    def before_entity_insertion(self, session, lid, etype, eid):
+        """called by the repository when an eid has been attributed for an
+        entity stored here but the entity has not been inserted in the system
+        table yet.
 
-    PUBLIC_KEYS = ('type', 'uri')
-    def remove_sensitive_information(self, sourcedef):
-        """remove sensitive information such as login / password from source
-        definition
-        """
-        for key in sourcedef.keys():
-            if not key in self.PUBLIC_KEYS:
-                sourcedef.pop(key)
-
-    def _cleanup_system_relations(self, session):
-        """remove relation in the system source referencing entities coming from
-        this source
+        This method must return the an Entity instance representation of this
+        entity.
         """
-        cu = session.system_sql('SELECT eid FROM entities WHERE source=%(uri)s',
-                                {'uri': self.uri})
-        myeids = ','.join(str(r[0]) for r in cu.fetchall())
-        if not myeids:
-            return
-        # delete relations referencing one of those eids
-        eidcolum = SQL_PREFIX + 'eid'
-        for rschema in self.schema.relations():
-            if rschema.final or rschema.type in VIRTUAL_RTYPES:
-                continue
-            if rschema.inlined:
-                column = SQL_PREFIX + rschema.type
-                for subjtype in rschema.subjects():
-                    table = SQL_PREFIX + str(subjtype)
-                    for objtype in rschema.objects(subjtype):
-                        if self.support_entity(objtype):
-                            sql = 'UPDATE %s SET %s=NULL WHERE %s IN (%s);' % (
-                                table, column, eidcolum, myeids)
-                            session.system_sql(sql)
-                            break
-                continue
-            for etype in rschema.subjects():
-                if self.support_entity(etype):
-                    sql = 'DELETE FROM %s_relation WHERE eid_from IN (%s);' % (
-                        rschema.type, myeids)
-                    session.system_sql(sql)
-                    break
-            for etype in rschema.objects():
-                if self.support_entity(etype):
-                    sql = 'DELETE FROM %s_relation WHERE eid_to IN (%s);' % (
-                        rschema.type, myeids)
-                    session.system_sql(sql)
-                    break
+        entity = self.repo.vreg['etypes'].etype_class(etype)(session)
+        entity.eid = eid
+        entity.cw_edited = EditedEntity(entity)
+        return entity
 
-    def cleanup_entities_info(self, session):
-        """cleanup system tables from information for entities coming from
-        this source. This should be called when a source is removed to
-        properly cleanup the database
-        """
-        self._cleanup_system_relations(session)
-        # fti / entities tables cleanup
-        # sqlite doesn't support DELETE FROM xxx USING yyy
-        dbhelper = session.pool.source('system').dbhelper
-        session.system_sql('DELETE FROM %s WHERE %s.%s IN (SELECT eid FROM '
-                           'entities WHERE entities.source=%%(uri)s)'
-                           % (dbhelper.fti_table, dbhelper.fti_table,
-                              dbhelper.fti_uid_attr),
-                           {'uri': self.uri})
-        session.system_sql('DELETE FROM entities WHERE source=%(uri)s',
-                           {'uri': self.uri})
-
-    # abstract methods to override (at least) in concrete source classes #######
-
-    def get_connection(self):
-        """open and return a connection to the source"""
-        raise NotImplementedError()
-
-    def check_connection(self, cnx):
-        """check connection validity, return None if the connection is still valid
-        else a new connection (called when the pool using the given connection is
-        being attached to a session)
-
-        do nothing by default
+    def after_entity_insertion(self, session, lid, entity):
+        """called by the repository after an entity stored here has been
+        inserted in the system table.
         """
         pass
 
-    def pool_reset(self, cnx):
-        """the pool using the given connection is being reseted from its current
-        attached session
-
-        do nothing by default
-        """
-        pass
+    # user authentication api ##################################################
 
     def authenticate(self, session, login, **kwargs):
         """if the source support CWUser entity type, it should implement
@@ -322,6 +292,8 @@
         """
         raise NotImplementedError()
 
+    # RQL query api ############################################################
+
     def syntax_tree_search(self, session, union,
                            args=None, cachekey=None, varmap=None, debug=0):
         """return result from this source for a rql query (actually from a rql
@@ -340,27 +312,7 @@
         res = self.syntax_tree_search(session, union, args, varmap=varmap)
         session.pool.source('system').manual_insert(res, table, session)
 
-    # system source don't have to implement the two methods below
-
-    def before_entity_insertion(self, session, lid, etype, eid):
-        """called by the repository when an eid has been attributed for an
-        entity stored here but the entity has not been inserted in the system
-        table yet.
-
-        This method must return the an Entity instance representation of this
-        entity.
-        """
-        entity = self.repo.vreg['etypes'].etype_class(etype)(session)
-        entity.eid = eid
-        entity.cw_edited = EditedEntity(entity)
-        return entity
-
-    def after_entity_insertion(self, session, lid, entity):
-        """called by the repository after an entity stored here has been
-        inserted in the system table.
-        """
-        pass
-
+    # write modification api ###################################################
     # read-only sources don't have to implement methods below
 
     def get_extid(self, entity):
--- a/server/sources/ldapuser.py	Mon Feb 07 15:13:05 2011 +0100
+++ b/server/sources/ldapuser.py	Mon Feb 07 15:13:05 2011 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
--- a/server/test/unittest_msplanner.py	Mon Feb 07 15:13:05 2011 +0100
+++ b/server/test/unittest_msplanner.py	Mon Feb 07 15:13:05 2011 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -20,7 +20,6 @@
 from __future__ import with_statement
 
 from logilab.common.decorators import clear_cache
-
 from yams.buildobjs import RelationDefinition
 from rql import BadRQLQuery
 
@@ -43,7 +42,6 @@
 from cubicweb.server.msplanner import MSPlanner, PartPlanInformation
 
 class FakeUserROSource(AbstractSource):
-    uri = 'zzz'
     support_entities = {'CWUser': False}
     support_relations = {}
     def syntax_tree_search(self, *args, **kwargs):
@@ -51,7 +49,6 @@
 
 
 class FakeCardSource(AbstractSource):
-    uri = 'ccc'
     support_entities = {'Card': True, 'Note': True, 'State': True}
     support_relations = {'in_state': True, 'multisource_rel': True, 'multisource_inlined_rel': True,
                          'multisource_crossed_rel': True,}