У меня есть запрос, использующий несколько операций, специфичных для Postgres:
SELECT
a.row_id,
a.name
FROM
a
JOIN
b
ON
b.json_record @> json_build_object('path', json_build_object('to', a.name))::jsonb
Насколько я понимаю, оператор @>
действует как сравнение, но методы сравнения для JSONB
в справочнике по SQLAlchemyтолько ключи , а не значения .
https://docs.sqlalchemy.org/en/latest/dialects/postgresql.html#sqlalchemy.dialects.postgresql.JSONB.Comparator
Мне не совсем ясно, как можно разработать этот запрос с помощью SQLAlchemy, если не использоватьнеобработанный запрос.
Редактировать 1
Основываясь на этом ответе , я дал приведенную ниже попытку.
session \
.query(A_Table) \
.join(
B_Table.json_record.contains({
'path': {
'to': A_Table.name
}
})
)
Это, однако, привело кв ошибке из строки 'to': A_Table.name
:
AttributeError: Neither 'BinaryExpression' object nor 'Comparator' object has an attribute 'selectable'
sqlalchemy/orm/query.py", line 2206, in join
from_joinpoint=from_joinpoint,
File "<string>", line 2, in _join
Так что я вместо этого попытался
session \
.query(A_Table) \
.filter(
B_Table.json_record.contains({
'path': {
'to': A_Table.name
}
})
)
, которая, по крайней мере, привела к другой ошибке, с некоторой генерацией SQL из SQLAlchemy:
sqlalchemy.exc.StatementError: (builtins.TypeError)
Object of type 'InstrumentedAttribute' is not JSON serializable
[SQL: 'SELECT a.row_id AS a_id, a.name AS a_name FROM a, b
WHERE b.json_record @> %(json_record_1)s'] [parameters: [{}]]
Этот SQL близок к тому, к чему я стремился, и может быть приемлемым, но пример, приведенный в ответе, предполагает, что я знаю значение заранее, когда то, что я хочу сделать, - это сравнениепротив значения строки.Обычно я делал бы:
.filter([a.name == b.json_record['path']['to'].astext])
Но я также пытаюсь использовать оптимизацию из индекса gin
для этого столбца JSONB
, в результате чего мне нужен оператор @>
.
Редактировать 2
Основываясь на ответе Ильи Эвериля, я смог отследить метод SQLAlchemy , реализованный в исходном коде , и с использованием метода sql-json
удалось получить SQL почти там.
session \
.query(A_Table) \
.join(
B_Table.json_record.contains({
json_sql({'path': json_sql({
'to': A_Table.name
}
})
)
Предоставление мне SQL:
SELECT
a.row_id,
a.name
FROM
a
JOIN
b
ON
b.json_record @> json_build_object('path', json_build_object('to', a.name))
Проблема с этим выводом заключается в том, что вместо:
json_build_object(..., json_build_object(...))
Допустимый синтаксис Postgres должен быть:
json_build_object(..., json_build_object(...))::jsonb
Как в ответе, так и в подходе исходного кода опирается на _FunctionGenerator
, который может построить функцию, но это не яснокак что-то может быть добавлено в конец метода во время compile
при прохождении этого маршрута.
Edit 3
NVM - автор ответа указал, что jsonb_build_object(...)
будет соответствовать этой моделибез флага.