Skip to content

Commit

Permalink
fix: Add required OpenAPI items object when the paramater is an array
Browse files Browse the repository at this point in the history
  • Loading branch information
laurenceisla committed Dec 20, 2022
1 parent e0df958 commit 1f69757
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- #2565, Fix bad M2M embedding on RPC - @steve-chavez
- #2575, Replace misleading error message when no function is found with a hint containing functions/parameters names suggestions - @laurenceisla
- #2569, Replace misleading error message when no relationship is found with a hint containing parent/child names suggestions - @laurenceisla
- #1405, Add the required OpenAPI items object when the parameter is an array - @laurenceisla

## [10.1.1] - 2022-11-08

### Fixed
Expand Down
15 changes: 12 additions & 3 deletions src/PostgREST/Response/OpenAPI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,16 @@ toSwaggerType "bigint" = Just SwaggerInteger
toSwaggerType "numeric" = Just SwaggerNumber
toSwaggerType "real" = Just SwaggerNumber
toSwaggerType "double precision" = Just SwaggerNumber
toSwaggerType "ARRAY" = Just SwaggerArray
toSwaggerType "json" = Nothing
toSwaggerType "jsonb" = Nothing
toSwaggerType _ = Just SwaggerString
toSwaggerType colType = case T.takeEnd 2 colType of
"[]" -> Just SwaggerArray
_ -> Just SwaggerString

makeSwaggerItemType :: Maybe (SwaggerType t) -> Text -> Maybe (Referenced Schema)
makeSwaggerItemType itemType colType = case itemType of
Just SwaggerArray -> Just $ Inline (mempty & type_ .~ toSwaggerType (T.dropEnd 2 colType))
_ -> Nothing

parseDefault :: Text -> Text -> Text
parseDefault colType colDefault =
Expand Down Expand Up @@ -119,14 +125,16 @@ makeProperty tbl rels col = (colName col, Inline s)
Just $ T.append (maybe "" (`T.append` "\n\n") $ colDescription col) (T.intercalate "\n" n)
else
colDescription col
pType = toSwaggerType (colType col)
s =
(mempty :: Schema)
& default_ .~ (JSON.decode . toUtf8Lazy . parseDefault (colType col) =<< colDefault col)
& description .~ d
& enum_ .~ e
& format ?~ colType col
& maxLength .~ (fromIntegral <$> colMaxLen col)
& type_ .~ toSwaggerType (colType col)
& type_ .~ pType
& items .~ (SwaggerItemsObject <$> makeSwaggerItemType pType (colType col))

makeProcSchema :: ProcDescription -> Schema
makeProcSchema pd =
Expand All @@ -141,6 +149,7 @@ makeProcProperty (ProcParam n t _ _) = (n, Inline s)
where
s = (mempty :: Schema)
& type_ .~ toSwaggerType t
& items .~ (SwaggerItemsObject <$> makeSwaggerItemType (toSwaggerType t) t)
& format ?~ t

makePreferParam :: [Text] -> Param
Expand Down
2 changes: 0 additions & 2 deletions src/PostgREST/SchemaCache.hs
Original file line number Diff line number Diff line change
Expand Up @@ -512,13 +512,11 @@ tablesSqlQuery pgVer =
CASE
WHEN t.typtype = 'd' THEN
CASE
WHEN bt.typelem <> 0::oid AND bt.typlen = (-1) THEN 'ARRAY'::text
WHEN nbt.nspname = 'pg_catalog'::name THEN format_type(t.typbasetype, NULL::integer)
ELSE format_type(a.atttypid, a.atttypmod)
END
ELSE
CASE
WHEN t.typelem <> 0::oid AND t.typlen = (-1) THEN 'ARRAY'::text
WHEN nt.nspname = 'pg_catalog'::name THEN format_type(a.atttypid, NULL::integer)
ELSE format_type(a.atttypid, a.atttypmod)
END
Expand Down
182 changes: 178 additions & 4 deletions test/spec/Feature/OpenApi/OpenApiSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,117 @@ spec actualPgVersion = describe "OpenAPI" $ do
}
|]

it "array types to array" $ do
r <- simpleBody <$> get "/"

let text_arr_types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_text_arr"
let int_arr_types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_int_arr"
let bool_arr_types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_bool_arr"
let char_arr_types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_char_arr"
let varchar_arr_types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_varchar_arr"
let bigint_arr_types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_bigint_arr"
let numeric_arr_types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_numeric_arr"
let json_arr_types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_json_arr"
let jsonb_arr_types = r ^? key "definitions" . key "openapi_types" . key "properties" . key "a_jsonb_arr"

liftIO $ do

text_arr_types `shouldBe` Just
[aesonQQ|
{
"format": "text[]",
"type": "array",
"items": {
"type": "string"
}
}
|]

int_arr_types `shouldBe` Just
[aesonQQ|
{
"format": "integer[]",
"type": "array",
"items": {
"type": "integer"
}
}
|]

bool_arr_types `shouldBe` Just
[aesonQQ|
{
"format": "boolean[]",
"type": "array",
"items": {
"type": "boolean"
}
}
|]

char_arr_types `shouldBe` Just
[aesonQQ|
{
"format": "character[]",
"type": "array",
"items": {
"type": "string"
}
}
|]

varchar_arr_types `shouldBe` Just
[aesonQQ|
{
"format": "character varying[]",
"type": "array",
"items": {
"type": "string"
}
}
|]

bigint_arr_types `shouldBe` Just
[aesonQQ|
{
"format": "bigint[]",
"type": "array",
"items": {
"type": "integer"
}
}
|]

numeric_arr_types `shouldBe` Just
[aesonQQ|
{
"format": "numeric[]",
"type": "array",
"items": {
"type": "number"
}
}
|]

json_arr_types `shouldBe` Just
[aesonQQ|
{
"format": "json[]",
"type": "array",
"items": {}
}
|]

jsonb_arr_types `shouldBe` Just
[aesonQQ|
{
"format": "jsonb[]",
"type": "array",
"items": {}
}
|]


describe "Detects default values" $ do

it "text" $ do
Expand Down Expand Up @@ -569,7 +680,7 @@ spec actualPgVersion = describe "OpenAPI" $ do
it "includes function summary/description and body schema for arguments" $ do
r <- simpleBody <$> get "/"

let method s = key "paths" . key "/rpc/varied_arguments" . key s
let method s = key "paths" . key "/rpc/varied_arguments_openapi" . key s
args = r ^? method "post" . key "parameters" . nth 0 . key "schema"
summary = r ^? method "post" . key "summary"
description = r ^? method "post" . key "description"
Expand All @@ -590,7 +701,15 @@ spec actualPgVersion = describe "OpenAPI" $ do
"date",
"money",
"enum",
"arr"
"text_arr",
"int_arr",
"bool_arr",
"char_arr",
"varchar_arr",
"bigint_arr",
"numeric_arr",
"json_arr",
"jsonb_arr"
],
"properties": {
"double": {
Expand All @@ -617,9 +736,64 @@ spec actualPgVersion = describe "OpenAPI" $ do
"format": "enum_menagerie_type",
"type": "string"
},
"arr": {
"text_arr": {
"format": "text[]",
"type": "string"
"type": "array",
"items": {
"type": "string"
}
},
"int_arr": {
"format": "integer[]",
"type": "array",
"items": {
"type": "integer"
}
},
"bool_arr": {
"format": "boolean[]",
"type": "array",
"items": {
"type": "boolean"
}
},
"char_arr": {
"format": "character[]",
"type": "array",
"items": {
"type": "string"
}
},
"varchar_arr": {
"format": "character varying[]",
"type": "array",
"items": {
"type": "string"
}
},
"bigint_arr": {
"format": "bigint[]",
"type": "array",
"items": {
"type": "integer"
}
},
"numeric_arr": {
"format": "numeric[]",
"type": "array",
"items": {
"type": "number"
}
},
"json_arr": {
"format": "json[]",
"type": "array",
"items": {}
},
"jsonb_arr": {
"format": "jsonb[]",
"type": "array",
"items": {}
},
"integer": {
"format": "integer",
Expand Down
61 changes: 60 additions & 1 deletion test/spec/fixtures/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,56 @@ $_$An RPC function

Just a test for RPC function arguments$_$;

CREATE FUNCTION varied_arguments_openapi(
double double precision,
"varchar" character varying,
"boolean" boolean,
date date,
money money,
enum enum_menagerie_type,
text_arr text[],
int_arr int[],
bool_arr boolean[],
char_arr char[],
varchar_arr varchar[],
bigint_arr bigint[],
numeric_arr numeric[],
json_arr json[],
jsonb_arr jsonb[],
"integer" integer default 42,
json json default '{}',
jsonb jsonb default '{}'
) RETURNS json
LANGUAGE sql
IMMUTABLE
AS $_$
SELECT json_build_object(
'double', double,
'varchar', "varchar",
'boolean', "boolean",
'date', date,
'money', money,
'enum', enum,
'text_arr', text_arr,
'int_arr', int_arr,
'bool_arr', bool_arr,
'char_arr', char_arr,
'varchar_arr', varchar_arr,
'bigint_arr', bigint_arr,
'numeric_arr', numeric_arr,
'json_arr', json_arr,
'jsonb_arr', jsonb_arr,
'integer', "integer",
'json', json,
'jsonb', jsonb
);
$_$;

COMMENT ON FUNCTION varied_arguments_openapi(double precision, character varying, boolean, date, money, enum_menagerie_type, text[], int[], boolean[], char[], varchar[], bigint[], numeric[], json[], jsonb[], integer, json, jsonb) IS
$_$An RPC function

Just a test for RPC function arguments$_$;


CREATE FUNCTION json_argument(arg json) RETURNS text
LANGUAGE sql
Expand Down Expand Up @@ -1814,7 +1864,16 @@ CREATE TABLE test.openapi_types(
"a_real" real,
"a_double_precision" double precision,
"a_json" json,
"a_jsonb" jsonb
"a_jsonb" jsonb,
"a_text_arr" text[],
"a_int_arr" int[],
"a_bool_arr" boolean[],
"a_char_arr" char[],
"a_varchar_arr" varchar[],
"a_bigint_arr" bigint[],
"a_numeric_arr" numeric[],
"a_json_arr" json[],
"a_jsonb_arr" jsonb[]
);

CREATE TABLE test.openapi_defaults(
Expand Down

0 comments on commit 1f69757

Please sign in to comment.