From 7d9f241d63b76cf3d4a5f1c146554cd9dc140656 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 3 Apr 2017 14:34:58 -0400 Subject: Add new "expanding" feature to bindparam() Added a new kind of :func:`.bindparam` called "expanding". This is for use in ``IN`` expressions where the list of elements is rendered into individual bound parameters at statement execution time, rather than at statement compilation time. This allows both a single bound parameter name to be linked to an IN expression of multiple elements, as well as allows query caching to be used with IN expressions. The new feature allows the related features of "select in" loading and "polymorphic in" loading to make use of the baked query extension to reduce call overhead. This feature should be considered to be **experimental** for 1.2. Fixes: #3953 Change-Id: Ie708414a3ab9c0af29998a2c7f239ff7633b1f6e --- lib/sqlalchemy/testing/requirements.py | 8 +++++ lib/sqlalchemy/testing/suite/test_select.py | 56 ++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) (limited to 'lib/sqlalchemy/testing') diff --git a/lib/sqlalchemy/testing/requirements.py b/lib/sqlalchemy/testing/requirements.py index d38a69159..95aef0e17 100644 --- a/lib/sqlalchemy/testing/requirements.py +++ b/lib/sqlalchemy/testing/requirements.py @@ -219,6 +219,14 @@ class SuiteRequirements(Requirements): "%(database)s %(does_support)s 'returning'" ) + @property + def tuple_in(self): + """Target platform supports the syntax + "(x, y) IN ((x1, y1), (x2, y2), ...)" + """ + + return exclusions.closed() + @property def duplicate_names_in_cursor_description(self): """target platform supports a SELECT statement that has diff --git a/lib/sqlalchemy/testing/suite/test_select.py b/lib/sqlalchemy/testing/suite/test_select.py index e7de356b8..4086a4c24 100644 --- a/lib/sqlalchemy/testing/suite/test_select.py +++ b/lib/sqlalchemy/testing/suite/test_select.py @@ -2,7 +2,7 @@ from .. import fixtures, config from ..assertions import eq_ from sqlalchemy import util -from sqlalchemy import Integer, String, select, func, bindparam, union +from sqlalchemy import Integer, String, select, func, bindparam, union, tuple_ from sqlalchemy import testing from ..schema import Table, Column @@ -310,3 +310,57 @@ class CompoundSelectTest(fixtures.TablesTest): u1.order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)] ) + + +class ExpandingBoundInTest(fixtures.TablesTest): + __backend__ = True + + @classmethod + def define_tables(cls, metadata): + Table("some_table", metadata, + Column('id', Integer, primary_key=True), + Column('x', Integer), + Column('y', Integer)) + + @classmethod + def insert_data(cls): + config.db.execute( + cls.tables.some_table.insert(), + [ + {"id": 1, "x": 1, "y": 2}, + {"id": 2, "x": 2, "y": 3}, + {"id": 3, "x": 3, "y": 4}, + {"id": 4, "x": 4, "y": 5}, + ] + ) + + def _assert_result(self, select, result, params=()): + eq_( + config.db.execute(select, params).fetchall(), + result + ) + + def test_bound_in_scalar(self): + table = self.tables.some_table + + stmt = select([table.c.id]).where( + table.c.x.in_(bindparam('q', expanding=True))) + + self._assert_result( + stmt, + [(2, ), (3, ), (4, )], + params={"q": [2, 3, 4]}, + ) + + @testing.requires.tuple_in + def test_bound_in_two_tuple(self): + table = self.tables.some_table + + stmt = select([table.c.id]).where( + tuple_(table.c.x, table.c.y).in_(bindparam('q', expanding=True))) + + self._assert_result( + stmt, + [(2, ), (3, ), (4, )], + params={"q": [(2, 3), (3, 4), (4, 5)]}, + ) -- cgit v1.2.1