spa2rql.py
author Alexandre Fayolle <alexandre.fayolle@logilab.fr>
Sat, 29 May 2010 09:52:31 +0000
branchstable
changeset 5600 a826996875e7
parent 5424 8ecbcbff9777
child 5613 bc0ebfbf5c5d
permissions -rw-r--r--
[win32 service] activate logging to the configured file as soon as possible since we don't always have access to the system events of the computer running CW it is important to get as much information as possible in the log file, especially startup failure messages.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
     1
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
     2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
     3
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
     4
# This file is part of CubicWeb.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
     5
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
     6
# CubicWeb is free software: you can redistribute it and/or modify it under the
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
     7
# terms of the GNU Lesser General Public License as published by the Free
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
     8
# Software Foundation, either version 2.1 of the License, or (at your option)
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
     9
# any later version.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
    10
#
5424
8ecbcbff9777 replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5421
diff changeset
    11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
    12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
    13
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
    14
# details.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
    15
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
    16
# You should have received a copy of the GNU Lesser General Public License along
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4212
diff changeset
    17
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    18
"""SPARQL -> RQL translator
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    19
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    20
"""
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    21
from logilab.common import make_domains
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    22
from rql import TypeResolverException
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    23
from fyzz.yappsparser import parse
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    24
from fyzz import ast
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    25
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    26
from cubicweb.xy import xy
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    27
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    28
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    29
class UnsupportedQuery(Exception): pass
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    30
2431
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    31
def order_limit_offset(sparqlst):
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    32
    addons = ''
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    33
    if sparqlst.orderby:
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    34
        sortterms = ', '.join('%s %s' % (var.name.upper(), ascdesc.upper())
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    35
                              for var, ascdesc in sparqlst.orderby)
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    36
        addons += ' ORDERBY %s' % sortterms
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    37
    if sparqlst.limit:
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    38
        addons += ' LIMIT %s' % sparqlst.limit
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    39
    if sparqlst.offset:
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    40
        addons += ' OFFSET %s' % sparqlst.offset
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    41
    return addons
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    42
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    43
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    44
class QueryInfo(object):
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    45
    """wrapper class containing necessary information to generate a RQL query
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    46
    from a sparql syntax tree
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    47
    """
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    48
    def __init__(self, sparqlst):
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    49
        self.sparqlst = sparqlst
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    50
        if sparqlst.selected == ['*']:
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    51
            self.selection = [var.upper() for var in sparqlst.variables]
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    52
        else:
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    53
            self.selection = [var.name.upper() for var in sparqlst.selected]
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    54
        self.possible_types = {}
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    55
        self.infer_types_info = []
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    56
        self.union_params = []
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    57
        self.restrictions = []
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    58
        self.literals = {}
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    59
        self._litcount = 0
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    60
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    61
    def add_literal(self, value):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    62
        key = chr(ord('a') + self._litcount)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    63
        self._litcount += 1
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    64
        self.literals[key] = value
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    65
        return key
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    66
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    67
    def set_possible_types(self, var, varpossibletypes):
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    68
        """set/restrict possible types for the given variable.
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    69
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    70
        :return: True if something changed, else false.
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    71
        :raise: TypeResolverException if no more type allowed
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    72
        """
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    73
        varpossibletypes = set(varpossibletypes)
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    74
        try:
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    75
            ctypes = self.possible_types[var]
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    76
            nbctypes = len(ctypes)
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    77
            ctypes &= varpossibletypes
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    78
            if not ctypes:
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    79
                raise TypeResolverException()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    80
            return len(ctypes) != nbctypes
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    81
        except KeyError:
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    82
            self.possible_types[var] = varpossibletypes
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    83
            return True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    84
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    85
    def infer_types(self):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    86
        # XXX should use something similar to rql.analyze for proper type inference
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    87
        modified = True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    88
        # loop to infer types until nothing changed
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    89
        while modified:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    90
            modified = False
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    91
            for yams_predicates, subjvar, obj in self.infer_types_info:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    92
                nbchoices = len(yams_predicates)
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    93
                # get possible types for the subject variable, according to the
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    94
                # current predicate
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    95
                svptypes = set(s for s, r, o in yams_predicates)
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    96
                if not '*' in svptypes:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    97
                    if self.set_possible_types(subjvar, svptypes):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    98
                        modified = True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    99
                # restrict predicates according to allowed subject var types
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   100
                if subjvar in self.possible_types:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   101
                    yams_predicates = [(s, r, o) for s, r, o in yams_predicates
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   102
                                       if s == '*' or s in self.possible_types[subjvar]]
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   103
                if isinstance(obj, ast.SparqlVar):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   104
                    # make a valid rql var name
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   105
                    objvar = obj.name.upper()
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   106
                    # get possible types for the object variable, according to
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   107
                    # the current predicate
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   108
                    ovptypes = set(o for s, r, o in yams_predicates)
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   109
                    if not '*' in ovptypes:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   110
                        if self.set_possible_types(objvar, ovptypes):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   111
                            modified = True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   112
                    # restrict predicates according to allowed object var types
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   113
                    if objvar in self.possible_types:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   114
                        yams_predicates = [(s, r, o) for s, r, o in yams_predicates
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   115
                                           if o == '*' or o in self.possible_types[objvar]]
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   116
                # ensure this still make sense
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   117
                if not yams_predicates:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   118
                    raise TypeResolverException()
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   119
                if len(yams_predicates) != nbchoices:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   120
                    modified = True
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   121
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   122
    def build_restrictions(self):
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   123
        # now, for each predicate
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   124
        for yams_predicates, subjvar, obj in self.infer_types_info:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   125
            rel = yams_predicates[0]
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   126
            # if there are several yams relation type equivalences, we will have
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   127
            # to generate several unioned rql queries
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   128
            for s, r, o in yams_predicates[1:]:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   129
                if r != rel[1]:
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   130
                    self.union_params.append((yams_predicates, subjvar, obj))
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   131
                    break
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   132
            # else we can simply add it to base rql restrictions
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   133
            else:
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   134
                restr = self.build_restriction(subjvar, rel[1], obj)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   135
                self.restrictions.append(restr)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   136
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   137
    def build_restriction(self, subjvar, rtype, obj):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   138
        if isinstance(obj, ast.SparqlLiteral):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   139
            key = self.add_literal(obj.value)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   140
            objvar = '%%(%s)s' % key
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   141
        else:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   142
            assert isinstance(obj, ast.SparqlVar)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   143
            # make a valid rql var name
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   144
            objvar = obj.name.upper()
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   145
        # else we can simply add it to base rql restrictions
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   146
        return '%s %s %s' % (subjvar, rtype, objvar)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   147
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   148
    def finalize(self):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   149
        """return corresponding rql query (string) / args (dict)"""
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   150
        for varname, ptypes in self.possible_types.iteritems():
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   151
            if len(ptypes) == 1:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   152
                self.restrictions.append('%s is %s' % (varname, iter(ptypes).next()))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   153
        unions = []
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   154
        for releq, subjvar, obj in self.union_params:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   155
            thisunions = []
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   156
            for st, rt, ot in releq:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   157
                thisunions.append([self.build_restriction(subjvar, rt, obj)])
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   158
                if st != '*':
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   159
                    thisunions[-1].append('%s is %s' % (subjvar, st))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   160
                if isinstance(obj, ast.SparqlVar) and ot != '*':
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   161
                    objvar = obj.name.upper()
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   162
                    thisunions[-1].append('%s is %s' % (objvar, objvar))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   163
            if not unions:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   164
                unions = thisunions
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   165
            else:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   166
                unions = zip(*make_domains([unions, thisunions]))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   167
        selection = 'Any ' + ', '.join(self.selection)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   168
        sparqlst = self.sparqlst
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   169
        if sparqlst.distinct:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   170
            selection = 'DISTINCT ' + selection
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   171
        if unions:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   172
            baserql = '%s WHERE %s' % (selection, ', '.join(self.restrictions))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   173
            rqls = ['(%s, %s)' % (baserql, ', '.join(unionrestrs))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   174
                    for unionrestrs in unions]
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   175
            rql = ' UNION '.join(rqls)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   176
            if sparqlst.orderby or sparqlst.limit or sparqlst.offset:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   177
                rql = '%s%s WITH %s BEING (%s)' % (
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   178
                    selection, order_limit_offset(sparqlst),
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   179
                    ', '.join(self.selection), rql)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   180
        else:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   181
            rql = '%s%s WHERE %s' % (selection, order_limit_offset(sparqlst),
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   182
                                      ', '.join(self.restrictions))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   183
        return rql, self.literals
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   184
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   185
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   186
class Sparql2rqlTranslator(object):
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   187
    def __init__(self, yschema):
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   188
        self.yschema = yschema
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   189
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   190
    def translate(self, sparql):
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   191
        sparqlst = parse(sparql)
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   192
        if sparqlst.type != 'select':
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   193
            raise UnsupportedQuery()
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   194
        qi = QueryInfo(sparqlst)
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   195
        for subj, predicate, obj in sparqlst.where:
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   196
            if not isinstance(subj, ast.SparqlVar):
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   197
                raise UnsupportedQuery()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   198
            # make a valid rql var name
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   199
            subjvar = subj.name.upper()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   200
            if predicate == ('', 'a'):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   201
                # special 'is' relation
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   202
                if not isinstance(obj, tuple):
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   203
                    raise UnsupportedQuery()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   204
                # restrict possible types for the subject variable
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   205
                qi.set_possible_types(
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   206
                    subjvar, xy.yeq(':'.join(obj), isentity=True))
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   207
            else:
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   208
                # 'regular' relation (eg not 'is')
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   209
                if not isinstance(predicate, tuple):
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   210
                    raise UnsupportedQuery()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   211
                # list of 3-uple
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   212
                #   (yams etype (subject), yams rtype, yams etype (object))
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   213
                # where subject / object entity type may '*' if not specified
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   214
                yams_predicates = xy.yeq(':'.join(predicate))
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   215
                qi.infer_types_info.append((yams_predicates, subjvar, obj))
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   216
                if not isinstance(obj, (ast.SparqlLiteral, ast.SparqlVar)):
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   217
                    raise UnsupportedQuery()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   218
        qi.infer_types()
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   219
        qi.build_restrictions()
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   220
        return qi