orchestrate-0.2.0.0: src/Database/Orchestrate/Events.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{- |
This module implements the <http://orchestrate.io/api/events API calls> for
working with Orchestrate events.
-}
module Database.Orchestrate.Events
(
-- * API Functions
getEvent
, createEvent
, updateEvent
, deleteEvent
, listEvents
-- * Location Conversion Functions
, locationEventItem
, eventItemLocation
) where
import Control.Applicative
import Control.Lens
import Control.Monad
import Data.Aeson
import Data.Maybe
import Data.Monoid
import qualified Data.Text as T
import Network.Wreq
import Database.Orchestrate.Types
import Database.Orchestrate.Utils
urlPath :: OrchestrateData a => a -> EventType -> Timestamp -> Int -> [T.Text]
urlPath a et ts o = [tableName a, dataKey a, "events", et, tshow ts, tshow o]
-- | This retrieves a single event. See <http://orchestrate.io/api/events the API documentation>
-- for more information.
--
-- For example, this retrieves a transaction event.
--
-- > getEvent data "transaction" 784111777000 79
getEvent :: (OrchestrateData a, FromJSON b)
=> a -- ^ The data that the event is associated with.
-> EventType -- ^ The kind of event.
-> Timestamp -- ^ The event's timestamp.
-> Int -- ^ The event's ordinal number.
-> OrchestrateIO (Maybe (EventItem b a)) -- ^ 'Just' the event or 'Nothing'.
getEvent a etype ts o =
join . fmap (decode . (^.responseBody)) <$> api404 [] up [] getWith
where up = urlPath a etype ts o
-- | This creates an event and returns its 'Location'. See
-- <http://orchestrate.io/api/events API document> for more information.
--
-- For example, this creates a transaction, using the current time for the
-- timestamp.
--
-- > createEvent data "transaction" transactionData Nothing
createEvent :: (OrchestrateData a, ToJSON b)
=> a -- ^ The data that the event is associated with.
-> EventType -- ^ The kind of event.
-> b -- ^ The event data.
-> Maybe Timestamp -- ^ The event's timestamp. If not given, the current time is used.
-> OrchestrateIO Location -- ^ Returns the event's location.
createEvent a eType e mts =
getLocation <$> api [] url [] (rot postWith (toJSON e))
where url = [tableName a, dataKey a, "events", eType]
++ maybeToList (fmap tshow mts)
-- | This updates the data for an event. The storage is keyed by type,
-- timestamp, and ordinal, so the event data can change. See the
-- <http://orchestrate.io/api/events API documentation> for more
-- information.
--
-- For example:
--
-- > updateEvent data "transaction" updatedTransactionData
-- > <$> loc ^? locationTimestamp
-- > <*> loc ^? locationOrdinal
updateEvent :: (OrchestrateData a, ToJSON b)
=> a -- ^ The data that the event is associated with.
-> EventType -- ^ The kind of event.
-> b -- ^ The updated event data.
-> Timestamp -- ^ The timestamp for the event.
-> Int -- ^ The ordinal for the event.
-> IfMatch' -- ^ If given, will only succeed if the ref matches
-- the event's currently stored ref.
-> OrchestrateIO Location -- ^ Returns the 'Location' for the new event data.
updateEvent a eType e ts o m =
getLocation <$> api (ifMatch' m) up [] (rot putWith (toJSON e))
where up = urlPath a eType ts o
-- | This deletes an event. See the <http://orchestrate.io/api/events API documentation>
-- for more information.
--
-- For example:
--
-- > deleteEvent data "transaction"
-- > <$> loc ^? locationTimestamp
-- > <*> loc ^? locationOrdinal
deleteEvent :: OrchestrateData a
=> a -- ^ The data that the event is associated with.
-> EventType -- ^ The kind of event.
-> Timestamp -- ^ The timestamp for the event.
-> Int -- ^ The ordinal for the event.
-> IfMatch' -- ^ If given, will only succeed if the ref matches
-- the event's currently stored ref.
-> OrchestrateIO ()
deleteEvent a eType ts o m =
void $ apiCheck (ifMatch' m) url ["purge" := ("true" :: T.Text)] deleteWith
where url = urlPath a eType ts o
-- | This lists all the events within a given range for a data. See the
-- <http://orchestrate.io/api/events API documentation> for more
-- information.
--
-- For example:
--
-- > listEvents data "transaction" (Just 25) (Open, Open)
listEvents :: (OrchestrateData a, FromJSON b)
=> a -- ^ The data the events are to associated with.
-> EventType -- ^ The type of events to retrieve.
-> Maybe Int -- ^ The maximum number of event data to return.
-- The default is 10, and the maximum is 100.
-> Range (Timestamp, Maybe Int) -- ^ The range of events to retrieve. Each range
-- is the timestamp and maybe the ordinal.
-> OrchestrateIO (EventList b a)
listEvents a eType limit (start, end) = apiCheckDecode [] up ps getWith
where up = [tableName a, dataKey a, "events", eType]
ps = catMaybes [ ("limit" :=) <$> limit
, rangeStart "Event" $ fmap eventRange start
, rangeEnd "Event" $ fmap eventRange end
]
eventRange (ts, mint) = tshow ts <> maybe mempty (("/" <>) . tshow) mint
-- | This takes a 'Location' and an event datum and returns the 'EventItem'
-- representing it.
locationEventItem :: Location -> a -> Maybe (EventItem a b)
locationEventItem loc a = EventItem <$> resultItem a <*> timestamp <*> ordinal
where timestamp = loc ^? locationTimestamp
ordinal = loc ^? locationOrdinal
resultItem x = (`ResultItem` x) <$> ePath
ePath = EventPath
<$> path
<*> loc ^? locationType
<*> timestamp
<*> ordinal
path = Path
<$> loc ^? locationCollection
<*> loc ^? locationKey
<*> loc ^? locationRef
-- | This takes an 'EventItem' and returns the datum and 'Location'
-- associated with that item.
eventItemLocation :: Monad m => EventItem a b -> OrchestrateT m (a, Location)
eventItemLocation ei = do
v <- view sessionVersion
let epath = ei ^. eventItem . itemPath
path = epath ^. eventPath
loc = T.intercalate "/" [ ""
, "v" <> tshow v
, path ^. itemCollection
, path ^. itemKey
, "events"
, epath ^. eventPathType
, tshow $ epath ^. eventPathTime
, tshow $ epath ^. eventPathOrd
]
return (ei ^. eventItem . itemValue, loc)