Files
deb-python-sqlalchemy-utils/sqlalchemy_utils/expression_parser.py
2015-03-17 17:35:55 +02:00

146 lines
3.8 KiB
Python

try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict
import six
import sqlalchemy as sa
from sqlalchemy.orm.attributes import InstrumentedAttribute
from sqlalchemy.sql.annotation import AnnotatedColumn
from sqlalchemy.sql.elements import (
Case,
ClauseList,
False_,
Grouping,
Label,
Null,
True_,
Tuple
)
from sqlalchemy.sql.expression import (
BinaryExpression,
BindParameter,
BooleanClauseList,
Cast,
UnaryExpression
)
class ExpressionParser(object):
parsers = OrderedDict((
(BinaryExpression, 'binary_expression'),
(BooleanClauseList, 'boolean_expression'),
(UnaryExpression, 'unary_expression'),
(sa.Column, 'column'),
(AnnotatedColumn, 'column'),
(BindParameter, 'bind_parameter'),
(False_, 'false'),
(True_, 'true'),
(Grouping, 'grouping'),
(ClauseList, 'clause_list'),
(Label, 'label'),
(Cast, 'cast'),
(Case, 'case'),
(Tuple, 'tuple'),
(Null, 'null'),
(InstrumentedAttribute, 'instrumented_attribute')
))
def expression(self, expr):
if expr is None:
return
for class_, parser in self.parsers.items():
if isinstance(expr, class_):
return getattr(self, parser)(expr)
raise Exception(
'Unknown expression type %s' % expr.__class__.__name__
)
def instrumented_attribute(self, expr):
return expr
def null(self, expr):
return expr
def tuple(self, expr):
return expr.__class__(
*map(self.expression, expr.clauses),
type_=expr.type
)
def clause_list(self, expr):
return expr.__class__(
*map(self.expression, expr.clauses),
group=expr.group,
group_contents=expr.group_contents,
operator=expr.operator
)
def label(self, expr):
return expr.__class__(
name=expr.name,
element=self.expression(expr._element),
type_=expr.type
)
def cast(self, expr):
return expr.__class__(
expression=self.expression(expr.clause),
type_=expr.type
)
def case(self, expr):
return expr.__class__(
whens=[
tuple(self.expression(x) for x in when) for when in expr.whens
],
value=self.expression(expr.value),
else_=self.expression(expr.else_)
)
def grouping(self, expr):
return expr.__class__(self.expression(expr.element))
def true(self, expr):
return expr
def false(self, expr):
return expr
def process_table(self, table):
return table
def column(self, column):
table = self.process_table(column.table)
return table.c[column.name]
def unary_expression(self, expr):
return expr.operator(self.expression(expr.element))
def bind_parameter(self, expr):
# somehow bind parameters passed as unicode are converted to
# ascii strings along the way, force convert them back to avoid
# sqlalchemy unicode warnings
if isinstance(expr.type, sa.Unicode):
expr.value = six.text_type(expr.value)
return expr
def binary_expression(self, expr):
return expr.__class__(
left=self.expression(expr.left),
right=self.expression(expr.right),
operator=expr.operator,
type_=expr.type,
negate=expr.negate,
modifiers=expr.modifiers.copy()
)
def boolean_expression(self, expr):
return expr.operator(*[
self.expression(child_expr)
for child_expr in expr.get_children()
])
def __call__(self, expr):
return self.expression(expr)