From d1a8c3a6f88cfd70039a2810c49e932f2bca360e Mon Sep 17 00:00:00 2001 From: steve-chavez Date: Sat, 7 Oct 2017 17:38:34 -0500 Subject: [PATCH] Fix #974 RPC error when function has single OUT param --- CHANGELOG.md | 1 + src/PostgREST/QueryBuilder.hs | 5 ++--- test/Feature/RpcSpec.hs | 19 +++++++++++++++++++ test/fixtures/schema.sql | 12 ++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc694ab40..647ec3304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - #954, make OpenAPI rpc output dependent on user privileges - @steve-chavez - #955, Support configurable aud claim - @statik - #996, Fix embedded column conflicts table name - @grotsev +- #974, Fix RPC error when function has single OUT param - @steve-chavez ## [0.4.3.0] - 2017-09-06 diff --git a/src/PostgREST/QueryBuilder.hs b/src/PostgREST/QueryBuilder.hs index 9dc97336d..148eb787f 100644 --- a/src/PostgREST/QueryBuilder.hs +++ b/src/PostgREST/QueryBuilder.hs @@ -150,14 +150,14 @@ callProc qi params returnsScalar selectQuery countQuery _ countTotal isSingle pa where sql = if returnsScalar then [qc| - WITH {sourceCTEName} AS ({_callSql}) + WITH {sourceCTEName} AS (select {fromQi qi}({_args})) SELECT {countResultF} AS total_result_set, 1 AS page_total, {scalarBodyF} as body FROM ({selectQuery}) _postgrest_t;|] else [qc| - WITH {sourceCTEName} AS ({_callSql}) + WITH {sourceCTEName} AS (select * from {fromQi qi}({_args})) SELECT {countResultF} AS total_result_set, pg_catalog.count(_postgrest_t) AS page_total, @@ -170,7 +170,6 @@ callProc qi params returnsScalar selectQuery countQuery _ countTotal isSingle pa else intercalate "," $ map _assignment (HM.toList params) _procName = qiName qi _assignment (n,v) = pgFmtIdent n <> ":=" <> insertableValue v - _callSql = [qc|select * from {fromQi qi}({_args}) |] :: Text decodeProc = HD.maybeRow procRow procRow = (,,) <$> HD.nullableValue HD.int8 <*> HD.value HD.int8 <*> HD.value HD.bytea diff --git a/test/Feature/RpcSpec.hs b/test/Feature/RpcSpec.hs index 43712c7d1..5e9959fc6 100644 --- a/test/Feature/RpcSpec.hs +++ b/test/Feature/RpcSpec.hs @@ -257,6 +257,25 @@ spec = get "/rpc/test" `shouldRespondWith` [json|[{"test":"hello","value":1}]|] { matchHeaders = [matchContentTypeJson] } + context "procs with OUT/INOUT params" $ do + it "returns a scalar result when there is a single OUT param" $ do + get "/rpc/single_out_param?num=5" `shouldRespondWith` + [json|6|] { matchHeaders = [matchContentTypeJson] } + get "/rpc/single_json_out_param?a=1&b=two" `shouldRespondWith` + [json|{"a": 1, "b": "two"}|] { matchHeaders = [matchContentTypeJson] } + + it "returns a scalar result when there is a single INOUT param" $ + get "/rpc/single_inout_param?num=2" `shouldRespondWith` + [json|3|] { matchHeaders = [matchContentTypeJson] } + + it "returns a row result when there are many OUT params" $ + get "/rpc/many_out_params" `shouldRespondWith` + [json|[{"my_json":{"a": 1, "b": "two"},"num":3,"str":"four"}]|] { matchHeaders = [matchContentTypeJson] } + + it "returns a row result when there are many INOUT params" $ + get "/rpc/many_inout_params?num=1&str=two" `shouldRespondWith` + [json| [{"num":1,"str":"two","b":true}]|] { matchHeaders = [matchContentTypeJson] } + context "only for POST rpc" $ do context "expects a single json object" $ do it "does not expand posted json into parameters" $ diff --git a/test/fixtures/schema.sql b/test/fixtures/schema.sql index a9a76f9ac..056e7f6d8 100755 --- a/test/fixtures/schema.sql +++ b/test/fixtures/schema.sql @@ -1273,10 +1273,22 @@ create table test.being_part ( part int not null references test.part(part) ); +create function test.single_out_param(num int, OUT num_plus_one int) AS $$ + select num + 1; +$$ language sql; + +create function test.single_json_out_param(a int, b text, OUT my_json pg_catalog.json) AS $$ + select json_build_object('a', a, 'b', b); +$$ language sql; + create function test.many_out_params(OUT my_json pg_catalog.json, OUT num int, OUT str text) AS $$ select '{"a": 1, "b": "two"}'::json, 3, 'four'::text; $$ language sql; +create function test.single_inout_param(INOUT num int) AS $$ + select num + 1; +$$ language sql; + create function test.many_inout_params(INOUT num int, INOUT str text, INOUT b bool DEFAULT true) AS $$ select num, str, b; $$ language sql;