{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}

{-|
Module: AWSLambda.Events.SQSEvent
Description: Types for SQS Lambda events
-}
module AWSLambda.Events.SQSEvent where

import           Control.Exception.Safe (MonadCatch)
import           Control.Lens
import           Control.Monad.IO.Class
import           Data.Aeson (FromJSON(..), genericParseJSON)
import           Data.Aeson.Casing (aesonPrefix, camelCase)
import           Data.Aeson.Embedded
import           Data.Aeson.TextValue
import           Data.ByteString (ByteString)
import           Data.HashMap.Strict (HashMap)
import           Data.Text (Text)
import           GHC.Generics (Generic)
import           Network.AWS.Data.Base64
import           Network.AWS.Data.Text (FromText)
import qualified Network.AWS.Types as AWS

import           AWSLambda.Events.MessageAttribute
import           AWSLambda.Events.Records
import           AWSLambda.Handler (lambdaMain)

data SQSMessage body = SQSMessage
  { SQSMessage body -> Text
_sqsmMessageId         :: !Text
  , SQSMessage body -> Text
_sqsmReceiptHandle     :: !Text
  , SQSMessage body -> TextValue body
_sqsmBody              :: !(TextValue body)
  , SQSMessage body -> HashMap Text Text
_sqsmAttributes        :: !(HashMap Text Text)
  , SQSMessage body -> HashMap Text MessageAttribute
_sqsmMessageAttributes :: !(HashMap Text MessageAttribute)
  , SQSMessage body -> Text
_sqsmMd5OfBody         :: !Text
  , SQSMessage body -> Text
_sqsmEventSource       :: !Text
  , SQSMessage body -> Text
_sqsmEventSourceARN    :: !Text
  , SQSMessage body -> Region
_sqsmAwsRegion         :: !AWS.Region
  } deriving (Int -> SQSMessage body -> ShowS
[SQSMessage body] -> ShowS
SQSMessage body -> String
(Int -> SQSMessage body -> ShowS)
-> (SQSMessage body -> String)
-> ([SQSMessage body] -> ShowS)
-> Show (SQSMessage body)
forall body. Show body => Int -> SQSMessage body -> ShowS
forall body. Show body => [SQSMessage body] -> ShowS
forall body. Show body => SQSMessage body -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SQSMessage body] -> ShowS
$cshowList :: forall body. Show body => [SQSMessage body] -> ShowS
show :: SQSMessage body -> String
$cshow :: forall body. Show body => SQSMessage body -> String
showsPrec :: Int -> SQSMessage body -> ShowS
$cshowsPrec :: forall body. Show body => Int -> SQSMessage body -> ShowS
Show, SQSMessage body -> SQSMessage body -> Bool
(SQSMessage body -> SQSMessage body -> Bool)
-> (SQSMessage body -> SQSMessage body -> Bool)
-> Eq (SQSMessage body)
forall body. Eq body => SQSMessage body -> SQSMessage body -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SQSMessage body -> SQSMessage body -> Bool
$c/= :: forall body. Eq body => SQSMessage body -> SQSMessage body -> Bool
== :: SQSMessage body -> SQSMessage body -> Bool
$c== :: forall body. Eq body => SQSMessage body -> SQSMessage body -> Bool
Eq, (forall x. SQSMessage body -> Rep (SQSMessage body) x)
-> (forall x. Rep (SQSMessage body) x -> SQSMessage body)
-> Generic (SQSMessage body)
forall x. Rep (SQSMessage body) x -> SQSMessage body
forall x. SQSMessage body -> Rep (SQSMessage body) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall body x. Rep (SQSMessage body) x -> SQSMessage body
forall body x. SQSMessage body -> Rep (SQSMessage body) x
$cto :: forall body x. Rep (SQSMessage body) x -> SQSMessage body
$cfrom :: forall body x. SQSMessage body -> Rep (SQSMessage body) x
Generic)

instance FromText message => FromJSON (SQSMessage message) where
  parseJSON :: Value -> Parser (SQSMessage message)
parseJSON = Options -> Value -> Parser (SQSMessage message)
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON (Options -> Value -> Parser (SQSMessage message))
-> Options -> Value -> Parser (SQSMessage message)
forall a b. (a -> b) -> a -> b
$ ShowS -> Options
aesonPrefix ShowS
camelCase

$(makeLenses ''SQSMessage)

type SQSEvent body = RecordsEvent (SQSMessage body)

-- | A Traversal to get messages from an SQSEvent
sqsMessages :: Traversal (SQSEvent message) (SQSEvent message') message message'
sqsMessages :: (message -> f message')
-> SQSEvent message -> f (SQSEvent message')
sqsMessages = ([SQSMessage message] -> f [SQSMessage message'])
-> SQSEvent message -> f (SQSEvent message')
forall a1 a2. Iso (RecordsEvent a1) (RecordsEvent a2) [a1] [a2]
reRecords (([SQSMessage message] -> f [SQSMessage message'])
 -> SQSEvent message -> f (SQSEvent message'))
-> ((message -> f message')
    -> [SQSMessage message] -> f [SQSMessage message'])
-> (message -> f message')
-> SQSEvent message
-> f (SQSEvent message')
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SQSMessage message -> f (SQSMessage message'))
-> [SQSMessage message] -> f [SQSMessage message']
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse ((SQSMessage message -> f (SQSMessage message'))
 -> [SQSMessage message] -> f [SQSMessage message'])
-> ((message -> f message')
    -> SQSMessage message -> f (SQSMessage message'))
-> (message -> f message')
-> [SQSMessage message]
-> f [SQSMessage message']
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TextValue message -> f (TextValue message'))
-> SQSMessage message -> f (SQSMessage message')
forall body body.
Lens
  (SQSMessage body)
  (SQSMessage body)
  (TextValue body)
  (TextValue body)
sqsmBody ((TextValue message -> f (TextValue message'))
 -> SQSMessage message -> f (SQSMessage message'))
-> ((message -> f message')
    -> TextValue message -> f (TextValue message'))
-> (message -> f message')
-> SQSMessage message
-> f (SQSMessage message')
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (message -> f message')
-> TextValue message -> f (TextValue message')
forall a1 a2. Iso (TextValue a1) (TextValue a2) a1 a2
unTextValue

-- | A Traversal to get embedded JSON values from an SQSEvent
sqsEmbedded :: Traversal (SQSEvent (Embedded v)) (SQSEvent (Embedded v')) v v'
sqsEmbedded :: (v -> f v') -> SQSEvent (Embedded v) -> f (SQSEvent (Embedded v'))
sqsEmbedded = (Embedded v -> f (Embedded v'))
-> SQSEvent (Embedded v) -> f (SQSEvent (Embedded v'))
forall message message'.
Traversal (SQSEvent message) (SQSEvent message') message message'
sqsMessages ((Embedded v -> f (Embedded v'))
 -> SQSEvent (Embedded v) -> f (SQSEvent (Embedded v')))
-> ((v -> f v') -> Embedded v -> f (Embedded v'))
-> (v -> f v')
-> SQSEvent (Embedded v)
-> f (SQSEvent (Embedded v'))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (v -> f v') -> Embedded v -> f (Embedded v')
forall a1 a2. Iso (Embedded a1) (Embedded a2) a1 a2
unEmbed

sqsBinary :: Traversal' (SQSEvent Base64) ByteString
sqsBinary :: (ByteString -> f ByteString)
-> SQSEvent Base64 -> f (SQSEvent Base64)
sqsBinary = (Base64 -> f Base64) -> SQSEvent Base64 -> f (SQSEvent Base64)
forall message message'.
Traversal (SQSEvent message) (SQSEvent message') message message'
sqsMessages ((Base64 -> f Base64) -> SQSEvent Base64 -> f (SQSEvent Base64))
-> ((ByteString -> f ByteString) -> Base64 -> f Base64)
-> (ByteString -> f ByteString)
-> SQSEvent Base64
-> f (SQSEvent Base64)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> f ByteString) -> Base64 -> f Base64
Iso' Base64 ByteString
_Base64

-- | Traverse all the messages in an SQS event
traverseSqs :: (FromJSON a, Applicative m) => (a -> m ()) -> SQSEvent (Embedded a) -> m ()
traverseSqs :: (a -> m ()) -> SQSEvent (Embedded a) -> m ()
traverseSqs a -> m ()
act = (SQSMessage (Embedded a) -> m ()) -> SQSEvent (Embedded a) -> m ()
forall (m :: * -> *) a.
Applicative m =>
(a -> m ()) -> RecordsEvent a -> m ()
traverseRecords ((SQSMessage (Embedded a) -> m ())
 -> SQSEvent (Embedded a) -> m ())
-> (SQSMessage (Embedded a) -> m ())
-> SQSEvent (Embedded a)
-> m ()
forall a b. (a -> b) -> a -> b
$ \SQSMessage (Embedded a)
record ->
    a -> m ()
act (a -> m ()) -> a -> m ()
forall a b. (a -> b) -> a -> b
$ SQSMessage (Embedded a)
record SQSMessage (Embedded a)
-> Getting a (SQSMessage (Embedded a)) a -> a
forall s a. s -> Getting a s a -> a
^. (TextValue (Embedded a) -> Const a (TextValue (Embedded a)))
-> SQSMessage (Embedded a) -> Const a (SQSMessage (Embedded a))
forall body body.
Lens
  (SQSMessage body)
  (SQSMessage body)
  (TextValue body)
  (TextValue body)
sqsmBody ((TextValue (Embedded a) -> Const a (TextValue (Embedded a)))
 -> SQSMessage (Embedded a) -> Const a (SQSMessage (Embedded a)))
-> ((a -> Const a a)
    -> TextValue (Embedded a) -> Const a (TextValue (Embedded a)))
-> Getting a (SQSMessage (Embedded a)) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Embedded a -> Const a (Embedded a))
-> TextValue (Embedded a) -> Const a (TextValue (Embedded a))
forall a1 a2. Iso (TextValue a1) (TextValue a2) a1 a2
unTextValue ((Embedded a -> Const a (Embedded a))
 -> TextValue (Embedded a) -> Const a (TextValue (Embedded a)))
-> ((a -> Const a a) -> Embedded a -> Const a (Embedded a))
-> (a -> Const a a)
-> TextValue (Embedded a)
-> Const a (TextValue (Embedded a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Const a a) -> Embedded a -> Const a (Embedded a)
forall a1 a2. Iso (Embedded a1) (Embedded a2) a1 a2
unEmbed

-- | A specialised version of the 'lambdaMain' entry-point
-- for handling individual SQS messages
sqsMain :: (FromJSON a, MonadCatch m, MonadIO m) => (a -> m ()) -> m ()
sqsMain :: (a -> m ()) -> m ()
sqsMain = (SQSEvent (Embedded a) -> m ()) -> m ()
forall event res (m :: * -> *).
(FromJSON event, ToJSON res, MonadCatch m, MonadIO m) =>
(event -> m res) -> m ()
lambdaMain ((SQSEvent (Embedded a) -> m ()) -> m ())
-> ((a -> m ()) -> SQSEvent (Embedded a) -> m ())
-> (a -> m ())
-> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> m ()) -> SQSEvent (Embedded a) -> m ()
forall a (m :: * -> *).
(FromJSON a, Applicative m) =>
(a -> m ()) -> SQSEvent (Embedded a) -> m ()
traverseSqs