dialects/postgres.py
import re
import sqlalchemy as sa
from sqlalchemy import cast
from sqlalchemy.dialects.postgresql import ARRAY, ENUM
def sql_enum_to_list(value):
"""
Interprets PostgreSQL's array syntax in terms of a list
Enums come back from SQL as '{val1,val2,val3}'
"""
if value is None:
return []
inner = re.match(r"^{(.*)}$", value).group(1)
return inner.split(",")
class ArrayOfEnum(ARRAY):
"""
Workaround for array-of-enum problem
See http://docs.sqlalchemy.org/en/latest/dialects/postgresql.html#postgresql-array-of-enum
"""
def bind_expression(self, bindvalue):
return cast(bindvalue, self)
def result_processor(self, dialect, coltype):
super_rp = super(ArrayOfEnum, self).result_processor(dialect, coltype)
def process(value):
# Convert array to Python objects
return super_rp(sql_enum_to_list(value))
return process
def fix_postgres_array_of_enum(connection, tbl):
"Change type of ENUM[] columns to a custom type"
for col in tbl.c:
col_str = str(col.type)
if col_str.endswith('[]'): # this is an array
enum_name = col_str[:-2]
try: # test if 'enum_name' is an enum
enum_ranges = connection.execute('''
SELECT enum_range(NULL::%s);
''' % enum_name).fetchone()
enum_values = sql_enum_to_list(enum_ranges[0])
enum = ENUM(*enum_values, name=enum_name)
tbl.c[col.name].type = ArrayOfEnum(enum)
except sa.exc.ProgrammingError as enum_excep:
if 'does not exist' in str(enum_excep):
pass # Must not have been an enum
else:
raise