Skip to content

Commit

Permalink
WIP: Add functions to /get path
Browse files Browse the repository at this point in the history
  • Loading branch information
laurenceisla committed Sep 21, 2024
1 parent 0f132f6 commit 34b2999
Show file tree
Hide file tree
Showing 3 changed files with 274 additions and 8 deletions.
203 changes: 198 additions & 5 deletions sql/components.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ create or replace function oas_build_component_schemas(schemas text[])
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_headers()
$$;

Expand Down Expand Up @@ -103,6 +104,82 @@ from (
) x;
$$;

create or replace function oas_build_component_schemas_from_functions_return_types(schemas text[])
returns jsonb language sql stable as
$$
with all_functions_returning_table_out_simple_types as (
-- Build Component Schemas for functions that RETURNS simple types or RETURNS TABLE or with IN/INOUT arguments
select *, not (return_type_is_out or return_type_is_table) as return_type_is_simple
from postgrest_get_all_functions(schemas)
where return_type_is_out or return_type_is_table or not return_type_is_composite
),
aggregated_function_returns as (
select
function_schema,
function_full_name,
function_description,
return_type_is_simple,
-- Build objects for functions with RETURNS TABLE or with IN/INOUT arguments
case when not return_type_is_simple then
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
) filter ( where argument_is_table or argument_is_out or argument_is_inout)
-- For functions with RETURNS <simple type> build the Schema according to the type
else
oas_schema_object(
type := postgrest_pgtype_to_oastype(return_type_name),
format := return_type_name::text,
items :=
case when return_type_item_name is not null then
oas_schema_object(
type := postgrest_pgtype_to_oastype(return_type_item_name),
format := return_type_item_name::text
)
end
)
end as arguments
from all_functions_returning_table_out_simple_types
group by function_schema, function_name, function_full_name, function_description, return_type_is_simple, return_type_name, return_type_item_name
)
select jsonb_object_agg(x.component_name, x.oas_schema)
from (
select
'rpc.' || function_full_name as component_name,
case when not return_type_is_simple then
oas_schema_object(
description := function_description,
properties := coalesce(arguments, '{}'),
type := 'object'
)
else
arguments
end as oas_schema
from
aggregated_function_returns
) x;
$$;

create or replace function oas_build_component_schemas_headers()
returns jsonb language sql stable as
$$
Expand Down Expand Up @@ -226,6 +303,7 @@ create or replace function oas_build_component_parameters(schemas text[])
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_common() ||
oas_build_component_parameters_headers_common();
$$;
Expand All @@ -245,9 +323,64 @@ 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)
from postgrest_get_all_tables_and_composite_types()
where
(table_schema = any(schemas) and (is_table or is_view))
-- All the tables and composite types returned by functions
or exists (
select 1
from postgrest_get_all_functions(schemas)
where return_type_composite_relid = table_oid
)
) _
) x;
$$;

create or replace function oas_build_component_parameters_query_params_from_function_args(schemas text[])
returns jsonb language sql stable as
$$
select jsonb_object_agg(x.param_name, x.param_schema)
from (
select format('funcParams.%1$s.%2$s', function_name, argument_name) as param_name,
oas_parameter_object(
name := argument_name,
"in" := 'query',
schema :=
case when argument_is_in then
oas_schema_object(
type := argument_oastype,
format := argument_type_name::text
)
when argument_is_variadic then
oas_schema_object(
type := 'array',
items := oas_schema_object(
type := argument_oastype,
format := argument_type_name::text
)
)
when argument_is_inout then
-- INOUT arguments can be used as argument and row filter at the same time, e.g. "?arg=1&arg=eq.1"
-- It would be more accurate to use "anyOf", but the OpenAPI UIs by different providers do not support it for query parameters
oas_schema_object(
type := 'array',
maxItems := 2,
items := oas_schema_object(
type := 'string'
)
)
else
-- TABLE and OUT arguments can be used as row filters
oas_schema_object(
type := 'string'
)
end
) as param_schema
from (
select function_name, argument_name, argument_is_in, argument_is_inout, argument_type_name, argument_is_variadic,
case when postgrest_pgtype_to_oastype(argument_type_name) = any ('{array,object}') then 'string' else postgrest_pgtype_to_oastype(argument_type_name) end as argument_oastype
from postgrest_get_all_functions(schemas)
where argument_input_qty > 0 and argument_name <> ''
) _
) x;
$$;
Expand Down Expand Up @@ -579,6 +712,7 @@ create or replace function oas_build_response_objects(schemas text[])
returns jsonb language sql stable as
$$
select oas_build_response_objects_from_tables(schemas) ||
oas_build_response_objects_from_function_return_types(schemas) ||
oas_build_response_objects_common();
$$;

Expand Down Expand Up @@ -616,6 +750,7 @@ from (
)
)
) as not_empty_response,
-- TODO: this should be null for tables/composite types returned by functions and not included in exposed schemas
'mayBeEmpty.' || table_full_name as may_be_empty,
case when insertable then
oas_response_object(
Expand Down Expand Up @@ -668,12 +803,70 @@ from (
)
end as may_be_empty_response
from postgrest_get_all_tables_and_composite_types()
where table_schema = any(schemas)
and (is_table or is_view)
where
(table_schema = any(schemas) and (is_table or is_view))
-- All the tables and composite types returned by functions
or exists (
select 1
from postgrest_get_all_functions(schemas) f
where return_type_composite_relid = table_oid
)
group by table_schema, table_full_name, insertable, is_table, is_view
) as x
$$;

create or replace function oas_build_response_objects_from_function_return_types(schemas text[])
returns jsonb language sql stable as
$$
select jsonb_object_agg(x.not_empty, x.not_empty_response)
from (
select 'rpc.' || function_full_name as not_empty,
oas_response_object(
description := 'Media types for RPC ' || function_full_name,
content := jsonb_build_object(
'application/json',
case when return_type_is_set then
oas_media_type_object(
schema := oas_schema_object(
type := 'array',
items := return_type_reference_schema
)
)
else
oas_media_type_object(
schema := return_type_reference_schema
)
end,
'application/vnd.pgrst.object+json',
oas_media_type_object(
schema := return_type_reference_schema
),
'application/vnd.pgrst.object+json;nulls=stripped',
oas_media_type_object(
schema := return_type_reference_schema
),
'text/csv',
oas_media_type_object(
schema := oas_schema_object(
type := 'string',
format := 'csv'
)
)
)
) as not_empty_response
from (
select *,
case when return_type_is_composite then
oas_build_reference_to_schemas(return_type_composite_full_name)
else
oas_build_reference_to_schemas('rpc.' || function_full_name)
end as return_type_reference_schema
from postgrest_get_all_functions(schemas)
) _
group by function_schema, function_name, function_full_name, return_type_is_set, return_type_reference_schema
) as x
$$;

create or replace function oas_build_response_objects_common()
returns jsonb language sql stable as
$$
Expand Down
76 changes: 75 additions & 1 deletion sql/paths.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ create or replace function oas_build_paths(schemas text[])
returns jsonb language sql stable as
$$
select oas_build_path_item_root() ||
oas_build_path_items_from_tables(schemas);
oas_build_path_items_from_tables(schemas) ||
oas_build_path_items_from_functions(schemas);
$$;

create or replace function oas_build_path_items_from_tables(schemas text[])
Expand Down Expand Up @@ -134,6 +135,79 @@ from (
) x;
$$;

create or replace function oas_build_path_items_from_functions(schemas text[])
returns jsonb language sql stable as
$$
select jsonb_object_agg(x.path, x.oas_path_item)
from (
select '/rpc/' || function_name as path,
oas_path_item_object(
get :=oas_operation_object(
description := function_description,
tags := array['(rpc) ' || function_name],
parameters :=
coalesce(
jsonb_agg(
oas_build_reference_to_parameters(format('funcParams.%1$s.%2$s', function_name, argument_name))
) filter ( where argument_name <> ''),
'[]'
) ||
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('range'),
oas_build_reference_to_parameters('preferGet')
)
else
jsonb_build_array(
oas_build_reference_to_parameters('preferGet')
)
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,
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, return_composite_param_ref
) x;
$$;

create or replace function oas_build_path_item_root()
returns jsonb language sql stable as
$$
Expand Down
3 changes: 1 addition & 2 deletions sql/utils.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ select case when type like any(array['character', 'character varying', 'text'])
when type like any(array['bigint', 'integer', 'smallint']) then 'integer'
when type like 'boolean' then 'boolean'
when type like '%[]' then 'array'
when type like 'json' then 'object'
when type like 'jsonb' then 'object'
when type like any(array['json', 'jsonb', 'record']) then 'object'
else 'string' end;
$$;

Expand Down

0 comments on commit 34b2999

Please sign in to comment.