diff -r c02e5ba43366 -r 37668bf302f5 hooks/integrity.py --- a/hooks/integrity.py Tue Jan 25 10:01:19 2011 +0100 +++ b/hooks/integrity.py Tue Jan 25 12:09:59 2011 +0100 @@ -110,15 +110,32 @@ category = 'integrity' -class CheckCardinalityHook(IntegrityHook): +class CheckCardinalityHookBeforeDeleteRelation(IntegrityHook): """check cardinalities are satisfied""" - __regid__ = 'checkcard' - events = ('after_add_entity', 'before_delete_relation') + __regid__ = 'checkcard_before_delete_relation' + events = ('before_delete_relation',) def __call__(self): - getattr(self, self.event)() + rtype = self.rtype + if rtype in DONT_CHECK_RTYPES_ON_DEL: + return + session = self._cw + eidfrom, eidto = self.eidfrom, self.eidto + pendingrdefs = session.transaction_data.get('pendingrdefs', ()) + if (session.describe(eidfrom)[0], rtype, session.describe(eidto)[0]) in pendingrdefs: + return + card = session.schema_rproperty(rtype, eidfrom, eidto, 'cardinality') + if card[0] in '1+' and not session.deleted_in_transaction(eidfrom): + _CheckSRelationOp.get_instance(self._cw).add_data((eidfrom, rtype)) + if card[1] in '1+' and not session.deleted_in_transaction(eidto): + _CheckORelationOp.get_instance(self._cw).add_data((eidto, rtype)) - def after_add_entity(self): +class CheckCardinalityHookAfterAddEntity(IntegrityHook): + """check cardinalities are satisfied""" + __regid__ = 'checkcard_after_add_entity' + events = ('after_add_entity',) + + def __call__(self): eid = self.entity.eid eschema = self.entity.e_schema for rschema, targetschemas, role in eschema.relation_definitions(): @@ -299,19 +316,33 @@ session = self.session pendingeids = session.transaction_data.get('pendingeids', ()) neweids = session.transaction_data.get('neweids', ()) + eids_by_etype_rtype = {} for eid, rtype in self.get_data(): # don't do anything if the entity is being created or deleted if not (eid in pendingeids or eid in neweids): etype = session.describe(eid)[0] - session.execute(self.base_rql % (etype, rtype), {'x': eid}) + key = (etype, rtype) + if key not in eids_by_etype_rtype: + eids_by_etype_rtype[key] = [str(eid)] + else: + eids_by_etype_rtype[key].append(str(eid)) + for (etype, rtype), eids in eids_by_etype_rtype.iteritems(): + # quite unexpectedly, not deleting too many entities at a time in + # this operation benefits to the exec speed (possibly on the RQL + # parsing side) + start = 0 + incr = 500 + while start < len(eids): + session.execute(self.base_rql % (etype, ','.join(eids[start:start+incr]), rtype)) + start += incr class _DelayedDeleteSEntityOp(_DelayedDeleteOp): """delete orphan subject entity of a composite relation""" - base_rql = 'DELETE %s X WHERE X eid %%(x)s, NOT X %s Y' + base_rql = 'DELETE %s X WHERE X eid IN (%s), NOT X %s Y' class _DelayedDeleteOEntityOp(_DelayedDeleteOp): """check required object relation""" - base_rql = 'DELETE %s X WHERE X eid %%(x)s, NOT Y %s X' + base_rql = 'DELETE %s X WHERE X eid IN (%s), NOT Y %s X' class DeleteCompositeOrphanHook(hook.Hook):