spa2rql.py
author Sylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 19 Oct 2009 17:36:37 +0200
changeset 3727 74bd06656bcc
parent 2435 85be7a811afe
child 4212 ab6573088b4a
permissions -rw-r--r--
typo
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     1
"""SPARQL -> RQL translator
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     2
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     3
:organization: Logilab
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     4
:copyright: 2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     5
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     6
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     7
"""
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     8
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
     9
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
    10
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
    11
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
    12
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    13
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
    14
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    15
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    16
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
    17
2431
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    18
def order_limit_offset(sparqlst):
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    19
    addons = ''
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    20
    if sparqlst.orderby:
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    21
        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
    22
                              for var, ascdesc in sparqlst.orderby)
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    23
        addons += ' ORDERBY %s' % sortterms
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    24
    if sparqlst.limit:
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    25
        addons += ' LIMIT %s' % sparqlst.limit
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    26
    if sparqlst.offset:
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    27
        addons += ' OFFSET %s' % sparqlst.offset
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    28
    return addons
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    29
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    30
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    31
class QueryInfo(object):
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    32
    """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
    33
    from a sparql syntax tree
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    34
    """
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    35
    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
    36
        self.sparqlst = sparqlst
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    37
        if sparqlst.selected == ['*']:
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    38
            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
    39
        else:
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    40
            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
    41
        self.possible_types = {}
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    42
        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
    43
        self.union_params = []
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    44
        self.restrictions = []
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    45
        self.literals = {}
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    46
        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
    47
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    48
    def add_literal(self, value):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    49
        key = chr(ord('a') + self._litcount)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    50
        self._litcount += 1
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    51
        self.literals[key] = value
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    52
        return key
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    53
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    54
    def set_possible_types(self, var, varpossibletypes):
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    55
        """set/restrict possible types for the given variable.
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    56
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    57
        :return: True if something changed, else false.
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    58
        :raise: TypeResolverException if no more type allowed
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    59
        """
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    60
        varpossibletypes = set(varpossibletypes)
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    61
        try:
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    62
            ctypes = self.possible_types[var]
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    63
            nbctypes = len(ctypes)
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    64
            ctypes &= varpossibletypes
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    65
            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
    66
                raise TypeResolverException()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    67
            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
    68
        except KeyError:
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    69
            self.possible_types[var] = varpossibletypes
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    70
            return True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    71
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    72
    def infer_types(self):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    73
        # 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
    74
        modified = True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    75
        # loop to infer types until nothing changed
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    76
        while modified:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    77
            modified = False
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    78
            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
    79
                nbchoices = len(yams_predicates)
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    80
                # 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
    81
                # current predicate
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    82
                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
    83
                if not '*' in svptypes:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    84
                    if self.set_possible_types(subjvar, svptypes):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    85
                        modified = True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    86
                # restrict predicates according to allowed subject var types
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    87
                if subjvar in self.possible_types:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    88
                    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
    89
                                       if s == '*' or s in self.possible_types[subjvar]]
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    90
                if isinstance(obj, ast.SparqlVar):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    91
                    # make a valid rql var name
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    92
                    objvar = obj.name.upper()
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    93
                    # get possible types for the object variable, according to
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    94
                    # the current predicate
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    95
                    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
    96
                    if not '*' in ovptypes:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    97
                        if self.set_possible_types(objvar, ovptypes):
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 object var types
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   100
                    if objvar 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 o == '*' or o in self.possible_types[objvar]]
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   103
                # ensure this still make sense
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   104
                if not yams_predicates:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   105
                    raise TypeResolverException()
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   106
                if len(yams_predicates) != nbchoices:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   107
                    modified = True
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   108
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   109
    def build_restrictions(self):
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   110
        # now, for each predicate
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   111
        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
   112
            rel = yams_predicates[0]
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   113
            # 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
   114
            # to generate several unioned rql queries
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   115
            for s, r, o in yams_predicates[1:]:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   116
                if r != rel[1]:
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   117
                    self.union_params.append((yams_predicates, subjvar, obj))
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   118
                    break
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   119
            # 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
   120
            else:
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   121
                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
   122
                self.restrictions.append(restr)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   123
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   124
    def build_restriction(self, subjvar, rtype, obj):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   125
        if isinstance(obj, ast.SparqlLiteral):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   126
            key = self.add_literal(obj.value)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   127
            objvar = '%%(%s)s' % key
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   128
        else:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   129
            assert isinstance(obj, ast.SparqlVar)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   130
            # make a valid rql var name
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   131
            objvar = obj.name.upper()
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
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   133
        return '%s %s %s' % (subjvar, rtype, objvar)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   134
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   135
    def finalize(self):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   136
        """return corresponding rql query (string) / args (dict)"""
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   137
        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
   138
            if len(ptypes) == 1:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   139
                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
   140
        unions = []
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   141
        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
   142
            thisunions = []
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   143
            for st, rt, ot in releq:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   144
                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
   145
                if st != '*':
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   146
                    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
   147
                if isinstance(obj, ast.SparqlVar) and ot != '*':
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   148
                    objvar = obj.name.upper()
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   149
                    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
   150
            if not unions:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   151
                unions = thisunions
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   152
            else:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   153
                unions = zip(*make_domains([unions, thisunions]))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   154
        selection = 'Any ' + ', '.join(self.selection)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   155
        sparqlst = self.sparqlst
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   156
        if sparqlst.distinct:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   157
            selection = 'DISTINCT ' + selection
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   158
        if unions:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   159
            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
   160
            rqls = ['(%s, %s)' % (baserql, ', '.join(unionrestrs))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   161
                    for unionrestrs in unions]
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   162
            rql = ' UNION '.join(rqls)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   163
            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
   164
                rql = '%s%s WITH %s BEING (%s)' % (
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   165
                    selection, order_limit_offset(sparqlst),
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   166
                    ', '.join(self.selection), rql)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   167
        else:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   168
            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
   169
                                      ', '.join(self.restrictions))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   170
        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
   171
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   172
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   173
class Sparql2rqlTranslator(object):
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   174
    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
   175
        self.yschema = yschema
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   176
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   177
    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
   178
        sparqlst = parse(sparql)
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   179
        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
   180
            raise UnsupportedQuery()
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   181
        qi = QueryInfo(sparqlst)
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   182
        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
   183
            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
   184
                raise UnsupportedQuery()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   185
            # 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
   186
            subjvar = subj.name.upper()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   187
            if predicate == ('', 'a'):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   188
                # 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
   189
                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
   190
                    raise UnsupportedQuery()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   191
                # 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
   192
                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
   193
                    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
   194
            else:
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   195
                # '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
   196
                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
   197
                    raise UnsupportedQuery()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   198
                # list of 3-uple
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   199
                #   (yams etype (subject), yams rtype, yams etype (object))
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   200
                # where subject / object entity type may '*' if not specified
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   201
                yams_predicates = xy.yeq(':'.join(predicate))
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   202
                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
   203
                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
   204
                    raise UnsupportedQuery()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   205
        qi.infer_types()
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   206
        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
   207
        return qi