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): |
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): |
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')) |