server/repository.py
changeset 5174 78438ad513ca
parent 5115 2e43ef618d14
child 5177 395e1ff018ae
equal deleted inserted replaced
5173:73760bbb66bd 5174:78438ad513ca
    31 
    31 
    32 from yams import BadSchemaDefinition
    32 from yams import BadSchemaDefinition
    33 from yams.schema import role_name
    33 from yams.schema import role_name
    34 from rql import RQLSyntaxError
    34 from rql import RQLSyntaxError
    35 
    35 
    36 from cubicweb import (CW_SOFTWARE_ROOT, CW_MIGRATION_MAP,
    36 from cubicweb import (CW_SOFTWARE_ROOT, CW_MIGRATION_MAP, QueryError,
    37                       UnknownEid, AuthenticationError, ExecutionError,
    37                       UnknownEid, AuthenticationError, ExecutionError,
    38                       ETypeNotSupportedBySources, MultiSourcesError,
    38                       ETypeNotSupportedBySources, MultiSourcesError,
    39                       BadConnectionId, Unauthorized, ValidationError,
    39                       BadConnectionId, Unauthorized, ValidationError,
    40                       RepositoryError, typed_eid, onevent)
    40                       RepositoryError, typed_eid, onevent)
    41 from cubicweb import cwvreg, schema, server
    41 from cubicweb import cwvreg, schema, server
    74     if card[0] in '1?':
    74     if card[0] in '1?':
    75         if not rschema.inlined: # inlined relations will be implicitly deleted
    75         if not rschema.inlined: # inlined relations will be implicitly deleted
    76             with security_enabled(session, read=False):
    76             with security_enabled(session, read=False):
    77                 session.execute('DELETE X %s Y WHERE X eid %%(x)s, '
    77                 session.execute('DELETE X %s Y WHERE X eid %%(x)s, '
    78                                 'NOT Y eid %%(y)s' % rtype,
    78                                 'NOT Y eid %%(y)s' % rtype,
    79                                 {'x': eidfrom, 'y': eidto}, 'x')
    79                                 {'x': eidfrom, 'y': eidto})
    80     if card[1] in '1?':
    80     if card[1] in '1?':
    81         with security_enabled(session, read=False):
    81         with security_enabled(session, read=False):
    82             session.execute('DELETE X %sY WHERE Y eid %%(y)s, '
    82             session.execute('DELETE X %sY WHERE Y eid %%(y)s, '
    83                             'NOT X eid %%(x)s' % rtype,
    83                             'NOT X eid %%(x)s' % rtype,
    84                             {'x': eidfrom, 'y': eidto}, 'y')
    84                             {'x': eidfrom, 'y': eidto})
    85 
    85 
    86 
    86 
    87 class Repository(object):
    87 class Repository(object):
    88     """a repository provides access to a set of persistent storages for
    88     """a repository provides access to a set of persistent storages for
    89     entities and relations
    89     entities and relations
   406 
   406 
   407     def _build_user(self, session, eid):
   407     def _build_user(self, session, eid):
   408         """return a CWUser entity for user with the given eid"""
   408         """return a CWUser entity for user with the given eid"""
   409         cls = self.vreg['etypes'].etype_class('CWUser')
   409         cls = self.vreg['etypes'].etype_class('CWUser')
   410         rql = cls.fetch_rql(session.user, ['X eid %(x)s'])
   410         rql = cls.fetch_rql(session.user, ['X eid %(x)s'])
   411         rset = session.execute(rql, {'x': eid}, 'x')
   411         rset = session.execute(rql, {'x': eid})
   412         assert len(rset) == 1, rset
   412         assert len(rset) == 1, rset
   413         cwuser = rset.get_entity(0, 0)
   413         cwuser = rset.get_entity(0, 0)
   414         # pylint: disable-msg=W0104
   414         # pylint: disable-msg=W0104
   415         # prefetch / cache cwuser's groups and properties. This is especially
   415         # prefetch / cache cwuser's groups and properties. This is especially
   416         # useful for internal sessions to avoid security insertions
   416         # useful for internal sessions to avoid security insertions
   565         # commit session at this point in case write operation has been done
   565         # commit session at this point in case write operation has been done
   566         # during `session_open` hooks
   566         # during `session_open` hooks
   567         session.commit()
   567         session.commit()
   568         return session.id
   568         return session.id
   569 
   569 
   570     def execute(self, sessionid, rqlstring, args=None, eid_key=None, build_descr=True):
   570     def execute(self, sessionid, rqlstring, args=None, build_descr=True):
   571         """execute a RQL query
   571         """execute a RQL query
   572 
   572 
   573         * rqlstring should be an unicode string or a plain ascii string
   573         * rqlstring should be an unicode string or a plain ascii string
   574         * args the optional parameters used in the query
   574         * args the optional parameters used in the query
   575         * build_descr is a flag indicating if the description should be
   575         * build_descr is a flag indicating if the description should be
   576           built on select queries
   576           built on select queries
   577         """
   577         """
   578         session = self._get_session(sessionid, setpool=True)
   578         session = self._get_session(sessionid, setpool=True)
   579         try:
   579         try:
   580             try:
   580             try:
   581                 return self.querier.execute(session, rqlstring, args, eid_key,
   581                 return self.querier.execute(session, rqlstring, args,
   582                                             build_descr)
   582                                             build_descr)
   583             except (Unauthorized, RQLSyntaxError):
   583             except (Unauthorized, RQLSyntaxError):
   584                 raise
   584                 raise
   585             except ValidationError, ex:
   585             except ValidationError, ex:
   586                 # need ValidationError normalization here so error may pass
   586                 # need ValidationError normalization here so error may pass
   833         return self.type_and_source_from_eid(eid, session)[0]
   833         return self.type_and_source_from_eid(eid, session)[0]
   834 
   834 
   835     def source_from_eid(self, eid, session=None):
   835     def source_from_eid(self, eid, session=None):
   836         """return the source for the given entity's eid"""
   836         """return the source for the given entity's eid"""
   837         return self.sources_by_uri[self.type_and_source_from_eid(eid, session)[1]]
   837         return self.sources_by_uri[self.type_and_source_from_eid(eid, session)[1]]
       
   838 
       
   839     def querier_cache_key(self, session, rql, args, eidkeys):
       
   840         cachekey = [rql]
       
   841         for key in sorted(eidkeys):
       
   842             try:
       
   843                 etype = self.type_from_eid(args[key], session)
       
   844             except KeyError:
       
   845                 raise QueryError('bad cache key %s (no value)' % key)
       
   846             except TypeError:
       
   847                 raise QueryError('bad cache key %s (value: %r)' % (
       
   848                     key, args[key]))
       
   849             cachekey.append(etype)
       
   850             # ensure eid is correctly typed in args
       
   851             args[key] = typed_eid(args[key])
       
   852         return tuple(cachekey)
   838 
   853 
   839     def eid2extid(self, source, eid, session=None):
   854     def eid2extid(self, source, eid, session=None):
   840         """get local id from an eid"""
   855         """get local id from an eid"""
   841         etype, uri, extid = self.type_and_source_from_eid(eid, session)
   856         etype, uri, extid = self.type_and_source_from_eid(eid, session)
   842         if source.uri != uri:
   857         if source.uri != uri:
   899             if source.should_call_hooks:
   914             if source.should_call_hooks:
   900                 self.hm.call_hooks('after_add_entity', session, entity=entity)
   915                 self.hm.call_hooks('after_add_entity', session, entity=entity)
   901             else:
   916             else:
   902                 # minimal meta-data
   917                 # minimal meta-data
   903                 session.execute('SET X is E WHERE X eid %(x)s, E name %(name)s',
   918                 session.execute('SET X is E WHERE X eid %(x)s, E name %(name)s',
   904                                 {'x': entity.eid, 'name': entity.__regid__}, 'x')
   919                                 {'x': entity.eid, 'name': entity.__regid__})
   905             session.commit(reset_pool)
   920             session.commit(reset_pool)
   906             return eid
   921             return eid
   907         except:
   922         except:
   908             session.rollback(reset_pool)
   923             session.rollback(reset_pool)
   909             raise
   924             raise
   947                     # don't skip inlined relation so they are regularly
   962                     # don't skip inlined relation so they are regularly
   948                     # deleted and so hooks are correctly called
   963                     # deleted and so hooks are correctly called
   949                     rql = 'DELETE X %s Y WHERE X eid %%(x)s' % rtype
   964                     rql = 'DELETE X %s Y WHERE X eid %%(x)s' % rtype
   950                 else:
   965                 else:
   951                     rql = 'DELETE Y %s X WHERE X eid %%(x)s' % rtype
   966                     rql = 'DELETE Y %s X WHERE X eid %%(x)s' % rtype
   952                 session.execute(rql, {'x': eid}, 'x', build_descr=False)
   967                 session.execute(rql, {'x': eid}, build_descr=False)
   953         self.system_source.delete_info(session, entity, sourceuri, extid)
   968         self.system_source.delete_info(session, entity, sourceuri, extid)
   954 
   969 
   955     def locate_relation_source(self, session, subject, rtype, object):
   970     def locate_relation_source(self, session, subject, rtype, object):
   956         subjsource = self.source_from_eid(subject, session)
   971         subjsource = self.source_from_eid(subject, session)
   957         objsource = self.source_from_eid(object, session)
   972         objsource = self.source_from_eid(object, session)