sqlalchemy-cratedb 0.38.0__py3-none-any.whl → 0.39.0__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.
@@ -24,17 +24,18 @@ import warnings
24
24
  from collections import defaultdict
25
25
 
26
26
  import sqlalchemy as sa
27
- from sqlalchemy.dialects.postgresql.base import PGCompiler
28
27
  from sqlalchemy.dialects.postgresql.base import RESERVED_WORDS as POSTGRESQL_RESERVED_WORDS
28
+ from sqlalchemy.dialects.postgresql.base import PGCompiler
29
29
  from sqlalchemy.sql import compiler
30
30
  from sqlalchemy.types import String
31
+
32
+ from .sa_version import SA_1_4, SA_VERSION
31
33
  from .type.geo import Geopoint, Geoshape
32
34
  from .type.object import MutableDict, ObjectTypeImpl
33
- from .sa_version import SA_VERSION, SA_1_4
34
35
 
35
36
 
36
37
  def rewrite_update(clauseelement, multiparams, params):
37
- """ change the params to enable partial updates
38
+ """change the params to enable partial updates
38
39
 
39
40
  sqlalchemy by default only supports updates of complex types in the form of
40
41
 
@@ -55,9 +56,8 @@ def rewrite_update(clauseelement, multiparams, params):
55
56
  for _params in _multiparams:
56
57
  newparams = {}
57
58
  for key, val in _params.items():
58
- if (
59
- not isinstance(val, MutableDict) or
60
- (not any(val._changed_keys) and not any(val._deleted_keys))
59
+ if not isinstance(val, MutableDict) or (
60
+ not any(val._changed_keys) and not any(val._deleted_keys)
61
61
  ):
62
62
  newparams[key] = val
63
63
  continue
@@ -68,7 +68,7 @@ def rewrite_update(clauseelement, multiparams, params):
68
68
  for subkey in val._deleted_keys:
69
69
  newparams["{0}['{1}']".format(key, subkey)] = None
70
70
  newmultiparams.append(newparams)
71
- _multiparams = (newmultiparams, )
71
+ _multiparams = (newmultiparams,)
72
72
  clause = clauseelement.values(newmultiparams[0])
73
73
  clause._crate_specific = True
74
74
  return clause, _multiparams, params
@@ -76,7 +76,7 @@ def rewrite_update(clauseelement, multiparams, params):
76
76
 
77
77
  @sa.event.listens_for(sa.engine.Engine, "before_execute", retval=True)
78
78
  def crate_before_execute(conn, clauseelement, multiparams, params, *args, **kwargs):
79
- is_crate = type(conn.dialect).__name__ == 'CrateDialect'
79
+ is_crate = type(conn.dialect).__name__ == "CrateDialect"
80
80
  if is_crate and isinstance(clauseelement, sa.sql.expression.Update):
81
81
  if SA_VERSION >= SA_1_4:
82
82
  if params is None:
@@ -98,19 +98,19 @@ def crate_before_execute(conn, clauseelement, multiparams, params, *args, **kwar
98
98
 
99
99
 
100
100
  class CrateDDLCompiler(compiler.DDLCompiler):
101
-
102
- __special_opts_tmpl = {
103
- 'partitioned_by': ' PARTITIONED BY ({0})'
104
- }
101
+ __special_opts_tmpl = {"partitioned_by": " PARTITIONED BY ({0})"}
105
102
  __clustered_opts_tmpl = {
106
- 'number_of_shards': ' INTO {0} SHARDS',
107
- 'clustered_by': ' BY ({0})',
103
+ "number_of_shards": " INTO {0} SHARDS",
104
+ "clustered_by": " BY ({0})",
108
105
  }
109
- __clustered_opt_tmpl = ' CLUSTERED{clustered_by}{number_of_shards}'
106
+ __clustered_opt_tmpl = " CLUSTERED{clustered_by}{number_of_shards}"
110
107
 
111
108
  def get_column_specification(self, column, **kwargs):
112
- colspec = self.preparer.format_column(column) + " " + \
113
- self.dialect.type_compiler.process(column.type)
109
+ colspec = (
110
+ self.preparer.format_column(column)
111
+ + " "
112
+ + self.dialect.type_compiler.process(column.type)
113
+ )
114
114
 
115
115
  default = self.get_column_default_string(column)
116
116
  if default is not None:
@@ -122,11 +122,9 @@ class CrateDDLCompiler(compiler.DDLCompiler):
122
122
  if column.nullable is False:
123
123
  colspec += " NOT NULL"
124
124
  elif column.nullable and column.primary_key:
125
- raise sa.exc.CompileError(
126
- "Primary key columns cannot be nullable"
127
- )
125
+ raise sa.exc.CompileError("Primary key columns cannot be nullable")
128
126
 
129
- if column.dialect_options['crate'].get('index') is False:
127
+ if column.dialect_options["crate"].get("index") is False:
130
128
  if isinstance(column.type, (Geopoint, Geoshape, ObjectTypeImpl)):
131
129
  raise sa.exc.CompileError(
132
130
  "Disabling indexing is not supported for column "
@@ -135,8 +133,8 @@ class CrateDDLCompiler(compiler.DDLCompiler):
135
133
 
136
134
  colspec += " INDEX OFF"
137
135
 
138
- if column.dialect_options['crate'].get('columnstore') is False:
139
- if not isinstance(column.type, (String, )):
136
+ if column.dialect_options["crate"].get("columnstore") is False:
137
+ if not isinstance(column.type, (String,)):
140
138
  raise sa.exc.CompileError(
141
139
  "Controlling the columnstore is only allowed for STRING columns"
142
140
  )
@@ -148,8 +146,7 @@ class CrateDDLCompiler(compiler.DDLCompiler):
148
146
  def visit_computed_column(self, generated):
149
147
  if generated.persisted is False:
150
148
  raise sa.exc.CompileError(
151
- "Virtual computed columns are not supported, set "
152
- "'persisted' to None or True"
149
+ "Virtual computed columns are not supported, set " "'persisted' to None or True"
153
150
  )
154
151
 
155
152
  return "GENERATED ALWAYS AS (%s)" % self.sql_compiler.process(
@@ -157,14 +154,14 @@ class CrateDDLCompiler(compiler.DDLCompiler):
157
154
  )
158
155
 
159
156
  def post_create_table(self, table):
160
- special_options = ''
157
+ special_options = ""
161
158
  clustered_options = defaultdict(str)
162
159
  table_opts = []
163
160
 
164
161
  opts = dict(
165
- (k[len(self.dialect.name) + 1:], v)
166
- for k, v, in table.kwargs.items()
167
- if k.startswith('%s_' % self.dialect.name)
162
+ (k[len(self.dialect.name) + 1 :], v)
163
+ for k, v in table.kwargs.items()
164
+ if k.startswith("%s_" % self.dialect.name)
168
165
  )
169
166
  for k, v in opts.items():
170
167
  if k in self.__special_opts_tmpl:
@@ -172,69 +169,73 @@ class CrateDDLCompiler(compiler.DDLCompiler):
172
169
  elif k in self.__clustered_opts_tmpl:
173
170
  clustered_options[k] = self.__clustered_opts_tmpl[k].format(v)
174
171
  else:
175
- table_opts.append('{0} = {1}'.format(k, v))
172
+ table_opts.append("{0} = {1}".format(k, v))
176
173
  if clustered_options:
177
174
  special_options += string.Formatter().vformat(
178
- self.__clustered_opt_tmpl, (), clustered_options)
175
+ self.__clustered_opt_tmpl, (), clustered_options
176
+ )
179
177
  if table_opts:
180
- return special_options + ' WITH ({0})'.format(
181
- ', '.join(sorted(table_opts)))
178
+ return special_options + " WITH ({0})".format(", ".join(sorted(table_opts)))
182
179
  return special_options
183
180
 
184
181
  def visit_foreign_key_constraint(self, constraint, **kw):
185
182
  """
186
183
  CrateDB does not support foreign key constraints.
187
184
  """
188
- warnings.warn("CrateDB does not support foreign key constraints, "
189
- "they will be omitted when generating DDL statements.")
190
- return None
185
+ warnings.warn(
186
+ "CrateDB does not support foreign key constraints, "
187
+ "they will be omitted when generating DDL statements.",
188
+ stacklevel=2,
189
+ )
190
+ return
191
191
 
192
192
  def visit_unique_constraint(self, constraint, **kw):
193
193
  """
194
194
  CrateDB does not support unique key constraints.
195
195
  """
196
- warnings.warn("CrateDB does not support unique constraints, "
197
- "they will be omitted when generating DDL statements.")
198
- return None
196
+ warnings.warn(
197
+ "CrateDB does not support unique constraints, "
198
+ "they will be omitted when generating DDL statements.",
199
+ stacklevel=2,
200
+ )
201
+ return
199
202
 
200
203
 
201
204
  class CrateTypeCompiler(compiler.GenericTypeCompiler):
202
-
203
205
  def visit_string(self, type_, **kw):
204
- return 'STRING'
206
+ return "STRING"
205
207
 
206
208
  def visit_unicode(self, type_, **kw):
207
- return 'STRING'
209
+ return "STRING"
208
210
 
209
211
  def visit_TEXT(self, type_, **kw):
210
- return 'STRING'
212
+ return "STRING"
211
213
 
212
214
  def visit_DECIMAL(self, type_, **kw):
213
- return 'DOUBLE'
215
+ return "DOUBLE"
214
216
 
215
217
  def visit_BIGINT(self, type_, **kw):
216
- return 'LONG'
218
+ return "LONG"
217
219
 
218
220
  def visit_NUMERIC(self, type_, **kw):
219
- return 'LONG'
221
+ return "LONG"
220
222
 
221
223
  def visit_INTEGER(self, type_, **kw):
222
- return 'INT'
224
+ return "INT"
223
225
 
224
226
  def visit_SMALLINT(self, type_, **kw):
225
- return 'SHORT'
227
+ return "SHORT"
226
228
 
227
229
  def visit_datetime(self, type_, **kw):
228
230
  return self.visit_TIMESTAMP(type_, **kw)
229
231
 
230
232
  def visit_date(self, type_, **kw):
231
- return 'TIMESTAMP'
233
+ return "TIMESTAMP"
232
234
 
233
235
  def visit_ARRAY(self, type_, **kw):
234
236
  if type_.dimensions is not None and type_.dimensions > 1:
235
- raise NotImplementedError(
236
- "CrateDB doesn't support multidimensional arrays")
237
- return 'ARRAY({0})'.format(self.process(type_.item_type))
237
+ raise NotImplementedError("CrateDB doesn't support multidimensional arrays")
238
+ return "ARRAY({0})".format(self.process(type_.item_type))
238
239
 
239
240
  def visit_OBJECT(self, type_, **kw):
240
241
  return "OBJECT"
@@ -251,32 +252,21 @@ class CrateTypeCompiler(compiler.GenericTypeCompiler):
251
252
 
252
253
  From `sqlalchemy.dialects.postgresql.base.PGTypeCompiler`.
253
254
  """
254
- return "TIMESTAMP %s" % (
255
- (type_.timezone and "WITH" or "WITHOUT") + " TIME ZONE",
256
- )
255
+ return "TIMESTAMP %s" % ((type_.timezone and "WITH" or "WITHOUT") + " TIME ZONE",)
257
256
 
258
257
 
259
258
  class CrateCompiler(compiler.SQLCompiler):
260
-
261
259
  def visit_getitem_binary(self, binary, operator, **kw):
262
- return "{0}['{1}']".format(
263
- self.process(binary.left, **kw),
264
- binary.right.value
265
- )
260
+ return "{0}['{1}']".format(self.process(binary.left, **kw), binary.right.value)
266
261
 
267
- def visit_json_getitem_op_binary(
268
- self, binary, operator, _cast_applied=False, **kw
269
- ):
270
- return "{0}['{1}']".format(
271
- self.process(binary.left, **kw),
272
- binary.right.value
273
- )
262
+ def visit_json_getitem_op_binary(self, binary, operator, _cast_applied=False, **kw):
263
+ return "{0}['{1}']".format(self.process(binary.left, **kw), binary.right.value)
274
264
 
275
265
  def visit_any(self, element, **kw):
276
266
  return "%s%sANY (%s)" % (
277
267
  self.process(element.left, **kw),
278
268
  compiler.OPERATORS[element.operator],
279
- self.process(element.right, **kw)
269
+ self.process(element.right, **kw),
280
270
  )
281
271
 
282
272
  def visit_ilike_case_insensitive_operand(self, element, **kw):
@@ -331,29 +321,32 @@ class CrateCompiler(compiler.SQLCompiler):
331
321
  def for_update_clause(self, select, **kw):
332
322
  # CrateDB does not support the `INSERT ... FOR UPDATE` clause.
333
323
  # See https://github.com/crate/crate-python/issues/577.
334
- warnings.warn("CrateDB does not support the 'INSERT ... FOR UPDATE' clause, "
335
- "it will be omitted when generating SQL statements.")
336
- return ''
324
+ warnings.warn(
325
+ "CrateDB does not support the 'INSERT ... FOR UPDATE' clause, "
326
+ "it will be omitted when generating SQL statements.",
327
+ stacklevel=2,
328
+ )
329
+ return ""
337
330
 
338
331
 
339
- CRATEDB_RESERVED_WORDS = \
340
- "add, alter, between, by, called, costs, delete, deny, directory, drop, escape, exists, " \
341
- "extract, first, function, if, index, input, insert, last, match, nulls, object, " \
342
- "persistent, recursive, reset, returns, revoke, set, stratify, transient, try_cast, " \
332
+ CRATEDB_RESERVED_WORDS = (
333
+ "add, alter, between, by, called, costs, delete, deny, directory, drop, escape, exists, "
334
+ "extract, first, function, if, index, input, insert, last, match, nulls, object, "
335
+ "persistent, recursive, reset, returns, revoke, set, stratify, transient, try_cast, "
343
336
  "unbounded, update".split(", ")
337
+ )
344
338
 
345
339
 
346
340
  class CrateIdentifierPreparer(sa.sql.compiler.IdentifierPreparer):
347
341
  """
348
342
  Define CrateDB's reserved words to be quoted properly.
349
343
  """
344
+
350
345
  reserved_words = set(list(POSTGRESQL_RESERVED_WORDS) + CRATEDB_RESERVED_WORDS)
351
346
 
352
347
  def _unquote_identifier(self, value):
353
348
  if value[0] == self.initial_quote:
354
- value = value[1:-1].replace(
355
- self.escape_to_quote, self.escape_quote
356
- )
349
+ value = value[1:-1].replace(self.escape_to_quote, self.escape_quote)
357
350
  return value
358
351
 
359
352
  def format_type(self, type_, use_schema=True):
@@ -363,10 +356,6 @@ class CrateIdentifierPreparer(sa.sql.compiler.IdentifierPreparer):
363
356
  name = self.quote(type_.name)
364
357
  effective_schema = self.schema_for_object(type_)
365
358
 
366
- if (
367
- not self.omit_schema
368
- and use_schema
369
- and effective_schema is not None
370
- ):
359
+ if not self.omit_schema and use_schema and effective_schema is not None:
371
360
  name = self.quote_schema(effective_schema) + "." + name
372
361
  return name
@@ -20,7 +20,7 @@
20
20
  # software solely pursuant to the terms of the relevant commercial agreement.
21
21
 
22
22
  import logging
23
- from datetime import datetime, date
23
+ from datetime import date, datetime
24
24
 
25
25
  from sqlalchemy import types as sqltypes
26
26
  from sqlalchemy.engine import default, reflection
@@ -28,11 +28,11 @@ from sqlalchemy.sql import functions
28
28
  from sqlalchemy.util import asbool, to_list
29
29
 
30
30
  from .compiler import (
31
- CrateTypeCompiler,
32
31
  CrateDDLCompiler,
33
32
  CrateIdentifierPreparer,
33
+ CrateTypeCompiler,
34
34
  )
35
- from .sa_version import SA_VERSION, SA_1_4, SA_2_0
35
+ from .sa_version import SA_1_4, SA_2_0, SA_VERSION
36
36
  from .type import FloatVector, ObjectArray, ObjectType
37
37
 
38
38
  TYPES_MAP = {
@@ -54,9 +54,12 @@ TYPES_MAP = {
54
54
  "text": sqltypes.String,
55
55
  "float_vector": FloatVector,
56
56
  }
57
+
58
+ # Needed for SQLAlchemy >= 1.1.
59
+ # TODO: Dissolve.
57
60
  try:
58
- # SQLAlchemy >= 1.1
59
61
  from sqlalchemy.types import ARRAY
62
+
60
63
  TYPES_MAP["integer_array"] = ARRAY(sqltypes.Integer)
61
64
  TYPES_MAP["boolean_array"] = ARRAY(sqltypes.Boolean)
62
65
  TYPES_MAP["short_array"] = ARRAY(sqltypes.SmallInteger)
@@ -71,7 +74,7 @@ try:
71
74
  TYPES_MAP["real_array"] = ARRAY(sqltypes.Float)
72
75
  TYPES_MAP["string_array"] = ARRAY(sqltypes.String)
73
76
  TYPES_MAP["text_array"] = ARRAY(sqltypes.String)
74
- except Exception:
77
+ except Exception: # noqa: S110
75
78
  pass
76
79
 
77
80
 
@@ -82,14 +85,16 @@ class Date(sqltypes.Date):
82
85
  def bind_processor(self, dialect):
83
86
  def process(value):
84
87
  if value is not None:
85
- assert isinstance(value, date)
86
- return value.strftime('%Y-%m-%d')
88
+ assert isinstance(value, date) # noqa: S101
89
+ return value.strftime("%Y-%m-%d")
90
+ return None
91
+
87
92
  return process
88
93
 
89
94
  def result_processor(self, dialect, coltype):
90
95
  def process(value):
91
96
  if not value:
92
- return
97
+ return None
93
98
  try:
94
99
  return datetime.utcfromtimestamp(value / 1e3).date()
95
100
  except TypeError:
@@ -103,27 +108,29 @@ class Date(sqltypes.Date):
103
108
  # the date will be returned in the format it was inserted.
104
109
  log.warning(
105
110
  "Received timestamp isn't a long value."
106
- "Trying to parse as date string and then as datetime string")
111
+ "Trying to parse as date string and then as datetime string"
112
+ )
107
113
  try:
108
- return datetime.strptime(value, '%Y-%m-%d').date()
114
+ return datetime.strptime(value, "%Y-%m-%d").date()
109
115
  except ValueError:
110
- return datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ').date()
116
+ return datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ").date()
117
+
111
118
  return process
112
119
 
113
120
 
114
121
  class DateTime(sqltypes.DateTime):
115
-
116
122
  def bind_processor(self, dialect):
117
123
  def process(value):
118
124
  if isinstance(value, (datetime, date)):
119
- return value.strftime('%Y-%m-%dT%H:%M:%S.%f%z')
125
+ return value.strftime("%Y-%m-%dT%H:%M:%S.%f%z")
120
126
  return value
127
+
121
128
  return process
122
129
 
123
130
  def result_processor(self, dialect, coltype):
124
131
  def process(value):
125
132
  if not value:
126
- return
133
+ return None
127
134
  try:
128
135
  return datetime.utcfromtimestamp(value / 1e3)
129
136
  except TypeError:
@@ -137,11 +144,13 @@ class DateTime(sqltypes.DateTime):
137
144
  # the date will be returned in the format it was inserted.
138
145
  log.warning(
139
146
  "Received timestamp isn't a long value."
140
- "Trying to parse as datetime string and then as date string")
147
+ "Trying to parse as datetime string and then as date string"
148
+ )
141
149
  try:
142
- return datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ')
150
+ return datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ")
143
151
  except ValueError:
144
- return datetime.strptime(value, '%Y-%m-%d')
152
+ return datetime.strptime(value, "%Y-%m-%d")
153
+
145
154
  return process
146
155
 
147
156
 
@@ -154,19 +163,22 @@ colspecs = {
154
163
 
155
164
  if SA_VERSION >= SA_2_0:
156
165
  from .compat.core20 import CrateCompilerSA20
166
+
157
167
  statement_compiler = CrateCompilerSA20
158
168
  elif SA_VERSION >= SA_1_4:
159
169
  from .compat.core14 import CrateCompilerSA14
170
+
160
171
  statement_compiler = CrateCompilerSA14
161
172
  else:
162
173
  from .compat.core10 import CrateCompilerSA10
174
+
163
175
  statement_compiler = CrateCompilerSA10
164
176
 
165
177
 
166
178
  class CrateDialect(default.DefaultDialect):
167
- name = 'crate'
168
- driver = 'crate-python'
169
- default_paramstyle = 'qmark'
179
+ name = "crate"
180
+ driver = "crate-python"
181
+ default_paramstyle = "qmark"
170
182
  statement_compiler = statement_compiler
171
183
  ddl_compiler = CrateDDLCompiler
172
184
  type_compiler = CrateTypeCompiler
@@ -192,15 +204,13 @@ class CrateDialect(default.DefaultDialect):
192
204
 
193
205
  # Currently, our SQL parser doesn't support unquoted column names that
194
206
  # start with _. Adding it here causes sqlalchemy to quote such columns.
195
- self.identifier_preparer.illegal_initial_characters.add('_')
207
+ self.identifier_preparer.illegal_initial_characters.add("_")
196
208
 
197
209
  def initialize(self, connection):
198
210
  # get lowest server version
199
- self.server_version_info = \
200
- self._get_server_version_info(connection)
211
+ self.server_version_info = self._get_server_version_info(connection)
201
212
  # get default schema name
202
- self.default_schema_name = \
203
- self._get_default_schema_name(connection)
213
+ self.default_schema_name = self._get_default_schema_name(connection)
204
214
 
205
215
  def do_rollback(self, connection):
206
216
  # if any exception is raised by the dbapi, sqlalchemy by default
@@ -212,9 +222,9 @@ class CrateDialect(default.DefaultDialect):
212
222
  def connect(self, host=None, port=None, *args, **kwargs):
213
223
  server = None
214
224
  if host:
215
- server = '{0}:{1}'.format(host, port or '4200')
216
- if 'servers' in kwargs:
217
- server = kwargs.pop('servers')
225
+ server = "{0}:{1}".format(host, port or "4200")
226
+ if "servers" in kwargs:
227
+ server = kwargs.pop("servers")
218
228
  servers = to_list(server)
219
229
  if servers:
220
230
  use_ssl = asbool(kwargs.pop("ssl", False))
@@ -224,7 +234,7 @@ class CrateDialect(default.DefaultDialect):
224
234
  return self.dbapi.connect(**kwargs)
225
235
 
226
236
  def _get_default_schema_name(self, connection):
227
- return 'doc'
237
+ return "doc"
228
238
 
229
239
  def _get_effective_schema_name(self, connection):
230
240
  schema_name_raw = connection.engine.url.query.get("schema")
@@ -241,6 +251,7 @@ class CrateDialect(default.DefaultDialect):
241
251
  @classmethod
242
252
  def import_dbapi(cls):
243
253
  from crate import client
254
+
244
255
  return client
245
256
 
246
257
  @classmethod
@@ -256,9 +267,7 @@ class CrateDialect(default.DefaultDialect):
256
267
  @reflection.cache
257
268
  def get_schema_names(self, connection, **kw):
258
269
  cursor = connection.exec_driver_sql(
259
- "select schema_name "
260
- "from information_schema.schemata "
261
- "order by schema_name asc"
270
+ "select schema_name " "from information_schema.schemata " "order by schema_name asc"
262
271
  )
263
272
  return [row[0] for row in cursor.fetchall()]
264
273
 
@@ -271,7 +280,7 @@ class CrateDialect(default.DefaultDialect):
271
280
  "WHERE {0} = ? "
272
281
  "AND table_type = 'BASE TABLE' "
273
282
  "ORDER BY table_name ASC, {0} ASC".format(self.schema_column),
274
- (schema or self.default_schema_name, )
283
+ (schema or self.default_schema_name,),
275
284
  )
276
285
  return [row[0] for row in cursor.fetchall()]
277
286
 
@@ -280,22 +289,25 @@ class CrateDialect(default.DefaultDialect):
280
289
  cursor = connection.exec_driver_sql(
281
290
  "SELECT table_name FROM information_schema.views "
282
291
  "ORDER BY table_name ASC, {0} ASC".format(self.schema_column),
283
- (schema or self.default_schema_name, )
292
+ (schema or self.default_schema_name,),
284
293
  )
285
294
  return [row[0] for row in cursor.fetchall()]
286
295
 
287
296
  @reflection.cache
288
297
  def get_columns(self, connection, table_name, schema=None, **kw):
289
- query = "SELECT column_name, data_type " \
290
- "FROM information_schema.columns " \
291
- "WHERE table_name = ? AND {0} = ? " \
292
- "AND column_name !~ ?" \
293
- .format(self.schema_column)
298
+ query = (
299
+ "SELECT column_name, data_type "
300
+ "FROM information_schema.columns "
301
+ "WHERE table_name = ? AND {0} = ? "
302
+ "AND column_name !~ ?".format(self.schema_column)
303
+ )
294
304
  cursor = connection.exec_driver_sql(
295
305
  query,
296
- (table_name,
297
- schema or self.default_schema_name,
298
- r"(.*)\[\'(.*)\'\]") # regex to filter subscript
306
+ (
307
+ table_name,
308
+ schema or self.default_schema_name,
309
+ r"(.*)\[\'(.*)\'\]",
310
+ ), # regex to filter subscript
299
311
  )
300
312
  return [self._create_column_info(row) for row in cursor.fetchall()]
301
313
 
@@ -330,17 +342,14 @@ class CrateDialect(default.DefaultDialect):
330
342
  rows = result.fetchone()
331
343
  return set(rows[0] if rows else [])
332
344
 
333
- pk_result = engine.exec_driver_sql(
334
- query,
335
- (table_name, schema or self.default_schema_name)
336
- )
345
+ pk_result = engine.exec_driver_sql(query, (table_name, schema or self.default_schema_name))
337
346
  pks = result_fun(pk_result)
338
- return {'constrained_columns': list(sorted(pks)),
339
- 'name': 'PRIMARY KEY'}
347
+ return {"constrained_columns": sorted(pks), "name": "PRIMARY KEY"}
340
348
 
341
349
  @reflection.cache
342
- def get_foreign_keys(self, connection, table_name, schema=None,
343
- postgresql_ignore_search_path=False, **kw):
350
+ def get_foreign_keys(
351
+ self, connection, table_name, schema=None, postgresql_ignore_search_path=False, **kw
352
+ ):
344
353
  # Crate doesn't support Foreign Keys, so this stays empty
345
354
  return []
346
355
 
@@ -354,12 +363,12 @@ class CrateDialect(default.DefaultDialect):
354
363
 
355
364
  def _create_column_info(self, row):
356
365
  return {
357
- 'name': row[0],
358
- 'type': self._resolve_type(row[1]),
366
+ "name": row[0],
367
+ "type": self._resolve_type(row[1]),
359
368
  # In Crate every column is nullable except PK
360
369
  # Primary Key Constraints are not nullable anyway, no matter what
361
370
  # we return here, so it's fine to return always `True`
362
- 'nullable': True
371
+ "nullable": True,
363
372
  }
364
373
 
365
374
  def _resolve_type(self, type_):
@@ -19,8 +19,8 @@
19
19
  # with Crate these terms will supersede the license and you may use the
20
20
  # software solely pursuant to the terms of the relevant commercial agreement.
21
21
 
22
- from sqlalchemy.sql.expression import ColumnElement, literal
23
22
  from sqlalchemy.ext.compiler import compiles
23
+ from sqlalchemy.sql.expression import ColumnElement, literal
24
24
 
25
25
 
26
26
  class Match(ColumnElement):
@@ -35,9 +35,8 @@ class Match(ColumnElement):
35
35
 
36
36
  def compile_column(self, compiler):
37
37
  if isinstance(self.column, dict):
38
- column = ', '.join(
39
- sorted(["{0} {1}".format(compiler.process(k), v)
40
- for k, v in self.column.items()])
38
+ column = ", ".join(
39
+ sorted(["{0} {1}".format(compiler.process(k), v) for k, v in self.column.items()])
41
40
  )
42
41
  return "({0})".format(column)
43
42
  else:
@@ -51,21 +50,22 @@ class Match(ColumnElement):
51
50
  using = "using {0}".format(self.match_type)
52
51
  with_clause = self.with_clause()
53
52
  if with_clause:
54
- using = ' '.join([using, with_clause])
53
+ using = " ".join([using, with_clause])
55
54
  return using
56
55
  if self.options:
57
- raise ValueError("missing match_type. " +
58
- "It's not allowed to specify options " +
59
- "without match_type")
56
+ raise ValueError(
57
+ "missing match_type. "
58
+ + "It's not allowed to specify options "
59
+ + "without match_type"
60
+ )
61
+ return None
60
62
 
61
63
  def with_clause(self):
62
64
  if self.options:
63
- options = ', '.join(
64
- sorted(["{0}={1}".format(k, v)
65
- for k, v in self.options.items()])
66
- )
65
+ options = ", ".join(sorted(["{0}={1}".format(k, v) for k, v in self.options.items()]))
67
66
 
68
67
  return "with ({0})".format(options)
68
+ return None
69
69
 
70
70
 
71
71
  def match(column, term, match_type=None, options=None):
@@ -89,11 +89,8 @@ def match(column, term, match_type=None, options=None):
89
89
 
90
90
  @compiles(Match)
91
91
  def compile_match(match, compiler, **kwargs):
92
- func = "match(%s, %s)" % (
93
- match.compile_column(compiler),
94
- match.compile_term(compiler)
95
- )
92
+ func = "match(%s, %s)" % (match.compile_column(compiler), match.compile_term(compiler))
96
93
  using = match.compile_using(compiler)
97
94
  if using:
98
- func = ' '.join([func, using])
95
+ func = " ".join([func, using])
99
96
  return func