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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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