Add literal statement render utility.

This commit is contained in:
Ryan Leckey
2013-07-26 01:33:08 -07:00
parent ec458211bc
commit 8a6fd87d4b
3 changed files with 58 additions and 3 deletions

View File

@@ -1,6 +1,7 @@
from .exceptions import ImproperlyConfigured
from .functions import (
sort_query, defer_except, escape_like, primary_keys, table_name
sort_query, defer_except, escape_like, primary_keys, table_name,
render_statement
)
from .listeners import coercion_listener
from .merge import merge, Merger
@@ -40,6 +41,7 @@ __all__ = (
merge,
primary_keys,
proxy_dict,
render_statement,
table_name,
ArrowType,
ColorType,

View File

@@ -1,8 +1,10 @@
from collections import defaultdict
import six
import datetime
import sqlalchemy as sa
from sqlalchemy.orm import defer
from sqlalchemy.orm.mapper import Mapper
from sqlalchemy.orm.query import _ColumnEntity
from sqlalchemy.orm.query import _ColumnEntity, Query
from sqlalchemy.orm.properties import ColumnProperty
from sqlalchemy.orm.util import AliasedInsp
from sqlalchemy.schema import MetaData, Table, ForeignKeyConstraint
@@ -352,3 +354,35 @@ def identity(obj):
if column.primary_key:
id_.append(getattr(obj, column.name))
return tuple(id_)
def render_statement(statement, bind=None):
"""
Generate an SQL expression string with bound parameters rendered inline
for the given SQLAlchemy statement.
"""
if isinstance(statement, Query):
if bind is None:
bind = statement.session.get_bind(statement._mapper_zero_or_none())
statement = statement.statement
elif bind is None:
bind = statement.bind
class Compiler(bind.dialect.statement_compiler):
def visit_bindparam(self, bindparam, *args, **kwargs):
return self.render_literal_value(bindparam.value, bindparam.type)
def render_literal_value(self, value, type_):
if isinstance(value, six.integer_types):
return str(value)
elif isinstance(value, (datetime.date, datetime.datetime)):
return "'%s'" % value
return super(Compiler, self).render_literal_value(value, type_)
return Compiler(bind.dialect, statement).process(statement)

View File

@@ -1,7 +1,10 @@
import sqlalchemy as sa
from sqlalchemy_utils import escape_like, defer_except
from sqlalchemy_utils.functions import non_indexed_foreign_keys
from tests import TestCase
from sqlalchemy_utils.functions import (
non_indexed_foreign_keys,
render_statement
)
class TestEscapeLike(TestCase):
@@ -62,3 +65,19 @@ class TestFindNonIndexedForeignKeys(TestCase):
]
assert 'category_id' in column_names
assert 'author_id' not in column_names
def test_render_statement_query(self):
query = self.session.query(self.User).filter_by(id=3)
render = render_statement(query)
assert 'SELECT user.id, user.name' in render
assert 'FROM user' in render
assert 'WHERE user.id = 3' in render
def test_render_statement(self):
statement = self.User.__table__.select().where(self.User.id == 3)
render = render_statement(statement, bind=self.session.bind)
assert 'SELECT user.id, user.name' in render
assert 'FROM user' in render
assert 'WHERE user.id = 3' in render