server/sources/native.py
changeset 8900 010a59e12d89
parent 8821 c4aa23af0baa
child 8916 2a424950463d
equal deleted inserted replaced
8899:c7a95ebcc093 8900:010a59e12d89
   195                                    'rtype': session._(rtype),
   195                                    'rtype': session._(rtype),
   196                                    'eid': eid})
   196                                    'eid': eid})
   197     sentity, oentity = entities
   197     sentity, oentity = entities
   198     try:
   198     try:
   199         rschema = session.vreg.schema.rschema(rtype)
   199         rschema = session.vreg.schema.rschema(rtype)
   200         rdef = rschema.rdefs[(sentity.__regid__, oentity.__regid__)]
   200         rdef = rschema.rdefs[(sentity.cw_etype, oentity.cw_etype)]
   201     except KeyError:
   201     except KeyError:
   202         raise _UndoException(session._(
   202         raise _UndoException(session._(
   203             "Can't restore relation %(rtype)s between %(subj)s and "
   203             "Can't restore relation %(rtype)s between %(subj)s and "
   204             "%(obj)s, that relation does not exists anymore in the "
   204             "%(obj)s, that relation does not exists anymore in the "
   205             "schema.")
   205             "schema.")
   628 
   628 
   629     def add_entity(self, session, entity):
   629     def add_entity(self, session, entity):
   630         """add a new entity to the source"""
   630         """add a new entity to the source"""
   631         with self._storage_handler(entity, 'added'):
   631         with self._storage_handler(entity, 'added'):
   632             attrs = self.preprocess_entity(entity)
   632             attrs = self.preprocess_entity(entity)
   633             sql = self.sqlgen.insert(SQL_PREFIX + entity.__regid__, attrs)
   633             sql = self.sqlgen.insert(SQL_PREFIX + entity.cw_etype, attrs)
   634             self.doexec(session, sql, attrs)
   634             self.doexec(session, sql, attrs)
   635             if session.ertype_supports_undo(entity.__regid__):
   635             if session.ertype_supports_undo(entity.cw_etype):
   636                 self._record_tx_action(session, 'tx_entity_actions', 'C',
   636                 self._record_tx_action(session, 'tx_entity_actions', 'C',
   637                                        etype=entity.__regid__, eid=entity.eid)
   637                                        etype=entity.cw_etype, eid=entity.eid)
   638 
   638 
   639     def update_entity(self, session, entity):
   639     def update_entity(self, session, entity):
   640         """replace an entity in the source"""
   640         """replace an entity in the source"""
   641         with self._storage_handler(entity, 'updated'):
   641         with self._storage_handler(entity, 'updated'):
   642             attrs = self.preprocess_entity(entity)
   642             attrs = self.preprocess_entity(entity)
   643             if session.ertype_supports_undo(entity.__regid__):
   643             if session.ertype_supports_undo(entity.cw_etype):
   644                 changes = self._save_attrs(session, entity, attrs)
   644                 changes = self._save_attrs(session, entity, attrs)
   645                 self._record_tx_action(session, 'tx_entity_actions', 'U',
   645                 self._record_tx_action(session, 'tx_entity_actions', 'U',
   646                                        etype=entity.__regid__, eid=entity.eid,
   646                                        etype=entity.cw_etype, eid=entity.eid,
   647                                        changes=self._binary(dumps(changes)))
   647                                        changes=self._binary(dumps(changes)))
   648             sql = self.sqlgen.update(SQL_PREFIX + entity.__regid__, attrs,
   648             sql = self.sqlgen.update(SQL_PREFIX + entity.cw_etype, attrs,
   649                                      ['cw_eid'])
   649                                      ['cw_eid'])
   650             self.doexec(session, sql, attrs)
   650             self.doexec(session, sql, attrs)
   651 
   651 
   652     def delete_entity(self, session, entity):
   652     def delete_entity(self, session, entity):
   653         """delete an entity from the source"""
   653         """delete an entity from the source"""
   654         with self._storage_handler(entity, 'deleted'):
   654         with self._storage_handler(entity, 'deleted'):
   655             if session.ertype_supports_undo(entity.__regid__):
   655             if session.ertype_supports_undo(entity.cw_etype):
   656                 attrs = [SQL_PREFIX + r.type
   656                 attrs = [SQL_PREFIX + r.type
   657                          for r in entity.e_schema.subject_relations()
   657                          for r in entity.e_schema.subject_relations()
   658                          if (r.final or r.inlined) and not r in VIRTUAL_RTYPES]
   658                          if (r.final or r.inlined) and not r in VIRTUAL_RTYPES]
   659                 changes = self._save_attrs(session, entity, attrs)
   659                 changes = self._save_attrs(session, entity, attrs)
   660                 self._record_tx_action(session, 'tx_entity_actions', 'D',
   660                 self._record_tx_action(session, 'tx_entity_actions', 'D',
   661                                        etype=entity.__regid__, eid=entity.eid,
   661                                        etype=entity.cw_etype, eid=entity.eid,
   662                                        changes=self._binary(dumps(changes)))
   662                                        changes=self._binary(dumps(changes)))
   663             attrs = {'cw_eid': entity.eid}
   663             attrs = {'cw_eid': entity.eid}
   664             sql = self.sqlgen.delete(SQL_PREFIX + entity.__regid__, attrs)
   664             sql = self.sqlgen.delete(SQL_PREFIX + entity.cw_etype, attrs)
   665             self.doexec(session, sql, attrs)
   665             self.doexec(session, sql, attrs)
   666 
   666 
   667     def add_relation(self, session, subject, rtype, object, inlined=False):
   667     def add_relation(self, session, subject, rtype, object, inlined=False):
   668         """add a relation to the source"""
   668         """add a relation to the source"""
   669         self._add_relations(session,  rtype, [(subject, object)], inlined)
   669         self._add_relations(session,  rtype, [(subject, object)], inlined)
   976         # begin by inserting eid/type/source/extid into the entities table
   976         # begin by inserting eid/type/source/extid into the entities table
   977         if extid is not None:
   977         if extid is not None:
   978             assert isinstance(extid, str)
   978             assert isinstance(extid, str)
   979             extid = b64encode(extid)
   979             extid = b64encode(extid)
   980         uri = 'system' if source.copy_based_source else source.uri
   980         uri = 'system' if source.copy_based_source else source.uri
   981         attrs = {'type': entity.__regid__, 'eid': entity.eid, 'extid': extid,
   981         attrs = {'type': entity.cw_etype, 'eid': entity.eid, 'extid': extid,
   982                  'source': uri, 'asource': source.uri, 'mtime': datetime.utcnow()}
   982                  'source': uri, 'asource': source.uri, 'mtime': datetime.utcnow()}
   983         self._handle_insert_entity_sql(session, self.sqlgen.insert('entities', attrs), attrs)
   983         self._handle_insert_entity_sql(session, self.sqlgen.insert('entities', attrs), attrs)
   984         # insert core relations: is, is_instance_of and cw_source
   984         # insert core relations: is, is_instance_of and cw_source
   985         try:
   985         try:
   986             self._handle_is_relation_sql(session, 'INSERT INTO is_relation(eid_from,eid_to) VALUES (%s,%s)',
   986             self._handle_is_relation_sql(session, 'INSERT INTO is_relation(eid_from,eid_to) VALUES (%s,%s)',
   995                                              (entity.eid, eschema_eid(session, eschema)))
   995                                              (entity.eid, eschema_eid(session, eschema)))
   996         if 'CWSource' in self.schema and source.eid is not None: # else, cw < 3.10
   996         if 'CWSource' in self.schema and source.eid is not None: # else, cw < 3.10
   997             self._handle_is_relation_sql(session, 'INSERT INTO cw_source_relation(eid_from,eid_to) VALUES (%s,%s)',
   997             self._handle_is_relation_sql(session, 'INSERT INTO cw_source_relation(eid_from,eid_to) VALUES (%s,%s)',
   998                                          (entity.eid, source.eid))
   998                                          (entity.eid, source.eid))
   999         # now we can update the full text index
   999         # now we can update the full text index
  1000         if self.do_fti and self.need_fti_indexation(entity.__regid__):
  1000         if self.do_fti and self.need_fti_indexation(entity.cw_etype):
  1001             if complete:
  1001             if complete:
  1002                 entity.complete(entity.e_schema.indexable_attributes())
  1002                 entity.complete(entity.e_schema.indexable_attributes())
  1003             self.index_entity(session, entity=entity)
  1003             self.index_entity(session, entity=entity)
  1004 
  1004 
  1005     def update_info(self, session, entity, need_fti_update):
  1005     def update_info(self, session, entity, need_fti_update):
  1007         if self.do_fti and need_fti_update:
  1007         if self.do_fti and need_fti_update:
  1008             # reindex the entity only if this query is updating at least
  1008             # reindex the entity only if this query is updating at least
  1009             # one indexable attribute
  1009             # one indexable attribute
  1010             self.index_entity(session, entity=entity)
  1010             self.index_entity(session, entity=entity)
  1011         # update entities.mtime.
  1011         # update entities.mtime.
  1012         # XXX Only if entity.__regid__ in self.multisources_etypes?
  1012         # XXX Only if entity.cw_etype in self.multisources_etypes?
  1013         attrs = {'eid': entity.eid, 'mtime': datetime.utcnow()}
  1013         attrs = {'eid': entity.eid, 'mtime': datetime.utcnow()}
  1014         self.doexec(session, self.sqlgen.update('entities', attrs, ['eid']), attrs)
  1014         self.doexec(session, self.sqlgen.update('entities', attrs, ['eid']), attrs)
  1015 
  1015 
  1016     def delete_info_multi(self, session, entities, uri):
  1016     def delete_info_multi(self, session, entities, uri):
  1017         """delete system information on deletion of a list of entities with the
  1017         """delete system information on deletion of a list of entities with the
  1189     def _save_attrs(self, session, entity, attrs):
  1189     def _save_attrs(self, session, entity, attrs):
  1190         """return a pickleable dictionary containing current values for given
  1190         """return a pickleable dictionary containing current values for given
  1191         attributes of the entity
  1191         attributes of the entity
  1192         """
  1192         """
  1193         restr = {'cw_eid': entity.eid}
  1193         restr = {'cw_eid': entity.eid}
  1194         sql = self.sqlgen.select(SQL_PREFIX + entity.__regid__, restr, attrs)
  1194         sql = self.sqlgen.select(SQL_PREFIX + entity.cw_etype, restr, attrs)
  1195         cu = self.doexec(session, sql, restr)
  1195         cu = self.doexec(session, sql, restr)
  1196         values = dict(zip(attrs, cu.fetchone()))
  1196         values = dict(zip(attrs, cu.fetchone()))
  1197         # ensure backend specific binary are converted back to string
  1197         # ensure backend specific binary are converted back to string
  1198         eschema = entity.e_schema
  1198         eschema = entity.e_schema
  1199         for column in attrs:
  1199         for column in attrs:
  1300         sql = self.sqlgen.insert(SQL_PREFIX + etype, action.changes)
  1300         sql = self.sqlgen.insert(SQL_PREFIX + etype, action.changes)
  1301         self.doexec(session, sql, action.changes)
  1301         self.doexec(session, sql, action.changes)
  1302         # restore record in entities (will update fti if needed)
  1302         # restore record in entities (will update fti if needed)
  1303         self.add_info(session, entity, self, None, True)
  1303         self.add_info(session, entity, self, None, True)
  1304         # remove record from deleted_entities if entity's type is multi-sources
  1304         # remove record from deleted_entities if entity's type is multi-sources
  1305         if entity.__regid__ in self.multisources_etypes:
  1305         if entity.cw_etype in self.multisources_etypes:
  1306             self.doexec(session,
  1306             self.doexec(session,
  1307                         'DELETE FROM deleted_entities WHERE eid=%s' % eid)
  1307                         'DELETE FROM deleted_entities WHERE eid=%s' % eid)
  1308         self.repo.hm.call_hooks('after_add_entity', session, entity=entity)
  1308         self.repo.hm.call_hooks('after_add_entity', session, entity=entity)
  1309         return errors
  1309         return errors
  1310 
  1310 
  1363         self.doexec(session, 'DELETE FROM is_instance_of_relation WHERE eid_from=%s' % eid)
  1363         self.doexec(session, 'DELETE FROM is_instance_of_relation WHERE eid_from=%s' % eid)
  1364         self.doexec(session, 'DELETE FROM cw_source_relation WHERE eid_from=%s' % self.eid)
  1364         self.doexec(session, 'DELETE FROM cw_source_relation WHERE eid_from=%s' % self.eid)
  1365         # XXX check removal of inlined relation?
  1365         # XXX check removal of inlined relation?
  1366         # delete the entity
  1366         # delete the entity
  1367         attrs = {'cw_eid': eid}
  1367         attrs = {'cw_eid': eid}
  1368         sql = self.sqlgen.delete(SQL_PREFIX + entity.__regid__, attrs)
  1368         sql = self.sqlgen.delete(SQL_PREFIX + entity.cw_etype, attrs)
  1369         self.doexec(session, sql, attrs)
  1369         self.doexec(session, sql, attrs)
  1370         # remove record from entities (will update fti if needed)
  1370         # remove record from entities (will update fti if needed)
  1371         self.delete_info_multi(session, [entity], self.uri)
  1371         self.delete_info_multi(session, [entity], self.uri)
  1372         self.repo.hm.call_hooks('after_delete_entity', session, entity=entity)
  1372         self.repo.hm.call_hooks('after_delete_entity', session, entity=entity)
  1373         return ()
  1373         return ()
  1383                           "deleted inbetween") % action.eid)
  1383                           "deleted inbetween") % action.eid)
  1384             return errors
  1384             return errors
  1385         self._reedit_entity(entity, action.changes, err)
  1385         self._reedit_entity(entity, action.changes, err)
  1386         entity.cw_edited.check()
  1386         entity.cw_edited.check()
  1387         self.repo.hm.call_hooks('before_update_entity', session, entity=entity)
  1387         self.repo.hm.call_hooks('before_update_entity', session, entity=entity)
  1388         sql = self.sqlgen.update(SQL_PREFIX + entity.__regid__, action.changes,
  1388         sql = self.sqlgen.update(SQL_PREFIX + entity.cw_etype, action.changes,
  1389                                  ['cw_eid'])
  1389                                  ['cw_eid'])
  1390         self.doexec(session, sql, action.changes)
  1390         self.doexec(session, sql, action.changes)
  1391         self.repo.hm.call_hooks('after_update_entity', session, entity=entity)
  1391         self.repo.hm.call_hooks('after_update_entity', session, entity=entity)
  1392         return errors
  1392         return errors
  1393 
  1393 
  1401             errors.append(unicode(ex))
  1401             errors.append(unicode(ex))
  1402         else:
  1402         else:
  1403             rschema = rdef.rtype
  1403             rschema = rdef.rtype
  1404             if rschema.inlined:
  1404             if rschema.inlined:
  1405                 sql = 'SELECT 1 FROM cw_%s WHERE cw_eid=%s and cw_%s=%s'\
  1405                 sql = 'SELECT 1 FROM cw_%s WHERE cw_eid=%s and cw_%s=%s'\
  1406                       % (sentity.__regid__, subj, rtype, obj)
  1406                       % (sentity.cw_etype, subj, rtype, obj)
  1407             else:
  1407             else:
  1408                 sql = 'SELECT 1 FROM %s_relation WHERE eid_from=%s and eid_to=%s'\
  1408                 sql = 'SELECT 1 FROM %s_relation WHERE eid_from=%s and eid_to=%s'\
  1409                       % (rtype, subj, obj)
  1409                       % (rtype, subj, obj)
  1410             cu = self.doexec(session, sql)
  1410             cu = self.doexec(session, sql)
  1411             if cu.fetchone() is None:
  1411             if cu.fetchone() is None: