spa2rql.py
author Julien Cristau <julien.cristau@logilab.fr>
Mon, 28 Apr 2014 11:20:26 +0200
changeset 9708 b36bc18f6ef7
parent 5621 6f32f08d91f3
child 10662 10942ed172de
permissions -rw-r--r--
[migration] move 'entities' table changes from 3.19.0 to bootstrap script The 'mtime' and 'source' columns need to go away before we attempt to do anything else with the repo, otherwise any addition of an entity is going to explode.
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/>.
5613
bc0ebfbf5c5d [sparql] fix type inference (test_dctitle_both_project_cwuser) and support for <http://www.w3.org/1999/02/22-rdf-syntax-ns#type tag (test_base_rdftype)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
    18
"""SPARQL -> RQL translator"""
2422
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
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
    21
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
    22
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
    23
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
    24
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    25
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
    26
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
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
    29
2431
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    30
def order_limit_offset(sparqlst):
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    31
    addons = ''
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    32
    if sparqlst.orderby:
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    33
        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
    34
                              for var, ascdesc in sparqlst.orderby)
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    35
        addons += ' ORDERBY %s' % sortterms
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    36
    if sparqlst.limit:
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    37
        addons += ' LIMIT %s' % sparqlst.limit
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    38
    if sparqlst.offset:
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    39
        addons += ' OFFSET %s' % sparqlst.offset
93c061eac647 sparql support for limit/offset/orderby
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2430
diff changeset
    40
    return addons
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    41
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    42
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    43
class QueryInfo(object):
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    44
    """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
    45
    from a sparql syntax tree
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    46
    """
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    47
    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
    48
        self.sparqlst = sparqlst
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    49
        if sparqlst.selected == ['*']:
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    50
            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
    51
        else:
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    52
            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
    53
        self.possible_types = {}
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    54
        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
    55
        self.union_params = []
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    56
        self.restrictions = []
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    57
        self.literals = {}
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    58
        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
    59
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    60
    def add_literal(self, value):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    61
        key = chr(ord('a') + self._litcount)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    62
        self._litcount += 1
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    63
        self.literals[key] = value
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
    64
        return key
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    65
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    66
    def set_possible_types(self, var, varpossibletypes):
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    67
        """set/restrict possible types for the given variable.
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    68
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    69
        :return: True if something changed, else false.
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    70
        :raise: TypeResolverException if no more type allowed
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    71
        """
2422
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    72
        varpossibletypes = set(varpossibletypes)
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    73
        try:
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    74
            ctypes = self.possible_types[var]
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    75
            nbctypes = len(ctypes)
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    76
            ctypes &= varpossibletypes
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    77
            if not ctypes:
5621
6f32f08d91f3 [sparql] improve error reporting and fix one bug
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 5613
diff changeset
    78
                raise TypeResolverException('No possible type')
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    79
            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
    80
        except KeyError:
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    81
            self.possible_types[var] = varpossibletypes
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    82
            return True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    83
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    84
    def infer_types(self):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    85
        # 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
    86
        modified = True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    87
        # loop to infer types until nothing changed
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    88
        while modified:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    89
            modified = False
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    90
            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
    91
                nbchoices = len(yams_predicates)
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    92
                # 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
    93
                # current predicate
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    94
                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
    95
                if not '*' in svptypes:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    96
                    if self.set_possible_types(subjvar, svptypes):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    97
                        modified = True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    98
                # restrict predicates according to allowed subject var types
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
    99
                if subjvar in self.possible_types:
5613
bc0ebfbf5c5d [sparql] fix type inference (test_dctitle_both_project_cwuser) and support for <http://www.w3.org/1999/02/22-rdf-syntax-ns#type tag (test_base_rdftype)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   100
                    yams_predicates[:] = [(s, r, o) for s, r, o in yams_predicates
bc0ebfbf5c5d [sparql] fix type inference (test_dctitle_both_project_cwuser) and support for <http://www.w3.org/1999/02/22-rdf-syntax-ns#type tag (test_base_rdftype)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   101
                                          if s == '*' or s in self.possible_types[subjvar]]
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   102
                if isinstance(obj, ast.SparqlVar):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   103
                    # make a valid rql var name
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   104
                    objvar = obj.name.upper()
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   105
                    # get possible types for the object variable, according to
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   106
                    # the current predicate
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   107
                    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
   108
                    if not '*' in ovptypes:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   109
                        if self.set_possible_types(objvar, ovptypes):
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   110
                            modified = True
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   111
                    # restrict predicates according to allowed object var types
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   112
                    if objvar in self.possible_types:
5613
bc0ebfbf5c5d [sparql] fix type inference (test_dctitle_both_project_cwuser) and support for <http://www.w3.org/1999/02/22-rdf-syntax-ns#type tag (test_base_rdftype)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   113
                        yams_predicates[:] = [(s, r, o) for s, r, o in yams_predicates
bc0ebfbf5c5d [sparql] fix type inference (test_dctitle_both_project_cwuser) and support for <http://www.w3.org/1999/02/22-rdf-syntax-ns#type tag (test_base_rdftype)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   114
                                              if o == '*' or o in self.possible_types[objvar]]
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   115
                # ensure this still make sense
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   116
                if not yams_predicates:
5621
6f32f08d91f3 [sparql] improve error reporting and fix one bug
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 5613
diff changeset
   117
                    raise TypeResolverException('No yams predicate')
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   118
                if len(yams_predicates) != nbchoices:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   119
                    modified = True
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   120
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   121
    def build_restrictions(self):
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   122
        # now, for each predicate
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   123
        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
   124
            rel = yams_predicates[0]
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   125
            # 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
   126
            # to generate several unioned rql queries
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   127
            for s, r, o in yams_predicates[1:]:
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   128
                if r != rel[1]:
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   129
                    self.union_params.append((yams_predicates, subjvar, obj))
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   130
                    break
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   131
            # 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
   132
            else:
2435
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   133
                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
   134
                self.restrictions.append(restr)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   135
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   136
    def build_restriction(self, subjvar, rtype, obj):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   137
        if isinstance(obj, ast.SparqlLiteral):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   138
            key = self.add_literal(obj.value)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   139
            objvar = '%%(%s)s' % key
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   140
        else:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   141
            assert isinstance(obj, ast.SparqlVar)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   142
            # make a valid rql var name
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   143
            objvar = obj.name.upper()
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   144
        # 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
   145
        return '%s %s %s' % (subjvar, rtype, objvar)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   146
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   147
    def finalize(self):
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   148
        """return corresponding rql query (string) / args (dict)"""
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   149
        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
   150
            if len(ptypes) == 1:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   151
                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
   152
        unions = []
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   153
        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
   154
            thisunions = []
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   155
            for st, rt, ot in releq:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   156
                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
   157
                if st != '*':
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   158
                    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
   159
                if isinstance(obj, ast.SparqlVar) and ot != '*':
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   160
                    objvar = obj.name.upper()
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   161
                    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
   162
            if not unions:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   163
                unions = thisunions
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   164
            else:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   165
                unions = zip(*make_domains([unions, thisunions]))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   166
        selection = 'Any ' + ', '.join(self.selection)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   167
        sparqlst = self.sparqlst
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   168
        if sparqlst.distinct:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   169
            selection = 'DISTINCT ' + selection
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   170
        if unions:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   171
            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
   172
            rqls = ['(%s, %s)' % (baserql, ', '.join(unionrestrs))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   173
                    for unionrestrs in unions]
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   174
            rql = ' UNION '.join(rqls)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   175
            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
   176
                rql = '%s%s WITH %s BEING (%s)' % (
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   177
                    selection, order_limit_offset(sparqlst),
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   178
                    ', '.join(self.selection), rql)
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   179
        else:
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   180
            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
   181
                                      ', '.join(self.restrictions))
85be7a811afe sparql: support for literal restriction
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2431
diff changeset
   182
        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
   183
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
class Sparql2rqlTranslator(object):
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   186
    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
   187
        self.yschema = yschema
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   188
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   189
    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
   190
        sparqlst = parse(sparql)
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   191
        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
   192
            raise UnsupportedQuery()
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   193
        qi = QueryInfo(sparqlst)
96da7dc42eb5 quick and dirty support from simple sparql queries + base ui
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   194
        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
   195
            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
   196
                raise UnsupportedQuery()
2430
7d9ed6c740ec cleanup/document/refactor
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2427
diff changeset
   197
            # 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
   198
            subjvar = subj.name.upper()
5613
bc0ebfbf5c5d [sparql] fix type inference (test_dctitle_both_project_cwuser) and support for <http://www.w3.org/1999/02/22-rdf-syntax-ns#type tag (test_base_rdftype)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   199
            if predicate in [('', 'a'),
bc0ebfbf5c5d [sparql] fix type inference (test_dctitle_both_project_cwuser) and support for <http://www.w3.org/1999/02/22-rdf-syntax-ns#type tag (test_base_rdftype)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   200
                             ('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'type')]:
2430
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