server/sources/remoterql.py
author Sylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 28 Aug 2013 11:36:44 +0200
branchstable
changeset 9223 233e770293a9
parent 8900 010a59e12d89
permissions -rw-r--r--
[date picker widgets] properly distinguish DOM id and input name. Closes #3096575
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
     1
# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
     2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
     3
#
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
     4
# This file is part of CubicWeb.
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
     5
#
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
     6
# CubicWeb is free software: you can redistribute it and/or modify it under the
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
     7
# terms of the GNU Lesser General Public License as published by the Free
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
     8
# Software Foundation, either version 2.1 of the License, or (at your option)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
     9
# any later version.
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    10
#
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    13
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    14
# details.
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    15
#
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    16
# You should have received a copy of the GNU Lesser General Public License along
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    17
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    18
"""Source to query another RQL remote repository"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    19
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    20
__docformat__ = "restructuredtext en"
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    21
_ = unicode
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    22
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    23
from os.path import join
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    24
from base64 import b64decode
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    25
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    26
from logilab.common.configuration import REQUIRED
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    27
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    28
from yams.schema import role_name
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    29
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    30
from rql.nodes import Constant
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    31
from rql.utils import rqlvar_maker
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    32
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    33
from cubicweb import dbapi, server
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    34
from cubicweb import ValidationError, BadConnectionId, UnknownEid
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    35
from cubicweb.schema import VIRTUAL_RTYPES
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    36
from cubicweb.server.sources import (AbstractSource, ConnectionWrapper,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    37
                                     TimedCache, dbg_st_search, dbg_results)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    38
from cubicweb.server.msplanner import neged_relation
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    39
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    40
def uidtype(union, col, etype, args):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    41
    select, col = union.locate_subquery(col, etype, args)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    42
    return getattr(select.selection[col], 'uidtype', None)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    43
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    44
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    45
class ReplaceByInOperator(Exception):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    46
    def __init__(self, eids):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    47
        self.eids = eids
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    48
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    49
class RemoteSource(AbstractSource):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    50
    """Generic external repository source"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    51
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    52
    # boolean telling if modification hooks should be called when something is
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    53
    # modified in this source
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    54
    should_call_hooks = False
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    55
    # boolean telling if the repository should connect to this source during
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    56
    # migration
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    57
    connect_for_migration = False
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    58
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    59
    options = (
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    60
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    61
        ('cubicweb-user',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    62
         {'type' : 'string',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    63
          'default': REQUIRED,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    64
          'help': 'user to use for connection on the distant repository',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    65
          'group': 'remote-source', 'level': 0,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    66
          }),
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    67
        ('cubicweb-password',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    68
         {'type' : 'password',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    69
          'default': '',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    70
          'help': 'user to use for connection on the distant repository',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    71
          'group': 'remote-source', 'level': 0,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    72
          }),
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    73
        ('base-url',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    74
         {'type' : 'string',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    75
          'default': '',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    76
          'help': 'url of the web site for the distant repository, if you want '
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    77
          'to generate external link to entities from this repository',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    78
          'group': 'remote-source', 'level': 1,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    79
          }),
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    80
        ('skip-external-entities',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    81
         {'type' : 'yn',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    82
          'default': False,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    83
          'help': 'should entities not local to the source be considered or not',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    84
          'group': 'remote-source', 'level': 0,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    85
          }),
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    86
        ('synchronization-interval',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    87
         {'type' : 'time',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    88
          'default': '5min',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    89
          'help': 'interval between synchronization with the external \
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    90
repository (default to 5 minutes).',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    91
          'group': 'remote-source', 'level': 2,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    92
          }))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    93
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    94
    PUBLIC_KEYS = AbstractSource.PUBLIC_KEYS + ('base-url',)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    95
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    96
    _conn = None
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    97
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
    98
    def __init__(self, repo, source_config, eid=None):
8356
e6688dd9fb52 [remote rql source] fix super call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8354
diff changeset
    99
        super(RemoteSource, self).__init__(repo, source_config, eid)
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   100
        self._query_cache = TimedCache(1800)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   101
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   102
    def update_config(self, source_entity, processed_config):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   103
        """update configuration from source entity"""
8674
001c1592060a [repo sources] move handling of source's url into abstract source as this becomes shared by most sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8545
diff changeset
   104
        super(RemoteSource, self).update_config(source_entity, processed_config)
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   105
        baseurl = processed_config.get('base-url')
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   106
        if baseurl and not baseurl.endswith('/'):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   107
            processed_config['base-url'] += '/'
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   108
        self.config = processed_config
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   109
        self._skip_externals = processed_config['skip-external-entities']
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   110
        if source_entity is not None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   111
            self.latest_retrieval = source_entity.latest_retrieval
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   112
8675
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   113
    def _entity_update(self, source_entity):
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   114
        super(RemoteSource, self)._entity_update(source_entity)
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   115
        if self.urls and len(self.urls) > 1:
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   116
            raise ValidationError(source_entity.eid, {'url': _('can only have one url')})
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   117
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   118
    def get_connection(self):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   119
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   120
            return self._get_connection()
8695
358d8bed9626 [toward-py3k] rewrite to "except AnException as exc:" (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8675
diff changeset
   121
        except ConnectionError as ex:
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   122
            self.critical("can't get connection to source %s: %s", self.uri, ex)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   123
            return ConnectionWrapper()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   124
8675
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   125
    def _get_connection(self):
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   126
        """open and return a connection to the source"""
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   127
        self.info('connecting to source %s as user %s',
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   128
                  self.urls[0], self.config['cubicweb-user'])
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   129
        # XXX check protocol according to source type (zmq / pyro)
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   130
        return dbapi.connect(self.urls[0], login=self.config['cubicweb-user'],
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   131
                             password=self.config['cubicweb-password'])
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   132
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   133
    def reset_caches(self):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   134
        """method called during test to reset potential source caches"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   135
        self._query_cache = TimedCache(1800)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   136
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   137
    def init(self, activated, source_entity):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   138
        """method called by the repository once ready to handle request"""
8707
28cbd267e96b [sources] fix classes that inherit from AbstractSource (closes #2718669)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8696
diff changeset
   139
        super(RemoteSource, self).init(activated, source_entity)
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   140
        self.load_mapping(source_entity._cw)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   141
        if activated:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   142
            interval = self.config['synchronization-interval']
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   143
            self.repo.looping_task(interval, self.synchronize)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   144
            self.repo.looping_task(self._query_cache.ttl.seconds/10,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   145
                                   self._query_cache.clear_expired)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   146
            self.latest_retrieval = source_entity.latest_retrieval
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   147
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   148
    def load_mapping(self, session=None):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   149
        self.support_entities = {}
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   150
        self.support_relations = {}
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   151
        self.dont_cross_relations = set(('owned_by', 'created_by'))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   152
        self.cross_relations = set()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   153
        assert self.eid is not None
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   154
        self._schemacfg_idx = {}
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   155
        self._load_mapping(session)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   156
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   157
    etype_options = set(('write',))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   158
    rtype_options = set(('maycross', 'dontcross', 'write',))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   159
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   160
    def _check_options(self, schemacfg, allowedoptions):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   161
        if schemacfg.options:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   162
            options = set(w.strip() for w in schemacfg.options.split(':'))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   163
        else:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   164
            options = set()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   165
        if options - allowedoptions:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   166
            options = ', '.join(sorted(options - allowedoptions))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   167
            msg = _('unknown option(s): %s' % options)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   168
            raise ValidationError(schemacfg.eid, {role_name('options', 'subject'): msg})
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   169
        return options
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   170
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   171
    def add_schema_config(self, schemacfg, checkonly=False):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   172
        """added CWSourceSchemaConfig, modify mapping accordingly"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   173
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   174
            ertype = schemacfg.schema.name
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   175
        except AttributeError:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   176
            msg = schemacfg._cw._("attribute/relation can't be mapped, only "
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   177
                                  "entity and relation types")
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   178
            raise ValidationError(schemacfg.eid, {role_name('cw_for_schema', 'subject'): msg})
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   179
        if schemacfg.schema.__regid__ == 'CWEType':
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   180
            options = self._check_options(schemacfg, self.etype_options)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   181
            if not checkonly:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   182
                self.support_entities[ertype] = 'write' in options
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   183
        else: # CWRType
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   184
            if ertype in ('is', 'is_instance_of', 'cw_source') or ertype in VIRTUAL_RTYPES:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   185
                msg = schemacfg._cw._('%s relation should not be in mapped') % ertype
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   186
                raise ValidationError(schemacfg.eid, {role_name('cw_for_schema', 'subject'): msg})
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   187
            options = self._check_options(schemacfg, self.rtype_options)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   188
            if 'dontcross' in options:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   189
                if 'maycross' in options:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   190
                    msg = schemacfg._("can't mix dontcross and maycross options")
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   191
                    raise ValidationError(schemacfg.eid, {role_name('options', 'subject'): msg})
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   192
                if 'write' in options:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   193
                    msg = schemacfg._("can't mix dontcross and write options")
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   194
                    raise ValidationError(schemacfg.eid, {role_name('options', 'subject'): msg})
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   195
                if not checkonly:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   196
                    self.dont_cross_relations.add(ertype)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   197
            elif not checkonly:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   198
                self.support_relations[ertype] = 'write' in options
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   199
                if 'maycross' in options:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   200
                    self.cross_relations.add(ertype)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   201
        if not checkonly:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   202
            # add to an index to ease deletion handling
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   203
            self._schemacfg_idx[schemacfg.eid] = ertype
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   204
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   205
    def del_schema_config(self, schemacfg, checkonly=False):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   206
        """deleted CWSourceSchemaConfig, modify mapping accordingly"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   207
        if checkonly:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   208
            return
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   209
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   210
            ertype = self._schemacfg_idx[schemacfg.eid]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   211
            if ertype[0].isupper():
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   212
                del self.support_entities[ertype]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   213
            else:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   214
                if ertype in self.support_relations:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   215
                    del self.support_relations[ertype]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   216
                    if ertype in self.cross_relations:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   217
                        self.cross_relations.remove(ertype)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   218
                else:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   219
                    self.dont_cross_relations.remove(ertype)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   220
        except Exception:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   221
            self.error('while updating mapping consequently to removal of %s',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   222
                       schemacfg)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   223
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   224
    def local_eid(self, cnx, extid, session):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   225
        etype, dexturi, dextid = cnx.describe(extid)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   226
        if dexturi == 'system' or not (
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   227
            dexturi in self.repo.sources_by_uri or self._skip_externals):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   228
            assert etype in self.support_entities, etype
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   229
            eid = self.repo.extid2eid(self, str(extid), etype, session)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   230
            if eid > 0:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   231
                return eid, True
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   232
        elif dexturi in self.repo.sources_by_uri:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   233
            source = self.repo.sources_by_uri[dexturi]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   234
            cnx = session.cnxset.connection(source.uri)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   235
            eid = source.local_eid(cnx, dextid, session)[0]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   236
            return eid, False
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   237
        return None, None
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   238
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   239
    def synchronize(self, mtime=None):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   240
        """synchronize content known by this repository with content in the
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   241
        external repository
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   242
        """
8675
b60329e40e26 [rql sources] uses an URL as remote host address for pyro/zmq rql sources,
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8674
diff changeset
   243
        self.info('synchronizing remote source %s', self.uri)
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   244
        cnx = self.get_connection()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   245
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   246
            extrepo = cnx._repo
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   247
        except AttributeError:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   248
            # fake connection wrapper returned when we can't connect to the
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   249
            # external source (hence we've no chance to synchronize...)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   250
            return
8696
0bb18407c053 [toward py3k] rewrite dict.keys() and dict.values() (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8695
diff changeset
   251
        etypes = list(self.support_entities)
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   252
        if mtime is None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   253
            mtime = self.latest_retrieval
8696
0bb18407c053 [toward py3k] rewrite dict.keys() and dict.values() (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8695
diff changeset
   254
        updatetime, modified, deleted = extrepo.entities_modified_since(etypes, mtime)
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   255
        self._query_cache.clear()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   256
        repo = self.repo
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   257
        session = repo.internal_session()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   258
        source = repo.system_source
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   259
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   260
            for etype, extid in modified:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   261
                try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   262
                    eid = self.local_eid(cnx, extid, session)[0]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   263
                    if eid is not None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   264
                        rset = session.eid_rset(eid, etype)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   265
                        entity = rset.get_entity(0, 0)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   266
                        entity.complete(entity.e_schema.indexable_attributes())
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   267
                        source.index_entity(session, entity)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   268
                except Exception:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   269
                    self.exception('while updating %s with external id %s of source %s',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   270
                                   etype, extid, self.uri)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   271
                    continue
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   272
            for etype, extid in deleted:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   273
                try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   274
                    eid = self.repo.extid2eid(self, str(extid), etype, session,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   275
                                              insert=False)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   276
                    # entity has been deleted from external repository but is not known here
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   277
                    if eid is not None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   278
                        entity = session.entity_from_eid(eid, etype)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   279
                        repo.delete_info(session, entity, self.uri,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   280
                                         scleanup=self.eid)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   281
                except Exception:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   282
                    if self.repo.config.mode == 'test':
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   283
                        raise
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   284
                    self.exception('while updating %s with external id %s of source %s',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   285
                                   etype, extid, self.uri)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   286
                    continue
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   287
            self.latest_retrieval = updatetime
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   288
            session.execute('SET X latest_retrieval %(date)s WHERE X eid %(x)s',
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   289
                            {'x': self.eid, 'date': self.latest_retrieval})
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   290
            session.commit()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   291
        finally:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   292
            session.close()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   293
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   294
    def get_connection(self):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   295
        raise NotImplementedError()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   296
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   297
    def check_connection(self, cnx):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   298
        """check connection validity, return None if the connection is still valid
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   299
        else a new connection
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   300
        """
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   301
        if not isinstance(cnx, ConnectionWrapper):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   302
            try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   303
                cnx.check()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   304
                return # ok
8545
eb7a171cec72 [repo pyro] fix previous commit: should not import Pyro in remoterql module/base class, it may be missing
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8536
diff changeset
   305
            except BadConnectionId:
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   306
                pass
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   307
        # try to reconnect
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   308
        return self.get_connection()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   309
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   310
    def syntax_tree_search(self, session, union, args=None, cachekey=None,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   311
                           varmap=None):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   312
        assert dbg_st_search(self.uri, union, varmap, args, cachekey)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   313
        rqlkey = union.as_string(kwargs=args)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   314
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   315
            results = self._query_cache[rqlkey]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   316
        except KeyError:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   317
            results = self._syntax_tree_search(session, union, args)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   318
            self._query_cache[rqlkey] = results
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   319
        assert dbg_results(results)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   320
        return results
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   321
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   322
    def _syntax_tree_search(self, session, union, args):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   323
        """return result from this source for a rql query (actually from a rql
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   324
        syntax tree and a solution dictionary mapping each used variable to a
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   325
        possible type). If cachekey is given, the query necessary to fetch the
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   326
        results (but not the results themselves) may be cached using this key.
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   327
        """
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   328
        if not args is None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   329
            args = args.copy()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   330
        # get cached cursor anyway
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   331
        cu = session.cnxset[self.uri]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   332
        if cu is None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   333
            # this is a ConnectionWrapper instance
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   334
            msg = session._("can't connect to source %s, some data may be missing")
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   335
            session.set_shared_data('sources_error', msg % self.uri, txdata=True)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   336
            return []
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   337
        translator = RQL2RQL(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   338
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   339
            rql = translator.generate(session, union, args)
8695
358d8bed9626 [toward-py3k] rewrite to "except AnException as exc:" (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8675
diff changeset
   340
        except UnknownEid as ex:
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   341
            if server.DEBUG:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   342
                print '  unknown eid', ex, 'no results'
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   343
            return []
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   344
        if server.DEBUG & server.DBG_RQL:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   345
            print '  translated rql', rql
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   346
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   347
            rset = cu.execute(rql, args)
8695
358d8bed9626 [toward-py3k] rewrite to "except AnException as exc:" (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8675
diff changeset
   348
        except Exception as ex:
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   349
            self.exception(str(ex))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   350
            msg = session._("error while querying source %s, some data may be missing")
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   351
            session.set_shared_data('sources_error', msg % self.uri, txdata=True)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   352
            return []
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   353
        descr = rset.description
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   354
        if rset:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   355
            needtranslation = []
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   356
            rows = rset.rows
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   357
            for i, etype in enumerate(descr[0]):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   358
                if (etype is None or not self.schema.eschema(etype).final
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   359
                    or uidtype(union, i, etype, args)):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   360
                    needtranslation.append(i)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   361
            if needtranslation:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   362
                cnx = session.cnxset.connection(self.uri)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   363
                for rowindex in xrange(rset.rowcount - 1, -1, -1):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   364
                    row = rows[rowindex]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   365
                    localrow = False
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   366
                    for colindex in needtranslation:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   367
                        if row[colindex] is not None: # optional variable
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   368
                            eid, local = self.local_eid(cnx, row[colindex], session)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   369
                            if local:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   370
                                localrow = True
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   371
                            if eid is not None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   372
                                row[colindex] = eid
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   373
                            else:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   374
                                # skip this row
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   375
                                del rows[rowindex]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   376
                                del descr[rowindex]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   377
                                break
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   378
                    else:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   379
                        # skip row if it only contains eids of entities which
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   380
                        # are actually from a source we also know locally,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   381
                        # except if some args specified (XXX should actually
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   382
                        # check if there are some args local to the source)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   383
                        if not (translator.has_local_eid or localrow):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   384
                            del rows[rowindex]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   385
                            del descr[rowindex]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   386
            results = rows
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   387
        else:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   388
            results = []
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   389
        return results
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   390
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   391
    def _entity_relations_and_kwargs(self, session, entity):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   392
        relations = []
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   393
        kwargs = {'x': self.repo.eid2extid(self, entity.eid, session)}
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   394
        for key, val in entity.cw_attr_cache.iteritems():
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   395
            relations.append('X %s %%(%s)s' % (key, key))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   396
            kwargs[key] = val
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   397
        return relations, kwargs
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   398
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   399
    def add_entity(self, session, entity):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   400
        """add a new entity to the source"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   401
        raise NotImplementedError()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   402
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   403
    def update_entity(self, session, entity):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   404
        """update an entity in the source"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   405
        relations, kwargs = self._entity_relations_and_kwargs(session, entity)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   406
        cu = session.cnxset[self.uri]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   407
        cu.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations), kwargs)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   408
        self._query_cache.clear()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   409
        entity.cw_clear_all_caches()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   410
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   411
    def delete_entity(self, session, entity):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   412
        """delete an entity from the source"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   413
        if session.deleted_in_transaction(self.eid):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   414
            # source is being deleted, don't propagate
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   415
            self._query_cache.clear()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   416
            return
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   417
        cu = session.cnxset[self.uri]
8900
010a59e12d89 use cw_etype instead of __regid__
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 8707
diff changeset
   418
        cu.execute('DELETE %s X WHERE X eid %%(x)s' % entity.cw_etype,
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   419
                   {'x': self.repo.eid2extid(self, entity.eid, session)})
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   420
        self._query_cache.clear()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   421
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   422
    def add_relation(self, session, subject, rtype, object):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   423
        """add a relation to the source"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   424
        cu = session.cnxset[self.uri]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   425
        cu.execute('SET X %s Y WHERE X eid %%(x)s, Y eid %%(y)s' % rtype,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   426
                   {'x': self.repo.eid2extid(self, subject, session),
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   427
                    'y': self.repo.eid2extid(self, object, session)})
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   428
        self._query_cache.clear()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   429
        session.entity_from_eid(subject).cw_clear_all_caches()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   430
        session.entity_from_eid(object).cw_clear_all_caches()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   431
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   432
    def delete_relation(self, session, subject, rtype, object):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   433
        """delete a relation from the source"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   434
        if session.deleted_in_transaction(self.eid):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   435
            # source is being deleted, don't propagate
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   436
            self._query_cache.clear()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   437
            return
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   438
        cu = session.cnxset[self.uri]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   439
        cu.execute('DELETE X %s Y WHERE X eid %%(x)s, Y eid %%(y)s' % rtype,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   440
                   {'x': self.repo.eid2extid(self, subject, session),
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   441
                    'y': self.repo.eid2extid(self, object, session)})
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   442
        self._query_cache.clear()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   443
        session.entity_from_eid(subject).cw_clear_all_caches()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   444
        session.entity_from_eid(object).cw_clear_all_caches()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   445
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   446
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   447
class RQL2RQL(object):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   448
    """translate a local rql query to be executed on a distant repository"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   449
    def __init__(self, source):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   450
        self.source = source
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   451
        self.repo = source.repo
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   452
        self.current_operator = None
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   453
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   454
    def _accept_children(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   455
        res = []
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   456
        for child in node.children:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   457
            rql = child.accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   458
            if rql is not None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   459
                res.append(rql)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   460
        return res
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   461
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   462
    def generate(self, session, rqlst, args):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   463
        self._session = session
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   464
        self.kwargs = args
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   465
        self.need_translation = False
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   466
        self.has_local_eid = False
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   467
        return self.visit_union(rqlst)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   468
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   469
    def visit_union(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   470
        s = self._accept_children(node)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   471
        if len(s) > 1:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   472
            return ' UNION '.join('(%s)' % q for q in s)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   473
        return s[0]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   474
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   475
    def visit_select(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   476
        """return the tree as an encoded rql string"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   477
        self._varmaker = rqlvar_maker(defined=node.defined_vars.copy())
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   478
        self._const_var = {}
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   479
        if node.distinct:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   480
            base = 'DISTINCT Any'
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   481
        else:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   482
            base = 'Any'
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   483
        s = ['%s %s' % (base, ','.join(v.accept(self) for v in node.selection))]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   484
        if node.groupby:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   485
            s.append('GROUPBY %s' % ', '.join(group.accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   486
                                              for group in node.groupby))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   487
        if node.orderby:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   488
            s.append('ORDERBY %s' % ', '.join(self.visit_sortterm(term)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   489
                                              for term in node.orderby))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   490
        if node.limit is not None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   491
            s.append('LIMIT %s' % node.limit)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   492
        if node.offset:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   493
            s.append('OFFSET %s' % node.offset)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   494
        restrictions = []
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   495
        if node.where is not None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   496
            nr = node.where.accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   497
            if nr is not None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   498
                restrictions.append(nr)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   499
        if restrictions:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   500
            s.append('WHERE %s' % ','.join(restrictions))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   501
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   502
        if node.having:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   503
            s.append('HAVING %s' % ', '.join(term.accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   504
                                             for term in node.having))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   505
        subqueries = []
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   506
        for subquery in node.with_:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   507
            subqueries.append('%s BEING (%s)' % (','.join(ca.name for ca in subquery.aliases),
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   508
                                                 self.visit_union(subquery.query)))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   509
        if subqueries:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   510
            s.append('WITH %s' % (','.join(subqueries)))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   511
        return ' '.join(s)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   512
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   513
    def visit_and(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   514
        res = self._accept_children(node)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   515
        if res:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   516
            return ', '.join(res)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   517
        return
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   518
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   519
    def visit_or(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   520
        res = self._accept_children(node)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   521
        if len(res) > 1:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   522
            return ' OR '.join('(%s)' % rql for rql in res)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   523
        elif res:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   524
            return res[0]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   525
        return
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   526
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   527
    def visit_not(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   528
        rql = node.children[0].accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   529
        if rql:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   530
            return 'NOT (%s)' % rql
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   531
        return
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   532
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   533
    def visit_exists(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   534
        rql = node.children[0].accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   535
        if rql:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   536
            return 'EXISTS(%s)' % rql
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   537
        return
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   538
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   539
    def visit_relation(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   540
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   541
            if isinstance(node.children[0], Constant):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   542
                # simplified rqlst, reintroduce eid relation
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   543
                try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   544
                    restr, lhs = self.process_eid_const(node.children[0])
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   545
                except UnknownEid:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   546
                    # can safely skip not relation with an unsupported eid
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   547
                    if neged_relation(node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   548
                        return
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   549
                    raise
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   550
            else:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   551
                lhs = node.children[0].accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   552
                restr = None
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   553
        except UnknownEid:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   554
            # can safely skip not relation with an unsupported eid
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   555
            if neged_relation(node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   556
                return
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   557
            # XXX what about optional relation or outer NOT EXISTS()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   558
            raise
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   559
        if node.optional in ('left', 'both'):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   560
            lhs += '?'
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   561
        if node.r_type == 'eid' or not self.source.schema.rschema(node.r_type).final:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   562
            self.need_translation = True
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   563
            self.current_operator = node.operator()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   564
            if isinstance(node.children[0], Constant):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   565
                self.current_etypes = (node.children[0].uidtype,)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   566
            else:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   567
                self.current_etypes = node.children[0].variable.stinfo['possibletypes']
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   568
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   569
            rhs = node.children[1].accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   570
        except UnknownEid:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   571
            # can safely skip not relation with an unsupported eid
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   572
            if neged_relation(node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   573
                return
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   574
            # XXX what about optional relation or outer NOT EXISTS()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   575
            raise
8695
358d8bed9626 [toward-py3k] rewrite to "except AnException as exc:" (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8675
diff changeset
   576
        except ReplaceByInOperator as ex:
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   577
            rhs = 'IN (%s)' % ','.join(eid for eid in ex.eids)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   578
        self.need_translation = False
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   579
        self.current_operator = None
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   580
        if node.optional in ('right', 'both'):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   581
            rhs += '?'
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   582
        if restr is not None:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   583
            return '%s %s %s, %s' % (lhs, node.r_type, rhs, restr)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   584
        return '%s %s %s' % (lhs, node.r_type, rhs)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   585
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   586
    def visit_comparison(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   587
        if node.operator in ('=', 'IS'):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   588
            return node.children[0].accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   589
        return '%s %s' % (node.operator.encode(),
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   590
                          node.children[0].accept(self))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   591
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   592
    def visit_mathexpression(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   593
        return '(%s %s %s)' % (node.children[0].accept(self),
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   594
                               node.operator.encode(),
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   595
                               node.children[1].accept(self))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   596
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   597
    def visit_function(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   598
        #if node.name == 'IN':
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   599
        res = []
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   600
        for child in node.children:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   601
            try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   602
                rql = child.accept(self)
8695
358d8bed9626 [toward-py3k] rewrite to "except AnException as exc:" (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8675
diff changeset
   603
            except UnknownEid as ex:
8354
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   604
                continue
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   605
            res.append(rql)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   606
        if not res:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   607
            raise ex
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   608
        return '%s(%s)' % (node.name, ', '.join(res))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   609
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   610
    def visit_constant(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   611
        if self.need_translation or node.uidtype:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   612
            if node.type == 'Int':
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   613
                self.has_local_eid = True
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   614
                return str(self.eid2extid(node.value))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   615
            if node.type == 'Substitute':
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   616
                key = node.value
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   617
                # ensure we have not yet translated the value...
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   618
                if not key in self._const_var:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   619
                    self.kwargs[key] = self.eid2extid(self.kwargs[key])
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   620
                    self._const_var[key] = None
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   621
                    self.has_local_eid = True
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   622
        return node.as_string()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   623
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   624
    def visit_variableref(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   625
        """get the sql name for a variable reference"""
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   626
        return node.name
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   627
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   628
    def visit_sortterm(self, node):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   629
        if node.asc:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   630
            return node.term.accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   631
        return '%s DESC' % node.term.accept(self)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   632
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   633
    def process_eid_const(self, const):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   634
        value = const.eval(self.kwargs)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   635
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   636
            return None, self._const_var[value]
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   637
        except Exception:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   638
            var = self._varmaker.next()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   639
            self.need_translation = True
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   640
            restr = '%s eid %s' % (var, self.visit_constant(const))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   641
            self.need_translation = False
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   642
            self._const_var[value] = var
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   643
            return restr, var
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   644
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   645
    def eid2extid(self, eid):
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   646
        try:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   647
            return self.repo.eid2extid(self.source, eid, self._session)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   648
        except UnknownEid:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   649
            operator = self.current_operator
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   650
            if operator is not None and operator != '=':
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   651
                # deal with query like "X eid > 12"
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   652
                #
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   653
                # The problem is that eid order in the external source may
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   654
                # differ from the local source
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   655
                #
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   656
                # So search for all eids from this source matching the condition
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   657
                # locally and then to replace the "> 12" branch by "IN (eids)"
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   658
                #
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   659
                # XXX we may have to insert a huge number of eids...)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   660
                sql = "SELECT extid FROM entities WHERE source='%s' AND type IN (%s) AND eid%s%s"
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   661
                etypes = ','.join("'%s'" % etype for etype in self.current_etypes)
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   662
                cu = self._session.system_sql(sql % (self.source.uri, etypes,
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   663
                                                      operator, eid))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   664
                # XXX buggy cu.rowcount which may be zero while there are some
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   665
                # results
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   666
                rows = cu.fetchall()
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   667
                if rows:
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   668
                    raise ReplaceByInOperator((b64decode(r[0]) for r in rows))
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   669
            raise
a9984ceebc26 [pyro] Refactor the pyrorql source
Vincent Michel and Alain Leufroy
parents:
diff changeset
   670