diff --git a/ChangeLog b/ChangeLog index bc9c7885a7098e9aa9629dd834fc2c6670e80215_Q2hhbmdlTG9n..e154f58bb9d6ffe875aa8fda57e6ed85e579e642_Q2hhbmdlTG9n 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,11 +2,19 @@ ================= -- -* support != operator for non equality -* support for CAST function -* support for regexp-based pattern matching using a REGEXP operator -* may now GROUPBY functions / column number -* fix parsing of negative float + * remove_group_var renamed into remove_group_term and fixed implementation + + * rql annotator add 'having' list into variable's stinfo, and + properly update variable graph + + * new undo_modification context manager on select nodes + +2011-06-09 -- 0.29.0 + * support != operator for non equality + * support for CAST function + * support for regexp-based pattern matching using a REGEXP operator + * may now GROUPBY functions / column number + * fix parsing of negative float 2011-01-12 -- 0.28.0 * enhance rewrite_shared_optional so one can specify where the new identity diff --git a/nodes.py b/nodes.py index bc9c7885a7098e9aa9629dd834fc2c6670e80215_bm9kZXMucHk=..e154f58bb9d6ffe875aa8fda57e6ed85e579e642_bm9kZXMucHk= 100644 --- a/nodes.py +++ b/nodes.py @@ -1,4 +1,4 @@ -# copyright 2004-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2004-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of rql. diff --git a/parser.g b/parser.g index bc9c7885a7098e9aa9629dd834fc2c6670e80215_cGFyc2VyLmc=..e154f58bb9d6ffe875aa8fda57e6ed85e579e642_cGFyc2VyLmc= 100644 --- a/parser.g +++ b/parser.g @@ -1,7 +1,7 @@ """yapps input grammar for RQL. :organization: Logilab -:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:copyright: 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr diff --git a/stcheck.py b/stcheck.py index bc9c7885a7098e9aa9629dd834fc2c6670e80215_c3RjaGVjay5weQ==..e154f58bb9d6ffe875aa8fda57e6ed85e579e642_c3RjaGVjay5weQ== 100644 --- a/stcheck.py +++ b/stcheck.py @@ -27,7 +27,7 @@ from rql._exceptions import BadRQLQuery from rql.utils import function_description from rql.nodes import (Relation, VariableRef, Constant, Not, Exists, Function, - And, Variable, variable_refs, make_relation) + And, Variable, Comparison, variable_refs, make_relation) from rql.stmts import Union @@ -521,6 +521,23 @@ for term in node.groupby: for vref in term.get_nodes(VariableRef): bloc_simplification(vref.variable, term) + try: + vargraph = node.vargraph + except AttributeError: + vargraph = None + # XXX node.having is a list of size 1 + assert len(node.having) == 1 + for term in node.having[0].get_nodes(Comparison): + for vref in term.iget_nodes(VariableRef): + vref.variable.stinfo.setdefault('having', []).append(term) + if vargraph is not None: + lhsvariables = set(vref.name for vref in term.children[0].get_nodes(VariableRef)) + rhsvariables = set(vref.name for vref in term.children[1].get_nodes(VariableRef)) + for v1 in lhsvariables: + for v2 in rhsvariables: + if v1 != v2: + vargraph.setdefault(v1, []).append(v2) + vargraph.setdefault(v2, []).append(v1) def rewrite_shared_optional(self, exists, var, identity_rel_scope=None): """if variable is shared across multiple scopes, need some tree diff --git a/stmts.py b/stmts.py index bc9c7885a7098e9aa9629dd834fc2c6670e80215_c3RtdHMucHk=..e154f58bb9d6ffe875aa8fda57e6ed85e579e642_c3RtdHMucHk= 100644 --- a/stmts.py +++ b/stmts.py @@ -1,4 +1,4 @@ -# copyright 2004-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2004-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of rql. @@ -27,6 +27,7 @@ from warnings import warn from logilab.common.decorators import cached +from logilab.common.deprecation import deprecated from rql import BadRQLQuery, CoercionError, nodes from rql.base import BaseNode, Node @@ -47,6 +48,13 @@ raise AssertionError('vref %r is not referenced (%r)' % (vref, vref.stmt)) return True +class undo_modification(object): + def __init__(self, select): + self.select = select + def __enter__(self): + self.select.save_state() + def __exit__(self): + self.select.recover() class ScopeNode(BaseNode): solutions = () # list of possibles solutions for used variables @@ -354,6 +362,9 @@ def should_register_op(self): return self.memorizing and not self.undoing + def undo_modification(self): + return undo_modification(self) + def save_state(self): """save the current tree""" self.undo_manager.push_state() @@ -708,7 +719,7 @@ elif node in self.orderby: self.remove_sort_term(node) elif node in self.groupby: - self.remove_group_var(node) + self.remove_group_term(node) elif node in self.having: self.having.remove(node) # XXX selection @@ -730,7 +741,7 @@ elif isinstance(vref.parent, nodes.SortTerm): self.remove_sort_term(vref.parent) elif vref in self.groupby: - self.remove_group_var(vref) + self.remove_group_term(vref) else: # selected variable self.remove_selected(vref) # effective undefine operation @@ -796,7 +807,7 @@ from rql.undo import AddGroupOperation self.undo_manager.add_operation(AddGroupOperation(vref)) - def remove_group_var(self, vref): + def remove_group_term(self, term): """remove the group variable and the group node if necessary""" if self.should_register_op: from rql.undo import RemoveGroupOperation @@ -800,9 +811,11 @@ """remove the group variable and the group node if necessary""" if self.should_register_op: from rql.undo import RemoveGroupOperation - self.undo_manager.add_operation(RemoveGroupOperation(vref)) - vref.unregister_reference() - self.groupby.remove(vref) + self.undo_manager.add_operation(RemoveGroupOperation(term)) + for vref in term.iget_nodes(nodes.VariableRef): + vref.unregister_reference() + self.groupby.remove(term) + remove_group_var = deprecated('[rql 0.29] use remove_group_term instead')(remove_group_term) def remove_groups(self): for vref in self.groupby[:]: @@ -806,7 +819,7 @@ def remove_groups(self): for vref in self.groupby[:]: - self.remove_group_var(vref) + self.remove_group_term(vref) def add_sort_var(self, var, asc=True): """add var in 'orderby' constraints diff --git a/test/unittest_nodes.py b/test/unittest_nodes.py index bc9c7885a7098e9aa9629dd834fc2c6670e80215_dGVzdC91bml0dGVzdF9ub2Rlcy5weQ==..e154f58bb9d6ffe875aa8fda57e6ed85e579e642_dGVzdC91bml0dGVzdF9ub2Rlcy5weQ== 100644 --- a/test/unittest_nodes.py +++ b/test/unittest_nodes.py @@ -1,5 +1,5 @@ # -*- coding: iso-8859-1 -*- -# copyright 2004-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2004-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of rql. @@ -232,7 +232,7 @@ tree.check_references() self.assertEqual(tree.as_string(), 'Any X') - def test_select_remove_group_var(self): + def test_select_remove_group_term(self): tree = self._parse('Any X GROUPBY X') tree.save_state() select = tree.children[0] @@ -236,7 +236,7 @@ tree = self._parse('Any X GROUPBY X') tree.save_state() select = tree.children[0] - select.remove_group_var(select.groupby[0]) + select.remove_group_term(select.groupby[0]) tree.check_references() self.assertEqual(tree.as_string(), 'Any X') tree.recover() diff --git a/test/unittest_parser.py b/test/unittest_parser.py index bc9c7885a7098e9aa9629dd834fc2c6670e80215_dGVzdC91bml0dGVzdF9wYXJzZXIucHk=..e154f58bb9d6ffe875aa8fda57e6ed85e579e642_dGVzdC91bml0dGVzdF9wYXJzZXIucHk= 100644 --- a/test/unittest_parser.py +++ b/test/unittest_parser.py @@ -1,5 +1,5 @@ # -*- coding: iso-8859-1 -*- -# copyright 2004-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2004-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of rql. diff --git a/undo.py b/undo.py index bc9c7885a7098e9aa9629dd834fc2c6670e80215_dW5kby5weQ==..e154f58bb9d6ffe875aa8fda57e6ed85e579e642_dW5kby5weQ== 100644 --- a/undo.py +++ b/undo.py @@ -196,7 +196,7 @@ def undo(self, selection): """undo the operation on the selection""" - self.stmt.remove_group_var(self.node) + self.stmt.remove_group_term(self.node) class RemoveGroupOperation(NodeOperation): """Defines how to undo 'remove group'."""