# HG changeset patch # User Sylvain Thénault # Date 1283933010 -7200 # Node ID ece6996e6ac8209ab5bb9e1670949897705e160a # Parent 564a6028067c2bbd66f950ad86afb7bf1c91f30e [schema deserial] fix loading of schema when mapping an entity type to an existing one To ensure rdef of the old entity type don't overwrite those already existing on the mapped entity type. Also rename some variables/arguments on the way to make things clearer. diff -r 564a6028067c -r ece6996e6ac8 schema.py --- a/schema.py Tue Sep 07 23:34:16 2010 +0200 +++ b/schema.py Wed Sep 08 10:03:30 2010 +0200 @@ -571,13 +571,7 @@ rdef.name = rdef.name.lower() rdef.subject = bw_normalize_etype(rdef.subject) rdef.object = bw_normalize_etype(rdef.object) - 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: - return - raise + rdefs = super(CubicWebSchema, self).add_relation_def(rdef) if rdefs: try: self._eid_index[rdef.eid] = rdefs diff -r 564a6028067c -r ece6996e6ac8 server/schemaserial.py --- 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():