server/sources/remoterql.py
author Aurelien Campeas <aurelien.campeas@logilab.fr>
Wed, 08 Jan 2014 14:00:31 +0100
changeset 9377 4e0d8f06efbc
parent 8900 010a59e12d89
permissions -rw-r--r--
[js/widgets] fix the InOut widget with modern jQuery versions Several things are done there: * reduction in size and complexity of the code * the unused defaultsettings are removed * the initial `unlinked` list is now correctly populated from python-side * the unit test is adjusted because it tested an irrelevant implementation detail which is no longer true (but the widget of course still handles correctly the linkto information) Tested with ie7, ie9, chromium, firefox. Tested with jQuery 1.6 (cw 3.17.x) and 1.10. Closes #3154531.
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