module Data.Validator.Draft4.Any where
import Control.Monad
import Data.Aeson.Types (Parser)
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as N
import Data.Maybe
import Data.Scientific
import Data.Set (Set)
import qualified Data.Set as S
import Data.Validator.Failure
import Data.Validator.Utils
import Data.Validator.Reference (resolveFragment, resolveReference)
import Import
import Prelude hiding (any, elem)
ref
:: forall err schema. (FromJSON schema, ToJSON schema, Show schema)
=> Maybe Text
-> (Maybe Text -> Maybe schema)
-> (Maybe Text -> schema -> Value -> [Failure err])
-> Text
-> Value
-> Maybe [Failure err]
ref scope getRef f reference x = do
let (mUri, mFragment) = resolveReference scope reference
schema <- getRef mUri
s <- resolveFragment mFragment schema
Just (f mUri s x)
newtype EnumVal
= EnumVal { _unEnumVal :: NonEmpty Value }
deriving (Eq, Show)
instance FromJSON EnumVal where
parseJSON v = checkUnique . _unNonEmpty' =<< parseJSON v
where
checkUnique :: NonEmpty Value -> Parser EnumVal
checkUnique a
| allUniqueValues' a = pure (EnumVal a)
| otherwise = fail "All elements of the Enum validator must be unique."
instance ToJSON EnumVal where
toJSON = toJSON . NonEmpty' . _unEnumVal
instance Arbitrary EnumVal where
arbitrary = do
xs <- traverse (const arbitraryValue) =<< (arbitrary :: Gen [()])
case N.nonEmpty (toUnique xs) of
Nothing -> EnumVal . pure <$> arbitraryValue
Just ne -> pure (EnumVal ne)
where
toUnique :: [Value] -> [Value]
toUnique = fmap _unOrdValue . S.toList . S.fromList . fmap OrdValue
enumVal :: EnumVal -> Value -> Maybe (Failure ())
enumVal (EnumVal vs) x
| not (allUniqueValues' vs) = Nothing
| x `elem` vs = Nothing
| otherwise =
Just $ Invalid () (toJSON (NonEmpty' vs)) mempty
data TypeVal
= TypeValString Text
| TypeValArray (Set Text)
deriving (Eq, Show)
instance FromJSON TypeVal where
parseJSON v = fmap TypeValString (parseJSON v)
<|> fmap TypeValArray (parseJSON v)
instance ToJSON TypeVal where
toJSON (TypeValString t) = toJSON t
toJSON (TypeValArray ts) = toJSON ts
instance Arbitrary TypeVal where
arbitrary = oneof [ TypeValString <$> arbitraryText
, TypeValArray <$> arbitrarySetOfText
]
typeVal :: TypeVal -> Value -> Maybe (Failure ())
typeVal (TypeValString t) x = isJsonType x (S.singleton t)
typeVal (TypeValArray ts) x = isJsonType x ts
isJsonType :: Value -> Set Text -> Maybe (Failure ())
isJsonType x ts
| S.null (S.intersection okTypes ts) = Just (Invalid () (toJSON ts) mempty)
| otherwise = Nothing
where
okTypes :: Set Text
okTypes =
case x of
Null -> S.singleton "null"
(Array _) -> S.singleton "array"
(Bool _) -> S.singleton "boolean"
(Object _) -> S.singleton "object"
(String _) -> S.singleton "string"
(Number y) ->
case toBoundedInteger y :: Maybe Int of
Nothing -> S.singleton "number"
Just _ -> S.fromList ["number", "integer"]
allOf
:: (schema -> Value -> [Failure err])
-> NonEmpty schema
-> Value
-> [Failure err]
allOf f subSchemas x = N.toList subSchemas >>= flip f x
anyOf
:: ToJSON schema
=> (schema -> Value -> [Failure err])
-> NonEmpty schema
-> Value
-> Maybe (Failure ())
anyOf f subSchemas x
| any null (flip f x <$> subSchemas) = Nothing
| otherwise = Just $ Invalid () (toJSON (NonEmpty' subSchemas)) mempty
oneOf
:: forall err schema. ToJSON schema
=> (schema -> Value -> [Failure err])
-> NonEmpty schema
-> Value
-> Maybe (Failure ())
oneOf f subSchemas x
| length successes == 1 = Nothing
| otherwise = Just $ Invalid ()
(toJSON (NonEmpty' subSchemas))
mempty
where
successes :: [[Failure err]]
successes = filter null $ flip f x <$> N.toList subSchemas
notVal
:: ToJSON schema
=> (schema -> Value -> [Failure err])
-> schema
-> Value
-> Maybe (Failure ())
notVal f schema x =
case f schema x of
[] -> Just (Invalid () (toJSON schema) mempty)
_ -> Nothing