module Aws.DynamoDb.Streams.Types
( 
  SequenceNumber
, SequenceNumberRange(..)
, sqnrStartingSequenceNumber
, sqnrEndingSequenceNumber
  
, ShardId
, Shard(..)
  
, shShardId
, shParentShardId
, shSequenceNumberRange
  
, ShardIterator
, ShardIteratorType(..)
  
, _ShardIteratorTrimHorizon
, _ShardIteratorLatest
, _ShardIteratorAtSequenceNumber
, _ShardIteratorAfterSequenceNumber
  
, AttributeValue(..)
  
, _AVBin
, _AVBool
, _AVBinSet
, _AVList
, _AVMap
, _AVNum
, _AVNumSet
, _AVNull
, _AVString
, _AVStringSet
  
  
, KeyType(..)
, keyTypeToText
  
, _KeyTypeHash
, _KeyTypeRange
  
, KeySchemaElement(..)
  
, kseAttributeName
, kseKeyType
  
  
, StreamViewType(..)
  
, _StreamViewKeysOnly
, _StreamViewNewImage
, _StreamViewOldImage
, _StreamViewNewAndOldImages
  
, StreamRecord(..)
  
, strKeys
, strNewImage
, strOldImage
, strSequenceNumber
, strSizeBytes
, strStreamViewType
  
, EventName(..)
  
, _EventInsert
, _EventModify
, _EventRemove
  
, Record(..)
  
, rAwsRegion
, rStreamRecord
, rEventId
, rEventName
, rEventSource
, rEventVersion
  
  
, StreamStatus(..)
  
, _StatusEnabling
, _StatusEnabled
, _StatusDisabling
, _StatusDisabled
  
, StreamId
, StreamDescription(..)
  
, sdCreationRequestDateTime
, sdKeySchema
, sdLastEvaluatedShardId
, sdShards
, sdStreamARN
, sdStreamId
, sdStreamStatus
, sdStreamViewType
, sdTableName
) where
import Aws.General
import Control.Applicative
import Control.Applicative.Unicode
import Control.Monad.Unicode
import Data.Aeson
import Data.Aeson.Types
import qualified Data.Attoparsec.Text as Atto
import qualified Data.ByteString as B
import qualified Data.ByteString.Base64 as B64
import Data.Foldable (asum)
import qualified Data.Map as M
import Data.Monoid.Unicode
import Data.Profunctor
import Data.Scientific
import qualified Data.Set as S
import Data.String
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import Data.Time
import Data.Time.Clock.POSIX
import Data.Traversable hiding (mapM)
import Data.Typeable
import Prelude.Unicode
newtype ShardId
  = ShardId
  { _sidText ∷ T.Text
  } deriving (Eq, Ord, Typeable, Show, Read)
instance ToJSON ShardId where
  toJSON = toJSON ∘ _sidText
instance FromJSON ShardId where
  parseJSON =
    withText "ShardId" $
      pure ∘ ShardId
newtype SequenceNumber
  = SequenceNumber
  { _sqnText ∷ T.Text
  } deriving (Eq, Ord, Typeable, Show, Read)
instance ToJSON SequenceNumber where
  toJSON = toJSON ∘ _sqnText
instance FromJSON SequenceNumber where
  parseJSON =
    withText "SequenceNumber" $
      pure ∘ SequenceNumber
data SequenceNumberRange
  = SequenceNumberRange
  { _sqnrStartingSequenceNumber ∷ !(Maybe SequenceNumber)
  , _sqnrEndingSequenceNumber ∷ !(Maybe SequenceNumber)
  } deriving (Eq, Ord, Typeable, Show, Read)
sqnrStartingSequenceNumber
  ∷ Functor f
  ⇒ (Maybe SequenceNumber → f (Maybe SequenceNumber))
  → SequenceNumberRange
  → f SequenceNumberRange
sqnrStartingSequenceNumber i SequenceNumberRange{..} =
  (\_sqnrStartingSequenceNumber → SequenceNumberRange{..})
    <$> i _sqnrStartingSequenceNumber
sqnrEndingSequenceNumber
  ∷ Functor f
  ⇒ (Maybe SequenceNumber → f (Maybe SequenceNumber))
  → SequenceNumberRange
  → f SequenceNumberRange
sqnrEndingSequenceNumber i SequenceNumberRange{..} =
  (\_sqnrEndingSequenceNumber → SequenceNumberRange{..})
    <$> i _sqnrEndingSequenceNumber
instance ToJSON SequenceNumberRange where
  toJSON SequenceNumberRange{..} = object
    [ "StartingSequenceNumber" .= _sqnrStartingSequenceNumber
    , "EndingSequenceNumber" .= _sqnrEndingSequenceNumber
    ]
instance FromJSON SequenceNumberRange where
  parseJSON =
    withObject "SequenceNumberRange" $ \o →
      pure SequenceNumberRange
        ⊛ o .:? "StartingSequenceNumber"
        ⊛ o .:? "EndingSequenceNumber"
data Shard
  = Shard
  { _shShardId ∷ !(Maybe ShardId)
    
  , _shParentShardId ∷ !(Maybe ShardId)
    
  , _shSequenceNumberRange ∷ !(Maybe SequenceNumberRange)
  
  } deriving (Eq, Ord, Typeable, Show, Read)
instance ToJSON Shard where
  toJSON Shard{..} = object
    [ "ShardId" .= _shShardId
    , "ParentShardId" .= _shParentShardId
    , "SequenceNumberRange" .= _shSequenceNumberRange
    ]
instance FromJSON Shard where
  parseJSON =
    withObject "Shard" $ \o →
      pure Shard
        ⊛ o .:? "ShardId"
        ⊛ o .:? "ParentShardId"
        ⊛ o .:? "SequenceNumberRange"
shShardId
  ∷ Functor f
  ⇒ (Maybe ShardId → f (Maybe ShardId))
  → Shard
  → f Shard
shShardId i Shard{..} =
  (\_shShardId → Shard{..})
    <$> i _shShardId
shParentShardId
  ∷ Functor f
  ⇒ (Maybe ShardId → f (Maybe ShardId))
  → Shard
  → f Shard
shParentShardId i Shard{..} =
  (\_shParentShardId → Shard{..})
    <$> i _shParentShardId
shSequenceNumberRange
  ∷ Functor f
  ⇒ (Maybe SequenceNumberRange → f (Maybe SequenceNumberRange))
  → Shard
  → f Shard
shSequenceNumberRange i Shard{..} =
  (\_shSequenceNumberRange → Shard{..})
    <$> i _shSequenceNumberRange
data AttributeValue
  = AVBin !B.ByteString
    
  | AVBool !Bool
  | AVBinSet !(S.Set B.ByteString)
    
  | AVList ![AttributeValue]
  | AVMap !(M.Map T.Text AttributeValue)
  | AVNum !Scientific
  | AVNumSet !(S.Set Scientific)
  | AVNull !Bool 
  | AVString !T.Text
  | AVStringSet !(S.Set T.Text)
  deriving (Eq, Ord, Show, Read, Typeable)
instance ToJSON AttributeValue where
  toJSON = \case
    AVBin b → object ["B" .= T.decodeUtf8 (B64.encode b)]
    AVBinSet bs → object ["BS" .= (T.decodeUtf8 ∘ B64.encode <$> S.toList bs)]
    AVBool b → object ["BOOL" .= b]
    AVList xs → object ["L" .= xs]
    AVMap xs → object ["M" .= xs]
    AVNum n → object ["N" .= T.pack (show n)]
    AVNumSet ns → object ["NS" .= (T.pack ∘ show <$> S.toList ns)]
    AVString s → object ["S" .= s]
    AVNull b → object ["NULL" .= b]
    AVStringSet ss → object ["SS" .= S.toList ss]
instance FromJSON AttributeValue where
  parseJSON =
    withObject "AttributeValue" $ \o → asum
      [ fmap AVBin ∘ parseBin =≪ o .: "B"
      , fmap (AVBinSet ∘ S.fromList) ∘ mapM parseBin =≪ o .: "BS"
      , AVBool <$> o .: "BOOL"
      , AVList <$> o .: "L"
      , AVMap <$> o .: "M"
      , fmap AVNum ∘ parseScientific =≪ o .: "N"
      , fmap (AVNumSet ∘ S.fromList) ∘ mapM parseScientific =≪ o .: "NS"
      , AVString <$> o.: "S"
      , AVStringSet ∘ S.fromList <$> o .: "SS"
      , AVNull <$> o .: "NULL"
      ]
    where
      parseBin =
        either (fail ∘ ("parseBin failed: " ⊕)) pure
          ∘ B64.decode
          ∘ T.encodeUtf8
      parseScientific (String str) =
        either (fail ∘ ("parseScientific failed: " ⊕)) pure $
          Atto.parseOnly Atto.scientific str
      parseScientific (Number n) = pure n
      parseScientific _ = fail "Unexpected JSON type in parseScientific"
_AVBin
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p B.ByteString (f B.ByteString)
  → p AttributeValue (f AttributeValue)
_AVBin =
  dimap to fro ∘ right'
    where
      to = \case
        AVBin e → Right e
        e → Left e
      fro = either pure (fmap AVBin)
_AVBool
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p Bool (f Bool)
  → p AttributeValue (f AttributeValue)
_AVBool =
  dimap to fro ∘ right'
    where
      to = \case
        AVBool e → Right e
        e → Left e
      fro = either pure (fmap AVBool)
_AVBinSet
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p (S.Set B.ByteString) (f (S.Set B.ByteString))
  → p AttributeValue (f AttributeValue)
_AVBinSet =
  dimap to fro ∘ right'
    where
      to = \case
        AVBinSet e → Right e
        e → Left e
      fro = either pure (fmap AVBinSet)
_AVList
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p [AttributeValue] (f [AttributeValue])
  → p AttributeValue (f AttributeValue)
_AVList =
  dimap to fro ∘ right'
    where
      to = \case
        AVList e → Right e
        e → Left e
      fro = either pure (fmap AVList)
_AVMap
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p (M.Map T.Text AttributeValue) (f (M.Map T.Text AttributeValue))
  → p AttributeValue (f AttributeValue)
_AVMap =
  dimap to fro ∘ right'
    where
      to = \case
        AVMap e → Right e
        e → Left e
      fro = either pure (fmap AVMap)
_AVNum
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p Scientific (f Scientific)
  → p AttributeValue (f AttributeValue)
_AVNum =
  dimap to fro ∘ right'
    where
      to = \case
        AVNum e → Right e
        e → Left e
      fro = either pure (fmap AVNum)
_AVNumSet
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p (S.Set Scientific) (f (S.Set Scientific))
  → p AttributeValue (f AttributeValue)
_AVNumSet =
  dimap to fro ∘ right'
    where
      to = \case
        AVNumSet e → Right e
        e → Left e
      fro = either pure (fmap AVNumSet)
_AVNull
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p Bool (f Bool)
  → p AttributeValue (f AttributeValue)
_AVNull =
  dimap to fro ∘ right'
    where
      to = \case
        AVNull e → Right e
        e → Left e
      fro = either pure (fmap AVNull)
_AVString
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p T.Text (f T.Text)
  → p AttributeValue (f AttributeValue)
_AVString =
  dimap to fro ∘ right'
    where
      to = \case
        AVString e → Right e
        e → Left e
      fro = either pure (fmap AVString)
_AVStringSet
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p (S.Set T.Text) (f (S.Set T.Text))
  → p AttributeValue (f AttributeValue)
_AVStringSet =
  dimap to fro ∘ right'
    where
      to = \case
        AVStringSet e → Right e
        e → Left e
      fro = either pure (fmap AVStringSet)
data KeyType
  = KeyTypeHash
  | KeyTypeRange
  deriving (Eq, Ord, Enum, Show, Read, Typeable)
keyTypeToText
  ∷ IsString s
  ⇒ KeyType
  → s
keyTypeToText = \case
  KeyTypeHash → "HASH"
  KeyTypeRange → "RANGE"
instance ToJSON KeyType where
  toJSON = keyTypeToText
instance FromJSON KeyType where
  parseJSON =
    parseEnum "KeyType" keyTypeToText
      [ KeyTypeHash
      , KeyTypeRange
      ]
parseEnum
  ∷ String
  → (α → T.Text)
  → [α]
  → Value
  → Parser α
parseEnum name render opts =
  withText name $ \str →
    asum $ parser str <$> opts
  where
    parser str o =
      o <$ if render o ≡ str
        then pure o
        else empty
_KeyTypeHash
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p KeyType (f KeyType)
_KeyTypeHash =
  dimap to fro ∘ right'
    where
      to = \case
        KeyTypeHash → Right ()
        e → Left e
      fro = either pure (const $ pure KeyTypeHash)
_KeyTypeRange
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p KeyType (f KeyType)
_KeyTypeRange =
  dimap to fro ∘ right'
    where
      to = \case
        KeyTypeRange → Right ()
        e → Left e
      fro = either pure (const $ pure KeyTypeRange)
data KeySchemaElement
  = KeySchemaElement
  { _kseAttributeName ∷ !T.Text
  , _kseKeyType ∷ !KeyType
  } deriving (Eq, Ord, Show, Read, Typeable)
instance ToJSON KeySchemaElement where
  toJSON KeySchemaElement{..} = object
    [ "AttributeName" .= _kseAttributeName
    , "KeyType" .= _kseKeyType
    ]
instance FromJSON KeySchemaElement where
  parseJSON =
    withObject "KeySchemaElement" $ \o →
      pure KeySchemaElement
        ⊛ o .: "AttributeName"
        ⊛ o .: "KeyType"
kseAttributeName
  ∷ Functor f
  ⇒ (T.Text → f T.Text)
  → KeySchemaElement
  → f KeySchemaElement
kseAttributeName i KeySchemaElement{..} =
  (\_kseAttributeName → KeySchemaElement{..})
    <$> i _kseAttributeName
kseKeyType
  ∷ Functor f
  ⇒ (KeyType → f KeyType)
  → KeySchemaElement
  → f KeySchemaElement
kseKeyType i KeySchemaElement{..} =
  (\_kseKeyType → KeySchemaElement{..})
    <$> i _kseKeyType
data StreamViewType
  = StreamViewKeysOnly
    
  | StreamViewNewImage
    
  | StreamViewOldImage
    
  | StreamViewNewAndOldImages
    
  deriving (Eq, Ord, Enum, Show, Read, Typeable)
streamViewTypeToText
  ∷ IsString s
  ⇒ StreamViewType
  → s
streamViewTypeToText = \case
  StreamViewKeysOnly → "KEYS_ONLY"
  StreamViewNewImage → "NEW_IMAGE"
  StreamViewOldImage → "OLD_IMAGE"
  StreamViewNewAndOldImages → "NEW_AND_OLD_IMAGES"
instance ToJSON StreamViewType where
  toJSON = streamViewTypeToText
instance FromJSON StreamViewType where
  parseJSON =
    parseEnum "StreamViewType" streamViewTypeToText
      [ StreamViewKeysOnly
      , StreamViewNewImage
      , StreamViewOldImage
      , StreamViewNewAndOldImages
      ]
_StreamViewKeysOnly
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p StreamViewType (f StreamViewType)
_StreamViewKeysOnly =
  dimap to fro ∘ right'
    where
      to = \case
        StreamViewKeysOnly → Right ()
        e → Left e
      fro = either pure (const $ pure StreamViewKeysOnly)
_StreamViewNewImage
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p StreamViewType (f StreamViewType)
_StreamViewNewImage =
  dimap to fro ∘ right'
    where
      to = \case
        StreamViewNewImage → Right ()
        e → Left e
      fro = either pure (const $ pure StreamViewNewImage)
_StreamViewOldImage
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p StreamViewType (f StreamViewType)
_StreamViewOldImage =
  dimap to fro ∘ right'
    where
      to = \case
        StreamViewOldImage → Right ()
        e → Left e
      fro = either pure (const $ pure StreamViewOldImage)
_StreamViewNewAndOldImages
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p StreamViewType (f StreamViewType)
_StreamViewNewAndOldImages =
  dimap to fro ∘ right'
    where
      to = \case
        StreamViewNewAndOldImages → Right ()
        e → Left e
      fro = either pure (const $ pure StreamViewNewAndOldImages)
data StreamRecord
  = StreamRecord
  { _strKeys ∷ !(Maybe (M.Map T.Text AttributeValue))
  , _strNewImage ∷ !(Maybe (M.Map T.Text AttributeValue))
  , _strOldImage ∷ !(Maybe (M.Map T.Text AttributeValue))
  , _strSequenceNumber ∷ !(Maybe SequenceNumber)
  , _strSizeBytes ∷ !(Maybe Integer)
  , _strStreamViewType ∷ !(Maybe StreamViewType)
  } deriving (Eq, Ord, Show, Read, Typeable)
instance ToJSON StreamRecord where
  toJSON StreamRecord{..} = object
    [ "Keys" .= _strKeys
    , "NewImage" .= _strNewImage
    , "OldImage" .= _strOldImage
    , "SequenceNumber" .= _strSequenceNumber
    , "SizeBytes" .= _strSizeBytes
    , "StreamViewType" .= _strStreamViewType
    ]
instance FromJSON StreamRecord where
  parseJSON =
    withObject "StreamRecord" $ \o →
      pure StreamRecord
        ⊛ o .:? "Keys"
        ⊛ o .:? "NewImage"
        ⊛ o .:? "OldImage"
        ⊛ o .:? "SequenceNumber"
        ⊛ o .:? "SizeBytes"
        ⊛ o .:? "StreamViewType"
strKeys
  ∷ Functor f
  ⇒ (Maybe (M.Map T.Text AttributeValue) → f (Maybe (M.Map T.Text AttributeValue)))
  → StreamRecord
  → f StreamRecord
strKeys i StreamRecord{..} =
  (\_strKeys → StreamRecord{..})
    <$> i _strKeys
strNewImage
  ∷ Functor f
  ⇒ (Maybe (M.Map T.Text AttributeValue) → f (Maybe (M.Map T.Text AttributeValue)))
  → StreamRecord
  → f StreamRecord
strNewImage i StreamRecord{..} =
  (\_strNewImage → StreamRecord{..})
    <$> i _strNewImage
strOldImage
  ∷ Functor f
  ⇒ (Maybe (M.Map T.Text AttributeValue) → f (Maybe (M.Map T.Text AttributeValue)))
  → StreamRecord
  → f StreamRecord
strOldImage i StreamRecord{..} =
  (\_strOldImage → StreamRecord{..})
    <$> i _strOldImage
strSequenceNumber
  ∷ Functor f
  ⇒ (Maybe SequenceNumber → f (Maybe SequenceNumber))
  → StreamRecord
  → f StreamRecord
strSequenceNumber i StreamRecord{..} =
  (\_strSequenceNumber → StreamRecord{..})
    <$> i _strSequenceNumber
strSizeBytes
  ∷ Functor f
  ⇒ (Maybe Integer → f (Maybe Integer))
  → StreamRecord
  → f StreamRecord
strSizeBytes i StreamRecord{..} =
  (\_strSizeBytes → StreamRecord{..})
    <$> i _strSizeBytes
strStreamViewType
  ∷ Functor f
  ⇒ (Maybe StreamViewType → f (Maybe StreamViewType))
  → StreamRecord
  → f StreamRecord
strStreamViewType i StreamRecord{..} =
  (\_strStreamViewType → StreamRecord{..})
    <$> i _strStreamViewType
newtype StreamId
  = StreamId
  { _stidText ∷ T.Text
  } deriving (Eq, Ord, Typeable, Show, Read)
instance ToJSON StreamId where
  toJSON = toJSON ∘ _stidText
instance FromJSON StreamId where
  parseJSON =
    withText "StreamId" $
      pure ∘ StreamId
data StreamStatus
  = StatusEnabling
    
  | StatusEnabled
    
  | StatusDisabling
    
  | StatusDisabled
    
  deriving (Eq, Ord, Enum, Show, Read, Typeable)
streamStatusToText
  ∷ IsString a
  ⇒ StreamStatus
  → a
streamStatusToText = \case
  StatusEnabling → "ENABLING"
  StatusEnabled → "ENABLED"
  StatusDisabling → "DISABLING"
  StatusDisabled → "DISABLED"
instance ToJSON StreamStatus where
  toJSON = streamStatusToText
instance FromJSON StreamStatus where
  parseJSON =
    parseEnum "StreamStatus" streamStatusToText
      [ StatusEnabling
      , StatusEnabled
      , StatusDisabling
      , StatusDisabled
      ]
_StatusEnabling
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p StreamStatus (f StreamStatus)
_StatusEnabling =
  dimap to fro ∘ right'
    where
      to = \case
        StatusEnabling → Right ()
        e → Left e
      fro = either pure (const $ pure StatusEnabling)
_StatusEnabled
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p StreamStatus (f StreamStatus)
_StatusEnabled =
  dimap to fro ∘ right'
    where
      to = \case
        StatusEnabled → Right ()
        e → Left e
      fro = either pure (const $ pure StatusEnabled)
_StatusDisabling
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p StreamStatus (f StreamStatus)
_StatusDisabling =
  dimap to fro ∘ right'
    where
      to = \case
        StatusDisabling → Right ()
        e → Left e
      fro = either pure (const $ pure StatusDisabling)
_StatusDisabled
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p StreamStatus (f StreamStatus)
_StatusDisabled =
  dimap to fro ∘ right'
    where
      to = \case
        StatusDisabled → Right ()
        e → Left e
      fro = either pure (const $ pure StatusDisabled)
data StreamDescription
  = StreamDescription
  { _sdCreationRequestDateTime ∷ !(Maybe UTCTime)
  , _sdKeySchema ∷ ![KeySchemaElement]
  , _sdLastEvaluatedShardId ∷ !(Maybe ShardId)
  , _sdShards ∷ ![Shard]
  , _sdStreamARN ∷ !(Maybe T.Text)
  , _sdStreamId ∷ !(Maybe StreamId)
  , _sdStreamStatus ∷ !(Maybe StreamStatus)
  , _sdStreamViewType ∷ !(Maybe StreamViewType)
  , _sdTableName ∷ !(Maybe T.Text)
  } deriving (Eq, Ord, Show, Read, Typeable)
instance ToJSON StreamDescription where
  toJSON StreamDescription{..} = object
    [ "CreationRequestDateTime" .= (Number ∘ fromInteger ∘ round ∘ utcTimeToPOSIXSeconds <$> _sdCreationRequestDateTime)
    , "KeySchema" .= _sdKeySchema
    , "Shards" .= _sdShards
    , "StreamARN" .= _sdStreamARN
    , "StreamId" .= _sdStreamId
    , "StreamStatus" .= _sdStreamStatus
    , "StreamViewType" .= _sdStreamViewType
    , "TableName" .= _sdTableName
    ]
instance FromJSON StreamDescription where
  parseJSON =
    withObject "StreamDescription" $ \o →
      pure StreamDescription
        ⊛ (fmap (posixSecondsToUTCTime ∘ fromInteger) <$> o .:? "CreationRequestDateTime")
        ⊛ o .:? "KeySchema" .!= []
        ⊛ o .:? "LastEvaluatedShardId"
        ⊛ o .:? "Shards" .!= []
        ⊛ o .:? "StreamARN"
        ⊛ o .:? "StreamId"
        ⊛ o .:? "StreamStatus"
        ⊛ o .:? "StreamViewType"
        ⊛ o .:? "TableName"
sdCreationRequestDateTime
  ∷ Functor f
  ⇒ (Maybe UTCTime → f (Maybe UTCTime))
  → StreamDescription
  → f StreamDescription
sdCreationRequestDateTime i StreamDescription{..} =
  (\_sdCreationRequestDateTime → StreamDescription{..})
    <$> i _sdCreationRequestDateTime
sdKeySchema
  ∷ Functor f
  ⇒ ([KeySchemaElement] → f [KeySchemaElement])
  → StreamDescription
  → f StreamDescription
sdKeySchema i StreamDescription{..} =
  (\_sdKeySchema → StreamDescription{..})
    <$> i _sdKeySchema
sdLastEvaluatedShardId
  ∷ Functor f
  ⇒ (Maybe ShardId → f (Maybe ShardId))
  → StreamDescription
  → f StreamDescription
sdLastEvaluatedShardId i StreamDescription{..} =
  (\_sdLastEvaluatedShardId → StreamDescription{..})
    <$> i _sdLastEvaluatedShardId
sdShards
  ∷ Functor f
  ⇒ ([Shard] → f [Shard])
  → StreamDescription
  → f StreamDescription
sdShards i StreamDescription{..} =
  (\_sdShards → StreamDescription{..})
    <$> i _sdShards
sdStreamARN
  ∷ Functor f
  ⇒ (Maybe T.Text → f (Maybe T.Text))
  → StreamDescription
  → f StreamDescription
sdStreamARN i StreamDescription{..} =
  (\_sdStreamARN → StreamDescription{..})
    <$> i _sdStreamARN
sdStreamId
  ∷ Functor f
  ⇒ (Maybe StreamId → f (Maybe StreamId))
  → StreamDescription
  → f StreamDescription
sdStreamId i StreamDescription{..} =
  (\_sdStreamId → StreamDescription{..})
    <$> i _sdStreamId
sdStreamStatus
  ∷ Functor f
  ⇒ (Maybe StreamStatus → f (Maybe StreamStatus))
  → StreamDescription
  → f StreamDescription
sdStreamStatus i StreamDescription{..} =
  (\_sdStreamStatus → StreamDescription{..})
    <$> i _sdStreamStatus
sdStreamViewType
  ∷ Functor f
  ⇒ (Maybe StreamViewType → f (Maybe StreamViewType))
  → StreamDescription
  → f StreamDescription
sdStreamViewType i StreamDescription{..} =
  (\_sdStreamViewType → StreamDescription{..})
    <$> i _sdStreamViewType
sdTableName
  ∷ Functor f
  ⇒ (Maybe T.Text → f (Maybe T.Text))
  → StreamDescription
  → f StreamDescription
sdTableName i StreamDescription{..} =
  (\_sdTableName → StreamDescription{..})
    <$> i _sdTableName
newtype EventId
  = EventId
  { _eidText ∷ T.Text
  } deriving (Eq, Ord, Typeable, Show, Read)
instance ToJSON EventId where
  toJSON = toJSON ∘ _eidText
instance FromJSON EventId where
  parseJSON =
    withText "EventId" $
      pure ∘ EventId
data EventName
  = EventInsert
  | EventModify
  | EventRemove
  deriving (Eq, Ord, Enum, Typeable, Show, Read)
eventNameToText
  ∷ IsString s
  ⇒ EventName
  → s
eventNameToText = \case
  EventInsert → "INSERT"
  EventModify → "MODIFY"
  EventRemove → "REMOVE"
instance ToJSON EventName where
  toJSON = eventNameToText
instance FromJSON EventName where
  parseJSON =
    parseEnum "EventName" eventNameToText
      [ EventInsert
      , EventModify
      , EventRemove
      ]
_EventInsert
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p EventName (f EventName)
_EventInsert =
  dimap to fro ∘ right'
    where
      to = \case
        EventInsert → Right ()
        e → Left e
      fro = either pure (const $ pure EventInsert)
_EventModify
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p EventName (f EventName)
_EventModify =
  dimap to fro ∘ right'
    where
      to = \case
        EventModify → Right ()
        e → Left e
      fro = either pure (const $ pure EventModify)
_EventRemove
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p EventName (f EventName)
_EventRemove =
  dimap to fro ∘ right'
    where
      to = \case
        EventRemove → Right ()
        e → Left e
      fro = either pure (const $ pure EventRemove)
data Record
  = Record
  { _rAwsRegion ∷ !(Maybe Region)
  , _rStreamRecord ∷ !(Maybe StreamRecord)
  , _rEventId ∷ !(Maybe EventId)
  , _rEventName ∷ !(Maybe EventName)
  , _rEventSource ∷ !(Maybe T.Text)
  , _rEventVersion ∷ !(Maybe T.Text)
  } deriving (Eq, Ord, Show, Read, Typeable)
instance ToJSON Record where
  toJSON Record{..} = object
    [ "awsRegion" .= (String ∘ regionToText <$> _rAwsRegion)
    , "dynamodb" .= _rStreamRecord
    , "eventID" .= _rEventId
    , "eventName" .= _rEventName
    , "eventSource" .= _rEventSource
    , "eventVersion" .= _rEventVersion
    ]
instance FromJSON Record where
  parseJSON =
    withObject "Record" $ \o →
      pure Record
        ⊛ (traverse (either fail pure ∘ fromText) =≪ o .:? "awsRegion")
        ⊛ o .:? "dynamodb"
        ⊛ o .:? "eventID"
        ⊛ o .:? "eventName"
        ⊛ o .:? "eventSource"
        ⊛ o .:? "eventVersion"
rAwsRegion
  ∷ Functor f
  ⇒ (Maybe Region → f (Maybe Region))
  → Record
  → f Record
rAwsRegion i Record{..} =
  (\_rAwsRegion → Record{..})
    <$> i _rAwsRegion
rStreamRecord
  ∷ Functor f
  ⇒ (Maybe StreamRecord → f (Maybe StreamRecord))
  → Record
  → f Record
rStreamRecord i Record{..} =
  (\_rStreamRecord → Record{..})
    <$> i _rStreamRecord
rEventId
  ∷ Functor f
  ⇒ (Maybe EventId → f (Maybe EventId))
  → Record
  → f Record
rEventId i Record{..} =
  (\_rEventId → Record{..})
    <$> i _rEventId
rEventName
  ∷ Functor f
  ⇒ (Maybe EventName → f (Maybe EventName))
  → Record
  → f Record
rEventName i Record{..} =
  (\_rEventName → Record{..})
    <$> i _rEventName
rEventSource
  ∷ Functor f
  ⇒ (Maybe T.Text → f (Maybe T.Text))
  → Record
  → f Record
rEventSource i Record{..} =
  (\_rEventSource → Record{..})
    <$> i _rEventSource
rEventVersion
  ∷ Functor f
  ⇒ (Maybe T.Text → f (Maybe T.Text))
  → Record
  → f Record
rEventVersion i Record{..} =
  (\_rEventVersion → Record{..})
    <$> i _rEventVersion
data ShardIteratorType
  = ShardIteratorTrimHorizon
  | ShardIteratorLatest
  | ShardIteratorAtSequenceNumber
  | ShardIteratorAfterSequenceNumber
  deriving (Eq, Ord, Enum, Read, Show, Typeable)
shardIteratorTypeToText
  ∷ IsString s
  ⇒ ShardIteratorType
  → s
shardIteratorTypeToText = \case
  ShardIteratorTrimHorizon → "TRIM_HORIZON"
  ShardIteratorLatest → "LATEST"
  ShardIteratorAtSequenceNumber → "AT_SEQUENCE_NUMBER"
  ShardIteratorAfterSequenceNumber → "AFTER_SEQUENCE_NUMBER"
instance ToJSON ShardIteratorType where
  toJSON = shardIteratorTypeToText
instance FromJSON ShardIteratorType where
  parseJSON =
    parseEnum "ShardIteratorType" shardIteratorTypeToText
      [ ShardIteratorTrimHorizon
      , ShardIteratorLatest
      , ShardIteratorAtSequenceNumber
      , ShardIteratorAfterSequenceNumber
      ]
_ShardIteratorTrimHorizon
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p ShardIteratorType (f ShardIteratorType)
_ShardIteratorTrimHorizon =
  dimap to fro ∘ right'
    where
      to = \case
        ShardIteratorTrimHorizon → Right ()
        e → Left e
      fro = either pure (const $ pure ShardIteratorTrimHorizon)
_ShardIteratorLatest
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p ShardIteratorType (f ShardIteratorType)
_ShardIteratorLatest =
  dimap to fro ∘ right'
    where
      to = \case
        ShardIteratorLatest → Right ()
        e → Left e
      fro = either pure (const $ pure ShardIteratorLatest)
_ShardIteratorAtSequenceNumber
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p ShardIteratorType (f ShardIteratorType)
_ShardIteratorAtSequenceNumber =
  dimap to fro ∘ right'
    where
      to = \case
        ShardIteratorAtSequenceNumber → Right ()
        e → Left e
      fro = either pure (const $ pure ShardIteratorAtSequenceNumber)
_ShardIteratorAfterSequenceNumber
  ∷ ( Choice p
    , Applicative f
    )
  ⇒ p () (f ())
  → p ShardIteratorType (f ShardIteratorType)
_ShardIteratorAfterSequenceNumber =
  dimap to fro ∘ right'
    where
      to = \case
        ShardIteratorAfterSequenceNumber → Right ()
        e → Left e
      fro = either pure (const $ pure ShardIteratorAfterSequenceNumber)
newtype ShardIterator
  = ShardIterator
  { _sitText ∷ T.Text
  } deriving (Eq, Ord, Typeable, Show, Read)
instance ToJSON ShardIterator where
  toJSON = toJSON ∘ _sitText
instance FromJSON ShardIterator where
  parseJSON =
    withText "ShardIterator" $
      pure ∘ ShardIterator