module Hasura.RQL.Types.Webhook.Transform.WithOptional
  ( WithOptional (..),
    withOptional,
    withOptionalField',
    withOptionalFieldWith',
  )
where

import Autodocodec (HasCodec (codec), ObjectCodec, ValueCodec, dimapCodec, optionalFieldWith')
import Data.Aeson (FromJSON, ToJSON)
import Data.Coerce (Coercible)
import Hasura.Prelude

-- | Enrich a 'Functor' @f@ with optionality; this is primarily useful when
-- one wants to annotate fields as optional when using the Higher-Kinded Data
-- pattern.
--
-- 'WithOptional'@ f@ is equivalent to @Compose Maybe f@.
newtype WithOptional f result = WithOptional
  { forall (f :: * -> *) result.
WithOptional f result -> Maybe (f result)
getOptional :: Maybe (f result)
  }
  deriving stock (WithOptional f result -> WithOptional f result -> Bool
(WithOptional f result -> WithOptional f result -> Bool)
-> (WithOptional f result -> WithOptional f result -> Bool)
-> Eq (WithOptional f result)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (f :: * -> *) result.
Eq (f result) =>
WithOptional f result -> WithOptional f result -> Bool
$c== :: forall (f :: * -> *) result.
Eq (f result) =>
WithOptional f result -> WithOptional f result -> Bool
== :: WithOptional f result -> WithOptional f result -> Bool
$c/= :: forall (f :: * -> *) result.
Eq (f result) =>
WithOptional f result -> WithOptional f result -> Bool
/= :: WithOptional f result -> WithOptional f result -> Bool
Eq, (forall a b. (a -> b) -> WithOptional f a -> WithOptional f b)
-> (forall a b. a -> WithOptional f b -> WithOptional f a)
-> Functor (WithOptional f)
forall a b. a -> WithOptional f b -> WithOptional f a
forall a b. (a -> b) -> WithOptional f a -> WithOptional f b
forall (f :: * -> *) a b.
Functor f =>
a -> WithOptional f b -> WithOptional f a
forall (f :: * -> *) a b.
Functor f =>
(a -> b) -> WithOptional f a -> WithOptional f b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall (f :: * -> *) a b.
Functor f =>
(a -> b) -> WithOptional f a -> WithOptional f b
fmap :: forall a b. (a -> b) -> WithOptional f a -> WithOptional f b
$c<$ :: forall (f :: * -> *) a b.
Functor f =>
a -> WithOptional f b -> WithOptional f a
<$ :: forall a b. a -> WithOptional f b -> WithOptional f a
Functor, (forall m. Monoid m => WithOptional f m -> m)
-> (forall m a. Monoid m => (a -> m) -> WithOptional f a -> m)
-> (forall m a. Monoid m => (a -> m) -> WithOptional f a -> m)
-> (forall a b. (a -> b -> b) -> b -> WithOptional f a -> b)
-> (forall a b. (a -> b -> b) -> b -> WithOptional f a -> b)
-> (forall b a. (b -> a -> b) -> b -> WithOptional f a -> b)
-> (forall b a. (b -> a -> b) -> b -> WithOptional f a -> b)
-> (forall a. (a -> a -> a) -> WithOptional f a -> a)
-> (forall a. (a -> a -> a) -> WithOptional f a -> a)
-> (forall a. WithOptional f a -> [a])
-> (forall a. WithOptional f a -> Bool)
-> (forall a. WithOptional f a -> Int)
-> (forall a. Eq a => a -> WithOptional f a -> Bool)
-> (forall a. Ord a => WithOptional f a -> a)
-> (forall a. Ord a => WithOptional f a -> a)
-> (forall a. Num a => WithOptional f a -> a)
-> (forall a. Num a => WithOptional f a -> a)
-> Foldable (WithOptional f)
forall a. Eq a => a -> WithOptional f a -> Bool
forall a. Num a => WithOptional f a -> a
forall a. Ord a => WithOptional f a -> a
forall m. Monoid m => WithOptional f m -> m
forall a. WithOptional f a -> Bool
forall a. WithOptional f a -> Int
forall a. WithOptional f a -> [a]
forall a. (a -> a -> a) -> WithOptional f a -> a
forall m a. Monoid m => (a -> m) -> WithOptional f a -> m
forall b a. (b -> a -> b) -> b -> WithOptional f a -> b
forall a b. (a -> b -> b) -> b -> WithOptional f a -> b
forall (f :: * -> *) a.
(Foldable f, Eq a) =>
a -> WithOptional f a -> Bool
forall (f :: * -> *) a.
(Foldable f, Num a) =>
WithOptional f a -> a
forall (f :: * -> *) a.
(Foldable f, Ord a) =>
WithOptional f a -> a
forall (f :: * -> *) m.
(Foldable f, Monoid m) =>
WithOptional f m -> m
forall (f :: * -> *) a. Foldable f => WithOptional f a -> Bool
forall (f :: * -> *) a. Foldable f => WithOptional f a -> Int
forall (f :: * -> *) a. Foldable f => WithOptional f a -> [a]
forall (f :: * -> *) a.
Foldable f =>
(a -> a -> a) -> WithOptional f a -> a
forall (f :: * -> *) m a.
(Foldable f, Monoid m) =>
(a -> m) -> WithOptional f a -> m
forall (f :: * -> *) b a.
Foldable f =>
(b -> a -> b) -> b -> WithOptional f a -> b
forall (f :: * -> *) a b.
Foldable f =>
(a -> b -> b) -> b -> WithOptional f a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
$cfold :: forall (f :: * -> *) m.
(Foldable f, Monoid m) =>
WithOptional f m -> m
fold :: forall m. Monoid m => WithOptional f m -> m
$cfoldMap :: forall (f :: * -> *) m a.
(Foldable f, Monoid m) =>
(a -> m) -> WithOptional f a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> WithOptional f a -> m
$cfoldMap' :: forall (f :: * -> *) m a.
(Foldable f, Monoid m) =>
(a -> m) -> WithOptional f a -> m
foldMap' :: forall m a. Monoid m => (a -> m) -> WithOptional f a -> m
$cfoldr :: forall (f :: * -> *) a b.
Foldable f =>
(a -> b -> b) -> b -> WithOptional f a -> b
foldr :: forall a b. (a -> b -> b) -> b -> WithOptional f a -> b
$cfoldr' :: forall (f :: * -> *) a b.
Foldable f =>
(a -> b -> b) -> b -> WithOptional f a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> WithOptional f a -> b
$cfoldl :: forall (f :: * -> *) b a.
Foldable f =>
(b -> a -> b) -> b -> WithOptional f a -> b
foldl :: forall b a. (b -> a -> b) -> b -> WithOptional f a -> b
$cfoldl' :: forall (f :: * -> *) b a.
Foldable f =>
(b -> a -> b) -> b -> WithOptional f a -> b
foldl' :: forall b a. (b -> a -> b) -> b -> WithOptional f a -> b
$cfoldr1 :: forall (f :: * -> *) a.
Foldable f =>
(a -> a -> a) -> WithOptional f a -> a
foldr1 :: forall a. (a -> a -> a) -> WithOptional f a -> a
$cfoldl1 :: forall (f :: * -> *) a.
Foldable f =>
(a -> a -> a) -> WithOptional f a -> a
foldl1 :: forall a. (a -> a -> a) -> WithOptional f a -> a
$ctoList :: forall (f :: * -> *) a. Foldable f => WithOptional f a -> [a]
toList :: forall a. WithOptional f a -> [a]
$cnull :: forall (f :: * -> *) a. Foldable f => WithOptional f a -> Bool
null :: forall a. WithOptional f a -> Bool
$clength :: forall (f :: * -> *) a. Foldable f => WithOptional f a -> Int
length :: forall a. WithOptional f a -> Int
$celem :: forall (f :: * -> *) a.
(Foldable f, Eq a) =>
a -> WithOptional f a -> Bool
elem :: forall a. Eq a => a -> WithOptional f a -> Bool
$cmaximum :: forall (f :: * -> *) a.
(Foldable f, Ord a) =>
WithOptional f a -> a
maximum :: forall a. Ord a => WithOptional f a -> a
$cminimum :: forall (f :: * -> *) a.
(Foldable f, Ord a) =>
WithOptional f a -> a
minimum :: forall a. Ord a => WithOptional f a -> a
$csum :: forall (f :: * -> *) a.
(Foldable f, Num a) =>
WithOptional f a -> a
sum :: forall a. Num a => WithOptional f a -> a
$cproduct :: forall (f :: * -> *) a.
(Foldable f, Num a) =>
WithOptional f a -> a
product :: forall a. Num a => WithOptional f a -> a
Foldable, (forall x. WithOptional f result -> Rep (WithOptional f result) x)
-> (forall x.
    Rep (WithOptional f result) x -> WithOptional f result)
-> Generic (WithOptional f result)
forall x. Rep (WithOptional f result) x -> WithOptional f result
forall x. WithOptional f result -> Rep (WithOptional f result) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (f :: * -> *) result x.
Rep (WithOptional f result) x -> WithOptional f result
forall (f :: * -> *) result x.
WithOptional f result -> Rep (WithOptional f result) x
$cfrom :: forall (f :: * -> *) result x.
WithOptional f result -> Rep (WithOptional f result) x
from :: forall x. WithOptional f result -> Rep (WithOptional f result) x
$cto :: forall (f :: * -> *) result x.
Rep (WithOptional f result) x -> WithOptional f result
to :: forall x. Rep (WithOptional f result) x -> WithOptional f result
Generic, Int -> WithOptional f result -> ShowS
[WithOptional f result] -> ShowS
WithOptional f result -> String
(Int -> WithOptional f result -> ShowS)
-> (WithOptional f result -> String)
-> ([WithOptional f result] -> ShowS)
-> Show (WithOptional f result)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (f :: * -> *) result.
Show (f result) =>
Int -> WithOptional f result -> ShowS
forall (f :: * -> *) result.
Show (f result) =>
[WithOptional f result] -> ShowS
forall (f :: * -> *) result.
Show (f result) =>
WithOptional f result -> String
$cshowsPrec :: forall (f :: * -> *) result.
Show (f result) =>
Int -> WithOptional f result -> ShowS
showsPrec :: Int -> WithOptional f result -> ShowS
$cshow :: forall (f :: * -> *) result.
Show (f result) =>
WithOptional f result -> String
show :: WithOptional f result -> String
$cshowList :: forall (f :: * -> *) result.
Show (f result) =>
[WithOptional f result] -> ShowS
showList :: [WithOptional f result] -> ShowS
Show)
  deriving newtype (Value -> Parser [WithOptional f result]
Value -> Parser (WithOptional f result)
(Value -> Parser (WithOptional f result))
-> (Value -> Parser [WithOptional f result])
-> FromJSON (WithOptional f result)
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
forall (f :: * -> *) result.
FromJSON (f result) =>
Value -> Parser [WithOptional f result]
forall (f :: * -> *) result.
FromJSON (f result) =>
Value -> Parser (WithOptional f result)
$cparseJSON :: forall (f :: * -> *) result.
FromJSON (f result) =>
Value -> Parser (WithOptional f result)
parseJSON :: Value -> Parser (WithOptional f result)
$cparseJSONList :: forall (f :: * -> *) result.
FromJSON (f result) =>
Value -> Parser [WithOptional f result]
parseJSONList :: Value -> Parser [WithOptional f result]
FromJSON, [WithOptional f result] -> Value
[WithOptional f result] -> Encoding
WithOptional f result -> Value
WithOptional f result -> Encoding
(WithOptional f result -> Value)
-> (WithOptional f result -> Encoding)
-> ([WithOptional f result] -> Value)
-> ([WithOptional f result] -> Encoding)
-> ToJSON (WithOptional f result)
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
forall (f :: * -> *) result.
ToJSON (f result) =>
[WithOptional f result] -> Value
forall (f :: * -> *) result.
ToJSON (f result) =>
[WithOptional f result] -> Encoding
forall (f :: * -> *) result.
ToJSON (f result) =>
WithOptional f result -> Value
forall (f :: * -> *) result.
ToJSON (f result) =>
WithOptional f result -> Encoding
$ctoJSON :: forall (f :: * -> *) result.
ToJSON (f result) =>
WithOptional f result -> Value
toJSON :: WithOptional f result -> Value
$ctoEncoding :: forall (f :: * -> *) result.
ToJSON (f result) =>
WithOptional f result -> Encoding
toEncoding :: WithOptional f result -> Encoding
$ctoJSONList :: forall (f :: * -> *) result.
ToJSON (f result) =>
[WithOptional f result] -> Value
toJSONList :: [WithOptional f result] -> Value
$ctoEncodingList :: forall (f :: * -> *) result.
ToJSON (f result) =>
[WithOptional f result] -> Encoding
toEncodingList :: [WithOptional f result] -> Encoding
ToJSON)

deriving newtype instance
  (NFData (f result)) =>
  NFData (WithOptional f result)

-------------------------------------------------------------------------------

-- | 'WithOptional' smart constructor for the special case of optional values
-- that are representationally equivalent to some "wrapper" type.
--
-- For example:
-- @
-- withOptional \@HeaderTransformsAction headers == WithOptional $ fmap HeadersTransform headers
-- @
--
-- In other words: this function observes the isomorphism between @'Maybe' a@
-- and  @'WithOptional' f b@ if an isomorphism exists between @a@ and @f b@.
withOptional ::
  forall a b f.
  (Coercible a (f b)) =>
  Maybe a ->
  WithOptional f b
withOptional :: forall a b (f :: * -> *).
Coercible a (f b) =>
Maybe a -> WithOptional f b
withOptional = Maybe a -> WithOptional f b
forall a b. Coercible a b => a -> b
coerce

-- | Define a field in an object codec that applies 'withOptional' when
-- decoding, and applies 'getOptional' when encoding.
withOptionalField' ::
  forall a b f.
  (Coercible a (f b), HasCodec a) =>
  Text ->
  ObjectCodec (WithOptional f b) (WithOptional f b)
withOptionalField' :: forall a b (f :: * -> *).
(Coercible a (f b), HasCodec a) =>
Text -> ObjectCodec (WithOptional f b) (WithOptional f b)
withOptionalField' Text
name = Text
-> ValueCodec a a
-> ObjectCodec (WithOptional f b) (WithOptional f b)
forall a b (f :: * -> *).
Coercible a (f b) =>
Text
-> ValueCodec a a
-> ObjectCodec (WithOptional f b) (WithOptional f b)
withOptionalFieldWith' Text
name (forall value. HasCodec value => JSONCodec value
codec @a)

-- | Define a field in an object codec that applies 'withOptional' when
-- decoding, and applies 'getOptional' when encoding.
--
-- This version takes a codec for the underlying value type as an argument.
withOptionalFieldWith' ::
  forall a b f.
  (Coercible a (f b)) =>
  Text ->
  ValueCodec a a ->
  ObjectCodec (WithOptional f b) (WithOptional f b)
withOptionalFieldWith' :: forall a b (f :: * -> *).
Coercible a (f b) =>
Text
-> ValueCodec a a
-> ObjectCodec (WithOptional f b) (WithOptional f b)
withOptionalFieldWith' Text
name ValueCodec a a
aCodec =
  (Maybe a -> WithOptional f b)
-> (WithOptional f b -> Maybe a)
-> Codec Object (Maybe a) (Maybe a)
-> Codec Object (WithOptional f b) (WithOptional f b)
forall oldOutput newOutput newInput oldInput context.
(oldOutput -> newOutput)
-> (newInput -> oldInput)
-> Codec context oldInput oldOutput
-> Codec context newInput newOutput
dimapCodec Maybe a -> WithOptional f b
forall a b (f :: * -> *).
Coercible a (f b) =>
Maybe a -> WithOptional f b
withOptional ((f b -> a) -> Maybe (f b) -> Maybe a
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap f b -> a
forall a b. Coercible a b => a -> b
coerce (Maybe (f b) -> Maybe a)
-> (WithOptional f b -> Maybe (f b)) -> WithOptional f b -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WithOptional f b -> Maybe (f b)
forall (f :: * -> *) result.
WithOptional f result -> Maybe (f result)
getOptional)
    (Codec Object (Maybe a) (Maybe a)
 -> Codec Object (WithOptional f b) (WithOptional f b))
-> Codec Object (Maybe a) (Maybe a)
-> Codec Object (WithOptional f b) (WithOptional f b)
forall a b. (a -> b) -> a -> b
$ Text -> ValueCodec a a -> Codec Object (Maybe a) (Maybe a)
forall input output.
Text
-> ValueCodec input output
-> ObjectCodec (Maybe input) (Maybe output)
optionalFieldWith' Text
name ValueCodec a a
aCodec