1 # copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
3 # |
3 # |
4 # This file is part of CubicWeb. |
4 # This file is part of CubicWeb. |
5 # |
5 # |
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
21 from yams import BadSchemaDefinition |
21 from yams import BadSchemaDefinition |
22 from rql import parse, nodes, RQLHelper |
22 from rql import parse, nodes, RQLHelper |
23 |
23 |
24 from cubicweb import Unauthorized, rqlrewrite |
24 from cubicweb import Unauthorized, rqlrewrite |
25 from cubicweb.schema import RRQLExpression, ERQLExpression |
25 from cubicweb.schema import RRQLExpression, ERQLExpression |
26 from cubicweb.devtools import repotest, TestServerConfiguration |
26 from cubicweb.devtools import repotest, TestServerConfiguration, BaseApptestConfiguration |
27 |
27 |
28 |
28 |
29 def setUpModule(*args): |
29 def setUpModule(*args): |
30 global rqlhelper, schema |
30 global rqlhelper, schema |
31 config = TestServerConfiguration(RQLRewriteTC.datapath('rewrite')) |
31 config = TestServerConfiguration(RQLRewriteTC.datapath('rewrite')) |
200 'EXISTS(X created_by B), EXISTS(Y created_by B), ' |
201 'EXISTS(X created_by B), EXISTS(Y created_by B), ' |
201 'X is Card, Y is IN(Division, Note, Societe) ' |
202 'X is Card, Y is IN(Division, Note, Societe) ' |
202 'WITH LA BEING (Any LA WHERE (EXISTS(A created_by B, LA documented_by A)) OR (EXISTS(E created_by B, LA concerne E)), ' |
203 'WITH LA BEING (Any LA WHERE (EXISTS(A created_by B, LA documented_by A)) OR (EXISTS(E created_by B, LA concerne E)), ' |
203 'B eid %(D)s, LA is Affaire)') |
204 'B eid %(D)s, LA is Affaire)') |
204 |
205 |
|
206 |
|
207 def test_ambiguous_optional_same_exprs(self): |
|
208 """See #3013535""" |
|
209 # see test of the same name in RewriteFullTC: original problem is |
|
210 # unreproducible here because it actually lies in |
|
211 # RQLRewriter.insert_local_checks |
|
212 rqlst = parse('Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s, X creation_date CD') |
|
213 rewrite(rqlst, {('X', 'X'): ('X created_by U',),}, {'a': 3}) |
|
214 self.assertEqual(rqlst.as_string(), |
|
215 u'Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s WITH X,CD BEING (Any X,CD WHERE X creation_date CD, EXISTS(X created_by B), B eid %(A)s, X is IN(Division, Note, Societe))') |
|
216 |
205 def test_optional_var_inlined(self): |
217 def test_optional_var_inlined(self): |
206 c1 = ('X require_permission P') |
218 c1 = ('X require_permission P') |
207 c2 = ('X inlined_card O, O require_permission P') |
219 c2 = ('X inlined_card O, O require_permission P') |
208 rqlst = parse('Any C,A,R WHERE A? inlined_card C, A ref R') |
220 rqlst = parse('Any C,A,R WHERE A? inlined_card C, A ref R') |
209 rewrite(rqlst, {('C', 'X'): (c1,), |
221 rewrite(rqlst, {('C', 'X'): (c1,), |
290 rqlst = parse('Card C WHERE C in_state STATE') |
302 rqlst = parse('Card C WHERE C in_state STATE') |
291 rewrite(rqlst, {('C', 'X'): (snippet,)}, {}) |
303 rewrite(rqlst, {('C', 'X'): (snippet,)}, {}) |
292 self.assertEqual(rqlst.as_string(), |
304 self.assertEqual(rqlst.as_string(), |
293 "Any C WHERE C in_state STATE, C is Card, " |
305 "Any C WHERE C in_state STATE, C is Card, " |
294 "EXISTS(STATE name 'hop'), STATE is State") |
306 "EXISTS(STATE name 'hop'), STATE is State") |
|
307 |
295 def test_relation_optimization_3_rhs(self): |
308 def test_relation_optimization_3_rhs(self): |
296 snippet = ('TW? subworkflow_exit X, TW name "hop"') |
309 snippet = ('TW? subworkflow_exit X, TW name "hop"') |
297 rqlst = parse('WorkflowTransition C WHERE C subworkflow_exit EXIT') |
310 rqlst = parse('WorkflowTransition C WHERE C subworkflow_exit EXIT') |
298 rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {}) |
311 rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {}) |
299 self.assertEqual(rqlst.as_string(), |
312 self.assertEqual(rqlst.as_string(), |
306 rqlst = parse('Card C WHERE C in_state STATE?') |
319 rqlst = parse('Card C WHERE C in_state STATE?') |
307 rewrite(rqlst, {('C', 'X'): (snippet,)}, {}) |
320 rewrite(rqlst, {('C', 'X'): (snippet,)}, {}) |
308 self.assertEqual(rqlst.as_string(), |
321 self.assertEqual(rqlst.as_string(), |
309 "Any C WHERE C in_state STATE?, C is Card, " |
322 "Any C WHERE C in_state STATE?, C is Card, " |
310 "EXISTS(C in_state A, A name 'hop', A is State), STATE is State") |
323 "EXISTS(C in_state A, A name 'hop', A is State), STATE is State") |
|
324 |
311 def test_relation_non_optimization_1_rhs(self): |
325 def test_relation_non_optimization_1_rhs(self): |
312 snippet = ('TW subworkflow_exit X, TW name "hop"') |
326 snippet = ('TW subworkflow_exit X, TW name "hop"') |
313 rqlst = parse('SubWorkflowExitPoint EXIT WHERE C? subworkflow_exit EXIT') |
327 rqlst = parse('SubWorkflowExitPoint EXIT WHERE C? subworkflow_exit EXIT') |
314 rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {}) |
328 rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {}) |
315 self.assertEqual(rqlst.as_string(), |
329 self.assertEqual(rqlst.as_string(), |
457 c_bad = ERQLExpression('X documented_by R, A in_state R') |
471 c_bad = ERQLExpression('X documented_by R, A in_state R') |
458 |
472 |
459 rqlst = parse('Any A, R WHERE A ref R, S is Affaire') |
473 rqlst = parse('Any A, R WHERE A ref R, S is Affaire') |
460 rewrite(rqlst, {('A', 'X'): (c_ok, c_bad)}, {}) |
474 rewrite(rqlst, {('A', 'X'): (c_ok, c_bad)}, {}) |
461 |
475 |
|
476 |
|
477 from cubicweb.devtools.testlib import CubicWebTC |
|
478 from logilab.common.decorators import classproperty |
|
479 |
|
480 class RewriteFullTC(CubicWebTC): |
|
481 @classproperty |
|
482 def config(cls): |
|
483 return BaseApptestConfiguration(apphome=cls.datapath('rewrite')) |
|
484 |
|
485 def process(self, rql, args=None): |
|
486 if args is None: |
|
487 args = {} |
|
488 querier = self.repo.querier |
|
489 union = querier.parse(rql) |
|
490 querier.solutions(self.session, union, args) |
|
491 querier._annotate(union) |
|
492 plan = querier.plan_factory(union, args, self.session) |
|
493 plan.preprocess(union) |
|
494 return union |
|
495 |
|
496 def test_ambiguous_optional_same_exprs(self): |
|
497 """See #3013535""" |
|
498 edef1 = self.schema['Societe'] |
|
499 edef2 = self.schema['Division'] |
|
500 edef3 = self.schema['Note'] |
|
501 with self.temporary_permissions((edef1, {'read': (ERQLExpression('X owned_by U'),)}), |
|
502 (edef2, {'read': (ERQLExpression('X owned_by U'),)}), |
|
503 (edef3, {'read': (ERQLExpression('X owned_by U'),)})): |
|
504 union = self.process('Any A,AR,X,CD WHERE A concerne X?, A ref AR, X creation_date CD') |
|
505 self.assertEqual(union.as_string(), 'Any A,AR,X,CD WHERE A concerne X?, A ref AR, A is Affaire WITH X,CD BEING (Any X,CD WHERE X creation_date CD, EXISTS(X owned_by %(A)s), X is IN(Division, Note, Societe))') |
|
506 |
|
507 |
462 if __name__ == '__main__': |
508 if __name__ == '__main__': |
463 unittest_main() |
509 unittest_main() |