server/sources/pyrorql.py
changeset 6944 0cf10429ad39
parent 6941 9ed02daa7dbb
child 6945 28bf94d062a9
equal deleted inserted replaced
6943:406a41c25e13 6944:0cf10429ad39
     1 # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     3 #
     3 #
     4 # This file is part of CubicWeb.
     4 # This file is part of CubicWeb.
     5 #
     5 #
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
    29 from Pyro.errors import PyroError, ConnectionClosedError
    29 from Pyro.errors import PyroError, ConnectionClosedError
    30 
    30 
    31 from logilab.common.configuration import REQUIRED
    31 from logilab.common.configuration import REQUIRED
    32 from logilab.common.optik_ext import check_yn
    32 from logilab.common.optik_ext import check_yn
    33 
    33 
       
    34 from yams.schema import role_name
       
    35 
    34 from rql.nodes import Constant
    36 from rql.nodes import Constant
    35 from rql.utils import rqlvar_maker
    37 from rql.utils import rqlvar_maker
    36 
    38 
    37 from cubicweb import dbapi, server
    39 from cubicweb import dbapi, server
    38 from cubicweb import BadConnectionId, UnknownEid, ConnectionError
    40 from cubicweb import ValidationError, BadConnectionId, UnknownEid, ConnectionError
       
    41 from cubicweb.schema import VIRTUAL_RTYPES
    39 from cubicweb.cwconfig import register_persistent_options
    42 from cubicweb.cwconfig import register_persistent_options
    40 from cubicweb.server.sources import (AbstractSource, ConnectionWrapper,
    43 from cubicweb.server.sources import (AbstractSource, ConnectionWrapper,
    41                                      TimedCache, dbg_st_search, dbg_results)
    44                                      TimedCache, dbg_st_search, dbg_results)
    42 from cubicweb.server.msplanner import neged_relation
    45 from cubicweb.server.msplanner import neged_relation
    43 
    46 
   174         self.support_entities = {}
   177         self.support_entities = {}
   175         self.support_relations = {}
   178         self.support_relations = {}
   176         self.dont_cross_relations = set(('owned_by', 'created_by'))
   179         self.dont_cross_relations = set(('owned_by', 'created_by'))
   177         self.cross_relations = set()
   180         self.cross_relations = set()
   178         assert self.eid is not None
   181         assert self.eid is not None
       
   182         self._schemacfg_idx = {}
   179         if session is None:
   183         if session is None:
   180             _session = self.repo.internal_session()
   184             _session = self.repo.internal_session()
   181         else:
   185         else:
   182             _session = session
   186             _session = session
   183         try:
   187         try:
   184             for rql, struct in [('Any ETN WHERE S cw_support ET, ET name ETN, ET is CWEType, S eid %(s)s',
   188             for schemacfg in _session.execute(
   185                                  self.support_entities),
   189                 'Any CFG,CFGO,SN,S WHERE '
   186                                 ('Any RTN WHERE S cw_support RT, RT name RTN, RT is CWRType, S eid %(s)s',
   190                 'CFG options CFGO, CFG cw_schema S, S name SN, '
   187                                  self.support_relations)]:
   191                 'CFG cw_for_source X, X eid %(x)s', {'x': self.eid}).entities():
   188                 for ertype, in _session.execute(rql, {'s': self.eid}):
   192                 self.add_schema_config(schemacfg)
   189                     struct[ertype] = True # XXX write support
       
   190             for rql, struct in [('Any RTN WHERE S cw_may_cross RT, RT name RTN, S eid %(s)s',
       
   191                                  self.cross_relations),
       
   192                                 ('Any RTN WHERE S cw_dont_cross RT, RT name RTN, S eid %(s)s',
       
   193                                  self.dont_cross_relations)]:
       
   194                 for rtype, in _session.execute(rql, {'s': self.eid}):
       
   195                     struct.add(rtype)
       
   196         finally:
   193         finally:
   197             if session is None:
   194             if session is None:
   198                 _session.close()
   195                 _session.close()
   199         # XXX move in hooks or schema constraints
   196 
   200         for rtype in ('is', 'is_instance_of', 'cw_source'):
   197     etype_options = set(('write',))
   201             assert rtype not in self.dont_cross_relations, \
   198     rtype_options = set(('maycross', 'dontcross', 'write',))
   202                    '%s relation should not be in dont_cross_relations' % rtype
   199 
   203             assert rtype not in self.support_relations, \
   200     def _check_options(self, schemacfg, allowedoptions):
   204                    '%s relation should not be in support_relations' % rtype
   201         if schemacfg.options:
       
   202             options = set(w.strip() for w in schemacfg.options.split(':'))
       
   203         else:
       
   204             options = set()
       
   205         if options - allowedoptions:
       
   206             options = ', '.join(sorted(options - allowedoptions))
       
   207             msg = _('unknown option(s): %s' % options)
       
   208             raise ValidationError(schemacfg.eid, {role_name('options', 'subject'): msg})
       
   209         return options
       
   210 
       
   211     def add_schema_config(self, schemacfg, checkonly=False):
       
   212         """added CWSourceSchemaConfig, modify mapping accordingly"""
       
   213         try:
       
   214             ertype = schemacfg.schema.name
       
   215         except AttributeError:
       
   216             msg = schemacfg._cw._("attribute/relation can't be mapped, only "
       
   217                                   "entity and relation types")
       
   218             raise ValidationError(schemacfg.eid, {role_name('cw_for_schema', 'subject'): msg})
       
   219         if schemacfg.schema.__regid__ == 'CWEType':
       
   220             options = self._check_options(schemacfg, self.etype_options)
       
   221             if not checkonly:
       
   222                 self.support_entities[ertype] = 'write' in options
       
   223         else: # CWRType
       
   224             if ertype in ('is', 'is_instance_of', 'cw_source') or ertype in VIRTUAL_RTYPES:
       
   225                 msg = schemacfg._cw._('%s relation should not be in mapped') % rtype
       
   226                 raise ValidationError(schemacfg.eid, {role_name('cw_for_schema', 'subject'): msg})
       
   227             options = self._check_options(schemacfg, self.rtype_options)
       
   228             if 'dontcross' in options:
       
   229                 if 'maycross' in options:
       
   230                     msg = schemacfg._("can't mix dontcross and maycross options")
       
   231                     raise ValidationError(schemacfg.eid, {role_name('options', 'subject'): msg})
       
   232                 if 'write' in options:
       
   233                     msg = schemacfg._("can't mix dontcross and write options")
       
   234                     raise ValidationError(schemacfg.eid, {role_name('options', 'subject'): msg})
       
   235                 if not checkonly:
       
   236                     self.dont_cross_relations.add(ertype)
       
   237             elif not checkonly:
       
   238                 self.support_relations[ertype] = 'write' in options
       
   239                 if 'maycross' in options:
       
   240                     self.cross_relations.add(ertype)
       
   241         if not checkonly:
       
   242             # add to an index to ease deletion handling
       
   243             self._schemacfg_idx[schemacfg.eid] = ertype
       
   244 
       
   245     def del_schema_config(self, schemacfg, checkonly=False):
       
   246         """deleted CWSourceSchemaConfig, modify mapping accordingly"""
       
   247         if checkonly:
       
   248             return
       
   249         try:
       
   250             ertype = self._schemacfg_idx[schemacfg.eid]
       
   251             if ertype[0].isupper():
       
   252                 del self.support_entities[ertype]
       
   253             else:
       
   254                 if ertype in self.support_relations:
       
   255                     del self.support_relations[ertype]
       
   256                     if ertype in self.cross_relations:
       
   257                         self.cross_relations.remove(ertype)
       
   258                 else:
       
   259                     self.dont_cross_relations.remove(ertype)
       
   260         except:
       
   261             self.error('while updating mapping consequently to removal of %s',
       
   262                        schemacfg)
   205 
   263 
   206     def local_eid(self, cnx, extid, session):
   264     def local_eid(self, cnx, extid, session):
   207         etype, dexturi, dextid = cnx.describe(extid)
   265         etype, dexturi, dextid = cnx.describe(extid)
   208         if dexturi == 'system' or not (
   266         if dexturi == 'system' or not (
   209             dexturi in self.repo.sources_by_uri or self._skip_externals):
   267             dexturi in self.repo.sources_by_uri or self._skip_externals):