Skip to content

Commit 4ffebaa

Browse files
laurenceislasteve-chavez
authored andcommitted
feat: add Paths Object for GET requests on RPC endpoints
* Adds "/rpc/<function_name>" endpoints for valid functions to the Paths Object. * Valid functions are those that have no unnamed parameters or have a single unnamed parameter of type `json`,`jsonb`,`text`,`xml`. The rest are invalid. * Only `RETURNS SET OF` functions can return `206` to a partial request. * Common parameters such as `select`, `or`, etc. can be used when a function RETURNS TABLE, composite types or has INOUT/OUT parameters.
1 parent 8e7bfc9 commit 4ffebaa

File tree

3 files changed

+304
-1
lines changed

3 files changed

+304
-1
lines changed

sql/paths.sql

+66-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ create or replace function oas_build_paths(schemas text[])
44
returns jsonb language sql stable as
55
$$
66
select oas_build_path_item_root() ||
7-
oas_build_path_items_from_tables(schemas);
7+
oas_build_path_items_from_tables(schemas) ||
8+
oas_build_path_items_from_functions(schemas);
89
$$;
910

1011
create or replace function oas_build_path_items_from_tables(schemas text[])
@@ -134,6 +135,70 @@ from (
134135
) x;
135136
$$;
136137

138+
create or replace function oas_build_path_items_from_functions(schemas text[])
139+
returns jsonb language sql stable as
140+
$$
141+
select jsonb_object_agg(x.path, x.oas_path_item)
142+
from (
143+
select '/rpc/' || function_name as path,
144+
oas_path_item_object(
145+
get :=oas_operation_object(
146+
summary := (postgrest_unfold_comment(function_description))[1],
147+
description := (postgrest_unfold_comment(function_description))[2],
148+
tags := array['(rpc) ' || function_name],
149+
parameters :=
150+
coalesce(
151+
jsonb_agg(
152+
oas_build_reference_to_parameters(format('rpcParam.%1$s.%2$s', function_full_name, argument_name))
153+
) filter ( where argument_name <> '' and (argument_is_in or argument_is_inout or argument_is_variadic)),
154+
'[]'
155+
) ||
156+
case when return_type_is_table or return_type_is_out or return_type_composite_relid <> 0 then
157+
jsonb_build_array(
158+
oas_build_reference_to_parameters('select'),
159+
oas_build_reference_to_parameters('order'),
160+
oas_build_reference_to_parameters('limit'),
161+
oas_build_reference_to_parameters('offset'),
162+
oas_build_reference_to_parameters('or'),
163+
oas_build_reference_to_parameters('and'),
164+
oas_build_reference_to_parameters('not.or'),
165+
oas_build_reference_to_parameters('not.and'),
166+
oas_build_reference_to_parameters('range'),
167+
oas_build_reference_to_parameters('preferGet')
168+
)
169+
else
170+
jsonb_build_array(
171+
oas_build_reference_to_parameters('preferGet')
172+
)
173+
end,
174+
responses :=
175+
case when return_type_is_set then
176+
jsonb_build_object(
177+
'200',
178+
oas_build_reference_to_responses('rpc.' || function_full_name, 'OK'),
179+
'206',
180+
oas_build_reference_to_responses('rpc.' || function_full_name, 'Partial Content')
181+
)
182+
else
183+
jsonb_build_object(
184+
'200',
185+
oas_build_reference_to_responses('rpc.' || function_full_name, 'OK')
186+
)
187+
end ||
188+
jsonb_build_object(
189+
'default',
190+
oas_build_reference_to_responses('defaultError', 'Error')
191+
)
192+
)
193+
) as oas_path_item
194+
from (
195+
select function_name, function_full_name, function_description, return_type_name, return_type_is_set, return_type_is_table, return_type_is_out, return_type_composite_relid, argument_name, argument_is_in, argument_is_inout, argument_is_variadic
196+
from postgrest_get_all_functions(schemas)
197+
) _
198+
group by function_name, function_full_name, function_description, return_type_name, return_type_is_set, return_type_is_table, return_type_is_out, return_type_composite_relid
199+
) x;
200+
$$;
201+
137202
create or replace function oas_build_path_item_root()
138203
returns jsonb language sql stable as
139204
$$

test/expected/paths.out

+179
Original file line numberDiff line numberDiff line change
@@ -701,3 +701,182 @@ select postgrest_openapi_spec('{test}')->'paths'->'/non_auto_updatable' ? 'delet
701701
f
702702
(1 row)
703703

704+
-- Functions
705+
-- GET operation object
706+
-- shows the function name as tag
707+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'tags');
708+
jsonb_pretty
709+
----------------------------------
710+
[ +
711+
"(rpc) get_products_by_size"+
712+
]
713+
(1 row)
714+
715+
-- uses a reference for the 200 HTTP code response
716+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'responses'->'200');
717+
jsonb_pretty
718+
----------------------------------------------------------------
719+
{ +
720+
"$ref": "#/components/responses/rpc.get_products_by_size",+
721+
"description": "OK" +
722+
}
723+
(1 row)
724+
725+
-- uses a reference for the 206 HTTP code response on `RETURNS SET OF` functions
726+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'responses'->'206');
727+
jsonb_pretty
728+
----------------------------------------------------------------
729+
{ +
730+
"$ref": "#/components/responses/rpc.get_products_by_size",+
731+
"description": "Partial Content" +
732+
}
733+
(1 row)
734+
735+
-- uses a reference for error responses
736+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'responses'->'default');
737+
jsonb_pretty
738+
----------------------------------------------------
739+
{ +
740+
"$ref": "#/components/responses/defaultError",+
741+
"description": "Error" +
742+
}
743+
(1 row)
744+
745+
-- shows the first line of the comment on the table as summary
746+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'summary');
747+
jsonb_pretty
748+
--------------------------------
749+
"Get Products By Size summary"
750+
(1 row)
751+
752+
-- shows the second line of the comment on the table as description
753+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'description');
754+
jsonb_pretty
755+
-----------------------------------------------------------------
756+
"Get Products By Size description\nthat spans\nmultiple lines."
757+
(1 row)
758+
759+
-- uses references for common parameters on `RETURNS <composite type>` functions
760+
select value
761+
from jsonb_array_elements(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_attribute'->'get'->'parameters')
762+
where value->>'$ref' not like '#/components/parameters/rpcParam.get_attribute.%';
763+
value
764+
-----------------------------------------------
765+
{"$ref": "#/components/parameters/select"}
766+
{"$ref": "#/components/parameters/order"}
767+
{"$ref": "#/components/parameters/limit"}
768+
{"$ref": "#/components/parameters/offset"}
769+
{"$ref": "#/components/parameters/or"}
770+
{"$ref": "#/components/parameters/and"}
771+
{"$ref": "#/components/parameters/not.or"}
772+
{"$ref": "#/components/parameters/not.and"}
773+
{"$ref": "#/components/parameters/range"}
774+
{"$ref": "#/components/parameters/preferGet"}
775+
(10 rows)
776+
777+
-- uses references for common parameters on `RETURNS TABLE` functions
778+
select value
779+
from jsonb_array_elements(postgrest_openapi_spec('{test}')->'paths'->'/rpc/returns_table'->'get'->'parameters')
780+
where value->>'$ref' not like '#/components/parameters/rpcParam.returns_table.%';
781+
value
782+
-----------------------------------------------
783+
{"$ref": "#/components/parameters/select"}
784+
{"$ref": "#/components/parameters/order"}
785+
{"$ref": "#/components/parameters/limit"}
786+
{"$ref": "#/components/parameters/offset"}
787+
{"$ref": "#/components/parameters/or"}
788+
{"$ref": "#/components/parameters/and"}
789+
{"$ref": "#/components/parameters/not.or"}
790+
{"$ref": "#/components/parameters/not.and"}
791+
{"$ref": "#/components/parameters/range"}
792+
{"$ref": "#/components/parameters/preferGet"}
793+
(10 rows)
794+
795+
-- uses references for common parameters on functions with INOUT/OUT parameters
796+
select value
797+
from jsonb_array_elements(postgrest_openapi_spec('{test}')->'paths'->'/rpc/returns_inout_out'->'get'->'parameters')
798+
where value->>'$ref' not like '#/components/parameters/rpcParam.returns_inout_out.%';
799+
value
800+
-----------------------------------------------
801+
{"$ref": "#/components/parameters/select"}
802+
{"$ref": "#/components/parameters/order"}
803+
{"$ref": "#/components/parameters/limit"}
804+
{"$ref": "#/components/parameters/offset"}
805+
{"$ref": "#/components/parameters/or"}
806+
{"$ref": "#/components/parameters/and"}
807+
{"$ref": "#/components/parameters/not.or"}
808+
{"$ref": "#/components/parameters/not.and"}
809+
{"$ref": "#/components/parameters/range"}
810+
{"$ref": "#/components/parameters/preferGet"}
811+
(10 rows)
812+
813+
-- does not use a reference for the 206 HTTP code response on functions that do not return `SET OF`
814+
select postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_attribute'->'get'->'responses' ? '206' as value;
815+
value
816+
-------
817+
f
818+
(1 row)
819+
820+
-- does not use a reference for common parameters (except for prefer headers) on functions that do not return composite types
821+
select value
822+
from jsonb_array_elements(postgrest_openapi_spec('{test}')->'paths'->'/rpc/returns_simple_type'->'get'->'parameters')
823+
where value->>'$ref' not like '#/components/parameters/rpcParam.returns_simple_type.%';
824+
value
825+
-----------------------------------------------
826+
{"$ref": "#/components/parameters/preferGet"}
827+
(1 row)
828+
829+
-- shows a function with a single unnamed parameter of accepted types
830+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/single_unnamed_json_param'->'get'->'tags');
831+
jsonb_pretty
832+
---------------------------------------
833+
[ +
834+
"(rpc) single_unnamed_json_param"+
835+
]
836+
(1 row)
837+
838+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/single_unnamed_jsonb_param'->'get'->'tags');
839+
jsonb_pretty
840+
----------------------------------------
841+
[ +
842+
"(rpc) single_unnamed_jsonb_param"+
843+
]
844+
(1 row)
845+
846+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/single_unnamed_text_param'->'get'->'tags');
847+
jsonb_pretty
848+
---------------------------------------
849+
[ +
850+
"(rpc) single_unnamed_text_param"+
851+
]
852+
(1 row)
853+
854+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/single_unnamed_xml_param'->'get'->'tags');
855+
jsonb_pretty
856+
--------------------------------------
857+
[ +
858+
"(rpc) single_unnamed_xml_param"+
859+
]
860+
(1 row)
861+
862+
-- does not show a function with a single unnamed parameter of non-accepted types
863+
select postgrest_openapi_spec('{test}')->'paths' ? '/rpc/single_unnamed_unrecognized_param' as value;
864+
value
865+
-------
866+
f
867+
(1 row)
868+
869+
-- does not show a function with unnamed parameters
870+
select postgrest_openapi_spec('{test}')->'paths' ? '/rpc/unnamed_params' as value;
871+
value
872+
-------
873+
f
874+
(1 row)
875+
876+
-- does not show a function with named and unnamed parameters
877+
select postgrest_openapi_spec('{test}')->'paths' ? '/rpc/named_and_unnamed_params' as value;
878+
value
879+
-------
880+
f
881+
(1 row)
882+

test/sql/paths.sql

+59
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,62 @@ where value->>'$ref' not like '#/components/parameters/rowFilter.big_products.%'
250250

251251
-- does not show a DELETE operation object for non auto-updatable views
252252
select postgrest_openapi_spec('{test}')->'paths'->'/non_auto_updatable' ? 'delete' as value;
253+
254+
-- Functions
255+
-- GET operation object
256+
257+
-- shows the function name as tag
258+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'tags');
259+
260+
-- uses a reference for the 200 HTTP code response
261+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'responses'->'200');
262+
263+
-- uses a reference for the 206 HTTP code response on `RETURNS SET OF` functions
264+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'responses'->'206');
265+
266+
-- uses a reference for error responses
267+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'responses'->'default');
268+
269+
-- shows the first line of the comment on the table as summary
270+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'summary');
271+
272+
-- shows the second line of the comment on the table as description
273+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_products_by_size'->'get'->'description');
274+
275+
-- uses references for common parameters on `RETURNS <composite type>` functions
276+
select value
277+
from jsonb_array_elements(postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_attribute'->'get'->'parameters')
278+
where value->>'$ref' not like '#/components/parameters/rpcParam.get_attribute.%';
279+
280+
-- uses references for common parameters on `RETURNS TABLE` functions
281+
select value
282+
from jsonb_array_elements(postgrest_openapi_spec('{test}')->'paths'->'/rpc/returns_table'->'get'->'parameters')
283+
where value->>'$ref' not like '#/components/parameters/rpcParam.returns_table.%';
284+
285+
-- uses references for common parameters on functions with INOUT/OUT parameters
286+
select value
287+
from jsonb_array_elements(postgrest_openapi_spec('{test}')->'paths'->'/rpc/returns_inout_out'->'get'->'parameters')
288+
where value->>'$ref' not like '#/components/parameters/rpcParam.returns_inout_out.%';
289+
290+
-- does not use a reference for the 206 HTTP code response on functions that do not return `SET OF`
291+
select postgrest_openapi_spec('{test}')->'paths'->'/rpc/get_attribute'->'get'->'responses' ? '206' as value;
292+
293+
-- does not use a reference for common parameters (except for prefer headers) on functions that do not return composite types
294+
select value
295+
from jsonb_array_elements(postgrest_openapi_spec('{test}')->'paths'->'/rpc/returns_simple_type'->'get'->'parameters')
296+
where value->>'$ref' not like '#/components/parameters/rpcParam.returns_simple_type.%';
297+
298+
-- shows a function with a single unnamed parameter of accepted types
299+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/single_unnamed_json_param'->'get'->'tags');
300+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/single_unnamed_jsonb_param'->'get'->'tags');
301+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/single_unnamed_text_param'->'get'->'tags');
302+
select jsonb_pretty(postgrest_openapi_spec('{test}')->'paths'->'/rpc/single_unnamed_xml_param'->'get'->'tags');
303+
304+
-- does not show a function with a single unnamed parameter of non-accepted types
305+
select postgrest_openapi_spec('{test}')->'paths' ? '/rpc/single_unnamed_unrecognized_param' as value;
306+
307+
-- does not show a function with unnamed parameters
308+
select postgrest_openapi_spec('{test}')->'paths' ? '/rpc/unnamed_params' as value;
309+
310+
-- does not show a function with named and unnamed parameters
311+
select postgrest_openapi_spec('{test}')->'paths' ? '/rpc/named_and_unnamed_params' as value;

0 commit comments

Comments
 (0)