sqlalchemy-cratedb 0.41.0.dev0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,65 @@
1
+ # -*- coding: utf-8; -*-
2
+ #
3
+ # Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
4
+ # license agreements. See the NOTICE file distributed with this work for
5
+ # additional information regarding copyright ownership. Crate licenses
6
+ # this file to you under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License. You may
8
+ # obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations
16
+ # under the License.
17
+ #
18
+ # However, if you have executed another commercial license agreement
19
+ # with Crate these terms will supersede the license and you may use the
20
+ # software solely pursuant to the terms of the relevant commercial agreement.
21
+
22
+ from .compat.api13 import monkeypatch_add_exec_driver_sql
23
+ from .dialect import dialect
24
+ from .predicate import match
25
+ from .sa_version import SA_1_4, SA_VERSION
26
+ from .support import insert_bulk
27
+ from .type.array import ObjectArray
28
+ from .type.geo import Geopoint, Geoshape
29
+ from .type.object import ObjectType
30
+ from .type.vector import FloatVector, knn_match
31
+
32
+ if SA_VERSION < SA_1_4:
33
+ import textwrap
34
+ import warnings
35
+
36
+ # SQLAlchemy 1.3 is effectively EOL.
37
+ SA13_DEPRECATION_WARNING = textwrap.dedent(
38
+ """
39
+ WARNING: SQLAlchemy 1.3 is effectively EOL.
40
+
41
+ SQLAlchemy 1.3 is EOL since 2023-01-27.
42
+ Future versions of the CrateDB SQLAlchemy dialect will drop support for SQLAlchemy 1.3.
43
+ It is recommended that you transition to using SQLAlchemy 1.4 or 2.0:
44
+
45
+ - https://docs.sqlalchemy.org/en/14/changelog/migration_14.html
46
+ - https://docs.sqlalchemy.org/en/20/changelog/migration_20.html
47
+ """.lstrip("\n")
48
+ )
49
+ warnings.warn(message=SA13_DEPRECATION_WARNING, category=DeprecationWarning, stacklevel=2)
50
+
51
+ # SQLAlchemy 1.3 does not have the `exec_driver_sql` method, so add it.
52
+ monkeypatch_add_exec_driver_sql()
53
+
54
+
55
+ __all__ = [
56
+ dialect,
57
+ FloatVector,
58
+ Geopoint,
59
+ Geoshape,
60
+ ObjectArray,
61
+ ObjectType,
62
+ match,
63
+ knn_match,
64
+ insert_bulk,
65
+ ]
File without changes
@@ -0,0 +1,152 @@
1
+ # -*- coding: utf-8; -*-
2
+ #
3
+ # Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
4
+ # license agreements. See the NOTICE file distributed with this work for
5
+ # additional information regarding copyright ownership. Crate licenses
6
+ # this file to you under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License. You may
8
+ # obtain a copy of the License at
9
+ #
10
+ # https://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations
16
+ # under the License.
17
+ #
18
+ # However, if you have executed another commercial license agreement
19
+ # with Crate these terms will supersede the license and you may use the
20
+ # software solely pursuant to the terms of the relevant commercial agreement.
21
+
22
+ """
23
+ Compatibility module for running a subset of SQLAlchemy 2.0 programs on
24
+ SQLAlchemy 1.3. By using monkey-patching, it can do two things:
25
+
26
+ 1. Add the `exec_driver_sql` method to SA's `Connection` and `Engine`.
27
+ 2. Amend the `sql.select` function to accept the calling semantics of
28
+ the modern variant.
29
+
30
+ Reason: `exec_driver_sql` gets used within the CrateDB dialect already,
31
+ and the new calling semantics of `sql.select` already get used within
32
+ many of the test cases already. Please note that the patch for
33
+ `sql.select` is only applied when running the test suite.
34
+ """
35
+
36
+ import collections.abc as collections_abc
37
+
38
+ from sqlalchemy import exc
39
+ from sqlalchemy.sql import Select
40
+ from sqlalchemy.sql import select as original_select
41
+ from sqlalchemy.util import immutabledict
42
+
43
+ # `_distill_params_20` copied from SA14's `sqlalchemy.engine.{base,util}`.
44
+ _no_tuple = ()
45
+ _no_kw = immutabledict()
46
+
47
+
48
+ def _distill_params_20(params):
49
+ if params is None:
50
+ return _no_tuple, _no_kw
51
+ elif isinstance(params, list):
52
+ # collections_abc.MutableSequence): # avoid abc.__instancecheck__
53
+ if params and not isinstance(params[0], (collections_abc.Mapping, tuple)):
54
+ raise exc.ArgumentError("List argument must consist only of tuples or dictionaries")
55
+
56
+ return (params,), _no_kw
57
+ elif isinstance(
58
+ params,
59
+ (tuple, dict, immutabledict),
60
+ # only do abc.__instancecheck__ for Mapping after we've checked
61
+ # for plain dictionaries and would otherwise raise
62
+ ) or isinstance(params, collections_abc.Mapping):
63
+ return (params,), _no_kw
64
+ else:
65
+ raise exc.ArgumentError("mapping or sequence expected for parameters")
66
+
67
+
68
+ def exec_driver_sql(self, statement, parameters=None, execution_options=None):
69
+ """
70
+ Adapter for `exec_driver_sql`, which is available since SA14, for SA13.
71
+ """
72
+ if execution_options is not None:
73
+ raise ValueError(
74
+ "SA13 backward-compatibility: `exec_driver_sql` does not support `execution_options`"
75
+ )
76
+ args_10style, kwargs_10style = _distill_params_20(parameters)
77
+ return self.execute(statement, *args_10style, **kwargs_10style)
78
+
79
+
80
+ def monkeypatch_add_exec_driver_sql():
81
+ """
82
+ Transparently add SA14's `exec_driver_sql()` method to SA13.
83
+
84
+ AttributeError: 'Connection' object has no attribute 'exec_driver_sql'
85
+ AttributeError: 'Engine' object has no attribute 'exec_driver_sql'
86
+ """
87
+ from sqlalchemy.engine.base import Connection, Engine
88
+
89
+ # Add `exec_driver_sql` method to SA's `Connection` and `Engine` classes.
90
+ Connection.exec_driver_sql = exec_driver_sql
91
+ Engine.exec_driver_sql = exec_driver_sql
92
+
93
+
94
+ def select_sa14(*columns, **kw) -> Select:
95
+ """
96
+ Adapt SA14/SA20's calling semantics of `sql.select()` to SA13.
97
+
98
+ With SA20, `select()` no longer accepts varied constructor arguments, only
99
+ the "generative" style of `select()` will be supported. The list of columns
100
+ / tables to select from should be passed positionally.
101
+
102
+ Derived from https://github.com/sqlalchemy/alembic/blob/b1fad6b6/alembic/util/sqla_compat.py#L557-L558
103
+
104
+ sqlalchemy.exc.ArgumentError: columns argument to select() must be a Python list or other iterable
105
+ """ # noqa: E501
106
+ if isinstance(columns, tuple) and isinstance(columns[0], list):
107
+ if "whereclause" in kw:
108
+ raise ValueError(
109
+ "SA13 backward-compatibility: `whereclause` is both in kwargs and columns tuple"
110
+ )
111
+ columns, whereclause = columns
112
+ kw["whereclause"] = whereclause
113
+ return original_select(columns, **kw)
114
+
115
+
116
+ def monkeypatch_amend_select_sa14():
117
+ """
118
+ Make SA13's `sql.select()` transparently accept calling semantics of SA14
119
+ and SA20, by swapping in the newer variant of `select_sa14()`.
120
+
121
+ This supports the test suite, because it already uses the modern calling
122
+ semantics.
123
+ """
124
+ import sqlalchemy
125
+
126
+ sqlalchemy.select = select_sa14
127
+ sqlalchemy.sql.select = select_sa14
128
+ sqlalchemy.sql.expression.select = select_sa14
129
+
130
+
131
+ @property
132
+ def connectionfairy_driver_connection_sa14(self):
133
+ """The connection object as returned by the driver after a connect.
134
+
135
+ .. versionadded:: 1.4.24
136
+
137
+ .. seealso::
138
+
139
+ :attr:`._ConnectionFairy.dbapi_connection`
140
+
141
+ :attr:`._ConnectionRecord.driver_connection`
142
+
143
+ :ref:`faq_dbapi_connection`
144
+
145
+ """
146
+ return self.connection
147
+
148
+
149
+ def monkeypatch_add_connectionfairy_driver_connection():
150
+ import sqlalchemy.pool.base
151
+
152
+ sqlalchemy.pool.base._ConnectionFairy.driver_connection = connectionfairy_driver_connection_sa14
@@ -0,0 +1,253 @@
1
+ # -*- coding: utf-8; -*-
2
+ #
3
+ # Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
4
+ # license agreements. See the NOTICE file distributed with this work for
5
+ # additional information regarding copyright ownership. Crate licenses
6
+ # this file to you under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License. You may
8
+ # obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations
16
+ # under the License.
17
+ #
18
+ # However, if you have executed another commercial license agreement
19
+ # with Crate these terms will supersede the license and you may use the
20
+ # software solely pursuant to the terms of the relevant commercial agreement.
21
+
22
+ import sqlalchemy as sa
23
+ from sqlalchemy.dialects.postgresql.base import PGCompiler
24
+ from sqlalchemy.sql.crud import (
25
+ REQUIRED,
26
+ _create_bind_param,
27
+ _extend_values_for_multiparams,
28
+ _get_multitable_params,
29
+ _get_stmt_parameters_params,
30
+ _key_getters_for_crud_column,
31
+ _scan_cols,
32
+ _scan_insert_from_select_cols,
33
+ )
34
+
35
+ from sqlalchemy_cratedb.compiler import CrateCompiler
36
+
37
+
38
+ class CrateCompilerSA10(CrateCompiler):
39
+ def returning_clause(self, stmt, returning_cols):
40
+ """
41
+ Generate RETURNING clause, PostgreSQL-compatible.
42
+ """
43
+ return PGCompiler.returning_clause(self, stmt, returning_cols)
44
+
45
+ def visit_update(self, update_stmt, **kw):
46
+ """
47
+ used to compile <sql.expression.Update> expressions
48
+ Parts are taken from the SQLCompiler base class.
49
+ """
50
+
51
+ # [10] CrateDB patch.
52
+ if not update_stmt.parameters and not hasattr(update_stmt, "_crate_specific"):
53
+ return super().visit_update(update_stmt, **kw)
54
+
55
+ self.isupdate = True
56
+
57
+ extra_froms = update_stmt._extra_froms
58
+
59
+ text = "UPDATE "
60
+
61
+ if update_stmt._prefixes:
62
+ text += self._generate_prefixes(update_stmt, update_stmt._prefixes, **kw)
63
+
64
+ table_text = self.update_tables_clause(update_stmt, update_stmt.table, extra_froms, **kw)
65
+
66
+ dialect_hints = None
67
+ if update_stmt._hints:
68
+ dialect_hints, table_text = self._setup_crud_hints(update_stmt, table_text)
69
+
70
+ # [10] CrateDB patch.
71
+ crud_params = _get_crud_params(self, update_stmt, **kw)
72
+
73
+ text += table_text
74
+
75
+ text += " SET "
76
+
77
+ # [10] CrateDB patch begin.
78
+ include_table = extra_froms and self.render_table_with_column_in_update_from
79
+
80
+ set_clauses = []
81
+
82
+ for k, v in crud_params:
83
+ clause = k._compiler_dispatch(self, include_table=include_table) + " = " + v
84
+ set_clauses.append(clause)
85
+
86
+ for k, v in update_stmt.parameters.items():
87
+ if isinstance(k, str) and "[" in k:
88
+ bindparam = sa.sql.bindparam(k, v)
89
+ set_clauses.append(k + " = " + self.process(bindparam))
90
+
91
+ text += ", ".join(set_clauses)
92
+ # [10] CrateDB patch end.
93
+
94
+ if self.returning or update_stmt._returning:
95
+ if not self.returning:
96
+ self.returning = update_stmt._returning
97
+ if self.returning_precedes_values:
98
+ text += " " + self.returning_clause(update_stmt, self.returning)
99
+
100
+ if extra_froms:
101
+ extra_from_text = self.update_from_clause(
102
+ update_stmt, update_stmt.table, extra_froms, dialect_hints, **kw
103
+ )
104
+ if extra_from_text:
105
+ text += " " + extra_from_text
106
+
107
+ if update_stmt._whereclause is not None:
108
+ t = self.process(update_stmt._whereclause)
109
+ if t:
110
+ text += " WHERE " + t
111
+
112
+ limit_clause = self.update_limit_clause(update_stmt)
113
+ if limit_clause:
114
+ text += " " + limit_clause
115
+
116
+ if self.returning and not self.returning_precedes_values:
117
+ text += " " + self.returning_clause(update_stmt, self.returning)
118
+
119
+ return text
120
+
121
+
122
+ def _get_crud_params(compiler, stmt, **kw):
123
+ """create a set of tuples representing column/string pairs for use
124
+ in an INSERT or UPDATE statement.
125
+
126
+ Also generates the Compiled object's postfetch, prefetch, and
127
+ returning column collections, used for default handling and ultimately
128
+ populating the ResultProxy's prefetch_cols() and postfetch_cols()
129
+ collections.
130
+
131
+ """
132
+
133
+ compiler.postfetch = []
134
+ compiler.insert_prefetch = []
135
+ compiler.update_prefetch = []
136
+ compiler.returning = []
137
+
138
+ # no parameters in the statement, no parameters in the
139
+ # compiled params - return binds for all columns
140
+ if compiler.column_keys is None and stmt.parameters is None:
141
+ return [
142
+ (c, _create_bind_param(compiler, c, None, required=True)) for c in stmt.table.columns
143
+ ]
144
+
145
+ if stmt._has_multi_parameters:
146
+ stmt_parameters = stmt.parameters[0]
147
+ else:
148
+ stmt_parameters = stmt.parameters
149
+
150
+ # getters - these are normally just column.key,
151
+ # but in the case of mysql multi-table update, the rules for
152
+ # .key must conditionally take tablename into account
153
+ (
154
+ _column_as_key,
155
+ _getattr_col_key,
156
+ _col_bind_name,
157
+ ) = _key_getters_for_crud_column(compiler, stmt)
158
+
159
+ # if we have statement parameters - set defaults in the
160
+ # compiled params
161
+ if compiler.column_keys is None:
162
+ parameters = {}
163
+ else:
164
+ parameters = dict(
165
+ (_column_as_key(key), REQUIRED)
166
+ for key in compiler.column_keys
167
+ if not stmt_parameters or key not in stmt_parameters
168
+ )
169
+
170
+ # create a list of column assignment clauses as tuples
171
+ values = []
172
+
173
+ if stmt_parameters is not None:
174
+ _get_stmt_parameters_params(
175
+ compiler, parameters, stmt_parameters, _column_as_key, values, kw
176
+ )
177
+
178
+ check_columns = {}
179
+
180
+ # special logic that only occurs for multi-table UPDATE
181
+ # statements
182
+ if compiler.isupdate and stmt._extra_froms and stmt_parameters:
183
+ _get_multitable_params(
184
+ compiler,
185
+ stmt,
186
+ stmt_parameters,
187
+ check_columns,
188
+ _col_bind_name,
189
+ _getattr_col_key,
190
+ values,
191
+ kw,
192
+ )
193
+
194
+ if compiler.isinsert and stmt.select_names:
195
+ _scan_insert_from_select_cols(
196
+ compiler,
197
+ stmt,
198
+ parameters,
199
+ _getattr_col_key,
200
+ _column_as_key,
201
+ _col_bind_name,
202
+ check_columns,
203
+ values,
204
+ kw,
205
+ )
206
+ else:
207
+ _scan_cols(
208
+ compiler,
209
+ stmt,
210
+ parameters,
211
+ _getattr_col_key,
212
+ _column_as_key,
213
+ _col_bind_name,
214
+ check_columns,
215
+ values,
216
+ kw,
217
+ )
218
+
219
+ # [10] CrateDB patch.
220
+ #
221
+ # This sanity check performed by SQLAlchemy currently needs to be
222
+ # deactivated in order to satisfy the rewriting logic of the CrateDB
223
+ # dialect in `rewrite_update` and `visit_update`.
224
+ #
225
+ # It can be quickly reproduced by activating this section and running the
226
+ # test cases::
227
+ #
228
+ # ./bin/test -vvvv -t dict_test
229
+ #
230
+ # That croaks like::
231
+ #
232
+ # sqlalchemy.exc.CompileError: Unconsumed column names: characters_name, data['nested']
233
+ #
234
+ # TODO: Investigate why this is actually happening and eventually mitigate
235
+ # the root cause.
236
+ """
237
+ if parameters and stmt_parameters:
238
+ check = (
239
+ set(parameters)
240
+ .intersection(_column_as_key(k) for k in stmt_parameters)
241
+ .difference(check_columns)
242
+ )
243
+ if check:
244
+ raise exc.CompileError(
245
+ "Unconsumed column names: %s"
246
+ % (", ".join("%s" % c for c in check))
247
+ )
248
+ """
249
+
250
+ if stmt._has_multi_parameters:
251
+ values = _extend_values_for_multiparams(compiler, stmt, values, kw)
252
+
253
+ return values