Context
Я работаю с jOOQ против базы данных PostgreSQL .
Я хочу использовать jsonb_object_agg(name, value)
в наборе результатов LEFT OUTER JOIN
.
Проблема
Объединение - это OUTER
соединение, иногда компонент name
функции агрегирования просто null
: это не может работать.Тогда я бы сказал:
COALESCE(
json_object_agg(table.name, table.value) FILTER (WHERE table.name IS NOT NULL),
'{}'
)::json
На данный момент код, который я использую для вызова jsonb_object_agg
, (не точно, но сводится к следующему) следующий:
public static Field<?> jsonbObjectAgg(final Field<?> key, final Select<?> select) {
return DSL.field("jsonb_object_agg({0}, ({1}))::jsonb", JSON_TYPE, key, select);
}
... где JSON_TYPE
- это:
private static final DataType<JsonNode> JSON_TYPE = SQLDataType.VARCHAR.asConvertedDataType(/* a custom Converter */);
Неполное решение
Я хотел бы использовать интерфейс jOOQ AggregateFilterStep
и, в частности,быть в состоянии использовать его AggregateFilterStep#filterWhere(Condition... conditions)
.
Однако класс org.jooq.impl.Function
, который implements AggregateFilterStep
(косвенно через AgregateFunction
и ArrayAggOrderByStep
) ограничен в видимости его package
, поэтому я не могу просто слепо перерабатывать реализацию DSL#ArrayAggOrderByStep
:
public static <T> ArrayAggOrderByStep<T[]> arrayAgg(Field<T> field) {
return new org.jooq.impl.Function<T[]>(Term.ARRAY_AGG, field.getDataType().getArrayDataType(), nullSafe(field));
}
Попытки
Самое близкое, что я получил к чему-то разумному, это ...создание моей собственной функции coalesceAggregation
, которая специально объединяет агрегированные поля:
// Can't quite use AggregateFunction there
// v v
public static <T> Field<T> coalesceAggregation(final Field<T> agg, final Condition coalesceWhen, @NonNull final T coalesceTo) {
return DSL.coalesce(DSL.field("{0} FILTER (WHERE {1})", agg.getType(), agg, coalesceWhen), coalesceTo);
}
public static <T> Field<T> coalesceAggregation(final Field<T> agg, @NonNull final T coalesceTo) {
return coalesceAggregation(agg, agg.isNotNull(), coalesceTo);
}
... Но затем я столкнулся с проблемами с моим типом T
, равным JsonNode
, где DSL#coalesce
кажется CAST
моим coalesceTo
до varchar
.
Или, вы знаете:
DSL.field("COALESCE(jsonb_object_agg({0}, ({1})) FILTER (WHERE {0} IS NOT NULL), '{}')::jsonb", JSON_TYPE, key, select)
Но это было бы самым последним средством: эточувствую, что я просто в шаге отПользователь вводит любой SQL-запрос в мою базу данных ?
Короче говоря
Есть ли способ в jOOQ"должным образом" реализовать собственную агрегатную функцию как фактическуюorg.jooq.AgregateFunction
?
Я бы хотел, чтобы он не генерировался как можно больше jooq-codegen
(не то, чтобы мне это не нравилось - просто ужасен наш конвейер).