Skip to content

Instantly share code, notes, and snippets.

@pmart123
Last active October 10, 2018 01:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pmart123/9d993624b32c3ae68055d12b05dc88be to your computer and use it in GitHub Desktop.
Save pmart123/9d993624b32c3ae68055d12b05dc88be to your computer and use it in GitHub Desktop.
Sqlalchemy DDL with views error
from sqlalchemy import (DDL, event, Column, TEXT, select, func,
FLOAT, CHAR, DATE, Table, table, MetaData)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.schema import CreateColumn
from sqlalchemy.sql.ddl import _CreateDropBase
from sqlalchemy.ext.compiler import compiles
class _View(Table):
__visit_name__ = 'view'
is_view = True
def View(name, metadata, selectable, replace=True, cascade=False):
v = _View(name, metadata)
t = table(name)
t.schema = metadata.schema
for c in selectable.c:
c._make_proxy(t)
event.listen(
metadata, 'after_create', CreateView(v, selectable, replace=replace)
)
event.listen(
metadata, 'before_drop', DropView(v, if_exists=True, cascade=cascade)
)
return t
class CreateView(_CreateDropBase):
__visit_name__ = 'create_view'
def __init__(self, element: View, selectable, on=None, bind=None,
replace=True):
super(CreateView, self).__init__(element, on=on, bind=bind)
self.columns = [CreateColumn(column) for column in element.columns]
self.selectable = selectable
self.replace = replace
@compiles(CreateView)
def visit_create_view(create, compiler, **kw):
view = create.element
preparer = compiler.dialect.identifier_preparer
text = '\nCREATE '
if create.replace:
text += 'OR REPLACE '
text += 'VIEW %s ' % preparer.format_table(view)
if create.columns:
column_names = [preparer.format_column(col.element)
for col in create.columns]
text += '(%s)' % ', '.join(column_names)
text += 'AS %s\n\n' % compiler.sql_compiler.process(create.selectable)
return text
class DropView(_CreateDropBase):
__visit_name__ = 'drop_view'
def __init__(self, element: View, on=None, bind=None,
cascade=False, if_exists=False):
super(DropView, self).__init__(element, on=on, bind=bind)
self.cascade = cascade
self.if_exists = if_exists
@compiles(DropView)
def compile(drop, compiler, **kw):
text = "\nDROP VIEW "
if drop.if_exists:
text += "IF EXISTS "
text += compiler.preparer.format_table(drop.element)
if drop.cascade:
text += " CASCADE"
return text
def mount_declare_schema(target_schema):
statement = 'CREATE SCHEMA IF NOT EXISTS {}'.format(target_schema.schema)
ddl_statement = DDL(statement)
event.listen(target_schema, 'before_create',
ddl_statement.execute_if(dialect='postgresql'))
return target_schema
SCHEMA_NAME = 'my_schema'
meta_schema = MetaData(schema=SCHEMA_NAME)
# Base class for models using declarative syntax
Base = declarative_base(metadata=meta_schema)
class Accounts(Base):
__tablename__ = 'accounts'
portfolio_code = Column(TEXT, primary_key=True)
account_code = Column(TEXT, nullable=True)
open_date = Column(DATE, nullable=True)
class Appraisals(Base):
__tablename__ = 'appraisals'
report_date = Column(DATE, primary_key=True)
portfolio_code = Column(TEXT, primary_key=True)
symbol = Column(TEXT, primary_key=True)
asset_class_code = Column(CHAR(1), nullable=False)
base_market_value = Column(FLOAT, nullable=False)
def broken_view_query():
aa = Appraisals.__table__.alias('aa')
acc = Accounts.__table__.alias('acc')
query = select([
aa.c.portfolio_code,
func.sum(aa.c.base_market_value).label('total_cash'),
]).select_from(
aa.join(acc, aa.c.portfolio_code == acc.c.portfolio_code)
).where(
aa.c.asset_class_code == 'c'
).group_by(
aa.c.report_date, aa.c.portfolio_code
)
return query
broken_view = View('broken_view', Base.metadata, broken_view_query())
Base.metadata = mount_declare_schema(Base.metadata)
def declare(engine):
Base.metadata.create_all(engine)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment