diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/dialect/postgresql/test_dialect.py | 155 | ||||
| -rw-r--r-- | test/orm/inheritance/test_basic.py | 19 | ||||
| -rw-r--r-- | test/orm/test_bulk.py | 94 | ||||
| -rw-r--r-- | test/orm/test_cycles.py | 102 | ||||
| -rw-r--r-- | test/orm/test_defaults.py | 82 | ||||
| -rw-r--r-- | test/orm/test_unitofwork.py | 52 | ||||
| -rw-r--r-- | test/orm/test_unitofworkv2.py | 461 | ||||
| -rw-r--r-- | test/sql/test_insert.py | 16 |
8 files changed, 664 insertions, 317 deletions
diff --git a/test/dialect/postgresql/test_dialect.py b/test/dialect/postgresql/test_dialect.py index 1fbe870ba..cc0f3b4df 100644 --- a/test/dialect/postgresql/test_dialect.py +++ b/test/dialect/postgresql/test_dialect.py @@ -1,5 +1,6 @@ # coding: utf-8 import datetime +import itertools import logging import logging.handlers @@ -26,10 +27,11 @@ from sqlalchemy import Table from sqlalchemy import testing from sqlalchemy import text from sqlalchemy import TypeDecorator +from sqlalchemy import util from sqlalchemy.dialects.postgresql import base as postgresql from sqlalchemy.dialects.postgresql import psycopg2 as psycopg2_dialect from sqlalchemy.dialects.postgresql.psycopg2 import EXECUTEMANY_BATCH -from sqlalchemy.dialects.postgresql.psycopg2 import EXECUTEMANY_DEFAULT +from sqlalchemy.dialects.postgresql.psycopg2 import EXECUTEMANY_PLAIN from sqlalchemy.dialects.postgresql.psycopg2 import EXECUTEMANY_VALUES from sqlalchemy.engine import cursor as _cursor from sqlalchemy.engine import engine_from_config @@ -45,6 +47,8 @@ from sqlalchemy.testing.assertions import AssertsExecutionResults from sqlalchemy.testing.assertions import eq_ from sqlalchemy.testing.assertions import eq_regex from sqlalchemy.testing.assertions import ne_ +from sqlalchemy.util import u +from sqlalchemy.util import ue from ...engine import test_execute if True: @@ -160,6 +164,7 @@ class ExecuteManyMode(object): __backend__ = True run_create_tables = "each" + run_deletes = None options = None @@ -174,6 +179,13 @@ class ExecuteManyMode(object): Column("z", Integer, server_default="5"), ) + Table( + u("Unitéble2"), + metadata, + Column(u("méil"), Integer, primary_key=True), + Column(ue("\u6e2c\u8a66"), Integer), + ) + def setup(self): super(ExecuteManyMode, self).setup() self.engine = engines.testing_engine(options=self.options) @@ -343,6 +355,22 @@ class ExecuteManyMode(object): ], ) + def test_insert_unicode_keys(self, connection): + table = self.tables[u("Unitéble2")] + + stmt = table.insert() + + connection.execute( + stmt, + [ + {u("méil"): 1, ue("\u6e2c\u8a66"): 1}, + {u("méil"): 2, ue("\u6e2c\u8a66"): 2}, + {u("méil"): 3, ue("\u6e2c\u8a66"): 3}, + ], + ) + + eq_(connection.execute(table.select()).all(), [(1, 1), (2, 2), (3, 3)]) + def test_update_fallback(self): from psycopg2 import extras @@ -423,57 +451,104 @@ class ExecutemanyBatchModeTest(ExecuteManyMode, fixtures.TablesTest): class ExecutemanyValuesInsertsTest(ExecuteManyMode, fixtures.TablesTest): options = {"executemany_mode": "values_only"} - def test_insert_returning_values(self): + def test_insert_returning_values(self, connection): """the psycopg2 dialect needs to assemble a fully buffered result with the return value of execute_values(). """ t = self.tables.data - with self.engine.connect() as conn: - page_size = conn.dialect.executemany_values_page_size or 100 - data = [ - {"x": "x%d" % i, "y": "y%d" % i} - for i in range(1, page_size * 5 + 27) - ] - result = conn.execute(t.insert().returning(t.c.x, t.c.y), data) - - eq_([tup[0] for tup in result.cursor.description], ["x", "y"]) - eq_(result.keys(), ["x", "y"]) - assert t.c.x in result.keys() - assert t.c.id not in result.keys() - assert not result._soft_closed - assert isinstance( - result.cursor_strategy, - _cursor.FullyBufferedCursorFetchStrategy, - ) - assert not result.cursor.closed - assert not result.closed - eq_(result.mappings().all(), data) + conn = connection + page_size = conn.dialect.executemany_values_page_size or 100 + data = [ + {"x": "x%d" % i, "y": "y%d" % i} + for i in range(1, page_size * 5 + 27) + ] + result = conn.execute(t.insert().returning(t.c.x, t.c.y), data) + + eq_([tup[0] for tup in result.cursor.description], ["x", "y"]) + eq_(result.keys(), ["x", "y"]) + assert t.c.x in result.keys() + assert t.c.id not in result.keys() + assert not result._soft_closed + assert isinstance( + result.cursor_strategy, _cursor.FullyBufferedCursorFetchStrategy, + ) + assert not result.cursor.closed + assert not result.closed + eq_(result.mappings().all(), data) + + assert result._soft_closed + # assert result.closed + assert result.cursor is None + + @testing.provide_metadata + def test_insert_returning_preexecute_pk(self, connection): + counter = itertools.count(1) + + t = Table( + "t", + self.metadata, + Column( + "id", + Integer, + primary_key=True, + default=lambda: util.next(counter), + ), + Column("data", Integer), + ) + self.metadata.create_all(connection) + + result = connection.execute( + t.insert().return_defaults(), + [{"data": 1}, {"data": 2}, {"data": 3}], + ) - assert result._soft_closed - # assert result.closed - assert result.cursor is None + eq_(result.inserted_primary_key_rows, [(1,), (2,), (3,)]) - def test_insert_returning_defaults(self): + def test_insert_returning_defaults(self, connection): t = self.tables.data - with self.engine.connect() as conn: + conn = connection - result = conn.execute(t.insert(), {"x": "x0", "y": "y0"}) - first_pk = result.inserted_primary_key[0] + result = conn.execute(t.insert(), {"x": "x0", "y": "y0"}) + first_pk = result.inserted_primary_key[0] - page_size = conn.dialect.executemany_values_page_size or 100 - total_rows = page_size * 5 + 27 - data = [ - {"x": "x%d" % i, "y": "y%d" % i} for i in range(1, total_rows) - ] - result = conn.execute(t.insert().returning(t.c.id, t.c.z), data) + page_size = conn.dialect.executemany_values_page_size or 100 + total_rows = page_size * 5 + 27 + data = [{"x": "x%d" % i, "y": "y%d" % i} for i in range(1, total_rows)] + result = conn.execute(t.insert().returning(t.c.id, t.c.z), data) - eq_( - result.all(), - [(pk, 5) for pk in range(1 + first_pk, total_rows + first_pk)], - ) + eq_( + result.all(), + [(pk, 5) for pk in range(1 + first_pk, total_rows + first_pk)], + ) + + def test_insert_return_pks_default_values(self, connection): + """test sending multiple, empty rows into an INSERT and getting primary + key values back. + + This has to use a format that indicates at least one DEFAULT in + multiple parameter sets, i.e. "INSERT INTO table (anycol) VALUES + (DEFAULT) (DEFAULT) (DEFAULT) ... RETURNING col" + + """ + t = self.tables.data + + conn = connection + + result = conn.execute(t.insert(), {"x": "x0", "y": "y0"}) + first_pk = result.inserted_primary_key[0] + + page_size = conn.dialect.executemany_values_page_size or 100 + total_rows = page_size * 5 + 27 + data = [{} for i in range(1, total_rows)] + result = conn.execute(t.insert().returning(t.c.id), data) + + eq_( + result.all(), + [(pk,) for pk in range(1 + first_pk, total_rows + first_pk)], + ) def test_insert_w_newlines(self): from psycopg2 import extras @@ -611,7 +686,7 @@ class ExecutemanyFlagOptionsTest(fixtures.TablesTest): def test_executemany_correct_flag_options(self): for opt, expected in [ - (None, EXECUTEMANY_DEFAULT), + (None, EXECUTEMANY_PLAIN), ("batch", EXECUTEMANY_BATCH), ("values_only", EXECUTEMANY_VALUES), ("values_plus_batch", EXECUTEMANY_VALUES_PLUS_BATCH), diff --git a/test/orm/inheritance/test_basic.py b/test/orm/inheritance/test_basic.py index e38758ee2..b4a17bf3a 100644 --- a/test/orm/inheritance/test_basic.py +++ b/test/orm/inheritance/test_basic.py @@ -40,6 +40,7 @@ from sqlalchemy.testing import is_ from sqlalchemy.testing import mock from sqlalchemy.testing.assertsql import AllOf from sqlalchemy.testing.assertsql import CompiledSQL +from sqlalchemy.testing.assertsql import Conditional from sqlalchemy.testing.assertsql import Or from sqlalchemy.testing.assertsql import RegexSQL from sqlalchemy.testing.schema import Column @@ -1829,10 +1830,20 @@ class JoinedNoFKSortingTest(fixtures.MappedTest): self.assert_sql_execution( testing.db, sess.flush, - CompiledSQL("INSERT INTO a () VALUES ()", {}), - CompiledSQL("INSERT INTO a () VALUES ()", {}), - CompiledSQL("INSERT INTO a () VALUES ()", {}), - CompiledSQL("INSERT INTO a () VALUES ()", {}), + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO a (id) VALUES (DEFAULT)", [{}, {}, {}, {}] + ), + ], + [ + CompiledSQL("INSERT INTO a () VALUES ()", {}), + CompiledSQL("INSERT INTO a () VALUES ()", {}), + CompiledSQL("INSERT INTO a () VALUES ()", {}), + CompiledSQL("INSERT INTO a () VALUES ()", {}), + ], + ), AllOf( CompiledSQL( "INSERT INTO b (id) VALUES (:id)", [{"id": 1}, {"id": 3}] diff --git a/test/orm/test_bulk.py b/test/orm/test_bulk.py index 79de19f68..27b187342 100644 --- a/test/orm/test_bulk.py +++ b/test/orm/test_bulk.py @@ -9,6 +9,7 @@ from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures from sqlalchemy.testing import mock from sqlalchemy.testing.assertsql import CompiledSQL +from sqlalchemy.testing.assertsql import Conditional from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table from test.orm import _fixtures @@ -91,15 +92,29 @@ class BulkInsertUpdateTest(BulkTest, _fixtures.FixtureTest): s.bulk_save_objects(objects, return_defaults=True) asserter.assert_( - CompiledSQL( - "INSERT INTO users (name) VALUES (:name)", [{"name": "u1"}] - ), - CompiledSQL( - "INSERT INTO users (name) VALUES (:name)", [{"name": "u2"}] - ), - CompiledSQL( - "INSERT INTO users (name) VALUES (:name)", [{"name": "u3"}] - ), + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO users (name) VALUES (:name)", + [{"name": "u1"}, {"name": "u2"}, {"name": "u3"}], + ), + ], + [ + CompiledSQL( + "INSERT INTO users (name) VALUES (:name)", + [{"name": "u1"}], + ), + CompiledSQL( + "INSERT INTO users (name) VALUES (:name)", + [{"name": "u2"}], + ), + CompiledSQL( + "INSERT INTO users (name) VALUES (:name)", + [{"name": "u3"}], + ), + ], + ) ) eq_(objects[0].__dict__["id"], 1) @@ -612,13 +627,30 @@ class BulkInheritanceTest(BulkTest, fixtures.MappedTest): "VALUES (:person_id, :status, :manager_name)", [{"person_id": 1, "status": "s1", "manager_name": "mn1"}], ), - CompiledSQL( - "INSERT INTO people (name, type) VALUES (:name, :type)", - [{"type": "engineer", "name": "e1"}], - ), - CompiledSQL( - "INSERT INTO people (name, type) VALUES (:name, :type)", - [{"type": "engineer", "name": "e2"}], + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO people (name, type) " + "VALUES (:name, :type)", + [ + {"type": "engineer", "name": "e1"}, + {"type": "engineer", "name": "e2"}, + ], + ), + ], + [ + CompiledSQL( + "INSERT INTO people (name, type) " + "VALUES (:name, :type)", + [{"type": "engineer", "name": "e1"}], + ), + CompiledSQL( + "INSERT INTO people (name, type) " + "VALUES (:name, :type)", + [{"type": "engineer", "name": "e2"}], + ), + ], ), CompiledSQL( "INSERT INTO engineers (person_id, status, primary_language) " @@ -762,14 +794,28 @@ class BulkInheritanceTest(BulkTest, fixtures.MappedTest): ) asserter.assert_( - CompiledSQL( - "INSERT INTO people (name) VALUES (:name)", [{"name": "b1"}] - ), - CompiledSQL( - "INSERT INTO people (name) VALUES (:name)", [{"name": "b2"}] - ), - CompiledSQL( - "INSERT INTO people (name) VALUES (:name)", [{"name": "b3"}] + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO people (name) VALUES (:name)", + [{"name": "b1"}, {"name": "b2"}, {"name": "b3"}], + ), + ], + [ + CompiledSQL( + "INSERT INTO people (name) VALUES (:name)", + [{"name": "b1"}], + ), + CompiledSQL( + "INSERT INTO people (name) VALUES (:name)", + [{"name": "b2"}], + ), + CompiledSQL( + "INSERT INTO people (name) VALUES (:name)", + [{"name": "b3"}], + ), + ], ), CompiledSQL( "INSERT INTO managers (person_id, status, manager_name) " diff --git a/test/orm/test_cycles.py b/test/orm/test_cycles.py index 22a26e617..5c61a6370 100644 --- a/test/orm/test_cycles.py +++ b/test/orm/test_cycles.py @@ -25,6 +25,7 @@ from sqlalchemy.testing import is_ from sqlalchemy.testing import mock from sqlalchemy.testing.assertsql import AllOf from sqlalchemy.testing.assertsql import CompiledSQL +from sqlalchemy.testing.assertsql import Conditional from sqlalchemy.testing.assertsql import RegexSQL from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table @@ -910,21 +911,37 @@ class OneToManyManyToOneTest(fixtures.MappedTest): testing.db, sess.flush, RegexSQL("^INSERT INTO person", {"data": "some data"}), - RegexSQL( - "^INSERT INTO ball", - lambda c: {"person_id": p.id, "data": "some data"}, - ), - RegexSQL( - "^INSERT INTO ball", - lambda c: {"person_id": p.id, "data": "some data"}, - ), - RegexSQL( - "^INSERT INTO ball", - lambda c: {"person_id": p.id, "data": "some data"}, - ), - RegexSQL( - "^INSERT INTO ball", - lambda c: {"person_id": p.id, "data": "some data"}, + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + RegexSQL( + "^INSERT INTO ball", + lambda c: [ + {"person_id": p.id, "data": "some data"}, + {"person_id": p.id, "data": "some data"}, + {"person_id": p.id, "data": "some data"}, + {"person_id": p.id, "data": "some data"}, + ], + ) + ], + [ + RegexSQL( + "^INSERT INTO ball", + lambda c: {"person_id": p.id, "data": "some data"}, + ), + RegexSQL( + "^INSERT INTO ball", + lambda c: {"person_id": p.id, "data": "some data"}, + ), + RegexSQL( + "^INSERT INTO ball", + lambda c: {"person_id": p.id, "data": "some data"}, + ), + RegexSQL( + "^INSERT INTO ball", + lambda c: {"person_id": p.id, "data": "some data"}, + ), + ], ), CompiledSQL( "UPDATE person SET favorite_ball_id=:favorite_ball_id " @@ -1054,25 +1071,42 @@ class OneToManyManyToOneTest(fixtures.MappedTest): self.assert_sql_execution( testing.db, sess.flush, - CompiledSQL( - "INSERT INTO ball (person_id, data) " - "VALUES (:person_id, :data)", - {"person_id": None, "data": "some data"}, - ), - CompiledSQL( - "INSERT INTO ball (person_id, data) " - "VALUES (:person_id, :data)", - {"person_id": None, "data": "some data"}, - ), - CompiledSQL( - "INSERT INTO ball (person_id, data) " - "VALUES (:person_id, :data)", - {"person_id": None, "data": "some data"}, - ), - CompiledSQL( - "INSERT INTO ball (person_id, data) " - "VALUES (:person_id, :data)", - {"person_id": None, "data": "some data"}, + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO ball (person_id, data) " + "VALUES (:person_id, :data)", + [ + {"person_id": None, "data": "some data"}, + {"person_id": None, "data": "some data"}, + {"person_id": None, "data": "some data"}, + {"person_id": None, "data": "some data"}, + ], + ), + ], + [ + CompiledSQL( + "INSERT INTO ball (person_id, data) " + "VALUES (:person_id, :data)", + {"person_id": None, "data": "some data"}, + ), + CompiledSQL( + "INSERT INTO ball (person_id, data) " + "VALUES (:person_id, :data)", + {"person_id": None, "data": "some data"}, + ), + CompiledSQL( + "INSERT INTO ball (person_id, data) " + "VALUES (:person_id, :data)", + {"person_id": None, "data": "some data"}, + ), + CompiledSQL( + "INSERT INTO ball (person_id, data) " + "VALUES (:person_id, :data)", + {"person_id": None, "data": "some data"}, + ), + ], ), CompiledSQL( "INSERT INTO person (favorite_ball_id, data) " diff --git a/test/orm/test_defaults.py b/test/orm/test_defaults.py index 5cadea5ff..94397e22a 100644 --- a/test/orm/test_defaults.py +++ b/test/orm/test_defaults.py @@ -11,6 +11,7 @@ from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures from sqlalchemy.testing.assertsql import assert_engine from sqlalchemy.testing.assertsql import CompiledSQL +from sqlalchemy.testing.assertsql import Conditional from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table @@ -229,38 +230,57 @@ class ComputedDefaultsOnUpdateTest(fixtures.MappedTest): eq_(t1.bar, 5 + 42) eq_(t2.bar, 10 + 42) - if eager and testing.db.dialect.implicit_returning: - asserter.assert_( - CompiledSQL( - "INSERT INTO test (id, foo) VALUES (%(id)s, %(foo)s) " - "RETURNING test.bar", - [{"foo": 5, "id": 1}], - dialect="postgresql", - ), - CompiledSQL( - "INSERT INTO test (id, foo) VALUES (%(id)s, %(foo)s) " - "RETURNING test.bar", - [{"foo": 10, "id": 2}], - dialect="postgresql", - ), - ) - else: - asserter.assert_( - CompiledSQL( - "INSERT INTO test (id, foo) VALUES (:id, :foo)", - [{"foo": 5, "id": 1}, {"foo": 10, "id": 2}], - ), - CompiledSQL( - "SELECT test.bar AS test_bar FROM test " - "WHERE test.id = :param_1", - [{"param_1": 1}], - ), - CompiledSQL( - "SELECT test.bar AS test_bar FROM test " - "WHERE test.id = :param_1", - [{"param_1": 2}], - ), + asserter.assert_( + Conditional( + eager and testing.db.dialect.implicit_returning, + [ + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO test (id, foo) " + "VALUES (%(id)s, %(foo)s) " + "RETURNING test.bar", + [{"foo": 5, "id": 1}, {"foo": 10, "id": 2}], + dialect="postgresql", + ), + ], + [ + CompiledSQL( + "INSERT INTO test (id, foo) " + "VALUES (%(id)s, %(foo)s) " + "RETURNING test.bar", + [{"foo": 5, "id": 1}], + dialect="postgresql", + ), + CompiledSQL( + "INSERT INTO test (id, foo) " + "VALUES (%(id)s, %(foo)s) " + "RETURNING test.bar", + [{"foo": 10, "id": 2}], + dialect="postgresql", + ), + ], + ) + ], + [ + CompiledSQL( + "INSERT INTO test (id, foo) VALUES (:id, :foo)", + [{"foo": 5, "id": 1}, {"foo": 10, "id": 2}], + ), + CompiledSQL( + "SELECT test.bar AS test_bar FROM test " + "WHERE test.id = :param_1", + [{"param_1": 1}], + ), + CompiledSQL( + "SELECT test.bar AS test_bar FROM test " + "WHERE test.id = :param_1", + [{"param_1": 2}], + ), + ], ) + ) @testing.combinations( ( diff --git a/test/orm/test_unitofwork.py b/test/orm/test_unitofwork.py index 3a1594a61..306fc0d2a 100644 --- a/test/orm/test_unitofwork.py +++ b/test/orm/test_unitofwork.py @@ -29,6 +29,7 @@ from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures from sqlalchemy.testing.assertsql import AllOf from sqlalchemy.testing.assertsql import CompiledSQL +from sqlalchemy.testing.assertsql import Conditional from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table from sqlalchemy.util import OrderedDict @@ -2789,21 +2790,42 @@ class SaveTest2(_fixtures.FixtureTest): self.assert_sql_execution( testing.db, session.flush, - CompiledSQL( - "INSERT INTO users (name) VALUES (:name)", {"name": "u1"} - ), - CompiledSQL( - "INSERT INTO users (name) VALUES (:name)", {"name": "u2"} - ), - CompiledSQL( - "INSERT INTO addresses (user_id, email_address) " - "VALUES (:user_id, :email_address)", - {"user_id": 1, "email_address": "a1"}, - ), - CompiledSQL( - "INSERT INTO addresses (user_id, email_address) " - "VALUES (:user_id, :email_address)", - {"user_id": 2, "email_address": "a2"}, + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO users (name) VALUES (:name)", + [{"name": "u1"}, {"name": "u2"}], + ), + CompiledSQL( + "INSERT INTO addresses (user_id, email_address) " + "VALUES (:user_id, :email_address)", + [ + {"user_id": 1, "email_address": "a1"}, + {"user_id": 2, "email_address": "a2"}, + ], + ), + ], + [ + CompiledSQL( + "INSERT INTO users (name) VALUES (:name)", + {"name": "u1"}, + ), + CompiledSQL( + "INSERT INTO users (name) VALUES (:name)", + {"name": "u2"}, + ), + CompiledSQL( + "INSERT INTO addresses (user_id, email_address) " + "VALUES (:user_id, :email_address)", + {"user_id": 1, "email_address": "a1"}, + ), + CompiledSQL( + "INSERT INTO addresses (user_id, email_address) " + "VALUES (:user_id, :email_address)", + {"user_id": 2, "email_address": "a2"}, + ), + ], ), ) diff --git a/test/orm/test_unitofworkv2.py b/test/orm/test_unitofworkv2.py index 2bd908c8f..08dd8c966 100644 --- a/test/orm/test_unitofworkv2.py +++ b/test/orm/test_unitofworkv2.py @@ -27,6 +27,7 @@ from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures from sqlalchemy.testing.assertsql import AllOf from sqlalchemy.testing.assertsql import CompiledSQL +from sqlalchemy.testing.assertsql import Conditional from sqlalchemy.testing.mock import Mock from sqlalchemy.testing.mock import patch from sqlalchemy.testing.schema import Column @@ -82,15 +83,30 @@ class RudimentaryFlushTest(UOWTest): CompiledSQL( "INSERT INTO users (name) VALUES (:name)", {"name": "u1"} ), - CompiledSQL( - "INSERT INTO addresses (user_id, email_address) " - "VALUES (:user_id, :email_address)", - lambda ctx: {"email_address": "a1", "user_id": u1.id}, - ), - CompiledSQL( - "INSERT INTO addresses (user_id, email_address) " - "VALUES (:user_id, :email_address)", - lambda ctx: {"email_address": "a2", "user_id": u1.id}, + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO addresses (user_id, email_address) " + "VALUES (:user_id, :email_address)", + lambda ctx: [ + {"email_address": "a1", "user_id": u1.id}, + {"email_address": "a2", "user_id": u1.id}, + ], + ), + ], + [ + CompiledSQL( + "INSERT INTO addresses (user_id, email_address) " + "VALUES (:user_id, :email_address)", + lambda ctx: {"email_address": "a1", "user_id": u1.id}, + ), + CompiledSQL( + "INSERT INTO addresses (user_id, email_address) " + "VALUES (:user_id, :email_address)", + lambda ctx: {"email_address": "a2", "user_id": u1.id}, + ), + ], ), ) @@ -183,15 +199,30 @@ class RudimentaryFlushTest(UOWTest): CompiledSQL( "INSERT INTO users (name) VALUES (:name)", {"name": "u1"} ), - CompiledSQL( - "INSERT INTO addresses (user_id, email_address) " - "VALUES (:user_id, :email_address)", - lambda ctx: {"email_address": "a1", "user_id": u1.id}, - ), - CompiledSQL( - "INSERT INTO addresses (user_id, email_address) " - "VALUES (:user_id, :email_address)", - lambda ctx: {"email_address": "a2", "user_id": u1.id}, + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO addresses (user_id, email_address) " + "VALUES (:user_id, :email_address)", + lambda ctx: [ + {"email_address": "a1", "user_id": u1.id}, + {"email_address": "a2", "user_id": u1.id}, + ], + ), + ], + [ + CompiledSQL( + "INSERT INTO addresses (user_id, email_address) " + "VALUES (:user_id, :email_address)", + lambda ctx: {"email_address": "a1", "user_id": u1.id}, + ), + CompiledSQL( + "INSERT INTO addresses (user_id, email_address) " + "VALUES (:user_id, :email_address)", + lambda ctx: {"email_address": "a2", "user_id": u1.id}, + ), + ], ), ) @@ -767,17 +798,32 @@ class SingleCycleTest(UOWTest): "(:parent_id, :data)", {"parent_id": None, "data": "n1"}, ), - AllOf( - CompiledSQL( - "INSERT INTO nodes (parent_id, data) VALUES " - "(:parent_id, :data)", - lambda ctx: {"parent_id": n1.id, "data": "n2"}, - ), - CompiledSQL( - "INSERT INTO nodes (parent_id, data) VALUES " - "(:parent_id, :data)", - lambda ctx: {"parent_id": n1.id, "data": "n3"}, - ), + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: [ + {"parent_id": n1.id, "data": "n2"}, + {"parent_id": n1.id, "data": "n3"}, + ], + ), + ], + [ + AllOf( + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: {"parent_id": n1.id, "data": "n2"}, + ), + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: {"parent_id": n1.id, "data": "n3"}, + ), + ), + ], ), ) @@ -864,17 +910,32 @@ class SingleCycleTest(UOWTest): "(:parent_id, :data)", {"parent_id": None, "data": "n1"}, ), - AllOf( - CompiledSQL( - "INSERT INTO nodes (parent_id, data) VALUES " - "(:parent_id, :data)", - lambda ctx: {"parent_id": n1.id, "data": "n2"}, - ), - CompiledSQL( - "INSERT INTO nodes (parent_id, data) VALUES " - "(:parent_id, :data)", - lambda ctx: {"parent_id": n1.id, "data": "n3"}, - ), + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: [ + {"parent_id": n1.id, "data": "n2"}, + {"parent_id": n1.id, "data": "n3"}, + ], + ), + ], + [ + AllOf( + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: {"parent_id": n1.id, "data": "n2"}, + ), + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: {"parent_id": n1.id, "data": "n3"}, + ), + ), + ], ), ) @@ -1009,35 +1070,67 @@ class SingleCycleTest(UOWTest): "(:parent_id, :data)", lambda ctx: {"parent_id": None, "data": "n1"}, ), - CompiledSQL( - "INSERT INTO nodes (parent_id, data) VALUES " - "(:parent_id, :data)", - lambda ctx: {"parent_id": n1.id, "data": "n11"}, - ), - CompiledSQL( - "INSERT INTO nodes (parent_id, data) VALUES " - "(:parent_id, :data)", - lambda ctx: {"parent_id": n1.id, "data": "n12"}, - ), - CompiledSQL( - "INSERT INTO nodes (parent_id, data) VALUES " - "(:parent_id, :data)", - lambda ctx: {"parent_id": n1.id, "data": "n13"}, - ), - CompiledSQL( - "INSERT INTO nodes (parent_id, data) VALUES " - "(:parent_id, :data)", - lambda ctx: {"parent_id": n12.id, "data": "n121"}, - ), - CompiledSQL( - "INSERT INTO nodes (parent_id, data) VALUES " - "(:parent_id, :data)", - lambda ctx: {"parent_id": n12.id, "data": "n122"}, + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: [ + {"parent_id": n1.id, "data": "n11"}, + {"parent_id": n1.id, "data": "n12"}, + {"parent_id": n1.id, "data": "n13"}, + ], + ), + ], + [ + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: {"parent_id": n1.id, "data": "n11"}, + ), + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: {"parent_id": n1.id, "data": "n12"}, + ), + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: {"parent_id": n1.id, "data": "n13"}, + ), + ], ), - CompiledSQL( - "INSERT INTO nodes (parent_id, data) VALUES " - "(:parent_id, :data)", - lambda ctx: {"parent_id": n12.id, "data": "n123"}, + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: [ + {"parent_id": n12.id, "data": "n121"}, + {"parent_id": n12.id, "data": "n122"}, + {"parent_id": n12.id, "data": "n123"}, + ], + ), + ], + [ + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: {"parent_id": n12.id, "data": "n121"}, + ), + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: {"parent_id": n12.id, "data": "n122"}, + ), + CompiledSQL( + "INSERT INTO nodes (parent_id, data) VALUES " + "(:parent_id, :data)", + lambda ctx: {"parent_id": n12.id, "data": "n123"}, + ), + ], ), ) @@ -1907,8 +2000,23 @@ class BatchInsertsTest(fixtures.MappedTest, testing.AssertsExecutionResults): self.assert_sql_execution( testing.db, sess.flush, - CompiledSQL("INSERT INTO t (data) VALUES (:data)", {"data": "t1"}), - CompiledSQL("INSERT INTO t (data) VALUES (:data)", {"data": "t2"}), + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO t (data) VALUES (:data)", + [{"data": "t1"}, {"data": "t2"}], + ), + ], + [ + CompiledSQL( + "INSERT INTO t (data) VALUES (:data)", {"data": "t1"} + ), + CompiledSQL( + "INSERT INTO t (data) VALUES (:data)", {"data": "t2"} + ), + ], + ), CompiledSQL( "INSERT INTO t (id, data) VALUES (:id, :data)", [ @@ -2256,40 +2364,56 @@ class EagerDefaultsTest(fixtures.MappedTest): s.add_all([t1, t2]) - if testing.db.dialect.implicit_returning: - self.assert_sql_execution( - testing.db, - s.commit, - CompiledSQL( - "INSERT INTO test (id) VALUES (%(id)s) RETURNING test.foo", - [{"id": 1}], - dialect="postgresql", - ), - CompiledSQL( - "INSERT INTO test (id) VALUES (%(id)s) RETURNING test.foo", - [{"id": 2}], - dialect="postgresql", - ), - ) - else: - self.assert_sql_execution( - testing.db, - s.commit, - CompiledSQL( - "INSERT INTO test (id) VALUES (:id)", - [{"id": 1}, {"id": 2}], - ), - CompiledSQL( - "SELECT test.foo AS test_foo FROM test " - "WHERE test.id = :param_1", - [{"param_1": 1}], - ), - CompiledSQL( - "SELECT test.foo AS test_foo FROM test " - "WHERE test.id = :param_1", - [{"param_1": 2}], - ), - ) + self.assert_sql_execution( + testing.db, + s.commit, + Conditional( + testing.db.dialect.implicit_returning, + [ + Conditional( + testing.db.dialect.insert_executemany_returning, + [ + CompiledSQL( + "INSERT INTO test (id) VALUES (%(id)s) " + "RETURNING test.foo", + [{"id": 1}, {"id": 2}], + dialect="postgresql", + ), + ], + [ + CompiledSQL( + "INSERT INTO test (id) VALUES (%(id)s) " + "RETURNING test.foo", + [{"id": 1}], + dialect="postgresql", + ), + CompiledSQL( + "INSERT INTO test (id) VALUES (%(id)s) " + "RETURNING test.foo", + [{"id": 2}], + dialect="postgresql", + ), + ], + ), + ], + [ + CompiledSQL( + "INSERT INTO test (id) VALUES (:id)", + [{"id": 1}, {"id": 2}], + ), + CompiledSQL( + "SELECT test.foo AS test_foo FROM test " + "WHERE test.id = :param_1", + [{"param_1": 1}], + ), + CompiledSQL( + "SELECT test.foo AS test_foo FROM test " + "WHERE test.id = :param_1", + [{"param_1": 2}], + ), + ], + ), + ) def test_update_defaults_nonpresent(self): Thing2 = self.classes.Thing2 @@ -2312,70 +2436,71 @@ class EagerDefaultsTest(fixtures.MappedTest): t4.foo = 8 t4.bar = 12 - if testing.db.dialect.implicit_returning: - self.assert_sql_execution( - testing.db, - s.flush, - CompiledSQL( - "UPDATE test2 SET foo=%(foo)s " - "WHERE test2.id = %(test2_id)s " - "RETURNING test2.bar", - [{"foo": 5, "test2_id": 1}], - dialect="postgresql", - ), - CompiledSQL( - "UPDATE test2 SET foo=%(foo)s, bar=%(bar)s " - "WHERE test2.id = %(test2_id)s", - [{"foo": 6, "bar": 10, "test2_id": 2}], - dialect="postgresql", - ), - CompiledSQL( - "UPDATE test2 SET foo=%(foo)s " - "WHERE test2.id = %(test2_id)s " - "RETURNING test2.bar", - [{"foo": 7, "test2_id": 3}], - dialect="postgresql", - ), - CompiledSQL( - "UPDATE test2 SET foo=%(foo)s, bar=%(bar)s " - "WHERE test2.id = %(test2_id)s", - [{"foo": 8, "bar": 12, "test2_id": 4}], - dialect="postgresql", - ), - ) - else: - self.assert_sql_execution( - testing.db, - s.flush, - CompiledSQL( - "UPDATE test2 SET foo=:foo WHERE test2.id = :test2_id", - [{"foo": 5, "test2_id": 1}], - ), - CompiledSQL( - "UPDATE test2 SET foo=:foo, bar=:bar " - "WHERE test2.id = :test2_id", - [{"foo": 6, "bar": 10, "test2_id": 2}], - ), - CompiledSQL( - "UPDATE test2 SET foo=:foo WHERE test2.id = :test2_id", - [{"foo": 7, "test2_id": 3}], - ), - CompiledSQL( - "UPDATE test2 SET foo=:foo, bar=:bar " - "WHERE test2.id = :test2_id", - [{"foo": 8, "bar": 12, "test2_id": 4}], - ), - CompiledSQL( - "SELECT test2.bar AS test2_bar FROM test2 " - "WHERE test2.id = :param_1", - [{"param_1": 1}], - ), - CompiledSQL( - "SELECT test2.bar AS test2_bar FROM test2 " - "WHERE test2.id = :param_1", - [{"param_1": 3}], - ), - ) + self.assert_sql_execution( + testing.db, + s.flush, + Conditional( + testing.db.dialect.implicit_returning, + [ + CompiledSQL( + "UPDATE test2 SET foo=%(foo)s " + "WHERE test2.id = %(test2_id)s " + "RETURNING test2.bar", + [{"foo": 5, "test2_id": 1}], + dialect="postgresql", + ), + CompiledSQL( + "UPDATE test2 SET foo=%(foo)s, bar=%(bar)s " + "WHERE test2.id = %(test2_id)s", + [{"foo": 6, "bar": 10, "test2_id": 2}], + dialect="postgresql", + ), + CompiledSQL( + "UPDATE test2 SET foo=%(foo)s " + "WHERE test2.id = %(test2_id)s " + "RETURNING test2.bar", + [{"foo": 7, "test2_id": 3}], + dialect="postgresql", + ), + CompiledSQL( + "UPDATE test2 SET foo=%(foo)s, bar=%(bar)s " + "WHERE test2.id = %(test2_id)s", + [{"foo": 8, "bar": 12, "test2_id": 4}], + dialect="postgresql", + ), + ], + [ + CompiledSQL( + "UPDATE test2 SET foo=:foo WHERE test2.id = :test2_id", + [{"foo": 5, "test2_id": 1}], + ), + CompiledSQL( + "UPDATE test2 SET foo=:foo, bar=:bar " + "WHERE test2.id = :test2_id", + [{"foo": 6, "bar": 10, "test2_id": 2}], + ), + CompiledSQL( + "UPDATE test2 SET foo=:foo WHERE test2.id = :test2_id", + [{"foo": 7, "test2_id": 3}], + ), + CompiledSQL( + "UPDATE test2 SET foo=:foo, bar=:bar " + "WHERE test2.id = :test2_id", + [{"foo": 8, "bar": 12, "test2_id": 4}], + ), + CompiledSQL( + "SELECT test2.bar AS test2_bar FROM test2 " + "WHERE test2.id = :param_1", + [{"param_1": 1}], + ), + CompiledSQL( + "SELECT test2.bar AS test2_bar FROM test2 " + "WHERE test2.id = :param_1", + [{"param_1": 3}], + ), + ], + ), + ) def go(): eq_(t1.bar, 2) diff --git a/test/sql/test_insert.py b/test/sql/test_insert.py index c7749e74c..e5f2fbe6d 100644 --- a/test/sql/test_insert.py +++ b/test/sql/test_insert.py @@ -936,11 +936,25 @@ class EmptyTest(_InsertTestBase, fixtures.TablesTest, AssertsCompiledSQL): dialect = default.DefaultDialect() dialect.supports_empty_insert = dialect.supports_default_values = True - stmt = table1.insert().values({}) # hide from 2to3 + stmt = table1.insert().values({}) self.assert_compile( stmt, "INSERT INTO mytable DEFAULT VALUES", dialect=dialect ) + def test_supports_empty_insert_true_executemany_mode(self): + table1 = self.tables.mytable + + dialect = default.DefaultDialect() + dialect.supports_empty_insert = dialect.supports_default_values = True + + stmt = table1.insert().values({}) + self.assert_compile( + stmt, + "INSERT INTO mytable (myid) VALUES (DEFAULT)", + dialect=dialect, + for_executemany=True, + ) + def test_supports_empty_insert_false(self): table1 = self.tables.mytable |
