Skip to content

Commit

Permalink
Support GEOMETRY, SUPER Redshift datatypes (#235)
Browse files Browse the repository at this point in the history
* Add GEOMETRY, SUPER Redshift datatypes

* Update CHANGES.rst
  • Loading branch information
Brooke-white committed Nov 3, 2021
1 parent c830f7b commit af22877
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 1 deletion.
3 changes: 2 additions & 1 deletion CHANGES.rst
Expand Up @@ -3,7 +3,8 @@

- Remove support for Python 2.7; now requires python ``>=3.4``
(`Pull #234 <https://github.com/sqlalchemy-redshift/sqlalchemy-redshift/pull/234>`_)

- Support GEOMETRY, SUPER Redshift datatypes
(`Pull #235 <https://github.com/sqlalchemy-redshift/sqlalchemy-redshift/pull/235>`_)

0.8.7 (2021-10-27)
------------------
Expand Down
56 changes: 56 additions & 0 deletions sqlalchemy_redshift/dialect.py
Expand Up @@ -29,6 +29,7 @@
CreateMaterializedView, DropMaterializedView, get_table_attributes
)
import importlib
import json

sa_version = Version(sa.__version__)

Expand Down Expand Up @@ -64,6 +65,8 @@ class RedshiftImpl(postgresql.PostgresqlImpl):
'TIMESTAMP',
'VARCHAR',
'DOUBLE_PRECISION',
'GEOMETRY',
'SUPER',
'TIMESTAMPTZ',
'TIMETZ',

Expand Down Expand Up @@ -211,6 +214,53 @@ def __init__(self):
super(TIMETZ, self).__init__(timezone=True)


class GEOMETRY(sa.dialects.postgresql.TEXT):
"""
Redshift defines a GEOMETRY column type
https://docs.aws.amazon.com/redshift/latest/dg/c_Supported_data_types.html
Adding an explicit type to the RedshiftDialect allows us follow the
SqlAlchemy conventions for "vendor-specific types."
https://docs.sqlalchemy.org/en/13/core/type_basics.html#vendor-specific-types
"""
__visit_name__ = 'GEOMETRY'

def __init__(self):
super(GEOMETRY, self).__init__()

def get_dbapi_type(self, dbapi):
return dbapi.GEOMETRY


class SUPER(sa.dialects.postgresql.TEXT):
"""
Redshift defines a SUPER column type
https://docs.aws.amazon.com/redshift/latest/dg/c_Supported_data_types.html
Adding an explicit type to the RedshiftDialect allows us follow the
SqlAlchemy conventions for "vendor-specific types."
https://docs.sqlalchemy.org/en/13/core/type_basics.html#vendor-specific-types
"""

__visit_name__ = 'SUPER'

def __init__(self):
super(SUPER, self).__init__()

def get_dbapi_type(self, dbapi):
return dbapi.SUPER

def bind_expression(self, bindvalue):
return sa.func.json_parse(bindvalue)

def process_bind_param(self, value, dialect):
if not isinstance(value, str):
return json.dumps(value)
return value


class RelationKey(namedtuple('RelationKey', ('name', 'schema'))):
"""
Structured tuple of table/view name and schema name.
Expand Down Expand Up @@ -426,6 +476,12 @@ def _fetch_redshift_column_attributes(self, column):

class RedshiftTypeCompiler(PGTypeCompiler):

def visit_GEOMETRY(self, type_, **kw):
return "GEOMETRY"

def visit_SUPER(self, type_, **kw):
return "SUPER"

def visit_TIMESTAMPTZ(self, type_, **kw):
return "TIMESTAMPTZ"

Expand Down
34 changes: 34 additions & 0 deletions tests/test_dialect_types.py
Expand Up @@ -30,13 +30,27 @@ def test_defined_types():
assert sqlalchemy_redshift.dialect.DOUBLE_PRECISION \
is sqlalchemy.dialects.postgresql.DOUBLE_PRECISION

assert sqlalchemy_redshift.dialect.GEOMETRY \
is not sqlalchemy.sql.sqltypes.TEXT

assert sqlalchemy_redshift.dialect.SUPER \
is not sqlalchemy.sql.sqltypes.TEXT

assert sqlalchemy_redshift.dialect.TIMESTAMPTZ \
is not sqlalchemy.sql.sqltypes.TIMESTAMP

assert sqlalchemy_redshift.dialect.TIMETZ \
is not sqlalchemy.sql.sqltypes.TIME

custom_type_inheritance = [
(
sqlalchemy_redshift.dialect.GEOMETRY,
sqlalchemy.sql.sqltypes.TEXT
),
(
sqlalchemy_redshift.dialect.SUPER,
sqlalchemy.sql.sqltypes.TEXT
),
(
sqlalchemy_redshift.dialect.TIMESTAMP,
sqlalchemy.sql.sqltypes.TIMESTAMP
Expand All @@ -55,6 +69,26 @@ def test_custom_types_extend_super_type(custom_type, super_type):


column_and_ddl = [
(
sqlalchemy_redshift.dialect.GEOMETRY,
(
u"\nCREATE TABLE t1 ("
u"\n\tid INTEGER NOT NULL, "
u"\n\tname VARCHAR, "
u"\n\ttest_col GEOMETRY, "
u"\n\tPRIMARY KEY (id)\n)\n\n"
)
),
(
sqlalchemy_redshift.dialect.SUPER,
(
u"\nCREATE TABLE t1 ("
u"\n\tid INTEGER NOT NULL, "
u"\n\tname VARCHAR, "
u"\n\ttest_col SUPER, "
u"\n\tPRIMARY KEY (id)\n)\n\n"
)
),
(
sqlalchemy_redshift.dialect.TIMESTAMPTZ,
(
Expand Down

0 comments on commit af22877

Please sign in to comment.