Именованные параметры в функциях базы данных с помощью SQLAlchemy
У меня есть функция в моей базе данных (Postgres), которая выглядит следующим образом:
create function test_f(a text default '*', b text default '+') returns text as $$
select a || ' ' || b;
$$ language sql;
Postgres позволяет вызывать его с именованными параметрами:
mytest=> select test_f('a', 'b');
test_f
--------
a b
(1 row)
mytest=> select test_f('a');
test_f
--------
a +
(1 row)
mytest=> select test_f(b:='a');
test_f
--------
* a
(1 row)
Я хочу сделать то же самое из Python, используя SQLAlchemy func
построить, но кажется, что func
не соблюдает именованные параметры:
In [85]: print(sqlalchemy.func.test_f('a', 'b'))
test_f(:test_f_1, :test_f_2)
In [86]: print(sqlalchemy.func.test_f('a'))
test_f(:test_f_1)
In [87]: print(sqlalchemy.func.test_f(a='a'))
test_f()
Я что-то упустил или func
не поддерживает именованные параметры?
1 ответ
Решение
Благодаря предложению Майкла Байера, я нашел решение своего собственного вопроса: хитрость заключается в том, чтобы использовать компилятор SQLAlchemy и некоторый правильный экранирование:
from psycopg2.extensions import adapt as sqlescape
import sqlalchemy
from sqlalchemy import select
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import ColumnClause
class MyFunc(ColumnClause):
def __init__(self, *args, **kwargs):
self.kwargs = kwargs
super().__init__(*args)
@compiles(MyFunc)
def compile_myfunc(element, compiler, **kw):
s = ','.join("%s:=%s" % (k, sqlescape(v)) for k, v in element.kwargs.items())
return "%s(%s)" % (element.name, s)
def call(engine, func, **kwargs):
return engine.execute(select([MyFunc(func, **kwargs)]))
engine = sqlalchemy.create_engine('postgresql+psycopg2://lbolla@localhost/mytest')
print(call(engine, 'test_f', a='a').scalar())
print(call(engine, 'test_f', b='b').scalar())