server/repository.py
changeset 4808 23df4a120c96
parent 4776 3bf51379baee
parent 4806 4f12f59b1a13
child 4834 b718626a0e60
equal deleted inserted replaced
4804:daa71eaf11e8 4808:23df4a120c96
    67         try:
    67         try:
    68             self.session.repo.clear_caches(
    68             self.session.repo.clear_caches(
    69                 self.session.transaction_data['neweids'])
    69                 self.session.transaction_data['neweids'])
    70         except KeyError:
    70         except KeyError:
    71             pass
    71             pass
    72 
       
    73 
       
    74 class FTIndexEntityOp(hook.LateOperation):
       
    75     """operation to delay entity full text indexation to commit
       
    76 
       
    77     since fti indexing may trigger discovery of other entities, it should be
       
    78     triggered on precommit, not commit, and this should be done after other
       
    79     precommit operation which may add relations to the entity
       
    80     """
       
    81 
       
    82     def precommit_event(self):
       
    83         session = self.session
       
    84         entity = self.entity
       
    85         if entity.eid in session.transaction_data.get('pendingeids', ()):
       
    86             return # entity added and deleted in the same transaction
       
    87         session.repo.system_source.fti_unindex_entity(session, entity.eid)
       
    88         for container in entity.fti_containers():
       
    89             session.repo.index_entity(session, container)
       
    90 
       
    91     def commit_event(self):
       
    92         pass
       
    93 
    72 
    94 
    73 
    95 def del_existing_rel_if_needed(session, eidfrom, rtype, eidto):
    74 def del_existing_rel_if_needed(session, eidfrom, rtype, eidto):
    96     """delete existing relation when adding a new one if card is 1 or ?
    75     """delete existing relation when adding a new one if card is 1 or ?
    97 
    76 
   131                                       'NOT X eid %%(x)s' % rtype,
   110                                       'NOT X eid %%(x)s' % rtype,
   132                                       {'x': eidfrom, 'y': eidto}, 'y')
   111                                       {'x': eidfrom, 'y': eidto}, 'y')
   133         if rset:
   112         if rset:
   134             safe_delete_relation(session, rschema, *rset[0])
   113             safe_delete_relation(session, rschema, *rset[0])
   135 
   114 
       
   115 
   136 def safe_delete_relation(session, rschema, subject, object):
   116 def safe_delete_relation(session, rschema, subject, object):
   137     if not rschema.has_perm(session, 'delete', fromeid=subject, toeid=object):
   117     if not rschema.has_perm(session, 'delete', fromeid=subject, toeid=object):
   138         raise Unauthorized()
   118         raise Unauthorized()
   139     session.repo.glob_delete_relation(session, subject, rschema.type, object)
   119     session.repo.glob_delete_relation(session, subject, rschema.type, object)
   140 
   120 
   162         # initial schema, should be build or replaced latter
   142         # initial schema, should be build or replaced latter
   163         self.schema = schema.CubicWebSchema(config.appid)
   143         self.schema = schema.CubicWebSchema(config.appid)
   164         self.vreg.schema = self.schema # until actual schema is loaded...
   144         self.vreg.schema = self.schema # until actual schema is loaded...
   165         # querier helper, need to be created after sources initialization
   145         # querier helper, need to be created after sources initialization
   166         self.querier = querier.QuerierHelper(self, self.schema)
   146         self.querier = querier.QuerierHelper(self, self.schema)
   167         # should we reindex in changes?
       
   168         self.do_fti = not config['delay-full-text-indexation']
       
   169         # sources
   147         # sources
   170         self.sources = []
   148         self.sources = []
   171         self.sources_by_uri = {}
   149         self.sources_by_uri = {}
   172         # FIXME: store additional sources info in the system database ?
   150         # FIXME: store additional sources info in the system database ?
   173         # FIXME: sources should be ordered (add_entity priority)
   151         # FIXME: sources should be ordered (add_entity priority)
   776         return session
   754         return session
   777 
   755 
   778     # data sources handling ###################################################
   756     # data sources handling ###################################################
   779     # * correspondance between eid and (type, source)
   757     # * correspondance between eid and (type, source)
   780     # * correspondance between eid and local id (i.e. specific to a given source)
   758     # * correspondance between eid and local id (i.e. specific to a given source)
   781     # * searchable text indexes
       
   782 
   759 
   783     def type_and_source_from_eid(self, eid, session=None):
   760     def type_and_source_from_eid(self, eid, session=None):
   784         """return a tuple (type, source, extid) for the entity with id <eid>"""
   761         """return a tuple (type, source, extid) for the entity with id <eid>"""
   785         try:
   762         try:
   786             eid = typed_eid(eid)
   763             eid = typed_eid(eid)
   903     def add_info(self, session, entity, source, extid=None, complete=True):
   880     def add_info(self, session, entity, source, extid=None, complete=True):
   904         """add type and source info for an eid into the system table,
   881         """add type and source info for an eid into the system table,
   905         and index the entity with the full text index
   882         and index the entity with the full text index
   906         """
   883         """
   907         # begin by inserting eid/type/source/extid into the entities table
   884         # begin by inserting eid/type/source/extid into the entities table
   908         self.system_source.add_info(session, entity, source, extid)
       
   909         if complete:
       
   910             entity.complete(entity.e_schema.indexable_attributes())
       
   911         new = session.transaction_data.setdefault('neweids', set())
   885         new = session.transaction_data.setdefault('neweids', set())
   912         new.add(entity.eid)
   886         new.add(entity.eid)
   913         # now we can update the full text index
   887         self.system_source.add_info(session, entity, source, extid, complete)
   914         if self.do_fti:
       
   915             FTIndexEntityOp(session, entity=entity)
       
   916         CleanupEidTypeCacheOp(session)
   888         CleanupEidTypeCacheOp(session)
   917 
   889 
   918     def delete_info(self, session, eid):
   890     def delete_info(self, session, eid):
   919         self._prepare_delete_info(session, eid)
   891         self._prepare_delete_info(session, eid)
   920         self._delete_info(session, eid)
   892         self._delete_info(session, eid)
   959                 selection = '%s %s X' % (var, rtype)
   931                 selection = '%s %s X' % (var, rtype)
   960             rql = 'DELETE %s WHERE X eid %%(x)s' % selection
   932             rql = 'DELETE %s WHERE X eid %%(x)s' % selection
   961             # unsafe_execute since we suppose that if user can delete the entity,
   933             # unsafe_execute since we suppose that if user can delete the entity,
   962             # he can delete all its relations without security checking
   934             # he can delete all its relations without security checking
   963             session.unsafe_execute(rql, {'x': eid}, 'x', build_descr=False)
   935             session.unsafe_execute(rql, {'x': eid}, 'x', build_descr=False)
   964 
       
   965     def index_entity(self, session, entity):
       
   966         """full text index a modified entity"""
       
   967         alreadydone = session.transaction_data.setdefault('indexedeids', set())
       
   968         if entity.eid in alreadydone:
       
   969             self.debug('skipping reindexation of %s, already done', entity.eid)
       
   970             return
       
   971         alreadydone.add(entity.eid)
       
   972         self.system_source.fti_index_entity(session, entity)
       
   973 
   936 
   974     def locate_relation_source(self, session, subject, rtype, object):
   937     def locate_relation_source(self, session, subject, rtype, object):
   975         subjsource = self.source_from_eid(subject, session)
   938         subjsource = self.source_from_eid(subject, session)
   976         objsource = self.source_from_eid(object, session)
   939         objsource = self.source_from_eid(object, session)
   977         if not subjsource is objsource:
   940         if not subjsource is objsource:
  1104                 self.hm.call_hooks('before_add_relation', session,
  1067                 self.hm.call_hooks('before_add_relation', session,
  1105                                     eidfrom=entity.eid, rtype=attr, eidto=value)
  1068                                     eidfrom=entity.eid, rtype=attr, eidto=value)
  1106             if not only_inline_rels:
  1069             if not only_inline_rels:
  1107                 self.hm.call_hooks('before_update_entity', session, entity=entity)
  1070                 self.hm.call_hooks('before_update_entity', session, entity=entity)
  1108         source.update_entity(session, entity)
  1071         source.update_entity(session, entity)
  1109         if not only_inline_rels:
  1072         self.system_source.update_info(session, entity, need_fti_update)
  1110             if need_fti_update and self.do_fti:
  1073         if source.should_call_hooks:
  1111                 # reindex the entity only if this query is updating at least
  1074             if not only_inline_rels:
  1112                 # one indexable attribute
       
  1113                 FTIndexEntityOp(session, entity=entity)
       
  1114             if source.should_call_hooks:
       
  1115                 self.hm.call_hooks('after_update_entity', session, entity=entity)
  1075                 self.hm.call_hooks('after_update_entity', session, entity=entity)
  1116         if source.should_call_hooks:
       
  1117             for attr, value, prevvalue in relations:
  1076             for attr, value, prevvalue in relations:
  1118                 # if the relation is already cached, update existant cache
  1077                 # if the relation is already cached, update existant cache
  1119                 relcache = entity.relation_cached(attr, 'subject')
  1078                 relcache = entity.relation_cached(attr, 'subject')
  1120                 if prevvalue is not None:
  1079                 if prevvalue is not None:
  1121                     self.hm.call_hooks('after_delete_relation', session,
  1080                     self.hm.call_hooks('after_delete_relation', session,