stakhanov 0.0.1.0 → 0.1.0.0
raw patch · 7 files changed
+37/−29 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Database.PostgreSQL.Stakhanov.Types: [lastReadAt] :: Message -> Maybe UTCTime
- Database.PostgreSQL.Stakhanov.Types: Message :: MsgId -> Int32 -> UTCTime -> UTCTime -> !Value -> !Maybe Value -> Message
+ Database.PostgreSQL.Stakhanov.Types: Message :: MsgId -> Int32 -> UTCTime -> Maybe UTCTime -> UTCTime -> Value -> Maybe Value -> Message
- Database.PostgreSQL.Stakhanov.Types: [headers] :: Message -> !Maybe Value
+ Database.PostgreSQL.Stakhanov.Types: [headers] :: Message -> Maybe Value
- Database.PostgreSQL.Stakhanov.Types: [message] :: Message -> !Value
+ Database.PostgreSQL.Stakhanov.Types: [message] :: Message -> Value
Files
- CHANGELOG.md +4/−0
- ReadMe.md +1/−0
- src/Database/PostgreSQL/Stakhanov.hs +2/−2
- src/Database/PostgreSQL/Stakhanov/Internal.hs +10/−9
- src/Database/PostgreSQL/Stakhanov/Statements.hs +15/−14
- src/Database/PostgreSQL/Stakhanov/Types.hs +4/−3
- stakhanov.cabal +1/−1
CHANGELOG.md view
@@ -3,3 +3,7 @@ ## 0.0.1.0 -- 2026-01-12 * First version.++## 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.
ReadMe.md view
@@ -2,3 +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).
src/Database/PostgreSQL/Stakhanov.hs view
@@ -181,7 +181,7 @@ -- | Reads one or more `Messages` from a `Queue` and /deletes them upon read/. ----- > λ: pop MyQueue 2+-- > λ: pop myQueue 2 -- > Right (Just [Message {msgId = 2, readCount = 13, enqueuedAt = 2025-12-09 09:51:50.259464 UTC, visibilityTimeout = 2025-12-15 10:46:41.096843 UTC, message = Object (fromList [("Action",String "hug"),("Quantity",Number 3)]), headers = Nothing},Message {msgId = 3, readCount = 2, enqueuedAt = 2025-12-15 10:44:45.612983 UTC, visibilityTimeout = 2025-12-29 18:04:32.938332 UTC, message = Object (fromList [("Action",String "hug"),("Quantity",Number 5)]), headers = Object (fromList [("Reason",String empathy"")])}]) -- pop@@ -251,7 +251,7 @@ -- | Add `Details` information, collected with `listQueues`, to a `Queue` record. -- -- > λ: Right list <- listQueues conn--- > λ: details MyQueue list+-- > λ: details myQueue list -- > Just (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}) -- details
src/Database/PostgreSQL/Stakhanov/Internal.hs view
@@ -25,12 +25,12 @@ allJSON = V.all isJSON maybeMessages- :: Vector (Int64, Int32, UTCTime, UTCTime, Value, Maybe Value)+ :: Vector (Int64, Int32, UTCTime, Maybe UTCTime, UTCTime, Value, Maybe Value) -> Maybe Messages maybeMessages v =- if V.null v- then Nothing- else Just $ tupleToMessage <$> v+ if V.null v+ then Nothing+ else Just $ tupleToMessage <$> v tupleToDetails :: (UTCTime,Bool,Bool) -> Details tupleToDetails (e1,e2,e3) =@@ -65,16 +65,17 @@ , queueVisibleLength = e6 } tupleToMessage- :: (Int64, Int32, UTCTime, UTCTime, Value, Maybe Value)+ :: (Int64, Int32, UTCTime, Maybe UTCTime, UTCTime, Value, Maybe Value) -> Message-tupleToMessage (e1,e2,e3,e4,e5,e6) =+tupleToMessage (e1,e2,e3,e4,e5,e6,e7) = Message { msgId = e1 , readCount = e2 , enqueuedAt = e3- , visibilityTimeout = e4- , message = e5- , headers = e6 }+ , lastReadAt = e4+ , visibilityTimeout = e5+ , message = e6+ , headers = e7 } maybeHeaders :: Maybe Value -> S.Snippet maybeHeaders (Just v) = "," <> S.encoderAndParam (E.nonNullable E.json) v <> "::jsonb"
src/Database/PostgreSQL/Stakhanov/Statements.hs view
@@ -52,8 +52,8 @@ sql = "select * from pgmq.send($1::text,$2::jsonb)" encoder = contrazip2- (E.param (E.nonNullable E.text))- (E.param (E.nonNullable E.jsonb))+ (E.param $ E.nonNullable E.text)+ (E.param $ E.nonNullable E.jsonb) decoder = D.singleRow $ D.column $ D.nonNullable D.int8 sendMessage' :: T.Text -> Value -> Maybe Value -> Maybe Delay -> Statement () Int64@@ -78,7 +78,7 @@ decoder = D.rowVector $ D.column $ D.nonNullable D.int8 in dynamicallyParameterized snippet decoder True -readMessagesWithPoll :: T.Text -> Int32 -> Int32 -> Maybe Int32 -> Maybe Int32 -> Statement () (V.Vector (Int64, Int32, UTCTime, UTCTime, Value, Maybe Value))+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 = let mp = maybe 5 id mmp pi = maybe 100 id mpi@@ -86,26 +86,26 @@ mconcat (L.intersperse "," [S.param q, S.param vt, S.param qty, S.param mp, S.param pi]) <> ")" in dynamicallyParameterized snippet tupleMessageDecoder True -readMessages :: Statement (T.Text,Int32,Int32) (V.Vector (Int64, Int32, UTCTime, UTCTime, Value, Maybe Value))+readMessages :: Statement (T.Text,Int32,Int32) (V.Vector (Int64, Int32, UTCTime, Maybe UTCTime, UTCTime, Value, Maybe Value)) readMessages = Statement sql encoder tupleMessageDecoder True where sql = "select " <> columnsMessage <> " from pgmq.read($1,$2,$3)" encoder = contrazip3- (E.param (E.nonNullable E.text))- (E.param (E.nonNullable E.int4))- (E.param (E.nonNullable E.int4))+ (E.param $ E.nonNullable E.text)+ (E.param $ E.nonNullable E.int4)+ (E.param $ E.nonNullable E.int4) -popMessages :: Statement (T.Text,Int32) (V.Vector (Int64, Int32, UTCTime, UTCTime, Value, Maybe Value))+popMessages :: Statement (T.Text,Int32) (V.Vector (Int64, Int32, UTCTime, Maybe UTCTime, UTCTime, Value, Maybe Value)) popMessages = Statement sql encoder tupleMessageDecoder True where sql = "select " <> columnsMessage <> " from pgmq.pop($1,$2)" encoder = contrazip2- (E.param (E.nonNullable E.text))- (E.param (E.nonNullable E.int4))+ (E.param $ E.nonNullable E.text)+ (E.param $ E.nonNullable E.int4) getMetrics :: Statement T.Text (Int64, Maybe Int32, Maybe Int32, Int64, UTCTime, Int64) getMetrics =@@ -157,25 +157,26 @@ decoder = D.rowVector (D.column (D.nonNullable D.int8)) in dynamicallyParameterized snippet decoder True -setMessagesVT :: T.Text -> V.Vector Int64 -> Int32 -> Statement () (V.Vector (Int64, Int32, UTCTime, UTCTime, Value, Maybe Value))+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 -tupleMessageDecoder :: D.Result (V.Vector (Int64, Int32, UTCTime, UTCTime, Value, Maybe Value))+tupleMessageDecoder :: D.Result (V.Vector (Int64, Int32, UTCTime, Maybe UTCTime, UTCTime, Value, Maybe Value)) tupleMessageDecoder = D.rowVector $- (,,,,,) <$>+ (,,,,,,) <$> D.column (D.nonNullable D.int8) <*> D.column (D.nonNullable D.int4) <*> D.column (D.nonNullable D.timestamptz) <*>+ D.column (D.nullable D.timestamptz) <*> D.column (D.nonNullable D.timestamptz) <*> D.column (D.nonNullable D.jsonb) <*> D.column (D.nullable D.jsonb) columnsMessage :: ByteString-columnsMessage = "msg_id,read_ct,enqueued_at,vt,message,headers"+columnsMessage = "msg_id,read_ct,enqueued_at,last_read_at,vt,message,headers" columnsMetrics :: ByteString columnsMetrics = "queue_length,newest_msg_age_sec,oldest_msg_age_sec,total_messages,scrape_time,queue_visible_length"
src/Database/PostgreSQL/Stakhanov/Types.hs view
@@ -45,13 +45,14 @@ { msgId :: MsgId , readCount :: Int32 , enqueuedAt :: UTCTime+ , lastReadAt :: Maybe UTCTime , visibilityTimeout :: UTCTime- , message :: !Value- , headers :: !(Maybe Value)+ , message :: Value+ , headers :: Maybe Value } deriving (Show) instance Eq Message where- Message i _ _ _ _ _ == Message i' _ _ _ _ _ = i == i'+ Message i _ _ _ _ _ _ == Message i' _ _ _ _ _ _ = i == i' data Metrics = Metrics
stakhanov.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: stakhanov-version: 0.0.1.0+version: 0.1.0.0 synopsis: A Haskell PGMQ client description: A fast Haskell PGMQ client for busy workers