From: Mike Bayer Date: Wed, 27 Sep 2017 14:14:57 +0000 (-0400) Subject: Support method form of any_(), all_() X-Git-Tag: rel_1_2_0~76^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=944c662d8add498577d6359251d4b94cd84d4011;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Support method form of any_(), all_() Fixed bug where the recently added :meth:`.ColumnOperators.any_` and :meth:`.ColumnOperators.all_` methods didn't work when called as methods, as opposed to using the standalone functions :func:`~.expression.any_` and :func:`~.expression.all_`. Also added documentation examples for these relatively unintuitive SQL operators. Change-Id: I3e56b463e9fd146a077b9970624f50cba27f9811 Fixes: #4093 --- diff --git a/doc/build/changelog/unreleased_11/4093.rst b/doc/build/changelog/unreleased_11/4093.rst new file mode 100644 index 0000000000..4fba8154a3 --- /dev/null +++ b/doc/build/changelog/unreleased_11/4093.rst @@ -0,0 +1,11 @@ +.. change:: + :tags: bug, sql + :tickets: 4093 + :versions: 1.2.0b3 + + Fixed bug where the recently added :meth:`.ColumnOperators.any_` + and :meth:`.ColumnOperators.all_` methods didn't work when called + as methods, as opposed to using the standalone functions + :func:`~.expression.any_` and :func:`~.expression.all_`. Also + added documentation examples for these relatively unintuitive + SQL operators. \ No newline at end of file diff --git a/lib/sqlalchemy/sql/default_comparator.py b/lib/sqlalchemy/sql/default_comparator.py index a52bdbaedc..7544c9a441 100644 --- a/lib/sqlalchemy/sql/default_comparator.py +++ b/lib/sqlalchemy/sql/default_comparator.py @@ -15,7 +15,7 @@ from .elements import BindParameter, True_, False_, BinaryExpression, \ Null, _const_expr, _clause_element_as_expr, \ ClauseList, ColumnElement, TextClause, UnaryExpression, \ collate, _is_literal, _literal_as_text, ClauseElement, and_, or_, \ - Slice, Visitable, _literal_as_binds + Slice, Visitable, _literal_as_binds, CollectionAggregate from .selectable import SelectBase, Alias, Selectable, ScalarSelect @@ -265,6 +265,8 @@ operator_lookup = { "json_path_getitem_op": (_binary_operate, ), "json_getitem_op": (_binary_operate, ), "concat_op": (_binary_operate,), + "any_op": (_scalar, CollectionAggregate._create_any), + "all_op": (_scalar, CollectionAggregate._create_all), "lt": (_boolean_compare, operators.ge), "le": (_boolean_compare, operators.gt), "ne": (_boolean_compare, operators.eq), diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py index a14afcb702..ef6f78929f 100644 --- a/lib/sqlalchemy/sql/operators.py +++ b/lib/sqlalchemy/sql/operators.py @@ -802,6 +802,22 @@ class ColumnOperators(Operators): """Produce a :func:`~.expression.any_` clause against the parent object. + This operator is only appropriate against a scalar subquery + object, or for some backends an column expression that is + against the ARRAY type, e.g.:: + + # postgresql '5 = ANY (somearray)' + expr = 5 == mytable.c.somearray.any_() + + # mysql '5 = ANY (SELECT value FROM table)' + expr = 5 == select([table.c.value]).as_scalar().any_() + + .. seealso:: + + :func:`~.expression.any_` - standalone version + + :func:`~.expression.all_` - ALL operator + .. versionadded:: 1.1 """ @@ -811,6 +827,22 @@ class ColumnOperators(Operators): """Produce a :func:`~.expression.all_` clause against the parent object. + This operator is only appropriate against a scalar subquery + object, or for some backends an column expression that is + against the ARRAY type, e.g.:: + + # postgresql '5 = ALL (somearray)' + expr = 5 == mytable.c.somearray.all_() + + # mysql '5 = ALL (SELECT value FROM table)' + expr = 5 == select([table.c.value]).as_scalar().all_() + + .. seealso:: + + :func:`~.expression.all_` - standalone version + + :func:`~.expression.any_` - ANY operator + .. versionadded:: 1.1 """ diff --git a/test/sql/test_operators.py b/test/sql/test_operators.py index 61295467d7..2a11688444 100644 --- a/test/sql/test_operators.py +++ b/test/sql/test_operators.py @@ -2714,6 +2714,15 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"param_1": 5} ) + def test_any_array_method(self): + t = self._fixture() + + self.assert_compile( + 5 == t.c.arrval.any_(), + ":param_1 = ANY (tab1.arrval)", + checkparams={"param_1": 5} + ) + def test_all_array(self): t = self._fixture() @@ -2723,6 +2732,15 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"param_1": 5} ) + def test_all_array_method(self): + t = self._fixture() + + self.assert_compile( + 5 == t.c.arrval.all_(), + ":param_1 = ALL (tab1.arrval)", + checkparams={"param_1": 5} + ) + def test_any_comparator_array(self): t = self._fixture() @@ -2831,6 +2849,16 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={'data_1': 10, 'param_1': 5} ) + def test_any_subq_method(self): + t = self._fixture() + + self.assert_compile( + 5 == select([t.c.data]).where(t.c.data < 10).as_scalar().any_(), + ":param_1 = ANY (SELECT tab1.data " + "FROM tab1 WHERE tab1.data < :data_1)", + checkparams={'data_1': 10, 'param_1': 5} + ) + def test_all_subq(self): t = self._fixture() @@ -2840,3 +2868,13 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): "FROM tab1 WHERE tab1.data < :data_1)", checkparams={'data_1': 10, 'param_1': 5} ) + + def test_all_subq_method(self): + t = self._fixture() + + self.assert_compile( + 5 == select([t.c.data]).where(t.c.data < 10).as_scalar().all_(), + ":param_1 = ALL (SELECT tab1.data " + "FROM tab1 WHERE tab1.data < :data_1)", + checkparams={'data_1': 10, 'param_1': 5} + )