server/schemaserial.py
branchstable
changeset 6191 ece6996e6ac8
parent 6189 9fa02f352c8c
child 6199 a88902af3813
--- a/server/schemaserial.py	Tue Sep 07 23:34:16 2010 +0200
+++ b/server/schemaserial.py	Wed Sep 08 10:03:30 2010 +0200
@@ -24,7 +24,7 @@
 
 from logilab.common.shellutils import ProgressBar
 
-from yams import schema as schemamod, buildobjs as ybo
+from yams import BadSchemaDefinition, schema as schemamod, buildobjs as ybo
 
 from cubicweb import CW_SOFTWARE_ROOT, typed_eid
 from cubicweb.schema import (CONSTRAINTS, ETYPE_NAME_MAP,
@@ -87,7 +87,7 @@
     """
     repo = session.repo
     dbhelper = repo.system_source.dbhelper
-    # 3.6 migration
+    # XXX bw compat (3.6 migration)
     sqlcu = session.pool['system']
     sqlcu.execute("SELECT * FROM cw_CWRType WHERE cw_name='symetric'")
     if sqlcu.fetchall():
@@ -95,8 +95,9 @@
                                       dbhelper.TYPE_MAPPING['Boolean'], True)
         sqlcu.execute(sql)
         sqlcu.execute("UPDATE cw_CWRType SET cw_name='symmetric' WHERE cw_name='symetric'")
-    sidx = {}
-    permsdict = deserialize_ertype_permissions(session)
+    ertidx = {}
+    copiedeids = set()
+    permsidx = deserialize_ertype_permissions(session)
     schema.reading_from_database = True
     for eid, etype, desc in session.execute(
         'Any X, N, D WHERE X is CWEType, X name N, X description D',
@@ -106,7 +107,7 @@
             # just set the eid
             eschema = schema.eschema(etype)
             eschema.eid = eid
-            sidx[eid] = eschema
+            ertidx[eid] = etype
             continue
         if etype in ETYPE_NAME_MAP:
             needcopy = False
@@ -115,7 +116,8 @@
             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
+                # the new type already exists, we should copy (eg make existing
+                # instances of the old type instances of the new type)
                 assert etype.lower() != netype.lower()
                 needcopy = True
             else:
@@ -139,16 +141,16 @@
             repo.clear_caches(tocleanup)
             session.commit(False)
             if needcopy:
-                from logilab.common.testlib import mock_object
-                sidx[eid] = mock_object(type=netype)
+                ertidx[eid] = netype
+                copiedeids.add(eid)
                 # 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)
-        sidx[eid] = eschema
-        set_perms(eschema, permsdict)
+        ertidx[eid] = etype
+        eschema = schema.add_entity_type(
+            ybo.EntityType(name=etype, description=desc, eid=eid))
+        set_perms(eschema, permsidx)
     for etype, stype in session.execute(
         'Any XN, ETN WHERE X is CWEType, X name XN, X specializes ET, ET name ETN',
         build_descr=False):
@@ -159,43 +161,66 @@
     for eid, rtype, desc, sym, il, ftc in session.execute(
         'Any X,N,D,S,I,FTC WHERE X is CWRType, X name N, X description D, '
         'X symmetric S, X inlined I, X fulltext_container FTC', build_descr=False):
-        rtype = ybo.RelationType(name=rtype, description=desc,
-                                 symmetric=bool(sym), inlined=bool(il),
-                                 fulltext_container=ftc, eid=eid)
-        rschema = schema.add_relation_type(rtype)
-        sidx[eid] = rschema
-    cstrsdict = deserialize_rdef_constraints(session)
+        ertidx[eid] = rtype
+        rschema = schema.add_relation_type(
+            ybo.RelationType(name=rtype, description=desc,
+                             symmetric=bool(sym), inlined=bool(il),
+                             fulltext_container=ftc, eid=eid))
+    cstrsidx = deserialize_rdef_constraints(session)
+    pendingrdefs = []
+    # closure to factorize common code of attribute/relation rdef addition
+    def _add_rdef(rdefeid, seid, reid, oeid, **kwargs):
+        rdef = ybo.RelationDefinition(ertidx[seid], ertidx[reid], ertidx[oeid],
+                                      constraints=cstrsidx.get(rdefeid, ()),
+                                      eid=rdefeid, **kwargs)
+        if seid in copiedeids or oeid in copiedeids:
+            # delay addition of this rdef. We'll insert them later if needed. We
+            # have to do this because:
+            #
+            # * on etype renaming, we want relation of the old entity type being
+            #   redirected to the new type during migration
+            #
+            # * in the case of a copy, we've to take care that rdef already
+            #   existing in the schema are not overwritten by a redirected one,
+            #   since we want correct eid on them (redirected rdef will be
+            #   removed in rename_entity_type)
+            pendingrdefs.append(rdef)
+        else:
+            # add_relation_def return a RelationDefinitionSchema if it has been
+            # actually added (can be None on duplicated relation definitions,
+            # e.g. if the relation type is marked as beeing symmetric)
+            rdefs = schema.add_relation_def(rdef)
+            if rdefs is not None:
+                set_perms(rdefs, permsidx)
+
     for values in session.execute(
         'Any X,SE,RT,OE,CARD,ORD,DESC,IDX,FTIDX,I18N,DFLT WHERE X is CWAttribute,'
         'X relation_type RT, X cardinality CARD, X ordernum ORD, X indexed IDX,'
         'X description DESC, X internationalizable I18N, X defaultval DFLT,'
         'X fulltextindexed FTIDX, X from_entity SE, X to_entity OE',
         build_descr=False):
-        rdefeid, seid, reid, teid, card, ord, desc, idx, ftidx, i18n, default = values
-        rdef = ybo.RelationDefinition(sidx[seid].type, sidx[reid].type, sidx[teid].type,
-                                      cardinality=card,
-                                      constraints=cstrsdict.get(rdefeid, ()),
-                                      order=ord, description=desc,
-                                      indexed=idx, fulltextindexed=ftidx,
-                                      internationalizable=i18n,
-                                      default=default, eid=rdefeid)
-        rdefs = schema.add_relation_def(rdef)
-        # rdefs can be None on duplicated relation definitions (e.g. symmetrics)
-        if rdefs is not None:
-            set_perms(rdefs, permsdict)
+        rdefeid, seid, reid, oeid, card, ord, desc, idx, ftidx, i18n, default = values
+        _add_rdef(rdefeid, seid, reid, oeid,
+                  cardinality=card, description=desc, order=ord,
+                  indexed=idx, fulltextindexed=ftidx, internationalizable=i18n,
+                  default=default)
     for values in session.execute(
         'Any X,SE,RT,OE,CARD,ORD,DESC,C WHERE X is CWRelation, X relation_type RT,'
         'X cardinality CARD, X ordernum ORD, X description DESC, '
         'X from_entity SE, X to_entity OE, X composite C', build_descr=False):
-        rdefeid, seid, reid, teid, card, ord, desc, c = values
-        rdef = ybo.RelationDefinition(sidx[seid].type, sidx[reid].type, sidx[teid].type,
-                                      constraints=cstrsdict.get(rdefeid, ()),
-                                      cardinality=card, composite=c,
-                                      description=desc, order=ord, eid=rdefeid)
-        rdefs = schema.add_relation_def(rdef)
-        # rdefs can be None on duplicated relation definitions (e.g. symmetrics)
+        rdefeid, seid, reid, oeid, card, ord, desc, comp = values
+        _add_rdef(rdefeid, seid, reid, oeid,
+                  cardinality=card, description=desc, order=ord,
+                  composite=comp)
+    for rdef in pendingrdefs:
+        try:
+            rdefs = schema.add_relation_def(rdef)
+        except BadSchemaDefinition:
+            continue
+        if rdef.subject == 'TestConfig' or rdef.object == 'TestConfig':
+            print 'EXTRA', rdefs
         if rdefs is not None:
-            set_perms(rdefs, permsdict)
+            set_perms(rdefs, permsidx)
     schema.infer_specialization_rules()
     session.commit()
     schema.reading_from_database = False
@@ -232,7 +257,7 @@
         res.setdefault(rdefeid, []).append(cstr)
     return res
 
-def set_perms(erschema, permsdict):
+def set_perms(erschema, permsidx):
     """set permissions on the given erschema according to the permission
     definition dictionary as built by deserialize_ertype_permissions for a
     given erschema's eid
@@ -240,7 +265,7 @@
     # reset erschema permissions here to avoid getting yams default anyway
     erschema.permissions = dict((action, ()) for action in erschema.ACTIONS)
     try:
-        thispermsdict = permsdict[erschema.eid]
+        thispermsdict = permsidx[erschema.eid]
     except KeyError:
         return
     for action, somethings in thispermsdict.iteritems():