haskell-pgmq-0.1.0.0: src/Database/PGMQ/Types.hs
{-|
Module : Database.PGMQ.Types
Description : PGMQ types
Copyright : (c) Gargantext, 2024-Present
License : AGPL
Maintainer : gargantext@iscpif.fr
Stability : experimental
Portability : POSIX
-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Database.PGMQ.Types
where
import Data.Aeson (FromJSON, ToJSON)
import Data.Time.LocalTime (ZonedTime, zonedTimeToUTC)
import Data.Typeable (Typeable)
import Database.PostgreSQL.Simple qualified as PSQL
import Database.PostgreSQL.Simple.FromRow qualified as PSQL (field, FromRow(..))
import Database.PostgreSQL.Simple.Newtypes qualified as PSQL (getAeson)
-- | Time in seconds before the message becomes visible (used when
-- | sending message to pgmq).
type Delay = Int -- in seconds
-- | Number of messages in metrics report
type MessageCount = Int
-- | The ID of a message in pgmq
type MessageId = Int
-- | Name of queue in pgmq
type Queue = String
-- | Number of times a message was read from pgmq
type ReadCount = Int
-- | https://tembo.io/pgmq/#visibility-timeout-vt
-- (in seconds)
-- pgmq guarantees exactly once delivery of a message within a
-- visibility timeout. The visibility timeout is the amount of time a
-- message is invisible to other consumers after it has been read by
-- a consumer. If the message is NOT deleted or archived within the
-- visibility timeout, it will become visible again and can be read
-- by another consumer.
type VisibilityTimeout = Int
-- | 'MaxPollSeconds' and 'PollIntervalMs' are used in 'pgmq.read_with_poll'
type MaxPollSeconds = Int
type PollIntervalMs = Int
-- | Basic message typeclass for PGMQ: it has to be jsonb-serializable
type SerializableMessage a = ( FromJSON a
, ToJSON a
-- NOTE This shouldn't be necessary
, Typeable a )
-- | Message, as returned by the 'pgmq.read' function
data Message a =
Message { msgId :: MessageId
, readCt :: ReadCount
, enqueuedAt :: ZonedTime
, archivedAt :: Maybe ZonedTime
, vt :: ZonedTime
, message :: a }
deriving (Show)
-- NOTE I'm not sure if this is needed
instance Eq a => Eq (Message a) where
(==) msg1 msg2 =
(msgId msg1) == (msgId msg2) &&
(readCt msg1) == (readCt msg2) &&
(zonedTimeToUTC $ vt msg1) == (zonedTimeToUTC $ vt msg2) &&
(message msg1) == (message msg2)
instance SerializableMessage a => PSQL.FromRow (Message a) where
fromRow = do
msgId <- PSQL.field
readCt <- PSQL.field
enqueuedAt <- PSQL.field
archivedAt <- PSQL.field
vt <- PSQL.field
messageA <- PSQL.field
return $ Message { message = PSQL.getAeson messageA, .. }
-- | Returned by pgmq.list_queues
data QueueInfo =
QueueInfo { queueName :: Queue
, isPartitioned :: Bool
, isUnlogged :: Bool
, createdAt :: ZonedTime }
deriving (Show)
instance PSQL.FromRow QueueInfo where
fromRow = do
queueName <- PSQL.field
isPartitioned <- PSQL.field
isUnlogged <- PSQL.field
createdAt <- PSQL.field
return $ QueueInfo { .. }
-- | Returned by pgmq.metrics, pgmq.metrics_all
data Metrics =
Metrics { queueName :: Queue
, queueLength :: Int
, newestMsgAgeSec :: Maybe Int
, oldestMsgAgeSec :: Maybe Int
, totalMessages :: MessageCount
, scrapeTime :: ZonedTime }
deriving (Show)
instance PSQL.FromRow Metrics where
fromRow = do
queueName <- PSQL.field
queueLength <- PSQL.field
newestMsgAgeSec <- PSQL.field
oldestMsgAgeSec <- PSQL.field
totalMessages <- PSQL.field
scrapeTime <- PSQL.field
return $ Metrics { .. }