forked from Raiza.dev/EliteBot
75 lines
2 KiB
Python
75 lines
2 KiB
Python
import inspect
|
|
import io
|
|
|
|
import sqlalchemy as sa
|
|
|
|
from .mock import create_mock_engine
|
|
from .orm import _get_query_compile_state
|
|
|
|
|
|
def render_expression(expression, bind, stream=None):
|
|
"""Generate a SQL expression from the passed python expression.
|
|
|
|
Only the global variable, `engine`, is available for use in the
|
|
expression. Additional local variables may be passed in the context
|
|
parameter.
|
|
|
|
Note this function is meant for convenience and protected usage. Do NOT
|
|
blindly pass user input to this function as it uses exec.
|
|
|
|
:param bind: A SQLAlchemy engine or bind URL.
|
|
:param stream: Render all DDL operations to the stream.
|
|
"""
|
|
|
|
# Create a stream if not present.
|
|
|
|
if stream is None:
|
|
stream = io.StringIO()
|
|
|
|
engine = create_mock_engine(bind, stream)
|
|
|
|
# Navigate the stack and find the calling frame that allows the
|
|
# expression to execuate.
|
|
|
|
for frame in inspect.stack()[1:]:
|
|
try:
|
|
frame = frame[0]
|
|
local = dict(frame.f_locals)
|
|
local['engine'] = engine
|
|
exec(expression, frame.f_globals, local)
|
|
break
|
|
except Exception:
|
|
pass
|
|
else:
|
|
raise ValueError('Not a valid python expression', engine)
|
|
|
|
return stream
|
|
|
|
|
|
def render_statement(statement, bind=None):
|
|
"""
|
|
Generate an SQL expression string with bound parameters rendered inline
|
|
for the given SQLAlchemy statement.
|
|
|
|
:param statement: SQLAlchemy Query object.
|
|
:param bind:
|
|
Optional SQLAlchemy bind, if None uses the bind of the given query
|
|
object.
|
|
"""
|
|
|
|
if isinstance(statement, sa.orm.query.Query):
|
|
if bind is None:
|
|
bind = statement.session.get_bind(
|
|
_get_query_compile_state(statement)._mapper_zero()
|
|
)
|
|
|
|
statement = statement.statement
|
|
|
|
elif bind is None:
|
|
bind = statement.bind
|
|
|
|
stream = io.StringIO()
|
|
engine = create_mock_engine(bind.engine, stream=stream)
|
|
engine.execute(statement)
|
|
|
|
return stream.getvalue()
|