Skip to content

Commit

Permalink
Simplify tuples with nullable element schema generation
Browse files Browse the repository at this point in the history
  • Loading branch information
Antoine Vandecrème authored and jean-baptiste.gourlet committed Jun 20, 2024
1 parent 839137c commit 9d2b913
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 19 deletions.
27 changes: 11 additions & 16 deletions src/Data/OpenApi/Internal/Schema.hs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ inlineNonRecursiveSchemas defs = inlineSchemasWhen nonRecursive defs
-- "type": "number"
-- }
-- ]
-- }
-- },
-- "type": "array"
-- }
--
Expand Down Expand Up @@ -579,7 +579,7 @@ sketchStrictSchema = go . toJSON
& type_ ?~ OpenApiArray
& maxItems ?~ fromIntegral sz
& minItems ?~ fromIntegral sz
& items ?~ OpenApiItemsArray (map (Inline . go) (V.toList xs))
& items ?~ OpenApiItemsObject (Inline $ mempty & anyOf ?~ (map (Inline . go) (V.toList xs)))
& uniqueItems ?~ allUnique
& enum_ ?~ [js]
where
Expand Down Expand Up @@ -991,22 +991,19 @@ gdeclareSchemaRef opts proxy = do
return $ Ref (Reference name)
_ -> Inline <$> gdeclareSchema opts proxy

addItem :: (Referenced Schema -> [Referenced Schema] -> [Referenced Schema])
-> Referenced Schema
-> Maybe OpenApiItems
-> Maybe OpenApiItems
addItem _ x Nothing = Just (OpenApiItemsArray [x])
addItem add x (Just (OpenApiItemsArray xs)) = case xs of
addItem :: Referenced Schema -> Maybe OpenApiItems -> Maybe OpenApiItems
addItem x Nothing = Just (OpenApiItemsArray [x])
addItem x (Just (OpenApiItemsArray xs)) = case xs of
[] -> Just $ OpenApiItemsObject x
[x'] | x == x' -> Just $ OpenApiItemsObject x
_ | x `elem` xs -> Just $ OpenApiItemsObject $ Inline $ mempty & anyOf ?~ xs
_ -> Just $ OpenApiItemsObject $ Inline $ mempty & anyOf ?~ (add x xs)
addItem add x (Just (OpenApiItemsObject (Inline s))) =
let appendMaybe = Just . maybe [x] (\xs -> if x `elem` xs then xs else add x xs)
_ -> Just $ OpenApiItemsObject $ Inline $ mempty & anyOf ?~ (xs ++ [x])
addItem x (Just (OpenApiItemsObject (Inline s))) =
let appendMaybe = Just . maybe [x] (\xs -> if x `elem` xs then xs else xs ++ [x])
in Just $ OpenApiItemsObject $ Inline $ s & anyOf %~ appendMaybe
addItem add x j@(Just (OpenApiItemsObject ref))
addItem x j@(Just (OpenApiItemsObject ref))
| x == ref = j
| otherwise = Just $ OpenApiItemsObject $ Inline $ mempty & anyOf ?~ (add x [ref])
| otherwise = Just $ OpenApiItemsObject $ Inline $ mempty & anyOf ?~ [ref, x]

withFieldSchema :: forall proxy s f. (Selector s, GToSchema f) =>
SchemaOptions -> proxy s f -> Bool -> Schema -> Declare (Definitions Schema) Schema
Expand All @@ -1024,8 +1021,7 @@ withFieldSchema opts _ isRequiredField schema = do
if T.null fname
then schema
& type_ ?~ OpenApiArray
& items %~ (if isRequiredField then id else addItem (:) nullSchema)
& items %~ addItem (\x xs -> xs ++ [x]) ref
& items %~ addItem ref
& maxItems %~ Just . maybe 1 (+1) -- increment maxItems
& minItems %~ Just . maybe 1 (+1) -- increment minItems
else schema
Expand All @@ -1035,7 +1031,6 @@ withFieldSchema opts _ isRequiredField schema = do
then required %~ (++ [fname])
else id
where
nullSchema = Inline $ mempty & type_ ?~ OpenApiNull
fname = T.pack (fieldLabelModifier opts (selName (Proxy3 :: Proxy3 s f p)))

-- | Optional record fields.
Expand Down
2 changes: 1 addition & 1 deletion src/Data/OpenApi/Internal/Schema/Validation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import Data.Aeson hiding (Result)
#if MIN_VERSION_aeson(2,0,0)
import qualified Data.Aeson.KeyMap as KeyMap
#endif
import Data.Foldable (asum, for_, sequenceA_,
import Data.Foldable (for_, sequenceA_,
traverse_)
#if !MIN_VERSION_aeson(2,0,0)
import Data.HashMap.Strict (HashMap)
Expand Down
2 changes: 1 addition & 1 deletion src/Data/OpenApi/Schema/Validation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ import Data.OpenApi.Internal.Schema.Validation
-- >>> validateToJSON ([Just "hello", Nothing] :: [Maybe String])
-- ["expected JSON value of type OpenApiString"]
-- >>> validateToJSON (123, Nothing :: Maybe String)
-- ["expected JSON value of type OpenApiString"]
-- ["Value not valid under any of 'anyOf' schemas: Null"]
--
-- However, when @'Maybe' a@ is a type of a record field,
-- validation takes @'required'@ property of the @'Schema'@
Expand Down
29 changes: 28 additions & 1 deletion test/Data/OpenApi/CommonTestTypes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,6 @@ ispairSchemaJSON = [aesonQQ|
"type": "array",
"items": {
"anyOf": [
{ "type": "null" },
{ "type": "integer" },
{ "type": "string", "nullable": true }
]
Expand Down Expand Up @@ -584,6 +583,34 @@ pairwithrefSchemaJSON = [aesonQQ|
}
|]

-- ========================================================================
-- PairWithNullRef (non-record product data type with nullable ref)
-- ========================================================================
data PairWithNullRef = PairWithNullRef Integer (Maybe Point)
deriving (Generic)

instance ToSchema PairWithNullRef

pairwithnullrefSchemaJSON :: Value
pairwithnullrefSchemaJSON = [aesonQQ|
{
"type": "array",
"items": {
"anyOf": [
{ "type": "integer" },
{
"anyOf": [
{ "$ref": "#/components/schemas/Point"} ,
{ "type": "object", "nullable": true }
]
}
]
},
"minItems": 2,
"maxItems": 2
}
|]

-- ========================================================================
-- Point (record data type with custom fieldLabelModifier)
-- ========================================================================
Expand Down
1 change: 1 addition & 0 deletions test/Data/OpenApi/SchemaSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ spec = do
context "Either String Int" $ checkToSchema (Proxy :: Proxy EitherStringInt) eitherSchemaJSON
context "ISHomogeneousPair" $ checkToSchema (Proxy :: Proxy ISHomogeneousPair) ishomogeneouspairSchemaJSON
context "PairWithRef" $ checkToSchema (Proxy :: Proxy PairWithRef) pairwithrefSchemaJSON
context "PairWithNullRef" $ checkToSchema (Proxy :: Proxy PairWithNullRef) pairwithnullrefSchemaJSON
context "Point (fieldLabelModifier)" $ checkToSchema (Proxy :: Proxy Point) pointSchemaJSON
context "Point5 (many field record)" $ do
checkToSchema (Proxy :: Proxy Point5) point5SchemaJSON
Expand Down

0 comments on commit 9d2b913

Please sign in to comment.