Sqlalchemy 0.7.7 array_agg filter_by
September 5, 2015
Тем, кто из-за legacy кода не имеет возможности обновить библиотеку sqlalchemy, данный вариант вполне подойдет.
С версией 1.1 в sqlalchemy появился aggregate_order_by внутри sqlalchemy.dialects.postgresql. В случае же с 0.7.7 приходится делать влт так:
from sqlalchemy.sql.expression import ColumnElement, _literal_as_column
from sqlalchemy.dialects.postgres import ARRAY
from sqlalchemy.ext.compiler import compiles
class array_agg(ColumnElement):
def __init__(self, expr, order_by=None):
self.type = ARRAY(sa.Integer)
self.expr = _literal_as_column(expr)
self.order_by = _literal_as_column(order_by) if order_by is not None else None
@property
def _from_objects(self):
return self.expr._from_objects
@compiles(array_agg, 'postgresql')
def compile_array_agg(element, compiler, **kwargs):
head = 'array_agg(%s' % (
compiler.process(element.expr)
)
if element.order_by is not None:
tail = ' ORDER BY %s)' % compiler.process(element.order_by)
else:
tail = ')'
return head + tail
Применение тоже простое:
query = session.query(array_agg(Foo.bar, order_by=Foo.bar.desc()))
# Print compiled SQL query.
print query.statement.compile(dialect=postgresql.dialect())
# Run the query and print result.
print query.scalar()
Конечно, в новой версии все весьма проще и понятнее =)
from sqlalchemy.dialects.postgresql import aggregate_order_by
expr = func.array_agg(aggregate_order_by(table.c.a, table.c.b.desc()))
stmt = select([expr])
Более подробнее о различиях можно прочитать тут