hooks/integrity.py
branchstable
changeset 6889 37668bf302f5
parent 6838 6c7adf825b3c
child 6894 ba3f7e655414
equal deleted inserted replaced
6888:c02e5ba43366 6889:37668bf302f5
   108 class IntegrityHook(hook.Hook):
   108 class IntegrityHook(hook.Hook):
   109     __abstract__ = True
   109     __abstract__ = True
   110     category = 'integrity'
   110     category = 'integrity'
   111 
   111 
   112 
   112 
   113 class CheckCardinalityHook(IntegrityHook):
   113 class CheckCardinalityHookBeforeDeleteRelation(IntegrityHook):
   114     """check cardinalities are satisfied"""
   114     """check cardinalities are satisfied"""
   115     __regid__ = 'checkcard'
   115     __regid__ = 'checkcard_before_delete_relation'
   116     events = ('after_add_entity', 'before_delete_relation')
   116     events = ('before_delete_relation',)
   117 
   117 
   118     def __call__(self):
   118     def __call__(self):
   119         getattr(self, self.event)()
   119         rtype = self.rtype
   120 
   120         if rtype in DONT_CHECK_RTYPES_ON_DEL:
   121     def after_add_entity(self):
   121             return
       
   122         session = self._cw
       
   123         eidfrom, eidto = self.eidfrom, self.eidto
       
   124         pendingrdefs = session.transaction_data.get('pendingrdefs', ())
       
   125         if (session.describe(eidfrom)[0], rtype, session.describe(eidto)[0]) in pendingrdefs:
       
   126             return
       
   127         card = session.schema_rproperty(rtype, eidfrom, eidto, 'cardinality')
       
   128         if card[0] in '1+' and not session.deleted_in_transaction(eidfrom):
       
   129             _CheckSRelationOp.get_instance(self._cw).add_data((eidfrom, rtype))
       
   130         if card[1] in '1+' and not session.deleted_in_transaction(eidto):
       
   131             _CheckORelationOp.get_instance(self._cw).add_data((eidto, rtype))
       
   132 
       
   133 class CheckCardinalityHookAfterAddEntity(IntegrityHook):
       
   134     """check cardinalities are satisfied"""
       
   135     __regid__ = 'checkcard_after_add_entity'
       
   136     events = ('after_add_entity',)
       
   137 
       
   138     def __call__(self):
   122         eid = self.entity.eid
   139         eid = self.entity.eid
   123         eschema = self.entity.e_schema
   140         eschema = self.entity.e_schema
   124         for rschema, targetschemas, role in eschema.relation_definitions():
   141         for rschema, targetschemas, role in eschema.relation_definitions():
   125             # skip automatically handled relations
   142             # skip automatically handled relations
   126             if rschema.type in DONT_CHECK_RTYPES_ON_ADD:
   143             if rschema.type in DONT_CHECK_RTYPES_ON_ADD:
   297 
   314 
   298     def precommit_event(self):
   315     def precommit_event(self):
   299         session = self.session
   316         session = self.session
   300         pendingeids = session.transaction_data.get('pendingeids', ())
   317         pendingeids = session.transaction_data.get('pendingeids', ())
   301         neweids = session.transaction_data.get('neweids', ())
   318         neweids = session.transaction_data.get('neweids', ())
       
   319         eids_by_etype_rtype = {}
   302         for eid, rtype in self.get_data():
   320         for eid, rtype in self.get_data():
   303             # don't do anything if the entity is being created or deleted
   321             # don't do anything if the entity is being created or deleted
   304             if not (eid in pendingeids or eid in neweids):
   322             if not (eid in pendingeids or eid in neweids):
   305                 etype = session.describe(eid)[0]
   323                 etype = session.describe(eid)[0]
   306                 session.execute(self.base_rql % (etype, rtype), {'x': eid})
   324                 key = (etype, rtype)
       
   325                 if key not in eids_by_etype_rtype:
       
   326                     eids_by_etype_rtype[key] = [str(eid)]
       
   327                 else:
       
   328                     eids_by_etype_rtype[key].append(str(eid))
       
   329         for (etype, rtype), eids in eids_by_etype_rtype.iteritems():
       
   330             # quite unexpectedly, not deleting too many entities at a time in
       
   331             # this operation benefits to the exec speed (possibly on the RQL
       
   332             # parsing side)
       
   333             start = 0
       
   334             incr = 500
       
   335             while start < len(eids):
       
   336                 session.execute(self.base_rql % (etype, ','.join(eids[start:start+incr]), rtype))
       
   337                 start += incr
   307 
   338 
   308 class _DelayedDeleteSEntityOp(_DelayedDeleteOp):
   339 class _DelayedDeleteSEntityOp(_DelayedDeleteOp):
   309     """delete orphan subject entity of a composite relation"""
   340     """delete orphan subject entity of a composite relation"""
   310     base_rql = 'DELETE %s X WHERE X eid %%(x)s, NOT X %s Y'
   341     base_rql = 'DELETE %s X WHERE X eid IN (%s), NOT X %s Y'
   311 
   342 
   312 class _DelayedDeleteOEntityOp(_DelayedDeleteOp):
   343 class _DelayedDeleteOEntityOp(_DelayedDeleteOp):
   313     """check required object relation"""
   344     """check required object relation"""
   314     base_rql = 'DELETE %s X WHERE X eid %%(x)s, NOT Y %s X'
   345     base_rql = 'DELETE %s X WHERE X eid IN (%s), NOT Y %s X'
   315 
   346 
   316 
   347 
   317 class DeleteCompositeOrphanHook(hook.Hook):
   348 class DeleteCompositeOrphanHook(hook.Hook):
   318     """delete the composed of a composite relation when this relation is deleted
   349     """delete the composed of a composite relation when this relation is deleted
   319     """
   350     """