From 0b1d8cb4fa678bf8f22b0ab2dd8dc128b7881413 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Mon, 16 Nov 2020 20:29:12 +0100 Subject: [PATCH] Add minimal SQLAlchemy 1.4 compatibility for CrateCompiler > A major initiative in the 1.4 series is to approach the model of both Core SQL statements as well as the ORM Query to allow for an efficient, cacheable model of statement creation and compilation, where the compilation step would be cached, based on a cache key generated by the created statement object, which itself is newly created for each use. While there is probably more to it, this patch tries to at least make the CrateCompiler work with the new subsystem infrastructure. --- src/crate/client/sqlalchemy/compiler.py | 76 ++++++++++++++++++----- src/crate/client/sqlalchemy/sa_version.py | 1 + 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/crate/client/sqlalchemy/compiler.py b/src/crate/client/sqlalchemy/compiler.py index 84945944d..a754ce195 100644 --- a/src/crate/client/sqlalchemy/compiler.py +++ b/src/crate/client/sqlalchemy/compiler.py @@ -26,7 +26,7 @@ from sqlalchemy.sql import crud from sqlalchemy.sql import compiler from .types import MutableDict -from .sa_version import SA_1_1, SA_VERSION +from .sa_version import SA_1_1, SA_1_4, SA_VERSION def rewrite_update(clauseelement, multiparams, params): @@ -198,7 +198,20 @@ def visit_insert(self, insert_stmt, asfrom=False, **kw): "selectable": insert_stmt}) self.isinsert = True - crud_params = crud._get_crud_params(self, insert_stmt, **kw) + + if SA_VERSION >= SA_1_4: + # Minimal patch to be compatible with SQLAlchemy 1.4. + # For a more thorough implementation, please follow + # https://github.com/crate/crate-python/pull/391. + compile_state = insert_stmt._compile_state_factory( + insert_stmt, self, **kw + ) + insert_stmt = compile_state.statement + crud_params = crud._get_crud_params(self, insert_stmt, compile_state, **kw) + _has_multi_parameters = compile_state._has_multi_parameters + else: + crud_params = crud._get_crud_params(self, insert_stmt, **kw) + _has_multi_parameters = insert_stmt._has_multi_parameters if not crud_params and \ not self.dialect.supports_default_values and \ @@ -207,7 +220,7 @@ def visit_insert(self, insert_stmt, asfrom=False, **kw): "The '%s' dialect with current database version settings does " "not support empty inserts." % self.dialect.name) - if insert_stmt._has_multi_parameters: + if _has_multi_parameters: if not self.dialect.supports_multivalues_insert: raise NotImplementedError( "The '%s' dialect with current database " @@ -262,7 +275,7 @@ def visit_insert(self, insert_stmt, asfrom=False, **kw): text += " (%s)" % self.process(self._insert_from_select, **kw) elif not crud_params and supports_default_values: text += " DEFAULT VALUES" - elif insert_stmt._has_multi_parameters: + elif _has_multi_parameters: text += " VALUES %s" % ( ", ".join( "(%s)" % ( @@ -294,7 +307,16 @@ def visit_update(self, update_stmt, **kw): self.isupdate = True - extra_froms = update_stmt._extra_froms + if SA_VERSION >= SA_1_4: + # Minimal patch to be compatible with SQLAlchemy 1.4. + # For a more thorough implementation, please follow + # https://github.com/crate/crate-python/pull/391. + compile_state = update_stmt._compile_state_factory( + update_stmt, compiler, **kw + ) + extra_froms = compile_state._extra_froms + else: + extra_froms = update_stmt._extra_froms text = 'UPDATE ' @@ -351,10 +373,21 @@ def visit_update(self, update_stmt, **kw): if extra_from_text: text += " " + extra_from_text - if update_stmt._whereclause is not None: - t = self.process(update_stmt._whereclause) - if t: - text += " WHERE " + t + if SA_VERSION >= SA_1_4: + # Minimal patch to be compatible with SQLAlchemy 1.4. + # For a more thorough implementation, please follow + # https://github.com/crate/crate-python/pull/391. + if update_stmt._where_criteria: + t = self._generate_delimited_and_list( + update_stmt._where_criteria, **kw + ) + if t: + text += " WHERE " + t + else: + if update_stmt._whereclause is not None: + t = self.process(update_stmt._whereclause) + if t: + text += " WHERE " + t limit_clause = self.update_limit_clause(update_stmt) if limit_clause: @@ -384,20 +417,33 @@ def _get_crud_params(compiler, stmt, **kw): required=True)) for c in stmt.table.columns] - if stmt._has_multi_parameters: - stmt_parameters = stmt.parameters[0] - else: - stmt_parameters = stmt.parameters - # getters - these are normally just column.key, # but in the case of mysql multi-table update, the rules for # .key must conditionally take tablename into account - if SA_VERSION >= SA_1_1: + if SA_VERSION >= SA_1_4: + # Minimal patch to be compatible with SQLAlchemy 1.4. + # For a more thorough implementation, please follow + # https://github.com/crate/crate-python/pull/391. + compile_state = stmt._compile_state_factory( + stmt, compiler, **kw + ) + stmt = compile_state.statement + _column_as_key, _getattr_col_key, _col_bind_name = \ + crud._key_getters_for_crud_column(compiler, stmt, compile_state) + _has_multi_parameters = compile_state._has_multi_parameters + elif SA_VERSION >= SA_1_1: _column_as_key, _getattr_col_key, _col_bind_name = \ crud._key_getters_for_crud_column(compiler, stmt) + _has_multi_parameters = stmt._has_multi_parameters else: _column_as_key, _getattr_col_key, _col_bind_name = \ crud._key_getters_for_crud_column(compiler) + _has_multi_parameters = stmt._has_multi_parameters + + if _has_multi_parameters: + stmt_parameters = stmt.parameters[0] + else: + stmt_parameters = stmt.parameters # if we have statement parameters - set defaults in the # compiled params diff --git a/src/crate/client/sqlalchemy/sa_version.py b/src/crate/client/sqlalchemy/sa_version.py index f51441368..cead74714 100644 --- a/src/crate/client/sqlalchemy/sa_version.py +++ b/src/crate/client/sqlalchemy/sa_version.py @@ -25,3 +25,4 @@ SA_VERSION = V(sa.__version__) SA_1_1 = V('1.1a0') +SA_1_4 = V('1.4.0b1')