spa2rql.py
changeset 2435 85be7a811afe
parent 2431 93c061eac647
child 4212 ab6573088b4a
equal deleted inserted replaced
2434:ed85d69576b4 2435:85be7a811afe
    24     if sparqlst.limit:
    24     if sparqlst.limit:
    25         addons += ' LIMIT %s' % sparqlst.limit
    25         addons += ' LIMIT %s' % sparqlst.limit
    26     if sparqlst.offset:
    26     if sparqlst.offset:
    27         addons += ' OFFSET %s' % sparqlst.offset
    27         addons += ' OFFSET %s' % sparqlst.offset
    28     return addons
    28     return addons
       
    29 
    29 
    30 
    30 class QueryInfo(object):
    31 class QueryInfo(object):
    31     """wrapper class containing necessary information to generate a RQL query
    32     """wrapper class containing necessary information to generate a RQL query
    32     from a sparql syntax tree
    33     from a sparql syntax tree
    33     """
    34     """
    39             self.selection = [var.name.upper() for var in sparqlst.selected]
    40             self.selection = [var.name.upper() for var in sparqlst.selected]
    40         self.possible_types = {}
    41         self.possible_types = {}
    41         self.infer_types_info = []
    42         self.infer_types_info = []
    42         self.union_params = []
    43         self.union_params = []
    43         self.restrictions = []
    44         self.restrictions = []
    44 
    45         self.literals = {}
    45     def finalize(self):
    46         self._litcount = 0
    46         """return corresponding rql query"""
    47 
    47         for varname, ptypes in self.possible_types.iteritems():
    48     def add_literal(self, value):
    48             if len(ptypes) == 1:
    49         key = chr(ord('a') + self._litcount)
    49                 self.restrictions.append('%s is %s' % (varname, iter(ptypes).next()))
    50         self._litcount += 1
    50         unions = []
    51         self.literals[key] = value
    51         for releq, subjvar, objvar in self.union_params:
    52         return key
    52             thisunions = []
       
    53             for st, rt, ot in releq:
       
    54                 thisunions.append(['%s %s %s' % (subjvar, rt, objvar)])
       
    55                 if st != '*':
       
    56                     thisunions[-1].append('%s is %s' % (subjvar, st))
       
    57                 if ot != '*':
       
    58                     thisunions[-1].append('%s is %s' % (objvar, ot))
       
    59             if not unions:
       
    60                 unions = thisunions
       
    61             else:
       
    62                 unions = zip(*make_domains([unions, thisunions]))
       
    63         selection = 'Any ' + ', '.join(self.selection)
       
    64         sparqlst = self.sparqlst
       
    65         if sparqlst.distinct:
       
    66             selection = 'DISTINCT ' + selection
       
    67         if not unions:
       
    68             return '%s%s WHERE %s' % (selection, order_limit_offset(sparqlst),
       
    69                                       ', '.join(self.restrictions))
       
    70         baserql = '%s WHERE %s' % (selection, ', '.join(self.restrictions))
       
    71         rqls = ['(%s, %s)' % (baserql, ', '.join(unionrestrs))
       
    72                 for unionrestrs in unions]
       
    73         rql = ' UNION '.join(rqls)
       
    74         if sparqlst.orderby or sparqlst.limit or sparqlst.offset:
       
    75             rql = '%s%s WITH %s BEING (%s)' % (
       
    76                 selection, order_limit_offset(sparqlst),
       
    77                 ', '.join(self.selection), rql)
       
    78         return rql
       
    79 
    53 
    80     def set_possible_types(self, var, varpossibletypes):
    54     def set_possible_types(self, var, varpossibletypes):
    81         """set/restrict possible types for the given variable.
    55         """set/restrict possible types for the given variable.
    82 
    56 
    83         :return: True if something changed, else false.
    57         :return: True if something changed, else false.
   129                 # ensure this still make sense
   103                 # ensure this still make sense
   130                 if not yams_predicates:
   104                 if not yams_predicates:
   131                     raise TypeResolverException()
   105                     raise TypeResolverException()
   132                 if len(yams_predicates) != nbchoices:
   106                 if len(yams_predicates) != nbchoices:
   133                     modified = True
   107                     modified = True
       
   108 
       
   109     def build_restrictions(self):
   134         # now, for each predicate
   110         # now, for each predicate
   135         for yams_predicates, subjvar, obj in self.infer_types_info:
   111         for yams_predicates, subjvar, obj in self.infer_types_info:
   136             rel = yams_predicates[0]
   112             rel = yams_predicates[0]
   137             objvar = obj.name.upper()
       
   138             # if there are several yams relation type equivalences, we will have
   113             # if there are several yams relation type equivalences, we will have
   139             # to generate several unioned rql queries
   114             # to generate several unioned rql queries
   140             for s, r, o in yams_predicates[1:]:
   115             for s, r, o in yams_predicates[1:]:
   141                 if r != rel[1]:
   116                 if r != rel[1]:
   142                     self.union_params.append((yams_predicates, subjvar, objvar))
   117                     self.union_params.append((yams_predicates, subjvar, obj))
   143                     break
   118                     break
       
   119             # else we can simply add it to base rql restrictions
   144             else:
   120             else:
   145                 # else we can simply add it to base rql restrictions
   121                 restr = self.build_restriction(subjvar, rel[1], obj)
   146                 self.restrictions.append('%s %s %s' % (subjvar, rel[1], objvar))
   122                 self.restrictions.append(restr)
       
   123 
       
   124     def build_restriction(self, subjvar, rtype, obj):
       
   125         if isinstance(obj, ast.SparqlLiteral):
       
   126             key = self.add_literal(obj.value)
       
   127             objvar = '%%(%s)s' % key
       
   128         else:
       
   129             assert isinstance(obj, ast.SparqlVar)
       
   130             # make a valid rql var name
       
   131             objvar = obj.name.upper()
       
   132         # else we can simply add it to base rql restrictions
       
   133         return '%s %s %s' % (subjvar, rtype, objvar)
       
   134 
       
   135     def finalize(self):
       
   136         """return corresponding rql query (string) / args (dict)"""
       
   137         for varname, ptypes in self.possible_types.iteritems():
       
   138             if len(ptypes) == 1:
       
   139                 self.restrictions.append('%s is %s' % (varname, iter(ptypes).next()))
       
   140         unions = []
       
   141         for releq, subjvar, obj in self.union_params:
       
   142             thisunions = []
       
   143             for st, rt, ot in releq:
       
   144                 thisunions.append([self.build_restriction(subjvar, rt, obj)])
       
   145                 if st != '*':
       
   146                     thisunions[-1].append('%s is %s' % (subjvar, st))
       
   147                 if isinstance(obj, ast.SparqlVar) and ot != '*':
       
   148                     objvar = obj.name.upper()
       
   149                     thisunions[-1].append('%s is %s' % (objvar, objvar))
       
   150             if not unions:
       
   151                 unions = thisunions
       
   152             else:
       
   153                 unions = zip(*make_domains([unions, thisunions]))
       
   154         selection = 'Any ' + ', '.join(self.selection)
       
   155         sparqlst = self.sparqlst
       
   156         if sparqlst.distinct:
       
   157             selection = 'DISTINCT ' + selection
       
   158         if unions:
       
   159             baserql = '%s WHERE %s' % (selection, ', '.join(self.restrictions))
       
   160             rqls = ['(%s, %s)' % (baserql, ', '.join(unionrestrs))
       
   161                     for unionrestrs in unions]
       
   162             rql = ' UNION '.join(rqls)
       
   163             if sparqlst.orderby or sparqlst.limit or sparqlst.offset:
       
   164                 rql = '%s%s WITH %s BEING (%s)' % (
       
   165                     selection, order_limit_offset(sparqlst),
       
   166                     ', '.join(self.selection), rql)
       
   167         else:
       
   168             rql = '%s%s WHERE %s' % (selection, order_limit_offset(sparqlst),
       
   169                                       ', '.join(self.restrictions))
       
   170         return rql, self.literals
   147 
   171 
   148 
   172 
   149 class Sparql2rqlTranslator(object):
   173 class Sparql2rqlTranslator(object):
   150     def __init__(self, yschema):
   174     def __init__(self, yschema):
   151         self.yschema = yschema
   175         self.yschema = yschema
   174                 # list of 3-uple
   198                 # list of 3-uple
   175                 #   (yams etype (subject), yams rtype, yams etype (object))
   199                 #   (yams etype (subject), yams rtype, yams etype (object))
   176                 # where subject / object entity type may '*' if not specified
   200                 # where subject / object entity type may '*' if not specified
   177                 yams_predicates = xy.yeq(':'.join(predicate))
   201                 yams_predicates = xy.yeq(':'.join(predicate))
   178                 qi.infer_types_info.append((yams_predicates, subjvar, obj))
   202                 qi.infer_types_info.append((yams_predicates, subjvar, obj))
   179                 if isinstance(obj, ast.SparqlVar):
   203                 if not isinstance(obj, (ast.SparqlLiteral, ast.SparqlVar)):
   180                     # make a valid rql var name
       
   181                     objvar = obj.name.upper()
       
   182                 else:
       
   183                     raise UnsupportedQuery()
   204                     raise UnsupportedQuery()
   184         qi.infer_types()
   205         qi.infer_types()
       
   206         qi.build_restrictions()
   185         return qi
   207         return qi