goa/rqlinterpreter.py
branchtls-sprint
changeset 1802 d628defebc17
parent 1133 8a409ea0c9ec
child 1977 606923dff11b
equal deleted inserted replaced
1801:672acc730ce5 1802:d628defebc17
    21 
    21 
    22 def etype_from_key(key):
    22 def etype_from_key(key):
    23     return Key(key).kind()
    23     return Key(key).kind()
    24 
    24 
    25 def poss_var_types(myvar, ovar, kind, solutions):
    25 def poss_var_types(myvar, ovar, kind, solutions):
    26     return frozenset(etypes[myvar] for etypes in solutions 
    26     return frozenset(etypes[myvar] for etypes in solutions
    27                      if etypes[ovar] == kind)
    27                      if etypes[ovar] == kind)
    28 
    28 
    29 def expand_result(results, result, myvar, values, dsget=None):
    29 def expand_result(results, result, myvar, values, dsget=None):
    30     values = map(dsget, values)
    30     values = map(dsget, values)
    31     if values:
    31     if values:
    82             string.append('%s: [%s]' % (k, ', '.join(str(i) for i in v)))
    82             string.append('%s: [%s]' % (k, ', '.join(str(i) for i in v)))
    83         else:
    83         else:
    84             string.append('%s: %s' % (k, v))
    84             string.append('%s: %s' % (k, v))
    85     return '{%s}' % ', '.join(string)
    85     return '{%s}' % ', '.join(string)
    86 
    86 
    87                          
    87 
    88 class EidMismatch(Exception):
    88 class EidMismatch(Exception):
    89     def __init__(self, varname, value):
    89     def __init__(self, varname, value):
    90         self.varname = varname
    90         self.varname = varname
    91         self.value = value
    91         self.value = value
    92 
    92 
    99             raise NotImplementedError('unsupported operator')
    99             raise NotImplementedError('unsupported operator')
   100         self.rel = rel
   100         self.rel = rel
   101         self.operator = operator
   101         self.operator = operator
   102         self.rtype = rel.r_type
   102         self.rtype = rel.r_type
   103         self.var = rel.children[0]
   103         self.var = rel.children[0]
   104         
   104 
   105     def __repr__(self):
   105     def __repr__(self):
   106         return '<%s for %s>' % (self.__class__.__name__, self.rel)
   106         return '<%s for %s>' % (self.__class__.__name__, self.rel)
   107     
   107 
   108     @property
   108     @property
   109     def rhs(self):
   109     def rhs(self):
   110         return self.rel.children[1].children[0]
   110         return self.rel.children[1].children[0]
   111 
   111 
   112         
   112 
   113 class MultipleRestriction(object):
   113 class MultipleRestriction(object):
   114     def __init__(self, restrictions):
   114     def __init__(self, restrictions):
   115         self.restrictions = restrictions
   115         self.restrictions = restrictions
   116         
   116 
   117     def resolve(self, solutions, fixed):
   117     def resolve(self, solutions, fixed):
   118         return _resolve(self.restrictions, solutions, fixed)
   118         return _resolve(self.restrictions, solutions, fixed)
   119 
   119 
   120     
   120 
   121 class VariableSelection(Restriction):
   121 class VariableSelection(Restriction):
   122     def __init__(self, rel, dsget, prefix='s'):
   122     def __init__(self, rel, dsget, prefix='s'):
   123         Restriction.__init__(self, rel)
   123         Restriction.__init__(self, rel)
   124         self._dsget = dsget
   124         self._dsget = dsget
   125         self._not = self.rel.neged(strict=True)
   125         self._not = self.rel.neged(strict=True)
   126         self._prefix = prefix + '_'
   126         self._prefix = prefix + '_'
   127         
   127 
   128     def __repr__(self):
   128     def __repr__(self):
   129         return '<%s%s for %s>' % (self._prefix[0], self.__class__.__name__, self.rel)
   129         return '<%s%s for %s>' % (self._prefix[0], self.__class__.__name__, self.rel)
   130         
   130 
   131     @property
   131     @property
   132     def searched_var(self):
   132     def searched_var(self):
   133         if self._prefix == 's_':
   133         if self._prefix == 's_':
   134             return self.var.name
   134             return self.var.name
   135         return self.rhs.name
   135         return self.rhs.name
   136         
   136 
   137     @property
   137     @property
   138     def constraint_var(self):
   138     def constraint_var(self):
   139         if self._prefix == 's_':
   139         if self._prefix == 's_':
   140             return self.rhs.name
   140             return self.rhs.name
   141         return self.var.name
   141         return self.var.name
   142         
   142 
   143     def _possible_values(self, myvar, ovar, entity, solutions, dsprefix):
   143     def _possible_values(self, myvar, ovar, entity, solutions, dsprefix):
   144         if self.rtype == 'identity':
   144         if self.rtype == 'identity':
   145             return (entity.key(),)
   145             return (entity.key(),)
   146         value = entity.get(dsprefix + self.rtype)
   146         value = entity.get(dsprefix + self.rtype)
   147         if value is None:
   147         if value is None:
   148             return []
   148             return []
   149         if not isinstance(value, list):
   149         if not isinstance(value, list):
   150             value = [value]
   150             value = [value]
   151         vartypes = poss_var_types(myvar, ovar, entity.kind(), solutions)
   151         vartypes = poss_var_types(myvar, ovar, entity.kind(), solutions)
   152         return (v for v in value if v.kind() in vartypes)
   152         return (v for v in value if v.kind() in vartypes)
   153         
   153 
   154     def complete_and_filter(self, solutions, results):
   154     def complete_and_filter(self, solutions, results):
   155         myvar = self.rhs.name
   155         myvar = self.rhs.name
   156         ovar = self.var.name
   156         ovar = self.var.name
   157         rtype = self.rtype
   157         rtype = self.rtype
   158         if self.schema.rschema(rtype).is_final():
   158         if self.schema.rschema(rtype).is_final():
   171                     values = self._possible_values(myvar, ovar, result[ovar],
   171                     values = self._possible_values(myvar, ovar, result[ovar],
   172                                                    solutions, 's_')
   172                                                    solutions, 's_')
   173                     expand_result(results, result, myvar, values, self._dsget)
   173                     expand_result(results, result, myvar, values, self._dsget)
   174         else:
   174         else:
   175             assert self.rhs.name in results[0]
   175             assert self.rhs.name in results[0]
   176             self.object_complete_and_filter(solutions, results)           
   176             self.object_complete_and_filter(solutions, results)
   177             
   177 
   178     def filter(self, solutions, results):
   178     def filter(self, solutions, results):
   179         myvar = self.rhs.name
   179         myvar = self.rhs.name
   180         ovar = self.var.name
   180         ovar = self.var.name
   181         newsols = {}
   181         newsols = {}
   182         for result in results[:]:
   182         for result in results[:]:
   185             if not key in newsols:
   185             if not key in newsols:
   186                 values = self._possible_values(myvar, ovar, entity, solutions, 's_')
   186                 values = self._possible_values(myvar, ovar, entity, solutions, 's_')
   187                 newsols[key] = frozenset(v for v in values)
   187                 newsols[key] = frozenset(v for v in values)
   188             if self._not:
   188             if self._not:
   189                 if result[myvar].key() in newsols[key]:
   189                 if result[myvar].key() in newsols[key]:
   190                     results.remove(result)                
   190                     results.remove(result)
   191             elif not result[myvar].key() in newsols[key]:
   191             elif not result[myvar].key() in newsols[key]:
   192                 results.remove(result)
   192                 results.remove(result)
   193     
   193 
   194     def object_complete_and_filter(self, solutions, results):
   194     def object_complete_and_filter(self, solutions, results):
   195         if self._not:
   195         if self._not:
   196             raise NotImplementedError()
   196             raise NotImplementedError()
   197         myvar = self.var.name
   197         myvar = self.var.name
   198         ovar = self.rhs.name
   198         ovar = self.rhs.name
   199         for result in results[:]:
   199         for result in results[:]:
   200             values = self._possible_values(myvar, ovar, result[ovar],
   200             values = self._possible_values(myvar, ovar, result[ovar],
   201                                            solutions, 'o_')
   201                                            solutions, 'o_')
   202             expand_result(results, result, myvar, values, self._dsget)
   202             expand_result(results, result, myvar, values, self._dsget)
   203 
   203 
   204     
   204 
   205 class EidRestriction(Restriction):
   205 class EidRestriction(Restriction):
   206     def __init__(self, rel, dsget):
   206     def __init__(self, rel, dsget):
   207         Restriction.__init__(self, rel)
   207         Restriction.__init__(self, rel)
   208         self._dsget = dsget
   208         self._dsget = dsget
   209 
   209 
   214 
   214 
   215 class RelationRestriction(VariableSelection):
   215 class RelationRestriction(VariableSelection):
   216 
   216 
   217     def _get_value(self, fixed):
   217     def _get_value(self, fixed):
   218         return fixed[self.constraint_var].key()
   218         return fixed[self.constraint_var].key()
   219     
   219 
   220     def fill_query(self, fixed, query, operator=None):
   220     def fill_query(self, fixed, query, operator=None):
   221         restr = '%s%s %s' % (self._prefix, self.rtype, operator or self.operator)
   221         restr = '%s%s %s' % (self._prefix, self.rtype, operator or self.operator)
   222         query[restr] = self._get_value(fixed)
   222         query[restr] = self._get_value(fixed)
   223 
   223 
   224     def resolve(self, solutions, fixed):
   224     def resolve(self, solutions, fixed):
   233 
   233 
   234 class NotRelationRestriction(RelationRestriction):
   234 class NotRelationRestriction(RelationRestriction):
   235 
   235 
   236     def _get_value(self, fixed):
   236     def _get_value(self, fixed):
   237         return None
   237         return None
   238     
   238 
   239     def resolve(self, solutions, fixed):
   239     def resolve(self, solutions, fixed):
   240         if self.rtype == 'identity':
   240         if self.rtype == 'identity':
   241             raise NotImplementedError()
   241             raise NotImplementedError()
   242         return _resolve([self], solutions, fixed)
   242         return _resolve([self], solutions, fixed)
   243 
   243 
   253                 raise NotImplementedError('LIKE is only supported for prefix search')
   253                 raise NotImplementedError('LIKE is only supported for prefix search')
   254             if not value.endswith('%'):
   254             if not value.endswith('%'):
   255                 raise NotImplementedError('LIKE is only supported for prefix search')
   255                 raise NotImplementedError('LIKE is only supported for prefix search')
   256             self.operator = '>'
   256             self.operator = '>'
   257             self.value = value[:-1]
   257             self.value = value[:-1]
   258             
   258 
   259     def complete_and_filter(self, solutions, results):
   259     def complete_and_filter(self, solutions, results):
   260         # check lhs var first in case this is a restriction
   260         # check lhs var first in case this is a restriction
   261         assert self._not
   261         assert self._not
   262         myvar, rtype, value = self.var.name, self.rtype, self.value
   262         myvar, rtype, value = self.var.name, self.rtype, self.value
   263         for result in results[:]:
   263         for result in results[:]:
   264             if result[myvar].get('s_'+rtype) == value:
   264             if result[myvar].get('s_'+rtype) == value:
   265                 results.remove(result)
   265                 results.remove(result)
   266             
   266 
   267     def _get_value(self, fixed):
   267     def _get_value(self, fixed):
   268         return self.value
   268         return self.value
   269 
   269 
   270 
   270 
   271 class DateAttributeRestriction(AttributeRestriction):
   271 class DateAttributeRestriction(AttributeRestriction):
   292         self.value = values
   292         self.value = values
   293 
   293 
   294     @property
   294     @property
   295     def operator(self):
   295     def operator(self):
   296         return 'in'
   296         return 'in'
   297             
   297 
   298 
   298 
   299 class TypeRestriction(AttributeRestriction):
   299 class TypeRestriction(AttributeRestriction):
   300     def __init__(self, var):
   300     def __init__(self, var):
   301         self.var = var
   301         self.var = var
   302 
   302 
   303     def __repr__(self):
   303     def __repr__(self):
   304         return '<%s for %s>' % (self.__class__.__name__, self.var)
   304         return '<%s for %s>' % (self.__class__.__name__, self.var)
   305     
   305 
   306     def resolve(self, solutions, fixed):
   306     def resolve(self, solutions, fixed):
   307         objs = []
   307         objs = []
   308         for etype in frozenset(etypes[self.var.name] for etypes in solutions):
   308         for etype in frozenset(etypes[self.var.name] for etypes in solutions):
   309             objs += Query(etype).Run()
   309             objs += Query(etype).Run()
   310         return objs
   310         return objs
   328     def __init__(self, functions, args, term):
   328     def __init__(self, functions, args, term):
   329         self.functions = functions
   329         self.functions = functions
   330         self.args = args
   330         self.args = args
   331         self.term = term
   331         self.term = term
   332         self._solution = self.term.stmt.solutions[0]
   332         self._solution = self.term.stmt.solutions[0]
   333         
   333 
   334     def compute(self, result):
   334     def compute(self, result):
   335         """return (entity type, value) to which self.term is evaluated according
   335         """return (entity type, value) to which self.term is evaluated according
   336         to the given result dictionnary and to query arguments (self.args)
   336         to the given result dictionnary and to query arguments (self.args)
   337         """
   337         """
   338         return self.term.accept(self, result)
   338         return self.term.accept(self, result)
   339 
   339 
   340     def visit_function(self, node, result):
   340     def visit_function(self, node, result):
   341         args = tuple(n.accept(self, result)[1] for n in node.children)
   341         args = tuple(n.accept(self, result)[1] for n in node.children)
   342         value = self.functions[node.name](*args)
   342         value = self.functions[node.name](*args)
   343         return node.get_type(self._solution, self.args), value
   343         return node.get_type(self._solution, self.args), value
   344     
   344 
   345     def visit_variableref(self, node, result):
   345     def visit_variableref(self, node, result):
   346         value = result[node.name]
   346         value = result[node.name]
   347         try:
   347         try:
   348             etype = value.kind()
   348             etype = value.kind()
   349             value = str(value.key())
   349             value = str(value.key())
   350         except AttributeError:
   350         except AttributeError:
   351             etype = self._solution[node.name]
   351             etype = self._solution[node.name]
   352         return etype, value
   352         return etype, value
   353     
   353 
   354     def visit_constant(self, node, result):
   354     def visit_constant(self, node, result):
   355         return node.get_type(kwargs=self.args), node.eval(self.args)
   355         return node.get_type(kwargs=self.args), node.eval(self.args)
   356     
   356 
   357         
   357 
   358 class RQLInterpreter(object):
   358 class RQLInterpreter(object):
   359     """algorithm:
   359     """algorithm:
   360     1. visit the restriction clauses and collect restriction for each subject
   360     1. visit the restriction clauses and collect restriction for each subject
   361        of a relation. Different restriction types are:
   361        of a relation. Different restriction types are:
   362        * EidRestriction
   362        * EidRestriction
   367     2. resolve eid restrictions
   367     2. resolve eid restrictions
   368     3. for each select in union:
   368     3. for each select in union:
   369            for each solution in select'solutions:
   369            for each solution in select'solutions:
   370                1. resolve variables which have attribute restriction
   370                1. resolve variables which have attribute restriction
   371                2. resolve relation restriction
   371                2. resolve relation restriction
   372                3. resolve selection and add to global results 
   372                3. resolve selection and add to global results
   373     """
   373     """
   374     def __init__(self, schema):
   374     def __init__(self, schema):
   375         self.schema = schema
   375         self.schema = schema
   376         Restriction.schema = schema # yalta!
   376         Restriction.schema = schema # yalta!
   377         self.rqlhelper = RQLHelper(schema, {'eid': etype_from_key})
   377         self.rqlhelper = RQLHelper(schema, {'eid': etype_from_key})
   378         self._stored_proc = {'LOWER': lambda x: x.lower(),
   378         self._stored_proc = {'LOWER': lambda x: x.lower(),
   379                              'UPPER': lambda x: x.upper()}
   379                              'UPPER': lambda x: x.upper()}
   380         for cb in SQL_CONNECT_HOOKS.get('sqlite', []):
   380         for cb in SQL_CONNECT_HOOKS.get('sqlite', []):
   381             cb(self)
   381             cb(self)
   382             
   382 
   383     # emulate sqlite connection interface so we can reuse stored procedures
   383     # emulate sqlite connection interface so we can reuse stored procedures
   384     def create_function(self, name, nbargs, func):
   384     def create_function(self, name, nbargs, func):
   385         self._stored_proc[name] = func
   385         self._stored_proc[name] = func
   386         
   386 
   387     def create_aggregate(self, name, nbargs, func):
   387     def create_aggregate(self, name, nbargs, func):
   388         self._stored_proc[name] = func
   388         self._stored_proc[name] = func
   389 
   389 
   390         
   390 
   391     def execute(self, operation, parameters=None, eid_key=None, build_descr=True):
   391     def execute(self, operation, parameters=None, eid_key=None, build_descr=True):
   392         rqlst = self.rqlhelper.parse(operation, annotate=True)
   392         rqlst = self.rqlhelper.parse(operation, annotate=True)
   393         try:
   393         try:
   394             self.rqlhelper.compute_solutions(rqlst, kwargs=parameters)
   394             self.rqlhelper.compute_solutions(rqlst, kwargs=parameters)
   395         except BadKeyError:
   395         except BadKeyError:
   396             results, description = [], []
   396             results, description = [], []
   397         else:
   397         else:
   398             results, description = self.interpret(rqlst, parameters)
   398             results, description = self.interpret(rqlst, parameters)
   399         return ResultSet(results, operation, parameters, description, rqlst=rqlst)
   399         return ResultSet(results, operation, parameters, description, rqlst=rqlst)
   400         
   400 
   401     def interpret(self, node, kwargs, dsget=None):
   401     def interpret(self, node, kwargs, dsget=None):
   402         if dsget is None:
   402         if dsget is None:
   403             self._dsget = Get
   403             self._dsget = Get
   404         else:
   404         else:
   405             self._dsget = dsget
   405             self._dsget = dsget
   415         for child in node.children:
   415         for child in node.children:
   416             pres, pdescr = self.visit_select(child, extra)
   416             pres, pdescr = self.visit_select(child, extra)
   417             results += pres
   417             results += pres
   418             description += pdescr
   418             description += pdescr
   419         return results, description
   419         return results, description
   420     
   420 
   421     def visit_select(self, node, extra):
   421     def visit_select(self, node, extra):
   422         constraints = {}
   422         constraints = {}
   423         if node.where is not None:
   423         if node.where is not None:
   424             node.where.accept(self, constraints, extra)
   424             node.where.accept(self, constraints, extra)
   425         fixed, toresolve, postresolve, postfilters = {}, {}, {}, []
   425         fixed, toresolve, postresolve, postfilters = {}, {}, {}, []
   439         # compute eid restrictions
   439         # compute eid restrictions
   440         kwargs = extra['kwargs']
   440         kwargs = extra['kwargs']
   441         for varname, restrictions in constraints.iteritems():
   441         for varname, restrictions in constraints.iteritems():
   442             for restr in restrictions[:]:
   442             for restr in restrictions[:]:
   443                 if isinstance(restr, EidRestriction):
   443                 if isinstance(restr, EidRestriction):
   444                     assert not varname in fixed    
   444                     assert not varname in fixed
   445                     try:
   445                     try:
   446                         value = restr.resolve(kwargs)
   446                         value = restr.resolve(kwargs)
   447                         fixed[varname] = value
   447                         fixed[varname] = value
   448                     except EntityNotFoundError:
   448                     except EntityNotFoundError:
   449                         return [], []
   449                         return [], []
   453         for varname, restrictions in constraints.iteritems():
   453         for varname, restrictions in constraints.iteritems():
   454             for restr in restrictions:
   454             for restr in restrictions:
   455                 if isinstance(restr, AttributeRestriction):
   455                 if isinstance(restr, AttributeRestriction):
   456                     toresolve.setdefault(varname, []).append(restr)
   456                     toresolve.setdefault(varname, []).append(restr)
   457                 elif isinstance(restr, NotRelationRestriction) or (
   457                 elif isinstance(restr, NotRelationRestriction) or (
   458                     isinstance(restr, RelationRestriction) and 
   458                     isinstance(restr, RelationRestriction) and
   459                     not restr.searched_var in fixed and restr.constraint_var in fixed):
   459                     not restr.searched_var in fixed and restr.constraint_var in fixed):
   460                     toresolve.setdefault(varname, []).append(restr)
   460                     toresolve.setdefault(varname, []).append(restr)
   461                 else:
   461                 else:
   462                     postresolve.setdefault(varname, []).append(restr)
   462                     postresolve.setdefault(varname, []).append(restr)
   463             try:
   463             try:
   493                 # init results
   493                 # init results
   494                 for value in values:
   494                 for value in values:
   495                     partres.append({varname: value})
   495                     partres.append({varname: value})
   496             elif not varname in partres[0]:
   496             elif not varname in partres[0]:
   497                 # cartesian product
   497                 # cartesian product
   498                 for res in partres:                    
   498                 for res in partres:
   499                     res[varname] = values[0]
   499                     res[varname] = values[0]
   500                 for res in partres[:]:
   500                 for res in partres[:]:
   501                     for value in values[1:]:
   501                     for value in values[1:]:
   502                         res = res.copy()
   502                         res = res.copy()
   503                         res[varname] = value
   503                         res[varname] = value
   504                         partres.append(res)
   504                         partres.append(res)
   505             else:
   505             else:
   506                 # union 
   506                 # union
   507                 for res in varpartres:
   507                 for res in varpartres:
   508                     for value in values:
   508                     for value in values:
   509                         res = res.copy()
   509                         res = res.copy()
   510                         res[varname] = value
   510                         res[varname] = value
   511                         partres.append(res)
   511                         partres.append(res)
   512         #print 'partres', len(partres)
   512         #print 'partres', len(partres)
   513         #print partres                        
   513         #print partres
   514         # Note: don't check for empty partres since constant selection may still
   514         # Note: don't check for empty partres since constant selection may still
   515         # produce result at this point
   515         # produce result at this point
   516         # sort to get RelationRestriction before AttributeSelection
   516         # sort to get RelationRestriction before AttributeSelection
   517         restrictions = sorted((restr for restrictions in postresolve.itervalues()
   517         restrictions = sorted((restr for restrictions in postresolve.itervalues()
   518                                for restr in restrictions),
   518                                for restr in restrictions),
   567                 for i, sol in enumerate(partres):
   567                 for i, sol in enumerate(partres):
   568                     etype, value = resolver.compute(sol)
   568                     etype, value = resolver.compute(sol)
   569                     append_result(res, descr, i, j, value, etype)
   569                     append_result(res, descr, i, j, value, etype)
   570         #print '--------->', res
   570         #print '--------->', res
   571         return res, descr
   571         return res, descr
   572     
   572 
   573     def visit_and(self, node, constraints, extra): 
   573     def visit_and(self, node, constraints, extra):
   574         for child in node.children:
   574         for child in node.children:
   575             child.accept(self, constraints, extra)
   575             child.accept(self, constraints, extra)
   576     def visit_exists(self, node, constraints, extra):
   576     def visit_exists(self, node, constraints, extra):
   577         extra['has_exists'] = True
   577         extra['has_exists'] = True
   578         self.visit_and(node, constraints, extra)
   578         self.visit_and(node, constraints, extra)
   579     
   579 
   580     def visit_not(self, node, constraints, extra):
   580     def visit_not(self, node, constraints, extra):
   581         for child in node.children:
   581         for child in node.children:
   582             child.accept(self, constraints, extra)
   582             child.accept(self, constraints, extra)
   583         try:
   583         try:
   584             extra.pop(node)
   584             extra.pop(node)
   585         except KeyError:
   585         except KeyError:
   586             raise NotImplementedError()
   586             raise NotImplementedError()
   587         
   587 
   588     def visit_relation(self, node, constraints, extra):
   588     def visit_relation(self, node, constraints, extra):
   589         if node.is_types_restriction():
   589         if node.is_types_restriction():
   590             return
   590             return
   591         rschema = self.schema.rschema(node.r_type)
   591         rschema = self.schema.rschema(node.r_type)
   592         neged = node.neged(strict=True)
   592         neged = node.neged(strict=True)
   598             self._visit_final_relation(rschema, node, constraints, extra)
   598             self._visit_final_relation(rschema, node, constraints, extra)
   599         elif neged:
   599         elif neged:
   600             self._visit_non_final_neged_relation(rschema, node, constraints)
   600             self._visit_non_final_neged_relation(rschema, node, constraints)
   601         else:
   601         else:
   602             self._visit_non_final_relation(rschema, node, constraints)
   602             self._visit_non_final_relation(rschema, node, constraints)
   603                 
   603 
   604     def _visit_non_final_relation(self, rschema, node, constraints, not_=False):
   604     def _visit_non_final_relation(self, rschema, node, constraints, not_=False):
   605         lhs, rhs = node.get_variable_parts()
   605         lhs, rhs = node.get_variable_parts()
   606         for v1, v2, prefix in ((lhs, rhs, 's'), (rhs, lhs, 'o')):
   606         for v1, v2, prefix in ((lhs, rhs, 's'), (rhs, lhs, 'o')):
   607             #if not_:
   607             #if not_:
   608             nbrels = len(v2.variable.stinfo['relations'])
   608             nbrels = len(v2.variable.stinfo['relations'])
   609             #else:
   609             #else:
   610             #    nbrels = len(v2.variable.stinfo['relations']) - len(v2.variable.stinfo['uidrels'])
   610             #    nbrels = len(v2.variable.stinfo['relations']) - len(v2.variable.stinfo['uidrels'])
   611             if nbrels > 1:
   611             if nbrels > 1:
   612                 constraints.setdefault(v1.name, []).append(
   612                 constraints.setdefault(v1.name, []).append(
   613                     RelationRestriction(node, self._dsget, prefix))
   613                     RelationRestriction(node, self._dsget, prefix))
   614                 # just init an empty list for v2 variable to avoid a 
   614                 # just init an empty list for v2 variable to avoid a
   615                 # TypeRestriction being added for it
   615                 # TypeRestriction being added for it
   616                 constraints.setdefault(v2.name, [])
   616                 constraints.setdefault(v2.name, [])
   617                 break
   617                 break
   618         else:
   618         else:
   619             constraints.setdefault(rhs.name, []).append(
   619             constraints.setdefault(rhs.name, []).append(
   620                 VariableSelection(node, self._dsget, 's'))
   620                 VariableSelection(node, self._dsget, 's'))
   621                 
   621 
   622     def _visit_non_final_neged_relation(self, rschema, node, constraints):
   622     def _visit_non_final_neged_relation(self, rschema, node, constraints):
   623         lhs, rhs = node.get_variable_parts()
   623         lhs, rhs = node.get_variable_parts()
   624         for v1, v2, prefix in ((lhs, rhs, 's'), (rhs, lhs, 'o')):
   624         for v1, v2, prefix in ((lhs, rhs, 's'), (rhs, lhs, 'o')):
   625             stinfo = v2.variable.stinfo
   625             stinfo = v2.variable.stinfo
   626             if not stinfo['selected'] and len(stinfo['relations']) == 1:
   626             if not stinfo['selected'] and len(stinfo['relations']) == 1:
   651             elif isinstance(rhs, nodes.Function) and rhs.name == 'IN':
   651             elif isinstance(rhs, nodes.Function) and rhs.name == 'IN':
   652                 constraints.setdefault(varname, []).append(
   652                 constraints.setdefault(varname, []).append(
   653                     AttributeInRestriction(node, extra['kwargs']))
   653                     AttributeInRestriction(node, extra['kwargs']))
   654             else:
   654             else:
   655                 raise NotImplementedError()
   655                 raise NotImplementedError()
   656         
   656 
   657     def _not_implemented(self, *args, **kwargs):
   657     def _not_implemented(self, *args, **kwargs):
   658         raise NotImplementedError()
   658         raise NotImplementedError()
   659     
   659 
   660     visit_or = _not_implemented
   660     visit_or = _not_implemented
   661     # shouldn't occurs
   661     # shouldn't occurs
   662     visit_set = _not_implemented
   662     visit_set = _not_implemented
   663     visit_insert = _not_implemented
   663     visit_insert = _not_implemented
   664     visit_delete = _not_implemented
   664     visit_delete = _not_implemented
   665         
   665 
   666 
   666 
   667 from logging import getLogger
   667 from logging import getLogger
   668 from cubicweb import set_log_methods
   668 from cubicweb import set_log_methods
   669 set_log_methods(RQLInterpreter, getLogger('cubicweb.goa.rqlinterpreter'))
   669 set_log_methods(RQLInterpreter, getLogger('cubicweb.goa.rqlinterpreter'))
   670 set_log_methods(Restriction, getLogger('cubicweb.goa.rqlinterpreter'))
   670 set_log_methods(Restriction, getLogger('cubicweb.goa.rqlinterpreter'))