crate 0.29.0__py2.py3-none-any.whl → 0.30.1__py2.py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. crate/client/__init__.py +1 -1
  2. crate/client/_pep440.py +501 -0
  3. crate/client/connection.py +3 -3
  4. crate/client/sqlalchemy/__init__.py +24 -0
  5. crate/client/sqlalchemy/compat/__init__.py +0 -0
  6. crate/client/sqlalchemy/compat/api13.py +156 -0
  7. crate/client/sqlalchemy/compat/core10.py +264 -0
  8. crate/client/sqlalchemy/compat/core14.py +359 -0
  9. crate/client/sqlalchemy/compat/core20.py +447 -0
  10. crate/client/sqlalchemy/compiler.py +1 -481
  11. crate/client/sqlalchemy/dialect.py +32 -17
  12. crate/client/sqlalchemy/sa_version.py +4 -3
  13. crate/client/sqlalchemy/tests/__init__.py +17 -6
  14. crate/client/sqlalchemy/tests/array_test.py +6 -3
  15. crate/client/sqlalchemy/tests/bulk_test.py +7 -4
  16. crate/client/sqlalchemy/tests/compiler_test.py +10 -9
  17. crate/client/sqlalchemy/tests/connection_test.py +25 -11
  18. crate/client/sqlalchemy/tests/create_table_test.py +19 -16
  19. crate/client/sqlalchemy/tests/datetime_test.py +6 -3
  20. crate/client/sqlalchemy/tests/dialect_test.py +42 -13
  21. crate/client/sqlalchemy/tests/dict_test.py +17 -13
  22. crate/client/sqlalchemy/tests/function_test.py +6 -3
  23. crate/client/sqlalchemy/tests/insert_from_select_test.py +9 -6
  24. crate/client/sqlalchemy/tests/match_test.py +6 -3
  25. crate/client/sqlalchemy/tests/update_test.py +6 -3
  26. crate/client/sqlalchemy/tests/warnings_test.py +33 -0
  27. crate/client/test_connection.py +25 -0
  28. crate/client/tests.py +98 -119
  29. crate/testing/layer.py +1 -1
  30. crate/testing/settings.py +51 -0
  31. crate/testing/test_layer.py +188 -2
  32. crate/testing/tests.py +2 -38
  33. crate/testing/util.py +20 -0
  34. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/METADATA +10 -8
  35. crate-0.30.1.dist-info/RECORD +53 -0
  36. crate-0.29.0.dist-info/RECORD +0 -44
  37. /crate-0.29.0-py3.9-nspkg.pth → /crate-0.30.1-py3.9-nspkg.pth +0 -0
  38. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/LICENSE +0 -0
  39. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/NOTICE +0 -0
  40. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/WHEEL +0 -0
  41. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/entry_points.txt +0 -0
  42. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/namespace_packages.txt +0 -0
  43. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,359 @@
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 import selectable
25
+ from sqlalchemy.sql.crud import (REQUIRED, _create_bind_param,
26
+ _extend_values_for_multiparams,
27
+ _get_stmt_parameter_tuples_params,
28
+ _get_update_multitable_params,
29
+ _key_getters_for_crud_column, _scan_cols,
30
+ _scan_insert_from_select_cols)
31
+
32
+ from crate.client.sqlalchemy.compiler import CrateCompiler
33
+
34
+
35
+ class CrateCompilerSA14(CrateCompiler):
36
+
37
+ def returning_clause(self, stmt, returning_cols):
38
+ """
39
+ Generate RETURNING clause, PostgreSQL-compatible.
40
+ """
41
+ return PGCompiler.returning_clause(self, stmt, returning_cols)
42
+
43
+ def visit_update(self, update_stmt, **kw):
44
+
45
+ compile_state = update_stmt._compile_state_factory(
46
+ update_stmt, self, **kw
47
+ )
48
+ update_stmt = compile_state.statement
49
+
50
+ # [14] CrateDB patch.
51
+ if not compile_state._dict_parameters and \
52
+ not hasattr(update_stmt, '_crate_specific'):
53
+ return super().visit_update(update_stmt, **kw)
54
+
55
+ toplevel = not self.stack
56
+ if toplevel:
57
+ self.isupdate = True
58
+ if not self.compile_state:
59
+ self.compile_state = compile_state
60
+
61
+ extra_froms = compile_state._extra_froms
62
+ is_multitable = bool(extra_froms)
63
+
64
+ if is_multitable:
65
+ # main table might be a JOIN
66
+ main_froms = set(selectable._from_objects(update_stmt.table))
67
+ render_extra_froms = [
68
+ f for f in extra_froms if f not in main_froms
69
+ ]
70
+ correlate_froms = main_froms.union(extra_froms)
71
+ else:
72
+ render_extra_froms = []
73
+ correlate_froms = {update_stmt.table}
74
+
75
+ self.stack.append(
76
+ {
77
+ "correlate_froms": correlate_froms,
78
+ "asfrom_froms": correlate_froms,
79
+ "selectable": update_stmt,
80
+ }
81
+ )
82
+
83
+ text = "UPDATE "
84
+
85
+ if update_stmt._prefixes:
86
+ text += self._generate_prefixes(
87
+ update_stmt, update_stmt._prefixes, **kw
88
+ )
89
+
90
+ table_text = self.update_tables_clause(
91
+ update_stmt, update_stmt.table, render_extra_froms, **kw
92
+ )
93
+
94
+ # [14] CrateDB patch.
95
+ crud_params = _get_crud_params(
96
+ self, update_stmt, compile_state, **kw
97
+ )
98
+
99
+ if update_stmt._hints:
100
+ dialect_hints, table_text = self._setup_crud_hints(
101
+ update_stmt, table_text
102
+ )
103
+ else:
104
+ dialect_hints = None
105
+
106
+ if update_stmt._independent_ctes:
107
+ for cte in update_stmt._independent_ctes:
108
+ cte._compiler_dispatch(self, **kw)
109
+
110
+ text += table_text
111
+
112
+ text += " SET "
113
+
114
+ # [14] CrateDB patch begin.
115
+ include_table = \
116
+ extra_froms and self.render_table_with_column_in_update_from
117
+
118
+ set_clauses = []
119
+
120
+ for c, expr, value in crud_params:
121
+ key = c._compiler_dispatch(self, include_table=include_table)
122
+ clause = key + ' = ' + value
123
+ set_clauses.append(clause)
124
+
125
+ for k, v in compile_state._dict_parameters.items():
126
+ if isinstance(k, str) and '[' in k:
127
+ bindparam = sa.sql.bindparam(k, v)
128
+ clause = k + ' = ' + self.process(bindparam)
129
+ set_clauses.append(clause)
130
+
131
+ text += ', '.join(set_clauses)
132
+ # [14] CrateDB patch end.
133
+
134
+ if self.returning or update_stmt._returning:
135
+ if self.returning_precedes_values:
136
+ text += " " + self.returning_clause(
137
+ update_stmt, self.returning or update_stmt._returning
138
+ )
139
+
140
+ if extra_froms:
141
+ extra_from_text = self.update_from_clause(
142
+ update_stmt,
143
+ update_stmt.table,
144
+ render_extra_froms,
145
+ dialect_hints,
146
+ **kw
147
+ )
148
+ if extra_from_text:
149
+ text += " " + extra_from_text
150
+
151
+ if update_stmt._where_criteria:
152
+ t = self._generate_delimited_and_list(
153
+ update_stmt._where_criteria, **kw
154
+ )
155
+ if t:
156
+ text += " WHERE " + t
157
+
158
+ limit_clause = self.update_limit_clause(update_stmt)
159
+ if limit_clause:
160
+ text += " " + limit_clause
161
+
162
+ if (
163
+ self.returning or update_stmt._returning
164
+ ) and not self.returning_precedes_values:
165
+ text += " " + self.returning_clause(
166
+ update_stmt, self.returning or update_stmt._returning
167
+ )
168
+
169
+ if self.ctes:
170
+ nesting_level = len(self.stack) if not toplevel else None
171
+ text = self._render_cte_clause(nesting_level=nesting_level) + text
172
+
173
+ self.stack.pop(-1)
174
+
175
+ return text
176
+
177
+
178
+ def _get_crud_params(compiler, stmt, compile_state, **kw):
179
+ """create a set of tuples representing column/string pairs for use
180
+ in an INSERT or UPDATE statement.
181
+
182
+ Also generates the Compiled object's postfetch, prefetch, and
183
+ returning column collections, used for default handling and ultimately
184
+ populating the CursorResult's prefetch_cols() and postfetch_cols()
185
+ collections.
186
+
187
+ """
188
+
189
+ compiler.postfetch = []
190
+ compiler.insert_prefetch = []
191
+ compiler.update_prefetch = []
192
+ compiler.returning = []
193
+
194
+ # getters - these are normally just column.key,
195
+ # but in the case of mysql multi-table update, the rules for
196
+ # .key must conditionally take tablename into account
197
+ (
198
+ _column_as_key,
199
+ _getattr_col_key,
200
+ _col_bind_name,
201
+ ) = getters = _key_getters_for_crud_column(compiler, stmt, compile_state)
202
+
203
+ compiler._key_getters_for_crud_column = getters
204
+
205
+ # no parameters in the statement, no parameters in the
206
+ # compiled params - return binds for all columns
207
+ if compiler.column_keys is None and compile_state._no_parameters:
208
+ return [
209
+ (
210
+ c,
211
+ compiler.preparer.format_column(c),
212
+ _create_bind_param(compiler, c, None, required=True),
213
+ )
214
+ for c in stmt.table.columns
215
+ ]
216
+
217
+ if compile_state._has_multi_parameters:
218
+ spd = compile_state._multi_parameters[0]
219
+ stmt_parameter_tuples = list(spd.items())
220
+ elif compile_state._ordered_values:
221
+ spd = compile_state._dict_parameters
222
+ stmt_parameter_tuples = compile_state._ordered_values
223
+ elif compile_state._dict_parameters:
224
+ spd = compile_state._dict_parameters
225
+ stmt_parameter_tuples = list(spd.items())
226
+ else:
227
+ stmt_parameter_tuples = spd = None
228
+
229
+ # if we have statement parameters - set defaults in the
230
+ # compiled params
231
+ if compiler.column_keys is None:
232
+ parameters = {}
233
+ elif stmt_parameter_tuples:
234
+ parameters = dict(
235
+ (_column_as_key(key), REQUIRED)
236
+ for key in compiler.column_keys
237
+ if key not in spd
238
+ )
239
+ else:
240
+ parameters = dict(
241
+ (_column_as_key(key), REQUIRED) for key in compiler.column_keys
242
+ )
243
+
244
+ # create a list of column assignment clauses as tuples
245
+ values = []
246
+
247
+ if stmt_parameter_tuples is not None:
248
+ _get_stmt_parameter_tuples_params(
249
+ compiler,
250
+ compile_state,
251
+ parameters,
252
+ stmt_parameter_tuples,
253
+ _column_as_key,
254
+ values,
255
+ kw,
256
+ )
257
+
258
+ check_columns = {}
259
+
260
+ # special logic that only occurs for multi-table UPDATE
261
+ # statements
262
+ if compile_state.isupdate and compile_state.is_multitable:
263
+ _get_update_multitable_params(
264
+ compiler,
265
+ stmt,
266
+ compile_state,
267
+ stmt_parameter_tuples,
268
+ check_columns,
269
+ _col_bind_name,
270
+ _getattr_col_key,
271
+ values,
272
+ kw,
273
+ )
274
+
275
+ if compile_state.isinsert and stmt._select_names:
276
+ _scan_insert_from_select_cols(
277
+ compiler,
278
+ stmt,
279
+ compile_state,
280
+ parameters,
281
+ _getattr_col_key,
282
+ _column_as_key,
283
+ _col_bind_name,
284
+ check_columns,
285
+ values,
286
+ kw,
287
+ )
288
+ else:
289
+ _scan_cols(
290
+ compiler,
291
+ stmt,
292
+ compile_state,
293
+ parameters,
294
+ _getattr_col_key,
295
+ _column_as_key,
296
+ _col_bind_name,
297
+ check_columns,
298
+ values,
299
+ kw,
300
+ )
301
+
302
+ # [14] CrateDB patch.
303
+ #
304
+ # This sanity check performed by SQLAlchemy currently needs to be
305
+ # deactivated in order to satisfy the rewriting logic of the CrateDB
306
+ # dialect in `rewrite_update` and `visit_update`.
307
+ #
308
+ # It can be quickly reproduced by activating this section and running the
309
+ # test cases::
310
+ #
311
+ # ./bin/test -vvvv -t dict_test
312
+ #
313
+ # That croaks like::
314
+ #
315
+ # sqlalchemy.exc.CompileError: Unconsumed column names: characters_name, data['nested']
316
+ #
317
+ # TODO: Investigate why this is actually happening and eventually mitigate
318
+ # the root cause.
319
+ """
320
+ if parameters and stmt_parameter_tuples:
321
+ check = (
322
+ set(parameters)
323
+ .intersection(_column_as_key(k) for k, v in stmt_parameter_tuples)
324
+ .difference(check_columns)
325
+ )
326
+ if check:
327
+ raise exc.CompileError(
328
+ "Unconsumed column names: %s"
329
+ % (", ".join("%s" % (c,) for c in check))
330
+ )
331
+ """
332
+
333
+ if compile_state._has_multi_parameters:
334
+ values = _extend_values_for_multiparams(
335
+ compiler,
336
+ stmt,
337
+ compile_state,
338
+ values,
339
+ _column_as_key,
340
+ kw,
341
+ )
342
+ elif (
343
+ not values
344
+ and compiler.for_executemany # noqa: W503
345
+ and compiler.dialect.supports_default_metavalue # noqa: W503
346
+ ):
347
+ # convert an "INSERT DEFAULT VALUES"
348
+ # into INSERT (firstcol) VALUES (DEFAULT) which can be turned
349
+ # into an in-place multi values. This supports
350
+ # insert_executemany_returning mode :)
351
+ values = [
352
+ (
353
+ stmt.table.columns[0],
354
+ compiler.preparer.format_column(stmt.table.columns[0]),
355
+ "DEFAULT",
356
+ )
357
+ ]
358
+
359
+ return values