rqlrewrite.py
brancholdstable
changeset 4985 02b52bf9f5f8
parent 4721 8f63691ccb7f
child 4906 9a50539f01d1
equal deleted inserted replaced
4563:c25da7573ebd 4985:02b52bf9f5f8
    10 """
    10 """
    11 __docformat__ = "restructuredtext en"
    11 __docformat__ = "restructuredtext en"
    12 
    12 
    13 from rql import nodes as n, stmts, TypeResolverException
    13 from rql import nodes as n, stmts, TypeResolverException
    14 
    14 
    15 from logilab.common.compat import any
       
    16 from logilab.common.graph import has_path
    15 from logilab.common.graph import has_path
    17 
    16 
    18 from cubicweb import Unauthorized, typed_eid
    17 from cubicweb import Unauthorized, typed_eid
    19 
    18 
    20 
    19 
   108                 newsolutions.append(newsol)
   107                 newsolutions.append(newsol)
   109                 solutions.remove(newsol)
   108                 solutions.remove(newsol)
   110     return newsolutions
   109     return newsolutions
   111 
   110 
   112 
   111 
   113 class Unsupported(Exception): pass
   112 class Unsupported(Exception):
       
   113     """raised when an rql expression can't be inserted in some rql query
       
   114     because it create an unresolvable query (eg no solutions found)
       
   115     """
   114 
   116 
   115 
   117 
   116 class RQLRewriter(object):
   118 class RQLRewriter(object):
   117     """insert some rql snippets into another rql syntax tree
   119     """insert some rql snippets into another rql syntax tree
   118 
   120 
   289                 self.insert_snippets([((varname, 'X'), rqlexprs)])
   291                 self.insert_snippets([((varname, 'X'), rqlexprs)])
   290 
   292 
   291     def snippet_subquery(self, varmap, transformedsnippet):
   293     def snippet_subquery(self, varmap, transformedsnippet):
   292         """introduce the given snippet in a subquery"""
   294         """introduce the given snippet in a subquery"""
   293         subselect = stmts.Select()
   295         subselect = stmts.Select()
   294         selectvar, snippetvar = varmap
   296         selectvar = varmap[0]
   295         subselect.append_selected(n.VariableRef(
   297         subselect.append_selected(n.VariableRef(
   296             subselect.get_variable(selectvar)))
   298             subselect.get_variable(selectvar)))
   297         aliases = [selectvar]
   299         aliases = [selectvar]
   298         subselect.add_restriction(transformedsnippet.copy(subselect))
   300         subselect.add_restriction(transformedsnippet.copy(subselect))
   299         stinfo = self.varinfo['stinfo']
   301         stinfo = self.varinfo['stinfo']
   400         try:
   402         try:
   401             if target == 'object':
   403             if target == 'object':
   402                 orel = self.varinfo['lhs_rels'][sniprel.r_type]
   404                 orel = self.varinfo['lhs_rels'][sniprel.r_type]
   403                 cardindex = 0
   405                 cardindex = 0
   404                 ttypes_func = rschema.objects
   406                 ttypes_func = rschema.objects
   405                 rprop = rschema.rproperty
   407                 rdef = rschema.rdef
   406             else: # target == 'subject':
   408             else: # target == 'subject':
   407                 orel = self.varinfo['rhs_rels'][sniprel.r_type]
   409                 orel = self.varinfo['rhs_rels'][sniprel.r_type]
   408                 cardindex = 1
   410                 cardindex = 1
   409                 ttypes_func = rschema.subjects
   411                 ttypes_func = rschema.subjects
   410                 rprop = lambda x, y, z: rschema.rproperty(y, x, z)
   412                 rdef = lambda x, y: rschema.rdef(y, x)
   411         except KeyError, ex:
   413         except KeyError:
   412             # may be raised by self.varinfo['xhs_rels'][sniprel.r_type]
   414             # may be raised by self.varinfo['xhs_rels'][sniprel.r_type]
   413             return None
   415             return None
   414         # can't share neged relation or relations with different outer join
   416         # can't share neged relation or relations with different outer join
   415         if (orel.neged(strict=True) or sniprel.neged(strict=True)
   417         if (orel.neged(strict=True) or sniprel.neged(strict=True)
   416             or (orel.optional and orel.optional != sniprel.optional)):
   418             or (orel.optional and orel.optional != sniprel.optional)):
   417             return None
   419             return None
   418         # if cardinality is in '?1', we can ignore the snippet relation and use
   420         # if cardinality is in '?1', we can ignore the snippet relation and use
   419         # variable from the original query
   421         # variable from the original query
   420         for etype in self.varinfo['stinfo']['possibletypes']:
   422         for etype in self.varinfo['stinfo']['possibletypes']:
   421             for ttype in ttypes_func(etype):
   423             for ttype in ttypes_func(etype):
   422                 if rprop(etype, ttype, 'cardinality')[cardindex] in '+*':
   424                 if rdef(etype, ttype).cardinality[cardindex] in '+*':
   423                     return None
   425                     return None
   424         return orel
   426         return orel
   425 
   427 
   426     def _use_orig_term(self, snippet_varname, term):
   428     def _use_orig_term(self, snippet_varname, term):
   427         key = (self.current_expr, self.varmap, snippet_varname)
   429         key = (self.current_expr, self.varmap, snippet_varname)
   439                 # generate an identifier for the substitution
   441                 # generate an identifier for the substitution
   440                 argname = select.allocate_varname()
   442                 argname = select.allocate_varname()
   441                 while argname in self.kwargs:
   443                 while argname in self.kwargs:
   442                     argname = select.allocate_varname()
   444                     argname = select.allocate_varname()
   443                 # insert "U eid %(u)s"
   445                 # insert "U eid %(u)s"
   444                 var = select.get_variable(self.u_varname)
   446                 select.add_constant_restriction(
   445                 select.add_constant_restriction(select.get_variable(self.u_varname),
   447                     select.get_variable(self.u_varname),
   446                                                 'eid', unicode(argname), 'Substitute')
   448                     'eid', unicode(argname), 'Substitute')
   447                 self.kwargs[argname] = self.session.user.eid
   449                 self.kwargs[argname] = self.session.user.eid
   448             return self.u_varname
   450             return self.u_varname
   449         key = (self.current_expr, self.varmap, vname)
   451         key = (self.current_expr, self.varmap, vname)
   450         try:
   452         try:
   451             return self.rewritten[key]
   453             return self.rewritten[key]