cubicweb/hooks/syncschema.py
changeset 11417 5e5e224239c3
parent 11416 9c2fbb872e91
child 11763 39df042f4ab4
equal deleted inserted replaced
11416:9c2fbb872e91 11417:5e5e224239c3
    43 from cubicweb.server.sqlutils import SQL_PREFIX
    43 from cubicweb.server.sqlutils import SQL_PREFIX
    44 from cubicweb.hooks.synccomputed import RecomputeAttributeOperation
    44 from cubicweb.hooks.synccomputed import RecomputeAttributeOperation
    45 
    45 
    46 # core entity and relation types which can't be removed
    46 # core entity and relation types which can't be removed
    47 CORE_TYPES = BASE_TYPES | SCHEMA_TYPES | META_RTYPES | set(
    47 CORE_TYPES = BASE_TYPES | SCHEMA_TYPES | META_RTYPES | set(
    48     ('CWUser', 'CWGroup','login', 'upassword', 'name', 'in_group'))
    48     ('CWUser', 'CWGroup', 'login', 'upassword', 'name', 'in_group'))
    49 
    49 
    50 
    50 
    51 def get_constraints(cnx, entity):
    51 def get_constraints(cnx, entity):
    52     constraints = []
    52     constraints = []
    53     for cstreid in cnx.transaction_data.get(entity.eid, ()):
    53     for cstreid in cnx.transaction_data.get(entity.eid, ()):
    74         return
    74         return
    75     createdattrs.add(attrkey)
    75     createdattrs.add(attrkey)
    76     table = SQL_PREFIX + etype
    76     table = SQL_PREFIX + etype
    77     column = SQL_PREFIX + rtype
    77     column = SQL_PREFIX + rtype
    78     try:
    78     try:
    79         cnx.system_sql(str('ALTER TABLE %s ADD %s integer REFERENCES entities (eid)' % (table, column)),
    79         cnx.system_sql(str('ALTER TABLE %s ADD %s integer REFERENCES entities (eid)'
       
    80                            % (table, column)),
    80                        rollback_on_failure=False)
    81                        rollback_on_failure=False)
    81         cnx.info('added column %s to table %s', column, table)
    82         cnx.info('added column %s to table %s', column, table)
    82     except Exception:
    83     except Exception:
    83         # silent exception here, if this error has not been raised because the
    84         # silent exception here, if this error has not been raised because the
    84         # column already exists, index creation will fail anyway
    85         # column already exists, index creation will fail anyway
   238     * create the necessary table
   239     * create the necessary table
   239     * set creation_date and modification_date by creating the necessary
   240     * set creation_date and modification_date by creating the necessary
   240       CWAttribute entities
   241       CWAttribute entities
   241     * add <meta rtype> relation by creating the necessary CWRelation entity
   242     * add <meta rtype> relation by creating the necessary CWRelation entity
   242     """
   243     """
   243     entity = None # make pylint happy
   244     entity = None  # make pylint happy
   244 
   245 
   245     def precommit_event(self):
   246     def precommit_event(self):
   246         cnx = self.cnx
   247         cnx = self.cnx
   247         entity = self.entity
   248         entity = self.entity
   248         schema = cnx.vreg.schema
   249         schema = cnx.vreg.schema
   358                     op.add_data(objtype)
   359                     op.add_data(objtype)
   359                 else:
   360                 else:
   360                     op.add_data(objtype)
   361                     op.add_data(objtype)
   361                     op.add_data(subjtype)
   362                     op.add_data(subjtype)
   362         # update the in-memory schema first
   363         # update the in-memory schema first
   363         self.oldvalues = dict( (attr, getattr(rschema, attr)) for attr in self.values)
   364         self.oldvalues = dict((attr, getattr(rschema, attr)) for attr in self.values)
   364         self.rschema.__dict__.update(self.values)
   365         self.rschema.__dict__.update(self.values)
   365         # then make necessary changes to the system source database
   366         # then make necessary changes to the system source database
   366         if 'inlined' not in self.values:
   367         if 'inlined' not in self.values:
   367             return # nothing to do
   368             return  # nothing to do
   368         inlined = self.values['inlined']
   369         inlined = self.values['inlined']
   369         # check in-lining is possible when inlined
   370         # check in-lining is possible when inlined
   370         if inlined:
   371         if inlined:
   371             self.entity.check_inlined_allowed()
   372             self.entity.check_inlined_allowed()
   372         # inlined changed, make necessary physical changes!
   373         # inlined changed, make necessary physical changes!
   374         rtype = rschema.type
   375         rtype = rschema.type
   375         eidcolumn = SQL_PREFIX + 'eid'
   376         eidcolumn = SQL_PREFIX + 'eid'
   376         if not inlined:
   377         if not inlined:
   377             # need to create the relation if it has not been already done by
   378             # need to create the relation if it has not been already done by
   378             # another event of the same transaction
   379             # another event of the same transaction
   379             if not rschema.type in cnx.transaction_data.get('createdtables', ()):
   380             if rschema.type not in cnx.transaction_data.get('createdtables', ()):
   380                 # create the necessary table
   381                 # create the necessary table
   381                 for sql in y2sql.rschema2sql(rschema):
   382                 for sql in y2sql.rschema2sql(rschema):
   382                     sqlexec(sql)
   383                     sqlexec(sql)
   383                 cnx.transaction_data.setdefault('createdtables', []).append(
   384                 cnx.transaction_data.setdefault('createdtables', []).append(
   384                     rschema.type)
   385                     rschema.type)
   387             for etype in rschema.subjects():
   388             for etype in rschema.subjects():
   388                 table = SQL_PREFIX + str(etype)
   389                 table = SQL_PREFIX + str(etype)
   389                 sqlexec('INSERT INTO %s_relation SELECT %s, %s FROM %s WHERE NOT %s IS NULL'
   390                 sqlexec('INSERT INTO %s_relation SELECT %s, %s FROM %s WHERE NOT %s IS NULL'
   390                         % (rtype, eidcolumn, column, table, column))
   391                         % (rtype, eidcolumn, column, table, column))
   391             # drop existant columns
   392             # drop existant columns
   392             #if cnx.repo.system_source.dbhelper.alter_column_support:
       
   393             for etype in rschema.subjects():
   393             for etype in rschema.subjects():
   394                 DropColumn.get_instance(cnx).add_data((str(etype), rtype))
   394                 DropColumn.get_instance(cnx).add_data((str(etype), rtype))
   395         else:
   395         else:
   396             for etype in rschema.subjects():
   396             for etype in rschema.subjects():
   397                 try:
   397                 try:
   425         # XXX revert changes on database
   425         # XXX revert changes on database
   426 
   426 
   427 
   427 
   428 class CWComputedRTypeUpdateOp(MemSchemaOperation):
   428 class CWComputedRTypeUpdateOp(MemSchemaOperation):
   429     """actually update some properties of a computed relation definition"""
   429     """actually update some properties of a computed relation definition"""
   430     rschema = entity = rule = None # make pylint happy
   430     rschema = entity = rule = None  # make pylint happy
   431     old_rule = None
   431     old_rule = None
   432 
   432 
   433     def precommit_event(self):
   433     def precommit_event(self):
   434         # update the in-memory schema first
   434         # update the in-memory schema first
   435         self.old_rule = self.rschema.rule
   435         self.old_rule = self.rschema.rule
   447     * register an operation to add the relation definition to the
   447     * register an operation to add the relation definition to the
   448       instance's schema on commit
   448       instance's schema on commit
   449 
   449 
   450     constraints are handled by specific hooks
   450     constraints are handled by specific hooks
   451     """
   451     """
   452     entity = None # make pylint happy
   452     entity = None  # make pylint happy
   453 
   453 
   454     def init_rdef(self, **kwargs):
   454     def init_rdef(self, **kwargs):
   455         entity = self.entity
   455         entity = self.entity
   456         fromentity = entity.stype
   456         fromentity = entity.stype
   457         rdefdef = self.rdefdef = ybo.RelationDefinition(
   457         rdefdef = self.rdefdef = ybo.RelationDefinition(
   522         # final relations are not infered, propagate
   522         # final relations are not infered, propagate
   523         schema = cnx.vreg.schema
   523         schema = cnx.vreg.schema
   524         try:
   524         try:
   525             eschema = schema.eschema(rdefdef.subject)
   525             eschema = schema.eschema(rdefdef.subject)
   526         except KeyError:
   526         except KeyError:
   527             return # entity type currently being added
   527             return  # entity type currently being added
   528         # propagate attribute to children classes
   528         # propagate attribute to children classes
   529         rschema = schema.rschema(rdefdef.name)
   529         rschema = schema.rschema(rdefdef.name)
   530         # if relation type has been inserted in the same transaction, its final
   530         # if relation type has been inserted in the same transaction, its final
   531         # attribute is still set to False, so we've to ensure it's False
   531         # attribute is still set to False, so we've to ensure it's False
   532         rschema.final = True
   532         rschema.final = True
   533         insert_rdef_on_subclasses(cnx, eschema, rschema, rdefdef, props)
   533         insert_rdef_on_subclasses(cnx, eschema, rschema, rdefdef, props)
   534         # update existing entities with the default value of newly added attribute
   534         # update existing entities with the default value of newly added attribute
   535         if default is not None:
   535         if default is not None:
   536             default = convert_default_value(self.rdefdef, default)
   536             default = convert_default_value(self.rdefdef, default)
   537             cnx.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column),
   537             cnx.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column),
   538                                {'default': default})
   538                            {'default': default})
   539         # if attribute is computed, compute it
   539         # if attribute is computed, compute it
   540         if getattr(entity, 'formula', None):
   540         if getattr(entity, 'formula', None):
   541             # add rtype attribute for RelationDefinitionSchema api compat, this
   541             # add rtype attribute for RelationDefinitionSchema api compat, this
   542             # is what RecomputeAttributeOperation expect
   542             # is what RecomputeAttributeOperation expect
   543             rdefdef.rtype = rdefdef.name
   543             rdefdef.rtype = rdefdef.name
   561       first instance of this relation type, add the necessary table and set
   561       first instance of this relation type, add the necessary table and set
   562       default permissions
   562       default permissions
   563 
   563 
   564     constraints are handled by specific hooks
   564     constraints are handled by specific hooks
   565     """
   565     """
   566     entity = None # make pylint happy
   566     entity = None  # make pylint happy
   567 
   567 
   568     def precommit_event(self):
   568     def precommit_event(self):
   569         cnx = self.cnx
   569         cnx = self.cnx
   570         entity = self.entity
   570         entity = self.entity
   571         # update the in-memory schema first
   571         # update the in-memory schema first
   605     # XXX revertprecommit_event
   605     # XXX revertprecommit_event
   606 
   606 
   607 
   607 
   608 class RDefDelOp(MemSchemaOperation):
   608 class RDefDelOp(MemSchemaOperation):
   609     """an actual relation has been removed"""
   609     """an actual relation has been removed"""
   610     rdef = None # make pylint happy
   610     rdef = None  # make pylint happy
   611 
   611 
   612     def precommit_event(self):
   612     def precommit_event(self):
   613         cnx = self.cnx
   613         cnx = self.cnx
   614         rdef = self.rdef
   614         rdef = self.rdef
   615         rschema = rdef.rtype
   615         rschema = rdef.rtype
   668             self.cnx.vreg.schema.add_relation_def(rdef)
   668             self.cnx.vreg.schema.add_relation_def(rdef)
   669 
   669 
   670 
   670 
   671 class RDefUpdateOp(MemSchemaOperation):
   671 class RDefUpdateOp(MemSchemaOperation):
   672     """actually update some properties of a relation definition"""
   672     """actually update some properties of a relation definition"""
   673     rschema = rdefkey = values = None # make pylint happy
   673     rschema = rdefkey = values = None  # make pylint happy
   674     rdef = oldvalues = None
   674     rdef = oldvalues = None
   675     indexed_changed = null_allowed_changed = False
   675     indexed_changed = null_allowed_changed = False
   676 
   676 
   677     def precommit_event(self):
   677     def precommit_event(self):
   678         cnx = self.cnx
   678         cnx = self.cnx
   679         rdef = self.rdef = self.rschema.rdefs[self.rdefkey]
   679         rdef = self.rdef = self.rschema.rdefs[self.rdefkey]
   680         # update the in-memory schema first
   680         # update the in-memory schema first
   681         self.oldvalues = dict( (attr, getattr(rdef, attr)) for attr in self.values)
   681         self.oldvalues = dict((attr, getattr(rdef, attr)) for attr in self.values)
   682         rdef.update(self.values)
   682         rdef.update(self.values)
   683         # then make necessary changes to the system source database
   683         # then make necessary changes to the system source database
   684         syssource = cnx.repo.system_source
   684         syssource = cnx.repo.system_source
   685         if 'indexed' in self.values:
   685         if 'indexed' in self.values:
   686             syssource.update_rdef_indexed(cnx, rdef)
   686             syssource.update_rdef_indexed(cnx, rdef)
   687             self.indexed_changed = True
   687             self.indexed_changed = True
   688         if 'cardinality' in self.values and rdef.rtype.final \
   688         if ('cardinality' in self.values and rdef.rtype.final
   689               and self.values['cardinality'][0] != self.oldvalues['cardinality'][0]:
   689                 and self.values['cardinality'][0] != self.oldvalues['cardinality'][0]):
   690             syssource.update_rdef_null_allowed(self.cnx, rdef)
   690             syssource.update_rdef_null_allowed(self.cnx, rdef)
   691             self.null_allowed_changed = True
   691             self.null_allowed_changed = True
   692         if 'fulltextindexed' in self.values:
   692         if 'fulltextindexed' in self.values:
   693             UpdateFTIndexOp.get_instance(cnx).add_data(rdef.subject)
   693             UpdateFTIndexOp.get_instance(cnx).add_data(rdef.subject)
   694         if 'formula' in self.values:
   694         if 'formula' in self.values:
   715         rdef.constraints = list(rdef.constraints)
   715         rdef.constraints = list(rdef.constraints)
   716 
   716 
   717 
   717 
   718 class CWConstraintDelOp(MemSchemaOperation):
   718 class CWConstraintDelOp(MemSchemaOperation):
   719     """actually remove a constraint of a relation definition"""
   719     """actually remove a constraint of a relation definition"""
   720     rdef = oldcstr = newcstr = None # make pylint happy
   720     rdef = oldcstr = newcstr = None  # make pylint happy
   721     size_cstr_changed = unique_changed = False
   721     size_cstr_changed = unique_changed = False
   722 
   722 
   723     def precommit_event(self):
   723     def precommit_event(self):
   724         cnx = self.cnx
   724         cnx = self.cnx
   725         rdef = self.rdef
   725         rdef = self.rdef
   773             syssource.update_rdef_unique(self.cnx, self.rdef)
   773             syssource.update_rdef_unique(self.cnx, self.rdef)
   774 
   774 
   775 
   775 
   776 class CWConstraintAddOp(CWConstraintDelOp):
   776 class CWConstraintAddOp(CWConstraintDelOp):
   777     """actually update constraint of a relation definition"""
   777     """actually update constraint of a relation definition"""
   778     entity = None # make pylint happy
   778     entity = None  # make pylint happy
   779 
   779 
   780     def precommit_event(self):
   780     def precommit_event(self):
   781         cnx = self.cnx
   781         cnx = self.cnx
   782         rdefentity = self.entity.reverse_constrained_by[0]
   782         rdefentity = self.entity.reverse_constrained_by[0]
   783         rdef = self.rdef = cnx.vreg.schema.schema_by_eid(rdefentity.eid)
   783         rdef = self.rdef = cnx.vreg.schema.schema_by_eid(rdefentity.eid)
   818             cnx.system_sql('ALTER TABLE %s%s ADD CONSTRAINT %s CHECK(%s)' %
   818             cnx.system_sql('ALTER TABLE %s%s ADD CONSTRAINT %s CHECK(%s)' %
   819                            (SQL_PREFIX, rdef.subject, cstrname, check))
   819                            (SQL_PREFIX, rdef.subject, cstrname, check))
   820 
   820 
   821 
   821 
   822 class CWUniqueTogetherConstraintAddOp(MemSchemaOperation):
   822 class CWUniqueTogetherConstraintAddOp(MemSchemaOperation):
   823     entity = None # make pylint happy
   823     entity = None  # make pylint happy
   824 
   824 
   825     def precommit_event(self):
   825     def precommit_event(self):
   826         cnx = self.cnx
   826         cnx = self.cnx
   827         prefix = SQL_PREFIX
   827         prefix = SQL_PREFIX
   828         entity = self.entity
   828         entity = self.entity
   839         attrs = [r.name for r in entity.relations]
   839         attrs = [r.name for r in entity.relations]
   840         eschema._unique_together.append(attrs)
   840         eschema._unique_together.append(attrs)
   841 
   841 
   842 
   842 
   843 class CWUniqueTogetherConstraintDelOp(MemSchemaOperation):
   843 class CWUniqueTogetherConstraintDelOp(MemSchemaOperation):
   844     entity = cstrname = None # for pylint
   844     entity = cstrname = None  # make pylint happy
   845     cols = () # for pylint
   845     cols = ()  # make pylint happy
   846 
   846 
   847     def insert_index(self):
   847     def insert_index(self):
   848         # We need to run before CWConstraintDelOp: if a size constraint is
   848         # We need to run before CWConstraintDelOp: if a size constraint is
   849         # removed and the column is part of a unique_together constraint, we
   849         # removed and the column is part of a unique_together constraint, we
   850         # remove the unique_together index before changing the column's type.
   850         # remove the unique_together index before changing the column's type.
   871 
   871 
   872 # operations for in-memory schema synchronization  #############################
   872 # operations for in-memory schema synchronization  #############################
   873 
   873 
   874 class MemSchemaCWETypeDel(MemSchemaOperation):
   874 class MemSchemaCWETypeDel(MemSchemaOperation):
   875     """actually remove the entity type from the instance's schema"""
   875     """actually remove the entity type from the instance's schema"""
   876     etype = None # make pylint happy
   876     etype = None  # make pylint happy
   877 
   877 
   878     def postcommit_event(self):
   878     def postcommit_event(self):
   879         # del_entity_type also removes entity's relations
   879         # del_entity_type also removes entity's relations
   880         self.cnx.vreg.schema.del_entity_type(self.etype)
   880         self.cnx.vreg.schema.del_entity_type(self.etype)
   881 
   881 
   882 
   882 
   883 class MemSchemaCWRTypeAdd(MemSchemaOperation):
   883 class MemSchemaCWRTypeAdd(MemSchemaOperation):
   884     """actually add the relation type to the instance's schema"""
   884     """actually add the relation type to the instance's schema"""
   885     rtypedef = None # make pylint happy
   885     rtypedef = None  # make pylint happy
   886 
   886 
   887     def precommit_event(self):
   887     def precommit_event(self):
   888         self.cnx.vreg.schema.add_relation_type(self.rtypedef)
   888         self.cnx.vreg.schema.add_relation_type(self.rtypedef)
   889 
   889 
   890     def revertprecommit_event(self):
   890     def revertprecommit_event(self):
   891         self.cnx.vreg.schema.del_relation_type(self.rtypedef.name)
   891         self.cnx.vreg.schema.del_relation_type(self.rtypedef.name)
   892 
   892 
   893 
   893 
   894 class MemSchemaCWRTypeDel(MemSchemaOperation):
   894 class MemSchemaCWRTypeDel(MemSchemaOperation):
   895     """actually remove the relation type from the instance's schema"""
   895     """actually remove the relation type from the instance's schema"""
   896     rtype = None # make pylint happy
   896     rtype = None  # make pylint happy
   897 
   897 
   898     def postcommit_event(self):
   898     def postcommit_event(self):
   899         try:
   899         try:
   900             self.cnx.vreg.schema.del_relation_type(self.rtype)
   900             self.cnx.vreg.schema.del_relation_type(self.rtype)
   901         except KeyError:
   901         except KeyError:
   904 
   904 
   905 
   905 
   906 class MemSchemaPermissionAdd(MemSchemaOperation):
   906 class MemSchemaPermissionAdd(MemSchemaOperation):
   907     """synchronize schema when a *_permission relation has been added on a group
   907     """synchronize schema when a *_permission relation has been added on a group
   908     """
   908     """
   909     eid = action = group_eid = expr = None # make pylint happy
   909     eid = action = group_eid = expr = None  # make pylint happy
   910 
   910 
   911     def precommit_event(self):
   911     def precommit_event(self):
   912         """the observed connections.cnxset has been commited"""
   912         """the observed connections.cnxset has been commited"""
   913         try:
   913         try:
   914             erschema = self.cnx.vreg.schema.schema_by_eid(self.eid)
   914             erschema = self.cnx.vreg.schema.schema_by_eid(self.eid)
   959 
   959 
   960     # XXX revertprecommit_event
   960     # XXX revertprecommit_event
   961 
   961 
   962 
   962 
   963 class MemSchemaSpecializesAdd(MemSchemaOperation):
   963 class MemSchemaSpecializesAdd(MemSchemaOperation):
   964     etypeeid = parentetypeeid = None # make pylint happy
   964     etypeeid = parentetypeeid = None  # make pylint happy
   965 
   965 
   966     def precommit_event(self):
   966     def precommit_event(self):
   967         eschema = self.cnx.vreg.schema.schema_by_eid(self.etypeeid)
   967         eschema = self.cnx.vreg.schema.schema_by_eid(self.etypeeid)
   968         parenteschema = self.cnx.vreg.schema.schema_by_eid(self.parentetypeeid)
   968         parenteschema = self.cnx.vreg.schema.schema_by_eid(self.parentetypeeid)
   969         eschema._specialized_type = parenteschema.type
   969         eschema._specialized_type = parenteschema.type
   971 
   971 
   972     # XXX revertprecommit_event
   972     # XXX revertprecommit_event
   973 
   973 
   974 
   974 
   975 class MemSchemaSpecializesDel(MemSchemaOperation):
   975 class MemSchemaSpecializesDel(MemSchemaOperation):
   976     etypeeid = parentetypeeid = None # make pylint happy
   976     etypeeid = parentetypeeid = None  # make pylint happy
   977 
   977 
   978     def precommit_event(self):
   978     def precommit_event(self):
   979         try:
   979         try:
   980             eschema = self.cnx.vreg.schema.schema_by_eid(self.etypeeid)
   980             eschema = self.cnx.vreg.schema.schema_by_eid(self.etypeeid)
   981             parenteschema = self.cnx.vreg.schema.schema_by_eid(self.parentetypeeid)
   981             parenteschema = self.cnx.vreg.schema.schema_by_eid(self.parentetypeeid)
  1075         name = self.entity.name
  1075         name = self.entity.name
  1076         if name in CORE_TYPES:
  1076         if name in CORE_TYPES:
  1077             raise validation_error(self.entity, {None: _("can't be deleted")})
  1077             raise validation_error(self.entity, {None: _("can't be deleted")})
  1078         # delete relation definitions using this relation type
  1078         # delete relation definitions using this relation type
  1079         self._cw.execute('DELETE CWAttribute X WHERE X relation_type Y, Y eid %(x)s',
  1079         self._cw.execute('DELETE CWAttribute X WHERE X relation_type Y, Y eid %(x)s',
  1080                         {'x': self.entity.eid})
  1080                          {'x': self.entity.eid})
  1081         self._cw.execute('DELETE CWRelation X WHERE X relation_type Y, Y eid %(x)s',
  1081         self._cw.execute('DELETE CWRelation X WHERE X relation_type Y, Y eid %(x)s',
  1082                         {'x': self.entity.eid})
  1082                          {'x': self.entity.eid})
  1083         MemSchemaCWRTypeDel(self._cw, rtype=name)
  1083         MemSchemaCWRTypeDel(self._cw, rtype=name)
  1084 
  1084 
  1085 
  1085 
  1086 class AfterAddCWComputedRTypeHook(SyncSchemaHook):
  1086 class AfterAddCWComputedRTypeHook(SyncSchemaHook):
  1087     """after a CWComputedRType entity has been added:
  1087     """after a CWComputedRType entity has been added:
  1183             return
  1183             return
  1184         subjschema, rschema, objschema = rdef.as_triple()
  1184         subjschema, rschema, objschema = rdef.as_triple()
  1185         pendingrdefs = cnx.transaction_data.setdefault('pendingrdefs', set())
  1185         pendingrdefs = cnx.transaction_data.setdefault('pendingrdefs', set())
  1186         # first delete existing relation if necessary
  1186         # first delete existing relation if necessary
  1187         if rschema.final:
  1187         if rschema.final:
  1188             rdeftype = 'CWAttribute'
       
  1189             pendingrdefs.add((subjschema, rschema))
  1188             pendingrdefs.add((subjschema, rschema))
  1190         else:
  1189         else:
  1191             rdeftype = 'CWRelation'
       
  1192             pendingrdefs.add((subjschema, rschema, objschema))
  1190             pendingrdefs.add((subjschema, rschema, objschema))
  1193         RDefDelOp(cnx, rdef=rdef)
  1191         RDefDelOp(cnx, rdef=rdef)
  1194 
  1192 
  1195 
  1193 
  1196 # CWComputedRType hooks #######################################################
  1194 # CWComputedRType hooks #######################################################
  1307         except (KeyError, IndexError):
  1305         except (KeyError, IndexError):
  1308             self._cw.critical('constraint type no more accessible')
  1306             self._cw.critical('constraint type no more accessible')
  1309         else:
  1307         else:
  1310             CWConstraintDelOp(self._cw, rdef=rdef, oldcstr=cstr)
  1308             CWConstraintDelOp(self._cw, rdef=rdef, oldcstr=cstr)
  1311 
  1309 
       
  1310 
  1312 # unique_together constraints
  1311 # unique_together constraints
  1313 # XXX: use setoperations and before_add_relation here (on constraint_of and relations)
  1312 # XXX: use setoperations and before_add_relation here (on constraint_of and relations)
  1314 class AfterAddCWUniqueTogetherConstraintHook(SyncSchemaHook):
  1313 class AfterAddCWUniqueTogetherConstraintHook(SyncSchemaHook):
  1315     __regid__ = 'syncadd_cwuniquetogether_constraint'
  1314     __regid__ = 'syncadd_cwuniquetogether_constraint'
  1316     __select__ = SyncSchemaHook.__select__ & is_instance('CWUniqueTogetherConstraint')
  1315     __select__ = SyncSchemaHook.__select__ & is_instance('CWUniqueTogetherConstraint')
  1349     def __call__(self):
  1348     def __call__(self):
  1350         action = self.rtype.split('_', 1)[0]
  1349         action = self.rtype.split('_', 1)[0]
  1351         if self._cw.entity_metas(self.eidto)['type'] == 'CWGroup':
  1350         if self._cw.entity_metas(self.eidto)['type'] == 'CWGroup':
  1352             MemSchemaPermissionAdd(self._cw, action=action, eid=self.eidfrom,
  1351             MemSchemaPermissionAdd(self._cw, action=action, eid=self.eidfrom,
  1353                                    group_eid=self.eidto)
  1352                                    group_eid=self.eidto)
  1354         else: # RQLExpression
  1353         else:  # RQLExpression
  1355             expr = self._cw.entity_from_eid(self.eidto).expression
  1354             expr = self._cw.entity_from_eid(self.eidto).expression
  1356             MemSchemaPermissionAdd(self._cw, action=action, eid=self.eidfrom,
  1355             MemSchemaPermissionAdd(self._cw, action=action, eid=self.eidfrom,
  1357                                    expr=expr)
  1356                                    expr=expr)
  1358 
  1357 
  1359 
  1358 
  1370             return
  1369             return
  1371         action = self.rtype.split('_', 1)[0]
  1370         action = self.rtype.split('_', 1)[0]
  1372         if self._cw.entity_metas(self.eidto)['type'] == 'CWGroup':
  1371         if self._cw.entity_metas(self.eidto)['type'] == 'CWGroup':
  1373             MemSchemaPermissionDel(self._cw, action=action, eid=self.eidfrom,
  1372             MemSchemaPermissionDel(self._cw, action=action, eid=self.eidfrom,
  1374                                    group_eid=self.eidto)
  1373                                    group_eid=self.eidto)
  1375         else: # RQLExpression
  1374         else:  # RQLExpression
  1376             expr = self._cw.entity_from_eid(self.eidto).expression
  1375             expr = self._cw.entity_from_eid(self.eidto).expression
  1377             MemSchemaPermissionDel(self._cw, action=action, eid=self.eidfrom,
  1376             MemSchemaPermissionDel(self._cw, action=action, eid=self.eidfrom,
  1378                                    expr=expr)
  1377                                    expr=expr)
  1379 
       
  1380 
  1378 
  1381 
  1379 
  1382 class UpdateFTIndexOp(hook.DataOperationMixIn, hook.SingleLastOperation):
  1380 class UpdateFTIndexOp(hook.DataOperationMixIn, hook.SingleLastOperation):
  1383     """operation to update full text indexation of entity whose schema change
  1381     """operation to update full text indexation of entity whose schema change
  1384 
  1382 
  1408         if to_reindex:
  1406         if to_reindex:
  1409             # Transaction has already been committed
  1407             # Transaction has already been committed
  1410             cnx.cnxset.commit()
  1408             cnx.cnxset.commit()
  1411 
  1409 
  1412 
  1410 
  1413 
       
  1414 
       
  1415 # specializes synchronization hooks ############################################
  1411 # specializes synchronization hooks ############################################
  1416 
       
  1417 
  1412 
  1418 class AfterAddSpecializesHook(SyncSchemaHook):
  1413 class AfterAddSpecializesHook(SyncSchemaHook):
  1419     __regid__ = 'syncaddspecializes'
  1414     __regid__ = 'syncaddspecializes'
  1420     __select__ = SyncSchemaHook.__select__ & hook.match_rtype('specializes')
  1415     __select__ = SyncSchemaHook.__select__ & hook.match_rtype('specializes')
  1421     events = ('after_add_relation',)
  1416     events = ('after_add_relation',)