[schema migration] make some stuff to ease file 1.9 migration : we want to kill the Image entity so that existing image are turned into (existing entity type) File entities
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 20 May 2010 20:50:03 +0200
changeset 5558 afd1face1faf
parent 5557 1a534c596bff
child 5559 6b183d860295
[schema migration] make some stuff to ease file 1.9 migration : we want to kill the Image entity so that existing image are turned into (existing entity type) File entities
hooks/syncschema.py
schema.py
server/migractions.py
server/schemaserial.py
--- a/hooks/syncschema.py	Thu May 20 20:50:00 2010 +0200
+++ b/hooks/syncschema.py	Thu May 20 20:50:03 2010 +0200
@@ -34,7 +34,8 @@
 
 from cubicweb import ValidationError
 from cubicweb.selectors import implements
-from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, CONSTRAINTS, display_name
+from cubicweb.schema import (META_RTYPES, VIRTUAL_RTYPES, CONSTRAINTS,
+                             ETYPE_NAME_MAP, display_name)
 from cubicweb.server import hook, schemaserial as ss
 from cubicweb.server.sqlutils import SQL_PREFIX
 
@@ -815,9 +816,10 @@
         if name in CORE_ETYPES:
             raise ValidationError(self.entity.eid, {None: self._cw._('can\'t be deleted')})
         # delete every entities of this type
-        self._cw.execute('DELETE %s X' % name)
+        if not name in ETYPE_NAME_MAP:
+            self._cw.execute('DELETE %s X' % name)
+            MemSchemaCWETypeDel(self._cw, name)
         DropTable(self._cw, table=SQL_PREFIX + name)
-        MemSchemaCWETypeDel(self._cw, name)
 
 
 class AfterDelCWETypeHook(DelCWETypeHook):
@@ -982,7 +984,11 @@
 
     def __call__(self):
         session = self._cw
-        rdef = session.vreg.schema.schema_by_eid(self.eidfrom)
+        try:
+            rdef = session.vreg.schema.schema_by_eid(self.eidfrom)
+        except KeyError:
+            self.critical('cant get schema rdef associated to %s', self.eidfrom)
+            return
         subjschema, rschema, objschema = rdef.as_triple()
         pendings = session.transaction_data.get('pendingeids', ())
         pendingrdefs = session.transaction_data.setdefault('pendingrdefs', set())
@@ -1003,7 +1009,6 @@
         # we have to update physical schema systematically for final and inlined
         # relations, but only if it's the last instance for this relation type
         # for other relations
-
         if (rschema.final or rschema.inlined):
             rset = execute('Any COUNT(X) WHERE X is %s, X relation_type R, '
                            'R eid %%(x)s, X from_entity E, E name %%(name)s'
--- a/schema.py	Thu May 20 20:50:00 2010 +0200
+++ b/schema.py	Thu May 20 20:50:03 2010 +0200
@@ -568,7 +568,14 @@
         rdef.name = rdef.name.lower()
         rdef.subject = bw_normalize_etype(rdef.subject)
         rdef.object = bw_normalize_etype(rdef.object)
-        rdefs = super(CubicWebSchema, self).add_relation_def(rdef)
+        try:
+            rdefs = super(CubicWebSchema, self).add_relation_def(rdef)
+        except BadSchemaDefinition:
+            reversed_etype_map = dict( (v, k) for k, v in ETYPE_NAME_MAP.iteritems() )
+            if rdef.subject in reversed_etype_map or rdef.object in reversed_etype_map:
+                self.warning('huuuu')
+                return
+            raise
         if rdefs:
             try:
                 self._eid_index[rdef.eid] = rdefs
--- a/server/migractions.py	Thu May 20 20:50:00 2010 +0200
+++ b/server/migractions.py	Thu May 20 20:50:03 2010 +0200
@@ -51,7 +51,8 @@
 from yams.schema2sql import eschema2sql, rschema2sql
 
 from cubicweb import AuthenticationError
-from cubicweb.schema import (META_RTYPES, VIRTUAL_RTYPES,
+from cubicweb.schema import (ETYPE_NAME_MAP, META_RTYPES, VIRTUAL_RTYPES,
+                             PURE_VIRTUAL_RTYPES,
                              CubicWebRelationSchema, order_eschemas)
 from cubicweb.dbapi import get_repository, repo_connect
 from cubicweb.migration import MigrationHelper, yes
@@ -851,9 +852,23 @@
         `oldname` is a string giving the name of the existing entity type
         `newname` is a string giving the name of the renamed entity type
         """
-        self.rqlexec('SET ET name %(newname)s WHERE ET is CWEType, ET name %(oldname)s',
-                     {'newname' : unicode(newname), 'oldname' : oldname},
-                     ask_confirm=False)
+        schema = self.repo.schema
+        if newname in schema:
+            assert oldname in ETYPE_NAME_MAP, \
+                   '%s should be mappend to %s in ETYPE_NAME_MAP' % (oldname, newname)
+            attrs = ','.join([SQL_PREFIX + rschema.type
+                              for rschema in schema[newname].subject_relations()
+                              if (rschema.final or rschema.inlined)
+                              and not rschema in PURE_VIRTUAL_RTYPES])
+            self.sqlexec('INSERT INTO %s%s(%s) SELECT %s FROM %s%s' % (
+                SQL_PREFIX, newname, attrs, attrs, SQL_PREFIX, oldname))
+            # use rql to propagate deletion. XXX we may miss some stuff since
+            # only the bootstrap schema is set.
+            self.rqlexec('DELETE CWEType ET WHERE ET name %(n)s', {'n': oldname})
+        else:
+            self.rqlexec('SET ET name %(newname)s WHERE ET is CWEType, ET name %(oldname)s',
+                         {'newname' : unicode(newname), 'oldname' : oldname},
+                         ask_confirm=False)
         if commit:
             self.commit()
 
--- a/server/schemaserial.py	Thu May 20 20:50:00 2010 +0200
+++ b/server/schemaserial.py	Thu May 20 20:50:03 2010 +0200
@@ -27,7 +27,9 @@
 
 from yams import schema as schemamod, buildobjs as ybo
 
-from cubicweb.schema import CONSTRAINTS, ETYPE_NAME_MAP, VIRTUAL_RTYPES
+from cubicweb import CW_SOFTWARE_ROOT
+from cubicweb.schema import (CONSTRAINTS, ETYPE_NAME_MAP,
+                             VIRTUAL_RTYPES, PURE_VIRTUAL_RTYPES)
 from cubicweb.server import sqlutils
 
 def group_mapping(cursor, interactive=True):
@@ -100,17 +102,28 @@
             sidx[eid] = eschema
             continue
         if etype in ETYPE_NAME_MAP:
+            needcopy = False
             netype = ETYPE_NAME_MAP[etype]
             # can't use write rql queries at this point, use raw sql
-            session.system_sql('UPDATE %(p)sCWEType SET %(p)sname=%%(n)s WHERE %(p)seid=%%(x)s'
-                               % {'p': sqlutils.SQL_PREFIX},
-                               {'x': eid, 'n': netype})
-            session.system_sql('UPDATE entities SET type=%(n)s WHERE type=%(x)s',
-                               {'x': etype, 'n': netype})
+            sqlexec = session.system_sql
+            if sqlexec('SELECT 1 FROM %(p)sCWEType WHERE %(p)sname=%%(n)s'
+                       % {'p': sqlutils.SQL_PREFIX}, {'n': netype}).fetchone():
+                # the new type already exists, we should merge
+                assert etype.lower() != netype.lower()
+                needcopy = True
+            else:
+                # the new type doesn't exist, we should rename
+                sqlexec('UPDATE %(p)sCWEType SET %(p)sname=%%(n)s WHERE %(p)seid=%%(x)s'
+                        % {'p': sqlutils.SQL_PREFIX}, {'x': eid, 'n': netype})
+                if etype.lower() != netype.lower():
+                    sqlexec('ALTER TABLE %s%s RENAME TO %s%s' % (
+                        sqlutils.SQL_PREFIX, etype, sqlutils.SQL_PREFIX, netype))
+            sqlexec('UPDATE entities SET type=%(n)s WHERE type=%(x)s',
+                    {'x': etype, 'n': netype})
             session.commit(False)
             try:
-                session.system_sql('UPDATE deleted_entities SET type=%(n)s WHERE type=%(x)s',
-                                   {'x': etype, 'n': netype})
+                sqlexec('UPDATE deleted_entities SET type=%(n)s WHERE type=%(x)s',
+                        {'x': etype, 'n': netype})
             except:
                 pass
             tocleanup = [eid]
@@ -118,6 +131,12 @@
                           if etype == eidetype)
             repo.clear_caches(tocleanup)
             session.commit(False)
+            if needcopy:
+                from logilab.common.testlib import mock_object
+                sidx[eid] = mock_object(type=netype)
+                # copy / CWEType entity removal expected to be done through
+                # rename_entity_type in a migration script
+                continue
             etype = netype
         etype = ybo.EntityType(name=etype, description=desc, eid=eid)
         eschema = schema.add_entity_type(etype)