1095 # mark eid as being deleted in session info and setup cache update |
1095 # mark eid as being deleted in session info and setup cache update |
1096 # operation |
1096 # operation |
1097 hook.CleanupDeletedEidsCacheOp.get_instance(session).add_data(entity.eid) |
1097 hook.CleanupDeletedEidsCacheOp.get_instance(session).add_data(entity.eid) |
1098 self._delete_info(session, entity, sourceuri, extid, scleanup) |
1098 self._delete_info(session, entity, sourceuri, extid, scleanup) |
1099 |
1099 |
|
1100 def delete_info_multi(self, session, entities, sourceuri, extids, scleanup=False): |
|
1101 """same as delete_info but accepts a list of entities and |
|
1102 extids with the same etype and belonging to the same source |
|
1103 """ |
|
1104 # mark eid as being deleted in session info and setup cache update |
|
1105 # operation |
|
1106 op = hook.CleanupDeletedEidsCacheOp.get_instance(session) |
|
1107 for entity in entities: |
|
1108 op.add_data(entity.eid) |
|
1109 self._delete_info_multi(session, entities, sourceuri, extids, scleanup) |
|
1110 |
1100 def _delete_info(self, session, entity, sourceuri, extid, scleanup=False): |
1111 def _delete_info(self, session, entity, sourceuri, extid, scleanup=False): |
1101 """delete system information on deletion of an entity: |
1112 """delete system information on deletion of an entity: |
1102 * delete all remaining relations from/to this entity |
1113 * delete all remaining relations from/to this entity |
1103 * call delete info on the system source which will transfer record from |
1114 * call delete info on the system source which will transfer record from |
1104 the entities table to the deleted_entities table |
1115 the entities table to the deleted_entities table |
1126 build_descr=False) |
1137 build_descr=False) |
1127 except: |
1138 except: |
1128 self.exception('error while cascading delete for entity %s ' |
1139 self.exception('error while cascading delete for entity %s ' |
1129 'from %s. RQL: %s', entity, sourceuri, rql) |
1140 'from %s. RQL: %s', entity, sourceuri, rql) |
1130 self.system_source.delete_info(session, entity, sourceuri, extid) |
1141 self.system_source.delete_info(session, entity, sourceuri, extid) |
|
1142 |
|
1143 def _delete_info_multi(self, session, entities, sourceuri, extids, scleanup=False): |
|
1144 """same as _delete_info but accepts a list of entities with |
|
1145 the same etype and belinging to the same source. |
|
1146 """ |
|
1147 pendingrtypes = session.transaction_data.get('pendingrtypes', ()) |
|
1148 # delete remaining relations: if user can delete the entity, he can |
|
1149 # delete all its relations without security checking |
|
1150 assert entities and len(entities) == len(extids) |
|
1151 with security_enabled(session, read=False, write=False): |
|
1152 eids = [_e.eid for _e in entities] |
|
1153 in_eids = ','.join((str(eid) for eid in eids)) |
|
1154 for rschema, _, role in entities[0].e_schema.relation_definitions(): |
|
1155 rtype = rschema.type |
|
1156 if rtype in schema.VIRTUAL_RTYPES or rtype in pendingrtypes: |
|
1157 continue |
|
1158 if role == 'subject': |
|
1159 # don't skip inlined relation so they are regularly |
|
1160 # deleted and so hooks are correctly called |
|
1161 rql = 'DELETE X %s Y WHERE X eid IN (%s)' % (rtype, in_eids) |
|
1162 else: |
|
1163 rql = 'DELETE Y %s X WHERE X eid IN (%s)' % (rtype, in_eids) |
|
1164 if scleanup: |
|
1165 # source cleaning: only delete relations stored locally |
|
1166 rql += ', NOT (Y cw_source S, S name %(source)s)' |
|
1167 try: |
|
1168 session.execute(rql, {'source': sourceuri}, |
|
1169 build_descr=False) |
|
1170 except: |
|
1171 self.exception('error while cascading delete for entity %s ' |
|
1172 'from %s. RQL: %s', entities, sourceuri, rql) |
|
1173 self.system_source.delete_info_multi(session, entities, sourceuri, extids) |
1131 |
1174 |
1132 def locate_relation_source(self, session, subject, rtype, object): |
1175 def locate_relation_source(self, session, subject, rtype, object): |
1133 subjsource = self.source_from_eid(subject, session) |
1176 subjsource = self.source_from_eid(subject, session) |
1134 objsource = self.source_from_eid(object, session) |
1177 objsource = self.source_from_eid(object, session) |
1135 if not subjsource is objsource: |
1178 if not subjsource is objsource: |
1295 eidfrom=entity.eid, rtype=attr, eidto=value) |
1338 eidfrom=entity.eid, rtype=attr, eidto=value) |
1296 finally: |
1339 finally: |
1297 if orig_edited is not None: |
1340 if orig_edited is not None: |
1298 entity.cw_edited = orig_edited |
1341 entity.cw_edited = orig_edited |
1299 |
1342 |
1300 def glob_delete_entity(self, session, eid): |
1343 |
1301 """delete an entity and all related entities from the repository""" |
1344 def glob_delete_entities(self, session, eids): |
1302 entity = session.entity_from_eid(eid) |
1345 """delete a list of entities and all related entities from the repository""" |
1303 etype, sourceuri, extid = self.type_and_source_from_eid(eid, session) |
1346 data_by_etype_source = {} # values are ([list of eids], |
1304 if server.DEBUG & server.DBG_REPO: |
1347 # [list of extid], |
1305 print 'DELETE entity', etype, eid |
1348 # [list of entities]) |
1306 source = self.sources_by_uri[sourceuri] |
1349 # |
1307 if source.should_call_hooks: |
1350 # WARNING: the way this dictionary is populated is heavily optimized |
1308 self.hm.call_hooks('before_delete_entity', session, entity=entity) |
1351 # and does not use setdefault on purpose. Unless a new release |
1309 self._delete_info(session, entity, sourceuri, extid) |
1352 # of the Python interpreter advertises large perf improvements |
1310 source.delete_entity(session, entity) |
1353 # in setdefault, this should not be changed without profiling. |
1311 if source.should_call_hooks: |
1354 |
1312 self.hm.call_hooks('after_delete_entity', session, entity=entity) |
1355 for eid in eids: |
|
1356 etype, sourceuri, extid = self.type_and_source_from_eid(eid, session) |
|
1357 entity = session.entity_from_eid(eid, etype) |
|
1358 _key = (etype, sourceuri) |
|
1359 if _key not in data_by_etype_source: |
|
1360 data_by_etype_source[_key] = ([eid], [extid], [entity]) |
|
1361 else: |
|
1362 _data = data_by_etype_source[_key] |
|
1363 _data[0].append(eid) |
|
1364 _data[1].append(extid) |
|
1365 _data[2].append(entity) |
|
1366 for (etype, sourceuri), (eids, extids, entities) in data_by_etype_source.iteritems(): |
|
1367 if server.DEBUG & server.DBG_REPO: |
|
1368 print 'DELETE entities', etype, eids |
|
1369 #print 'DELETE entities', etype, len(eids) |
|
1370 source = self.sources_by_uri[sourceuri] |
|
1371 if source.should_call_hooks: |
|
1372 self.hm.call_hooks('before_delete_entity', session, entities=entities) |
|
1373 self._delete_info_multi(session, entities, sourceuri, extids) # xxx |
|
1374 source.delete_entities(session, entities) |
|
1375 if source.should_call_hooks: |
|
1376 self.hm.call_hooks('after_delete_entity', session, entities=entities) |
1313 # don't clear cache here this is done in a hook on commit |
1377 # don't clear cache here this is done in a hook on commit |
1314 |
1378 |
1315 def glob_add_relation(self, session, subject, rtype, object): |
1379 def glob_add_relation(self, session, subject, rtype, object): |
1316 """add a relation to the repository""" |
1380 """add a relation to the repository""" |
1317 if server.DEBUG & server.DBG_REPO: |
1381 if server.DEBUG & server.DBG_REPO: |