From 88e4846e02795a777a1a99c40e1c1207bb675166 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Wed, 21 Dec 2022 22:00:39 +0100 Subject: [PATCH 1/3] Revert "SA20: Address deprecation warnings in SqlAlchemyDictTypeTest" This reverts commit b20fabad0aa9330db4cbeabf243dff49129eb399. --- .../client/sqlalchemy/tests/dict_test.py | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/crate/client/sqlalchemy/tests/dict_test.py b/src/crate/client/sqlalchemy/tests/dict_test.py index 655b55a4..5bd9ceed 100644 --- a/src/crate/client/sqlalchemy/tests/dict_test.py +++ b/src/crate/client/sqlalchemy/tests/dict_test.py @@ -37,11 +37,12 @@ class SqlAlchemyDictTypeTest(TestCase): + def setUp(self): self.engine = sa.create_engine('crate://') - metadata = sa.MetaData() - self.mytable = sa.Table('mytable', - metadata, + # FIXME: Deprecated with SA20. + metadata = sa.MetaData(bind=self.engine) + self.mytable = sa.Table('mytable', metadata, sa.Column('name', sa.String), sa.Column('data', Craty)) @@ -51,7 +52,7 @@ def assertSQL(self, expected_str, actual_expr): def test_select_with_dict_column(self): mytable = self.mytable self.assertSQL( - "SELECT mytable.data[:data_1] AS anon_1 FROM mytable", + "SELECT mytable.data['x'] AS anon_1 FROM mytable", select(mytable.c.data['x']) ) @@ -60,7 +61,7 @@ def test_select_with_dict_column_where_clause(self): s = select(mytable.c.data).\ where(mytable.c.data['x'] == 1) self.assertSQL( - "SELECT mytable.data FROM mytable WHERE mytable.data[:data_1] = :param_1", + "SELECT mytable.data FROM mytable WHERE mytable.data['x'] = ?", s ) @@ -70,7 +71,7 @@ def test_select_with_dict_column_nested_where(self): s = s.where(mytable.c.data['x']['y'] == 1) self.assertSQL( "SELECT mytable.name FROM mytable " + - "WHERE mytable.data[:data_1][:param_1] = :param_2", + "WHERE mytable.data['x']['y'] = ?", s ) @@ -79,7 +80,7 @@ def test_select_with_dict_column_where_clause_gt(self): s = select(mytable.c.data).\ where(mytable.c.data['x'] > 1) self.assertSQL( - "SELECT mytable.data FROM mytable WHERE mytable.data[:data_1] > :param_1", + "SELECT mytable.data FROM mytable WHERE mytable.data['x'] > ?", s ) @@ -89,7 +90,7 @@ def test_select_with_dict_column_where_clause_other_col(self): s = s.where(mytable.c.data['x'] == mytable.c.name) self.assertSQL( "SELECT mytable.name FROM mytable " + - "WHERE mytable.data[:data_1] = mytable.name", + "WHERE mytable.data['x'] = mytable.name", s ) @@ -97,10 +98,11 @@ def test_update_with_dict_column(self): mytable = self.mytable stmt = mytable.update().\ where(mytable.c.name == 'Arthur Dent').\ - values({mytable.c.data['x']: "Trillian"}) - + values({ + "data['x']": "Trillian" + }) self.assertSQL( - "UPDATE mytable SET data[:data_1]=:param_1 WHERE mytable.name = :name_1", + "UPDATE mytable SET data['x'] = ? WHERE mytable.name = ?", stmt ) From 01b5a09301e401a512d49bcb46342560e43a6483 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Wed, 21 Dec 2022 22:22:35 +0100 Subject: [PATCH 2/3] SA20: Fix SqlAlchemyDictTypeTest "Implicit" and "Connectionless" execution, and "bound metadata" have been removed beginning with SQLAlchemy 2.0 [1]. Earlier and contemporary versions of SQLAlchemy had the ability to associate an `Engine` with a `MetaData` object. This allowed a number of so-called "connectionless" execution patterns. That is no longer possible. Instead, the association with an `Engine` object has to be concluded differently. On this very spot, in the context of the `dict_test` test cases, the most easy fix was to move it to the invocation of the `compile()` method of the `selectable` instance, which is now returned by the `sqlalchemy.sql.*` primitives: expression = selectable.compile(bind=self.engine) This is needed, because otherwise, when not associating `Engine` with `MetaData` properly, `CrateDialect` would be bypassed, and the "paramstyle" [2] of SQLAlchemy's `DefaultDialect` would be used, which is actually "named" [3], as originally reflected per b20fabad0. This is probably wrong, because the CrateDB Python driver uses the "qmark" paramstyle [4]. [1] https://docs.sqlalchemy.org/en/20/changelog/migration_20.html#implicit-and-connectionless-execution-bound-metadata-removed [2] https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.create_engine.params.paramstyle [3] https://github.com/sqlalchemy/sqlalchemy/blob/rel_2_0_0b4/lib/sqlalchemy/engine/default.py#L204 [4] https://github.com/crate/crate-python/blob/0.29.0/src/crate/client/__init__.py#L36 --- src/crate/client/sqlalchemy/tests/dict_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crate/client/sqlalchemy/tests/dict_test.py b/src/crate/client/sqlalchemy/tests/dict_test.py index 5bd9ceed..dbec0eef 100644 --- a/src/crate/client/sqlalchemy/tests/dict_test.py +++ b/src/crate/client/sqlalchemy/tests/dict_test.py @@ -40,13 +40,13 @@ class SqlAlchemyDictTypeTest(TestCase): def setUp(self): self.engine = sa.create_engine('crate://') - # FIXME: Deprecated with SA20. - metadata = sa.MetaData(bind=self.engine) + metadata = sa.MetaData() self.mytable = sa.Table('mytable', metadata, sa.Column('name', sa.String), sa.Column('data', Craty)) - def assertSQL(self, expected_str, actual_expr): + def assertSQL(self, expected_str, selectable): + actual_expr = selectable.compile(bind=self.engine) self.assertEqual(expected_str, str(actual_expr).replace('\n', '')) def test_select_with_dict_column(self): From efca25e5f840708ab833d706348b549035d264fe Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 22 Dec 2022 02:14:40 +0100 Subject: [PATCH 3/3] SA20: Fix SqlAlchemyInsertFromSelectTest By binding the insert clause to an engine, use the "qmark" paramstyle again, instead of falling back to the "named" paramstyle of the default dialect. --- src/crate/client/sqlalchemy/tests/insert_from_select_test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/crate/client/sqlalchemy/tests/insert_from_select_test.py b/src/crate/client/sqlalchemy/tests/insert_from_select_test.py index af8624dd..b4be7005 100644 --- a/src/crate/client/sqlalchemy/tests/insert_from_select_test.py +++ b/src/crate/client/sqlalchemy/tests/insert_from_select_test.py @@ -75,8 +75,7 @@ def test_insert_from_select_triggered(self): ins = insert(self.character_archived).from_select(['name', 'age'], sel) self.session.execute(ins) self.session.commit() - # TODO: Verify if this is correct. self.assertSQL( - "INSERT INTO characters_archive (name, age) SELECT characters.name, characters.age FROM characters WHERE characters.status = :status_1", - ins + "INSERT INTO characters_archive (name, age) SELECT characters.name, characters.age FROM characters WHERE characters.status = ?", + ins.compile(bind=self.engine) )