我需要通过 Postgres 的 Rest API 一次更新几行。我想出如何做到这一点的唯一方法是通过函数调用,其中我将 JSON 传递给函数并迭代 JSON 并执行更新。
但是,根据我所做的,我遇到了两个问题之一。
如果我创建接受 json 或 jsonb 类型的通用函数,PostgREST 会告诉我:
No function matches the given name and argument types. You might need to add explicit type casts.
但是,如果我创建一个接受 json 或 jsonb 对象的重载函数,则会收到错误:
{"code":"PGRST203","details":null,"hint":"Try renaming the parameters or the function itself in the database so function overloading can be resolved","message":"Could not choose the best candidate function..."
如何解决这个问题? PostgREST 在没有重载的情况下无法找到该函数,但是在重载时,它可以找到该函数,但不知道该使用哪个函数。
SQL:
-- TABLE --
CREATE TABLE IF NOT EXISTS vehicle_database.test_table(
test_table_id BIGSERIAL PRIMARY KEY,
test_data INTEGER,
test_type VARCHAR(8)
);
-- Overloaded function using json --
CREATE OR REPLACE FUNCTION update_test_table(p_json json)
RETURNS void AS $$
DECLARE
json_item json;
BEGIN
FOR json_item IN SELECT json_array_elements(p_json) LOOP
PERFORM update_test_table_row(
(json_item->>'data')::integer,
(json_item->>'test_type')::text);
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- Overloaded function using jsonb --
CREATE OR REPLACE FUNCTION update_test_table(p_json jsonb)
RETURNS void AS $$
DECLARE
json_item json;
BEGIN
FOR json_item IN SELECT json_array_elements(p_json) LOOP
PERFORM update_test_table_row(
(json_item->>'data')::integer,
(json_item->>'test_type')::text);
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- Overloaded function using text --
CREATE OR REPLACE FUNCTION update_test_table(p_json text)
RETURNS void AS $$
DECLARE
json_item json;
BEGIN
json_data = p_json::JSONB;
PERFORM update_test_table(json_data);
END;
$$ LANGUAGE plpgsql;
-- Update the row
CREATE OR REPLACE FUNCTION update_test_table_row(p_data integer, p_type text)
RETURNS void AS $$
BEGIN
UPDATE test_table SET test_data = p_data WHERE test_type = p_type;
IF NOT FOUND THEN
RAISE NOTICE 'No rows updated for data: %, type: %', p_data, p_type;
END IF;
END;
$$ LANGUAGE plpgsql;
-- Permissions (same kind of users as in the tutorials)
GRANT EXECUTE ON FUNCTION update_test_table(p_json json) TO web_insert;
GRANT EXECUTE ON FUNCTION update_test_table(p_json jsonb) TO web_insert;
GRANT EXECUTE ON FUNCTION update_test_table(p_json text) TO web_insert;
GRANT EXECUTE ON FUNCTION update_test_table_row(p_data integer, p_type text) TO web_insert;
我是这样称呼它的:
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '[{"test_data":"4","test_type":"RED"}]' http://127.0.0.1:3000/rpc/update_test_table
$TOKEN
是我的私人令牌,与 jwt-secret 字段中的 PostgREST 一起使用。
不幸的是,PostgREST 没有详细的日志记录,而 Postgres 日志对此并没有真正的帮助。 Postgres 告诉我该函数不存在,但 Postgres 日志实际上并不打印 JSON 参数(它打印所有其他curl 参数,但不打印
-d
中包含的内容)。
找到答案了。
这不在 PostgREST 文档中,但应该包含在内。
如果您尝试从 PostgREST API 调用 RPC 函数,传递 JSON 数据或 JSONB 数据,则必须将该数据分配给变量。
因此,在上面列出的问题实例中,删除带有 text 参数的重载函数,然后删除其他重载函数之一(json 或 jsonb 参数)。
然后你的curl函数需要将JSON分配给与函数中的名称匹配的变量名称。
所以我的解决方案(删除2个重载函数后是):
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"p_json":[{"test_data":"4","test_type":"RED"}]}' \
http://127.0.0.1:3000/rpc/update_test_table