Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ SQL functions to build the OpenAPI output of a PostgREST instance.
- The first step in the roadmap is to migrate the OpenAPI spec from the PostgREST core repository (version 2.0 to 3.1):
- [x] Info object
- [x] Server object (replaces host, basePath and schemes from OAS 2.0)
- [ ] Components object
- [x] Components object
- [x] Schemas (definitions in OAS 2.0)
- [x] Security scheme (security definitions in OAS 2.0)
- [ ] Parameters
- [ ] Paths object
- [x] Parameters
- [x] Paths object
- [x] Tables and Views
- [x] GET
- [x] POST
- [x] PATCH
- [x] DELETE
- [ ] Functions
- [ ] GET
- [ ] POST
- [x] Functions
- [x] GET
- [x] POST
- [ ] External Documentation Object
- [ ] Handle relevant OpenAPI elements according to user permissions
- The next step is to fix the issues tagged with `OpenAPI` in the core repo.
Expand Down
176 changes: 171 additions & 5 deletions sql/components.sql
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ returns jsonb language sql stable as
$$
select oas_build_component_schemas_from_tables_and_composite_types(schemas) ||
oas_build_component_schemas_from_functions_return_types(schemas) ||
oas_build_component_schemas_from_functions_arguments(schemas) ||
oas_build_component_schemas_headers()
$$;

Expand Down Expand Up @@ -180,6 +181,64 @@ from (
) x;
$$;

create or replace function oas_build_component_schemas_from_functions_arguments(schemas text[])
returns jsonb language sql stable as
$$
with all_functions_with_arguments as (
-- Build Component Schemas for IN/INOUT or VARIADIC function arguments
select *
from postgrest_get_all_functions(schemas)
where argument_input_qty > 0
and (argument_is_in or argument_is_inout or argument_is_variadic)
and argument_name <> ''
),
aggregated_function_arguments as (
select
function_schema,
function_full_name,
function_description,
array_agg(argument_name order by argument_position) filter (where argument_is_required) AS required_arguments,
jsonb_object_agg(
argument_name,
case when argument_item_type_name is null and argument_is_composite then
oas_build_reference_to_schemas(argument_composite_full_name)
else
oas_schema_object(
type := postgrest_pgtype_to_oastype(argument_type_name),
format := argument_type_name::text,
items :=
case
when argument_item_type_name is null then
null
when argument_is_composite then
oas_build_reference_to_schemas(argument_composite_full_name)
else
oas_schema_object(
type := postgrest_pgtype_to_oastype(argument_item_type_name),
format := argument_item_type_name::text
)
end
)
end order by argument_position
) as arguments
from all_functions_with_arguments
group by function_schema, function_full_name, function_description
)
select jsonb_object_agg(x.component_name, x.oas_schema)
from (
select
'rpc.args.' || function_full_name as component_name,
oas_schema_object(
description := function_description,
properties := coalesce(arguments, '{}'),
type := 'object',
required := required_arguments
) as oas_schema
from
aggregated_function_arguments
) x;
$$;

create or replace function oas_build_component_schemas_headers()
returns jsonb language sql stable as
$$
Expand Down Expand Up @@ -304,6 +363,7 @@ returns jsonb language sql stable as
$$
select oas_build_component_parameters_query_params_from_tables(schemas) ||
oas_build_component_parameters_query_params_from_function_args(schemas) ||
oas_build_component_parameters_query_params_from_function_ret(schemas) ||
oas_build_component_parameters_query_params_common() ||
oas_build_component_parameters_headers_common();
$$;
Expand All @@ -322,14 +382,42 @@ from (
)
) as param_schema
from (
select table_full_name, column_name
from postgrest_get_all_tables_and_composite_types()
where table_schema = any(schemas)
and (is_table or is_view)
select table_full_name, column_name
from postgrest_get_all_tables_and_composite_types()
where (
table_schema = any(schemas)
and (is_table or is_view)
)
-- composite type columns can also be used as row filters if a function returns it
or exists (
select 1
from postgrest_get_all_functions(schemas)
where return_type_composite_relid = table_oid
)
) _
) x;
$$;

-- Builds "rowFilter"s for functions returning TABLE or INOUT/OUT types
create or replace function oas_build_component_parameters_query_params_from_function_ret(schemas text[])
returns jsonb language sql stable as
$$
select jsonb_object_agg(x.param_name, x.param_schema)
from (
select format('rowFilter.rpc.%1$s.%2$s', function_full_name, argument_name) as param_name,
oas_parameter_object(
name := argument_name,
"in" := 'query',
schema := oas_schema_object(
type := 'string'
)
) as param_schema
from postgrest_get_all_functions(schemas)
where argument_name <> ''
and (argument_is_inout or argument_is_out or argument_is_table)
) x;
$$;

create or replace function oas_build_component_parameters_query_params_from_function_args(schemas text[])
returns jsonb language sql stable as
$$
Expand Down Expand Up @@ -882,7 +970,8 @@ $$;
create or replace function oas_build_request_bodies(schemas text[])
returns jsonb language sql stable as
$$
select oas_build_request_bodies_from_tables(schemas);
select oas_build_request_bodies_from_tables(schemas) ||
oas_build_request_bodies_from_functions(schemas);
$$;

create or replace function oas_build_request_bodies_from_tables(schemas text[])
Expand Down Expand Up @@ -928,6 +1017,83 @@ from (
) as x;
$$;

create or replace function oas_build_request_bodies_from_functions(schemas text[])
returns jsonb language sql stable as
$$
select jsonb_object_agg('rpc.' || x.function_full_name, x.oas_req_body)
from (
select
function_full_name,
oas_request_body_object(
description := function_full_name,
required := argument_default_qty < argument_input_qty,
content :=
case when argument_input_qty = 1 and (array_agg(argument_name) filter (where argument_is_in or argument_is_inout))[1] = '' then
-- Media types according to the single unnamed parameter type
case function_input_argument_types[0]
when 'bytea'::regtype then
jsonb_build_object(
'application/octet-stream',
oas_media_type_object(
"schema" := oas_schema_object(
type := 'string',
format := 'binary'
)
)
)
when 'text'::regtype then
jsonb_build_object(
'text/plain',
oas_media_type_object(
"schema" := oas_schema_object(
type := 'string'
)
)
)
when 'xml'::regtype then
jsonb_build_object(
'text/xml',
oas_media_type_object(
"schema" := oas_schema_object(
type := 'string',
format := 'xml'
)
)
)
else -- single json or jsonb parameters
jsonb_build_object(
'application/json',
oas_media_type_object(
"schema" := '{}' -- json/jsonb types can be any type
)
)
end
else
jsonb_build_object(
'application/json',
oas_media_type_object(
"schema" := oas_build_reference_to_schemas('rpc.args.' || function_full_name)
),
'application/x-www-form-urlencoded',
oas_media_type_object(
"schema" := oas_build_reference_to_schemas('rpc.args.' || function_full_name)
),
'text/csv',
oas_media_type_object(
"schema" := oas_schema_object(
type := 'string',
format := 'csv'
)
)
)
end
) as oas_req_body
from postgrest_get_all_functions(schemas)
where argument_input_qty > 0
group by function_full_name, argument_input_qty, argument_default_qty, function_input_argument_types
) as x;
$$;

-- Security Schemes

create or replace function oas_build_component_security_schemes ()
Expand Down
66 changes: 63 additions & 3 deletions sql/paths.sql
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,73 @@ from (
'default',
oas_build_reference_to_responses('defaultError', 'Error')
)
),
post := oas_operation_object(
summary := (postgrest_unfold_comment(function_description))[1],
description := (postgrest_unfold_comment(function_description))[2],
tags := array['(rpc) ' || function_name],
requestBody := case when argument_input_qty > 0 then oas_build_reference_to_request_bodies('rpc.' || function_full_name) end,
parameters :=
-- TODO: The row filters for functions returning TABLE, OUT, INOUT and composite types should also work for the GET path.
-- Right now they're not included in GET, because the argument names (in rpcParams) could clash with the name of the return type columns (in rowFilter).
coalesce(
jsonb_agg(
oas_build_reference_to_parameters(format('rowFilter.rpc.%1$s.%2$s', function_full_name, argument_name))
) filter ( where argument_name <> '' and (argument_is_inout or argument_is_out or argument_is_table)),
'[]'
) ||
return_composite_param_ref ||
case when return_type_is_table or return_type_is_out or return_type_composite_relid <> 0 then
jsonb_build_array(
oas_build_reference_to_parameters('select'),
oas_build_reference_to_parameters('order'),
oas_build_reference_to_parameters('limit'),
oas_build_reference_to_parameters('offset'),
oas_build_reference_to_parameters('or'),
oas_build_reference_to_parameters('and'),
oas_build_reference_to_parameters('not.or'),
oas_build_reference_to_parameters('not.and'),
oas_build_reference_to_parameters('preferPostRpc')
)
else
jsonb_build_array(
oas_build_reference_to_parameters('preferPostRpc')
)
end,
responses :=
case when return_type_is_set then
jsonb_build_object(
'200',
oas_build_reference_to_responses('rpc.' || function_full_name, 'OK'),
'206',
oas_build_reference_to_responses('rpc.' || function_full_name, 'Partial Content')
)
else
jsonb_build_object(
'200',
oas_build_reference_to_responses('rpc.' || function_full_name, 'OK')
)
end ||
jsonb_build_object(
'default',
oas_build_reference_to_responses('defaultError', 'Error')
)
)
) as oas_path_item
from (
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
from postgrest_get_all_functions(schemas)
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_out, argument_is_table, argument_is_variadic, argument_input_qty,
comp.return_composite_param_ref
from postgrest_get_all_functions(schemas) f
left join lateral (
select coalesce(jsonb_agg(oas_build_reference_to_parameters(format('rowFilter.%1$s.%2$s', table_full_name, column_name))),'[]') as return_composite_param_ref
from (
select c.table_full_name, c.column_name
from postgrest_get_all_tables_and_composite_types() c
where f.return_type_composite_relid = c.table_oid
) _
) comp on true
) _
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
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, argument_input_qty, return_composite_param_ref
) x;
$$;

Expand Down
6 changes: 5 additions & 1 deletion sql/postgrest.sql
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ $$;
create or replace function postgrest_get_all_functions(schemas text[])
returns table (
argument_input_qty int,
argument_default_qty int,
argument_name text,
argument_reg_type oid,
argument_type_name text,
Expand All @@ -185,6 +186,7 @@ returns table (
function_name name,
function_full_name text,
function_description text,
function_input_argument_types oidvector,
return_type_name text,
return_type_item_name text,
return_type_is_set bool,
Expand Down Expand Up @@ -225,6 +227,7 @@ $$
all_functions AS (
SELECT
p.pronargs AS argument_input_qty,
p.pronargdefaults AS argument_default_qty,
COALESCE(pa.name, '') AS argument_name,
pa.type AS argument_reg_type,
format_type(ta.oid, NULL::integer) AS argument_type_name,
Expand All @@ -247,6 +250,7 @@ $$
-- The "full name" of the function `<schema>.<name>`. We omit `<schema>.` when it belongs to the `current_schema`
COALESCE(NULLIF(pn.nspname, current_schema) || '.', '') || p.proname AS function_full_name,
d.description AS function_description,
p.proargtypes AS function_input_argument_types,
format_type(t.oid, NULL::integer) AS return_type_name,
format_type(t_arr.oid, NULL::integer) AS return_type_item_name,
p.proretset AS return_type_is_set,
Expand Down Expand Up @@ -290,7 +294,7 @@ $$
WHERE x.argument_input_qty > 0
AND x.argument_name = ''
AND (x.argument_is_in OR x.argument_is_inout OR x.argument_is_variadic)
AND NOT (x.argument_input_qty = 1 AND x.argument_reg_type IN ('bytea'::regtype, 'json'::regtype, 'jsonb'::regtype, 'text'::regtype, 'xml'::regtype))
AND NOT (x.argument_input_qty = 1 AND x.function_input_argument_types[0] IN ('bytea'::regtype, 'json'::regtype, 'jsonb'::regtype, 'text'::regtype, 'xml'::regtype))
AND x.function_oid = a.function_oid
);
$$;
Expand Down
Loading
Loading