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])

Более подробнее о различиях можно прочитать тут

Комментарии

comments powered by Disqus