packages feed

stakhanov 0.1.0.0 → 0.1.0.1

raw patch · 7 files changed

+81/−77 lines, 7 filesdep −bytestringdep ~hasqldep ~hasql-dynamic-statementsdep ~hasql-thPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: bytestring

Dependency ranges changed: hasql, hasql-dynamic-statements, hasql-th

API changes (from Hackage documentation)

- Database.PostgreSQL.Stakhanov.Types: instance GHC.Internal.Show.Show Database.PostgreSQL.Stakhanov.Types.Details
- Database.PostgreSQL.Stakhanov.Types: instance GHC.Internal.Show.Show Database.PostgreSQL.Stakhanov.Types.HasqlConn
- Database.PostgreSQL.Stakhanov.Types: instance GHC.Internal.Show.Show Database.PostgreSQL.Stakhanov.Types.Message
- Database.PostgreSQL.Stakhanov.Types: instance GHC.Internal.Show.Show Database.PostgreSQL.Stakhanov.Types.Metrics
- Database.PostgreSQL.Stakhanov.Types: instance GHC.Internal.Show.Show Database.PostgreSQL.Stakhanov.Types.Queue
+ Database.PostgreSQL.Stakhanov.Types: instance GHC.Show.Show Database.PostgreSQL.Stakhanov.Types.Details
+ Database.PostgreSQL.Stakhanov.Types: instance GHC.Show.Show Database.PostgreSQL.Stakhanov.Types.HasqlConn
+ Database.PostgreSQL.Stakhanov.Types: instance GHC.Show.Show Database.PostgreSQL.Stakhanov.Types.Message
+ Database.PostgreSQL.Stakhanov.Types: instance GHC.Show.Show Database.PostgreSQL.Stakhanov.Types.Metrics
+ Database.PostgreSQL.Stakhanov.Types: instance GHC.Show.Show Database.PostgreSQL.Stakhanov.Types.Queue

Files

CHANGELOG.md view
@@ -7,3 +7,7 @@ ## 0.1.0.0 -- 2026-02-11  * Updated to work with pgmq v1.10.0. The field last_read_at has been added to message record.++## 0.1.0.1 -- 2026-05-02++* Updated to use Hasql >= 1.10 && < 1.11.
ReadMe.md view
@@ -2,4 +2,4 @@  The Haskell library `stakhanov`, built upon [Hasql](https://hackage.haskell.org/package/hasql)'s ecosystem and [Vector](https://hackage.haskell.org/package/vector), implements most of the functions of the [API](https://pgmq.github.io/pgmq/api/sql/functions/) of [PGMQ](https://pgmq.github.io/pgmq/), "a lightweight message queue, like AWS SQS and RSMQ but on Postgres". -`stakhanov v0.1.0.0` has been tested against [pgmq v1.10.0](https://github.com/pgmq/pgmq/releases/tag/v1.10.0).+`stakhanov v0.1.0.1` has been tested against [pgmq v1.10.0](https://github.com/pgmq/pgmq/releases/tag/v1.10.0) and [pgmq v1.11.1](https://github.com/pgmq/pgmq/releases/tag/v1.11.1).
src/Database/PostgreSQL/Stakhanov.hs view
@@ -50,8 +50,9 @@ import           Database.PostgreSQL.Stakhanov.Internal import           Database.PostgreSQL.Stakhanov.Statements import           Database.PostgreSQL.Stakhanov.Types-import qualified Hasql.Connection                         as C-import qualified Hasql.Session                            as S+import           Hasql.Connection+import           Hasql.Errors+import           Hasql.Session import           Prelude                                  hiding (drop, read)  -- | Create a new `Queue`.@@ -61,10 +62,10 @@ -- create   :: T.Text       -- ^ The name of the queue to create-  -> C.Connection -- ^ The PostgreSQL connection to use-  -> IO (Either S.SessionError Queue)+  -> Connection -- ^ The PostgreSQL connection to use+  -> IO (Either SessionError Queue) create t c =-  S.run (S.statement t createQueue) c >>=+  use c (statement t createQueue) >>=     pureMap (\_ -> Queue t (HasqlConn c) Nothing Nothing)  -- | Create an unlogged new `Queue`. This is useful@@ -76,10 +77,10 @@ -- createUnlogged   :: T.Text       -- ^ The name of the queue to create-  -> C.Connection -- ^ The PostgreSQL connection to use-  -> IO (Either S.SessionError Queue)+  -> Connection -- ^ The PostgreSQL connection to use+  -> IO (Either SessionError Queue) createUnlogged t c =-  S.run (S.statement t createUnloggedQueue) c >>=+  use c (statement t createUnloggedQueue) >>=     pureMap (\_ -> Queue t (HasqlConn c) Nothing Nothing)  -- | Declare an already existing `Queue`.@@ -89,7 +90,7 @@ -- declare   :: T.Text       -- ^ The name of the queue to declare-  -> C.Connection -- ^ The PostgreSQL connection to use+  -> Connection -- ^ The PostgreSQL connection to use   -> Queue declare t c = Queue t (HasqlConn c) Nothing Nothing @@ -97,25 +98,25 @@ -- Returns the number of `Messages` that were deleted. purge   :: Queue                            -- ^ The queue to work with-  -> IO (Either S.SessionError Int64) -- ^ Returns the number of messages that were deleted+  -> IO (Either SessionError Int64) -- ^ Returns the number of messages that were deleted purge Queue{..} =-  S.run (S.statement qName purgeQueue) (unHasqlConn qPGConn)+  use (unHasqlConn qPGConn) (statement qName purgeQueue)  -- | Deletes a `Queue` and its archive. drop   :: Queue                           -- ^ The queue to work with-  -> IO (Either S.SessionError Bool) -- ^ Returns `True` in case of deletion+  -> IO (Either SessionError Bool) -- ^ Returns `True` in case of deletion drop Queue{..} =-  S.run (S.statement qName dropQueue) (unHasqlConn qPGConn)+  use (unHasqlConn qPGConn) (statement qName dropQueue)  -- | Send a single `Message` to a `Queue`. -- Returns the `MsgId` of the just created `Message`. send   :: Queue                            -- ^ The queue to work with   -> Value                            -- ^ A JSON object to send as a message to the queue-  -> IO (Either S.SessionError MsgId) -- ^ Returns the message ID of the just created message+  -> IO (Either SessionError MsgId) -- ^ Returns the message ID of the just created message send Queue{..} v@(Object _) =-  S.run (S.statement (qName,v) sendMessage) (unHasqlConn qPGConn)+  use (unHasqlConn qPGConn) (statement (qName,v) sendMessage) send _         _            = fail "The Aeson Value must be an Object"  -- | Send a single `Message` to a `Queue` with optional metadata (a JSON object named headers)@@ -125,19 +126,19 @@   -> Value                            -- ^ A JSON object sent as a message to the queue   -> Maybe Value                      -- ^ Maybe a JSON object sent as headers/metadata to the queue   -> Maybe Delay                      -- ^ Maybe a time before which the message becomes visible-  -> IO (Either S.SessionError MsgId) -- ^ Returns the message ID of the just created message+  -> IO (Either SessionError MsgId) -- ^ Returns the message ID of the just created message send' Queue{..} v@(Object _) mv@(Just (Object _)) md =-  S.run (S.statement () $ sendMessage' qName v mv md) (unHasqlConn qPGConn)+  use (unHasqlConn qPGConn) (statement () $ sendMessage' qName v mv md) send' _ _ _ _  = fail "The Aeson Values must be Objects"  -- | Send on or more `Messages` to a `Queue`. Returns the `MsgId` of just created `Message`. batchSend   :: Queue                                       -- ^ The queue to work with   -> V.Vector Value                              -- ^ A vector of JSON objects sent as messages to the queue-  -> IO (Either S.SessionError MsgIds) -- ^ Returns a vector of message IDs of just created messages+  -> IO (Either SessionError MsgIds) -- ^ Returns a vector of message IDs of just created messages batchSend Queue{..} v =   if allJSON v-    then S.run (S.statement () $ sendMessages qName v) (unHasqlConn qPGConn)+    then use (unHasqlConn qPGConn) (statement () $ sendMessages qName v)     else fail "All Aeson Values of the Vector must be Objects"  -- | Send on or more `Messages` to a `Queue` with optional headers (a JSON object of metadata)@@ -147,12 +148,12 @@   -> V.Vector Value                              -- ^ A vector of JSON objects sent as messages to the queue   -> Maybe (V.Vector Value)                      -- ^ Maybe a vector of JSON objects sent as headers/metadata. Its length must be the same as the vector of messages   -> Maybe Delay                                 -- ^ Maybe a time before which messages becomes visible-  -> IO (Either S.SessionError MsgIds) -- ^ Returns a vector of message IDs of just created messages+  -> IO (Either SessionError MsgIds) -- ^ Returns a vector of message IDs of just created messages batchSend' Queue{..} vv mvv md =   if allJSON vv && maybe True allJSON mvv     then       if isNothing mvv || isJust mvv && V.length vv == V.length (fromJust mvv)-        then S.run (S.statement () $ sendMessages' qName vv mvv md) (unHasqlConn qPGConn)+        then use (unHasqlConn qPGConn) (statement () $ sendMessages' qName vv mvv md)         else fail "The vector of headers must be equal to the vector of messages"     else fail "All Aeson Values of Vectors must be Objects" @@ -162,9 +163,9 @@   :: Queue -- ^ The queue to work with   -> VT    -- ^ The Visibility Timeout : the time in seconds that message(s) become invisible after reading   -> Qty   -- ^ The number of messages to read from the queue-  -> IO (Either S.SessionError (Maybe Messages))+  -> IO (Either SessionError (Maybe Messages)) read Queue{..} v q =-  S.run (S.statement (qName,v,q) readMessages) (unHasqlConn qPGConn) >>= pureMap maybeMessages+  use (unHasqlConn qPGConn) (statement (qName,v,q) readMessages) >>= pureMap maybeMessages  -- | Same as `read`. Also provides convenient long-poll functionality. When there are no `Messages` in the `Queue`, -- the function call will wait for /max_poll_seconds/ in duration before returning. If messages reach the queue@@ -175,9 +176,9 @@   -> Qty                 -- ^ The number of messages to read from the queue   -> Maybe Seconds       -- ^ The max_poll_seconds : the time in seconds to wait for new messages to reach the queue. Defaults to 5   -> Maybe Milliseconds  -- ^ The milliseconds between the internal poll operations. Defaults to 100-  -> IO (Either S.SessionError (Maybe Messages))+  -> IO (Either SessionError (Maybe Messages)) readWithPoll Queue{..} v q mmp mpi =-  S.run (S.statement () $ readMessagesWithPoll qName v q mmp mpi) (unHasqlConn qPGConn) >>= pureMap maybeMessages+  use (unHasqlConn qPGConn) (statement () $ readMessagesWithPoll qName v q mmp mpi) >>= pureMap maybeMessages  -- | Reads one or more `Messages` from a `Queue` and /deletes them upon read/. --@@ -187,53 +188,53 @@ pop   :: Queue -- ^ The queue to work with   -> Qty   -- ^ The number of messages to pop from the queue (defaults to 1)-  -> IO (Either S.SessionError (Maybe Messages))+  -> IO (Either SessionError (Maybe Messages)) pop Queue{..} y =-  S.run (S.statement (qName,y) popMessages) (unHasqlConn qPGConn) >>= pureMap maybeMessages+  use (unHasqlConn qPGConn) (statement (qName,y) popMessages) >>= pureMap maybeMessages  -- | Removes a single requested `Message` from the specified `Queue` -- and inserts it into the `Queue`'s archive. archive   :: Queue -- ^ The queue to work with   -> MsgId -- ^ The message ID of the message to archive-  -> IO (Either S.SessionError Bool)+  -> IO (Either SessionError Bool) archive Queue{..} i =-  S.run (S.statement (qName,i) archiveMessage) (unHasqlConn qPGConn)+  use (unHasqlConn qPGConn) (statement (qName,i) archiveMessage)  -- | Deletes a batch of requested `Messages` from the specified `Queue` and inserts them into the `Queue`'s archive. -- Returns a `V.Vector` of `MsgId` that were successfully archived. batchArchive   :: Queue          -- ^ The queue to work with   -> V.Vector MsgId -- ^ A vector of message IDs to archive-  -> IO (Either S.SessionError MsgIds)+  -> IO (Either SessionError MsgIds) batchArchive Queue{..} v =-  S.run (S.statement () $ archiveMessages qName v) (unHasqlConn qPGConn)+  use (unHasqlConn qPGConn) (statement () $ archiveMessages qName v)  -- | Deletes a single `Message` from a `Queue`. delete   :: Queue -- ^ The queue to work with   -> MsgId -- ^ The message ID to delete-  -> IO (Either S.SessionError Bool)-delete Queue{..} i = S.run (S.statement (qName,i) deleteMessage) (unHasqlConn qPGConn)+  -> IO (Either SessionError Bool)+delete Queue{..} i = use (unHasqlConn qPGConn) (statement (qName,i) deleteMessage)  -- | Delete one or many `Messages` from a `Queue`. batchDelete   :: Queue  -- ^ The queue to work with   -> MsgIds -- ^ The vector of message IDs to delete-  -> IO (Either S.SessionError MsgIds)+  -> IO (Either SessionError MsgIds) batchDelete Queue{..} v =-  S.run (S.statement () $ deleteMessages qName v) (unHasqlConn qPGConn)+  use (unHasqlConn qPGConn) (statement () $ deleteMessages qName v) --- | List all the `Queue`s that currently exist, with a raw Hasql `C.Connection` as parameter.+-- | List all the `Queue`s that currently exist, with a raw Hasql `Connection` as parameter. -- -- > λ: listQueues conn -- > Right [Queue {qName = "test", qPGConn = "a Hasql connection", qDetails = Just (Details {createdAt = 2025-12-18 14:33:41.563365 UTC, isPartitioned = False, isUnlogged = False}), qMetrics = Nothing},Queue {qName = "MyQueue", qPGConn = "a Hasql connection", qDetails = Just (Details {createdAt = 2026-01-09 19:05:24.976526 UTC, isPartitioned = False, isUnlogged = False}), qMetrics = Nothing}] -- listQueues-  :: C.Connection -- ^ A Hasql connection-  -> IO (Either S.SessionError Queues)+  :: Connection -- ^ A Hasql connection+  -> IO (Either SessionError Queues) listQueues c =-  S.run (S.statement () getQueuesDetails) c >>= pureMap (toQueue <$>)+  use c (statement () getQueuesDetails) >>= pureMap (toQueue <$>)   where     toQueue r =       Queue@@ -245,7 +246,7 @@ -- | Same as `listQueues`, with a `Queue` as parameter. listQueues'   :: Queue -- ^ A queue to use its connection to reach PostgreSQL and add this connection to each queue collected-  -> IO (Either S.SessionError Queues)+  -> IO (Either SessionError Queues) listQueues' Queue{..} = listQueues (unHasqlConn qPGConn)  -- | Add `Details` information, collected with `listQueues`, to a `Queue` record.@@ -293,7 +294,7 @@   :: Queue   -- ^ The queue to work with   -> MsgIds  -- ^ The vector of message IDs to set visibility time   -> Seconds -- ^ Duration from now, in seconds, that the messages VT should be set to-  -> IO (Either S.SessionError Messages)+  -> IO (Either SessionError Messages) batchSetVT Queue{..} v s =-  S.run (S.statement () $ setMessagesVT qName v s) (unHasqlConn qPGConn) >>= pureMap (tupleToMessage <$>)+  use (unHasqlConn qPGConn) (statement () $ setMessagesVT qName v s) >>= pureMap (tupleToMessage <$>) 
src/Database/PostgreSQL/Stakhanov/Connection.hs view
@@ -3,16 +3,16 @@  module Database.PostgreSQL.Stakhanov.Connection where -import qualified Data.Text                           as T+import qualified Data.Text                 as T import           Hasql.Connection-import           Hasql.Connection.Setting            (connection)-import           Hasql.Connection.Setting.Connection (string)+import           Hasql.Connection.Settings (connectionString)+import           Hasql.Errors  -- | Get a local PostgreSQL connection to a Docker container of PGMQ, with the default PostgreSQL connection string "__postgres:\/\/postgres:postgres@0.0.0.0:5432/postgres__". acquireLocalPGConn :: IO (Either ConnectionError Connection)-acquireLocalPGConn = acquire [connection $ string "postgres://postgres:postgres@0.0.0.0:5432/postgres"]+acquireLocalPGConn = acquire $ connectionString "postgres://postgres:postgres@0.0.0.0:5432/postgres"  -- | Get a PostgreSQL connection configured with the given PostgreSQL connection string. acquirePGConn :: T.Text -> IO (Either ConnectionError Connection)-acquirePGConn t = acquire [connection $ string t]+acquirePGConn t = acquire $ connectionString t 
src/Database/PostgreSQL/Stakhanov/Metrics.hs view
@@ -21,7 +21,9 @@ import           Database.PostgreSQL.Stakhanov.Internal import           Database.PostgreSQL.Stakhanov.Statements import           Database.PostgreSQL.Stakhanov.Types-import qualified Hasql.Session                            as S+import           Hasql.Connection+import           Hasql.Errors+import           Hasql.Session  -- | Get `Queue`'s `Metrics`. --@@ -30,19 +32,19 @@ -- metrics   :: Queue                            -- ^ The name of the queue-  -> IO (Either S.SessionError Queue) -- ^ The queue with metrics added+  -> IO (Either SessionError Queue) -- ^ The queue with metrics added metrics q@Queue{..} =-  S.run (S.statement qName getMetrics) (unHasqlConn qPGConn) >>= pureMap addMetrics+  use (unHasqlConn qPGConn) (statement qName getMetrics) >>= pureMap addMetrics   where     addMetrics m = q { qMetrics = Just $ tupleToMetrics m }  -- | Get `Metrics` of all created `Queue`s. allMetrics   :: Queue -- ^ The connection to PostgreSQL-  -> IO (Either S.SessionError (V.Vector Queue))+  -> IO (Either SessionError (V.Vector Queue)) allMetrics Queue{..} =   let c = unHasqlConn qPGConn-  in S.run (S.statement () getAllMetrics) c >>= pureMap (tupleToQueueWithMetrics c <$>)+  in use c (statement () getAllMetrics) >>= pureMap (tupleToQueueWithMetrics c <$>)  -- | Number of messages currently in the queue. getQueueLength :: Queue -> Maybe Int64
src/Database/PostgreSQL/Stakhanov/Statements.hs view
@@ -2,7 +2,6 @@  import           Contravariant.Extras.Contrazip         (contrazip2, contrazip3) import           Data.Aeson-import           Data.ByteString import           Data.Int import qualified Data.List                              as L import           Data.Maybe                             (fromMaybe)@@ -13,7 +12,6 @@ import           Database.PostgreSQL.Stakhanov.Types import qualified Hasql.Decoders                         as D import qualified Hasql.DynamicStatements.Snippet        as S-import           Hasql.DynamicStatements.Statement import qualified Hasql.Encoders                         as E import           Hasql.Statement import qualified Hasql.TH                               as TH@@ -27,9 +25,9 @@  getQueuesDetails :: Statement () (V.Vector (T.Text, (UTCTime, Bool, Bool))) getQueuesDetails =-  Statement sql E.noParams decoder True+  preparable sql E.noParams decoder   where-    sql = "select queue_name,created_at,is_partitioned,is_unlogged from pgmq.list_queues()"+    sql = "select queue_name::text,created_at,is_partitioned,is_unlogged from pgmq.list_queues()"     decoder =       D.rowVector $         (,) <$>@@ -47,7 +45,7 @@  sendMessage :: Statement (T.Text,Value) Int64 sendMessage =-  Statement sql encoder decoder True+  preparable sql encoder decoder   where     sql = "select * from pgmq.send($1::text,$2::jsonb)"     encoder =@@ -62,13 +60,13 @@         "select * from pgmq.send(" <> S.param q <> ","         <> S.param v <> maybeHeaders mv <> maybeDelay mi <> ")"       decoder = D.singleRow $ D.column $ D.nonNullable D.int8-  in dynamicallyParameterized snippet decoder True+  in S.toStatement snippet decoder  sendMessages :: T.Text -> (V.Vector Value) -> Statement () (V.Vector Int64) sendMessages q msgs =   let snippet = "select * from pgmq.send_batch(" <> S.param q <> "," <> jsonbArrayEncoder msgs <> ")"       decoder = D.rowVector $ D.column $ D.nonNullable D.int8-  in dynamicallyParameterized snippet decoder True+  in S.toStatement snippet decoder  sendMessages' :: T.Text -> (V.Vector Value) -> Maybe (V.Vector Value) -> Maybe Delay -> Statement () (V.Vector Int64) sendMessages' q vv mvv md =@@ -76,7 +74,7 @@         "select * from pgmq.send_batch(" <> S.param q <> "," <> jsonbArrayEncoder vv         <> (fromMaybe mempty $ (mappend "," . jsonbArrayEncoder) <$> mvv) <> maybeDelay md <> ")"       decoder = D.rowVector $ D.column $ D.nonNullable D.int8-  in dynamicallyParameterized snippet decoder True+  in S.toStatement snippet decoder  readMessagesWithPoll :: T.Text -> Int32 -> Int32 -> Maybe Int32 -> Maybe Int32 -> Statement () (V.Vector (Int64, Int32, UTCTime, Maybe UTCTime, UTCTime, Value, Maybe Value)) readMessagesWithPoll q vt qty mmp mpi =@@ -84,11 +82,11 @@       pi = maybe 100 id mpi       snippet = "select " <> S.sql columnsMessage <> " from pgmq.read_with_poll(" <>                 mconcat (L.intersperse "," [S.param q, S.param vt, S.param qty, S.param mp, S.param pi]) <> ")"-  in dynamicallyParameterized snippet tupleMessageDecoder True+  in S.toStatement snippet tupleMessageDecoder  readMessages :: Statement (T.Text,Int32,Int32) (V.Vector (Int64, Int32, UTCTime, Maybe UTCTime, UTCTime, Value, Maybe Value)) readMessages =-  Statement sql encoder tupleMessageDecoder True+  preparable sql encoder tupleMessageDecoder   where     sql = "select " <> columnsMessage <> " from pgmq.read($1,$2,$3)"     encoder =@@ -99,7 +97,7 @@  popMessages :: Statement (T.Text,Int32) (V.Vector (Int64, Int32, UTCTime, Maybe UTCTime, UTCTime, Value, Maybe Value)) popMessages =-  Statement sql encoder tupleMessageDecoder True+  preparable sql encoder tupleMessageDecoder   where     sql = "select " <> columnsMessage <> " from pgmq.pop($1,$2)"     encoder =@@ -109,7 +107,7 @@  getMetrics :: Statement T.Text (Int64, Maybe Int32, Maybe Int32, Int64, UTCTime, Int64) getMetrics =-  Statement sql encoder decoder True+  preparable sql encoder decoder   where     sql = "select " <> columnsMetrics <> " from pgmq.metrics($1)"     encoder = E.param (E.nonNullable E.text)@@ -125,7 +123,7 @@  getAllMetrics :: Statement () (V.Vector (T.Text, Int64, Maybe Int32, Maybe Int32, Int64, UTCTime, Int64)) getAllMetrics =-  Statement sql E.noParams decoder True+  preparable sql E.noParams decoder   where     sql = "select queue_name," <> columnsMetrics <> " from pgmq.metrics_all()"     decoder =@@ -146,7 +144,7 @@ archiveMessages q v =   let snippet = "select * from pgmq.archive(" <> S.param q <> "," <> bigintArrayEncoder v <> ")"       decoder = D.rowVector (D.column (D.nonNullable D.int8))-  in dynamicallyParameterized snippet decoder True+  in S.toStatement snippet decoder  deleteMessage :: Statement (T.Text,Int64) Bool deleteMessage = [TH.singletonStatement|select pgmq.delete($1::text,$2::int8)::bool|]@@ -155,13 +153,13 @@ deleteMessages q v =   let snippet = "select * from pgmq.delete(" <> S.param q <> "," <> bigintArrayEncoder v <> ")"       decoder = D.rowVector (D.column (D.nonNullable D.int8))-  in dynamicallyParameterized snippet decoder True+  in S.toStatement snippet decoder  setMessagesVT :: T.Text -> V.Vector Int64 -> Int32 -> Statement () (V.Vector (Int64, Int32, UTCTime, Maybe UTCTime, UTCTime, Value, Maybe Value)) setMessagesVT q v s =   let snippet = "select * from pgmq.set_vt(" <> S.param q <> ","                 <> bigintArrayEncoder v <> "," <> S.param s <> ")"-  in dynamicallyParameterized snippet tupleMessageDecoder True+  in S.toStatement snippet tupleMessageDecoder  tupleMessageDecoder :: D.Result (V.Vector (Int64, Int32, UTCTime, Maybe UTCTime, UTCTime, Value, Maybe Value)) tupleMessageDecoder =@@ -175,9 +173,9 @@       D.column (D.nonNullable D.jsonb) <*>       D.column (D.nullable D.jsonb) -columnsMessage :: ByteString+columnsMessage :: T.Text columnsMessage = "msg_id,read_ct,enqueued_at,last_read_at,vt,message,headers" -columnsMetrics :: ByteString+columnsMetrics :: T.Text columnsMetrics = "queue_length,newest_msg_age_sec,oldest_msg_age_sec,total_messages,scrape_time,queue_visible_length" 
stakhanov.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               stakhanov-version:            0.1.0.0+version:            0.1.0.1 synopsis:           A Haskell PGMQ client description:   A fast Haskell PGMQ client for busy workers@@ -16,7 +16,7 @@ extra-doc-files:    CHANGELOG.md extra-source-files: ReadMe.md tested-with:-  GHC ==9.6.7 || ==9.8.4 || ==9.10.3 || ==9.12.2 || ==9.14.1+  GHC ==9.6.7 || ==9.8.4 || ==9.10.3 || ==9.12.4  source-repository head   type:     git@@ -46,11 +46,10 @@   build-depends:     , aeson                     >=2.2.3    && <2.4     , base                      >=4.8      && <5-    , bytestring                >=0.11.5.4 && <0.13     , contravariant-extras      >=0.3.5    && <0.3.6-    , hasql                     >=1.9      && <1.10-    , hasql-dynamic-statements  >=0.3      && <0.4-    , hasql-th                  >=0.4      && <0.5+    , hasql                     >=1.10      && <1.11+    , hasql-dynamic-statements  >=0.5      && <0.6+    , hasql-th                  >=0.5      && <0.6     , text                      >=1.2.3    && <2.2     , time                      >=1.9.3    && <1.16     , vector                    >=0.12.2   && <0.14