我在寻找正确的方法将 PL/pgSQL 中的用户定义函数转换为 jOOQ 代码时遇到问题。我在 PL/pgSQL 中的用户定义函数返回 JSON 类型,我需要以某种方式在 jOOQ 中调整/转换它。我用谷歌搜索了一些例子,但没有找到。
以防万一这是我在 PL/pgSQL 中的用户定义函数:
create or replace function public.get_order_by_order_id(o_id bigint) returns json as
$BODY$
DECLARE
total_oi_price double precision;
book_price double precision;
total_price double precision;
oi_amount integer;
order_items json;
item_recs RECORD;
book_json json;
single_order_item json;
found_order "vertx-jooq-cr".public.orders;
found_user json;
_item_id bigint;
item_array json[];
BEGIN
select * into found_order
from "vertx-jooq-cr".public.orders
where order_id = o_id;
select json_build_object('user_id', "vertx-jooq-cr".public.users.user_id, 'username', "vertx-jooq-cr".public.users.username)
into found_user
from "vertx-jooq-cr".public.users
INNER JOIN "vertx-jooq-cr".public.orders as o USING (user_id)
WHERE o.order_id = o_id;
total_price = 0.00;
FOR item_recs IN SELECT *
FROM public.order_item AS oi WHERE oi.order_id = o_id
LOOP
select public.get_book_by_book_id(item_recs.book_id) into book_json
from public.order_item
where public.order_item.order_item_id IN (item_recs.order_item_id);
select price INTO book_price FROM book AS b WHERE b.book_id = item_recs.book_id;
select amount INTO oi_amount FROM order_item AS oi WHERE oi.amount = item_recs.amount;
total_oi_price = book_price * oi_amount;
SELECT json_build_object('order_item_id', item_recs.order_item_id,
'amount', item_recs.amount,
'book', book_json,
'order_id', item_recs.order_id,
'total_order_item_price', trunc(total_oi_price::double precision::text::numeric, 2)) INTO single_order_item;
total_price := total_price + total_oi_price;
item_array = array_append(item_array, single_order_item);
END LOOP;
order_items = array_to_json(item_array);
return (select json_build_object(
'order_id', found_order.order_id,
'total_price', trunc(total_price::double precision::text::numeric, 2),
'order_date', found_order.order_date,
'user', found_user,
'order_items', order_items
));
end;
$BODY$
LANGUAGE 'plpgsql';
...以及另一个使用上面列出的功能的。
CREATE OR REPLACE FUNCTION get_all_orders() RETURNS JSON AS
$BODY$
DECLARE
single_order RECORD;
single_order_json json;
orders_array json[];
BEGIN
FOR single_order IN SELECT * FROM public.orders ORDER BY order_id
LOOP
SELECT get_order_by_order_id(single_order.order_id) INTO single_order_json;
orders_array = array_append(orders_array, single_order_json);
END LOOP;
return (select json_build_object(
'orders', orders_array
));
END;
$BODY$
LANGUAGE 'plpgsql';
这两个函数已在我的 Maven 项目中成功生成代码,最后一个get_all_orders()
函数需要对其执行 SELECT 操作并在我的 jOOQ 代码中返回 JSON 对象。
这是Routines.java
**.jooq 包中生成的类Keys.java
,DefaultCatalog.java
以及其他类:
/**
* Convenience access to all stored procedures and functions in public
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
public class Routines {
/**
* Call <code>public.get_all_orders</code>
*/
public static JSON getAllOrders(Configuration configuration) {
GetAllOrders f = new GetAllOrders();
f.execute(configuration);
return f.getReturnValue();
}
/**
* Get <code>public.get_all_orders</code> as a field.
*/
public static Field<JSON> getAllOrders() {
GetAllOrders f = new GetAllOrders();
return f.asField();
}
// other methods left out for code brevity
/**
* Call <code>public.get_order_by_order_id</code>
*/
public static JSON getOrderByOrderId(Configuration configuration, Long oId) {
GetOrderByOrderId f = new GetOrderByOrderId();
f.setOId(oId);
f.execute(configuration);
return f.getReturnValue();
}
/**
* Get <code>public.get_order_by_order_id</code> as a field.
*/
public static Field<JSON> getOrderByOrderId(Long oId) {
GetOrderByOrderId f = new GetOrderByOrderId();
f.setOId(oId);
return f.asField();
}
/**
* Get <code>public.get_order_by_order_id</code> as a field.
*/
public static Field<JSON> getOrderByOrderId(Field<Long> oId) {
GetOrderByOrderId f = new GetOrderByOrderId();
f.setOId(oId);
return f.asField();
}
}
这是我GetAllOrders.java
位于**.jooq.routines
包中的例程类
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
public class GetAllOrders extends AbstractRoutine<JSON> {
private static final long serialVersionUID = 917599810;
/**
* The parameter <code>public.get_all_orders.RETURN_VALUE</code>.
*/
public static final Parameter<JSON> RETURN_VALUE = Internal.createParameter("RETURN_VALUE", org.jooq.impl.SQLDataType.JSON, false, false);
/**
* Create a new routine call instance
*/
public GetAllOrders() {
super("get_all_orders", Public.PUBLIC, org.jooq.impl.SQLDataType.JSON);
setReturnParameter(RETURN_VALUE);
}
}
最后,这是我在 jOOQ 中执行 SELECT 查询的 jOOQ 代码:
Future<JsonObject> ordersFuture = queryExecutor.transaction(qe -> qe
.query(dsl -> dsl
.select(new Routines().getAllOrders())
));
... qe.query() 方法的定义如下:
@Override
public <R extends Record> Future<QueryResult> query(Function<DSLContext, ? extends ResultQuery<R>> queryFunction) {
return executeAny(queryFunction).map(ReactiveQueryResult::new);
}
产生的问题:
“类型不匹配:无法从 Future<Object> 转换为 Future<JsonObject>”
“类型不匹配:无法从 Future<QueryResult> 转换为 Future<Object>”
顺便说一句,我需要提到这是使用jOOQ 3.13.1的vertx-jooq实现。
非常感谢任何帮助/建议。
更新:
这里要求缺少类型和签名第一个transaction()
方法(更多信息在这里)
/**
* Convenience method to perform multiple calls on a transactional QueryExecutor, committing the transaction and
* returning a result.
* @param transaction your code using a transactional QueryExecutor.
* <pre>
* {@code
* ReactiveClassicGenericQueryExecutor nonTransactionalQueryExecutor...;
* Future<QueryResult> resultOfTransaction = nonTransactionalQueryExecutor.transaction(transactionalQueryExecutor ->
* {
* //make all calls on the provided QueryExecutor that runs all code in a transaction
* return transactionalQueryExecutor.execute(dslContext -> dslContext.insertInto(Tables.XYZ)...)
* .compose(i -> transactionalQueryExecutor.query(dslContext -> dslContext.selectFrom(Tables.XYZ).where(Tables.XYZ.SOME_VALUE.eq("FOO")));
* }
* );
* }
* </pre>
* @param <U> the return type.
* @return the result of the transaction.
*/
public <U> Future<U> transaction(Function<ReactiveClassicGenericQueryExecutor, Future<U>> transaction){
return beginTransaction()
.compose(queryExecutor -> transaction.apply(queryExecutor) //perform user tasks
.compose(res -> queryExecutor.commit() //commit the transaction
.map(v -> res))); //and return the result
}
...和executeAny()
(更多信息可在此处获得):
/**
* Executes the given queryFunction and returns a <code>RowSet</code>
* @param queryFunction the query to execute
* @return the results, never null
*/
public Future<RowSet<Row>> executeAny(Function<DSLContext, ? extends Query> queryFunction) {
Query query = createQuery(queryFunction);
log(query);
Promise<RowSet<Row>> rowPromise = Promise.promise();
delegate.preparedQuery(toPreparedQuery(query)).execute(getBindValues(query),rowPromise);
return rowPromise.future();
}
...这里是ReactiveQueryResult
UPDATE2:
这是我get_all_orders()
在 JSON 类型的 PL/pgSQL 中创建的函数的结果:
{
"orders": [
{
"order_id": 1,
"total_price": 29.99,
"order_date": "2019-08-22T10:06:33",
"user": {
"user_id": 1,
"username": "test"
},
"order_items": [
{
"order_item_id": 1,
"amount": 1,
"book": {
"book_id": 1,
"title": "Harry Potter and the Philosopher's Stone",
"price": 29.99,
"amount": 400,
"is_deleted": false,
"authors": [
{
"author_id": 4,
"first_name": "JK",
"last_name": "Rowling"
}
],
"categories": [
{
"category_id": 2,
"name": "Lyric",
"is_deleted": false
}
]
},
"order_id": 1,
"total_order_item_price": 29.99
}
]
},
{
"order_id": 2,
"total_price": 29.99,
"order_date": "2019-08-22T10:10:13",
"user": {
"user_id": 1,
"username": "test"
},
"order_items": [
{
"order_item_id": 2,
"amount": 1,
"book": {
"book_id": 1,
"title": "Harry Potter and the Philosopher's Stone",
"price": 29.99,
"amount": 400,
"is_deleted": false,
"authors": [
{
"author_id": 4,
"first_name": "JK",
"last_name": "Rowling"
}
],
"categories": [
{
"category_id": 2,
"name": "Lyric",
"is_deleted": false
}
]
},
"order_id": 2,
"total_order_item_price": 29.99
}
]
}
]
}