kiroku-store-0.11.0.0: src/Kiroku/Store/Subscription/DeadLetter/SQL.hs
{-# LANGUAGE MultilineStrings #-}
module Kiroku.Store.Subscription.DeadLetter.SQL (
listSubscriptionDeadLettersSession,
listSubscriptionDeadLettersStmt,
listSubscriptionDeadLettersFromStartStmt,
listSubscriptionMemberDeadLettersStmt,
listSubscriptionMemberDeadLettersFromStartStmt,
) where
import Contravariant.Extras (contrazip2, contrazip3, contrazip4, contrazip5)
import Control.Lens ((^.))
import Data.Generics.Labels ()
import Data.Int (Int32, Int64)
import Data.Text (Text)
import Data.Vector (Vector)
import Data.Vector qualified as V
import Hasql.Decoders qualified as D
import Hasql.Encoders qualified as E
import Hasql.Session (Session)
import Hasql.Session qualified as Session
import Hasql.Statement (Statement, preparable)
import Kiroku.Store.Subscription.Types
import Kiroku.Store.Types (EventId (..), GlobalPosition (..))
listSubscriptionDeadLettersFromStartStmt :: Statement (Text, Int32) (Vector SubscriptionDeadLetter)
listSubscriptionDeadLettersFromStartStmt =
preparable
"""
WITH RECURSIVE members(member) AS (
SELECT (SELECT consumer_group_member FROM dead_letters
WHERE subscription_name = $1 ORDER BY consumer_group_member LIMIT 1)
UNION ALL
SELECT (SELECT consumer_group_member FROM dead_letters
WHERE subscription_name = $1 AND consumer_group_member > m.member
ORDER BY consumer_group_member LIMIT 1)
FROM members m WHERE m.member IS NOT NULL
)
SELECT d.dead_letter_id, d.subscription_name, d.consumer_group_member, d.global_position, d.event_id, d.reason, d.reason_summary, d.attempt_count, d.created_at
FROM members m
CROSS JOIN LATERAL (
SELECT dead_letter_id, subscription_name, consumer_group_member, global_position, event_id, reason, reason_summary, attempt_count, created_at
FROM dead_letters
WHERE subscription_name = $1 AND consumer_group_member = m.member
ORDER BY global_position DESC, dead_letter_id DESC LIMIT $2
) d
WHERE m.member IS NOT NULL
ORDER BY d.global_position DESC, d.dead_letter_id DESC LIMIT $2
"""
(contrazip2 text int4)
(D.rowVector deadLetterRow)
listSubscriptionDeadLettersStmt :: Statement (Text, Int64, Int64, Int32) (Vector SubscriptionDeadLetter)
listSubscriptionDeadLettersStmt =
preparable
"""
WITH RECURSIVE members(member) AS (
SELECT (SELECT consumer_group_member FROM dead_letters
WHERE subscription_name = $1 ORDER BY consumer_group_member LIMIT 1)
UNION ALL
SELECT (SELECT consumer_group_member FROM dead_letters
WHERE subscription_name = $1 AND consumer_group_member > m.member
ORDER BY consumer_group_member LIMIT 1)
FROM members m WHERE m.member IS NOT NULL
)
SELECT d.dead_letter_id, d.subscription_name, d.consumer_group_member, d.global_position, d.event_id, d.reason, d.reason_summary, d.attempt_count, d.created_at
FROM members m
CROSS JOIN LATERAL (
SELECT dead_letter_id, subscription_name, consumer_group_member, global_position, event_id, reason, reason_summary, attempt_count, created_at
FROM dead_letters
WHERE subscription_name = $1 AND consumer_group_member = m.member
AND (global_position, dead_letter_id) < ($2, $3)
ORDER BY global_position DESC, dead_letter_id DESC LIMIT $4
) d
WHERE m.member IS NOT NULL
ORDER BY d.global_position DESC, d.dead_letter_id DESC LIMIT $4
"""
(contrazip4 text int8 int8 int4)
(D.rowVector deadLetterRow)
listSubscriptionMemberDeadLettersFromStartStmt :: Statement (Text, Int32, Int32) (Vector SubscriptionDeadLetter)
listSubscriptionMemberDeadLettersFromStartStmt =
preparable
"""
SELECT dead_letter_id, subscription_name, consumer_group_member, global_position, event_id, reason, reason_summary, attempt_count, created_at
FROM dead_letters
WHERE subscription_name = $1 AND consumer_group_member = $2
ORDER BY global_position DESC, dead_letter_id DESC LIMIT $3
"""
(contrazip3 text int4 int4)
(D.rowVector deadLetterRow)
listSubscriptionMemberDeadLettersStmt :: Statement (Text, Int32, Int64, Int64, Int32) (Vector SubscriptionDeadLetter)
listSubscriptionMemberDeadLettersStmt =
preparable
"""
SELECT dead_letter_id, subscription_name, consumer_group_member, global_position, event_id, reason, reason_summary, attempt_count, created_at
FROM dead_letters
WHERE subscription_name = $1 AND consumer_group_member = $2
AND (global_position, dead_letter_id) < ($3, $4)
ORDER BY global_position DESC, dead_letter_id DESC LIMIT $5
"""
(contrazip5 text int4 int8 int8 int4)
(D.rowVector deadLetterRow)
text :: E.Params Text
text = E.param (E.nonNullable E.text)
int4 :: E.Params Int32
int4 = E.param (E.nonNullable E.int4)
int8 :: E.Params Int64
int8 = E.param (E.nonNullable E.int8)
deadLetterRow :: D.Row SubscriptionDeadLetter
deadLetterRow =
SubscriptionDeadLetter
<$> D.column (D.nonNullable D.int8)
<*> (SubscriptionName <$> D.column (D.nonNullable D.text))
<*> D.column (D.nonNullable D.int4)
<*> (GlobalPosition <$> D.column (D.nonNullable D.int8))
<*> (EventId <$> D.column (D.nonNullable D.uuid))
<*> D.column (D.nonNullable D.jsonb)
<*> D.column (D.nonNullable D.text)
<*> D.column (D.nonNullable D.int4)
<*> D.column (D.nonNullable D.timestamptz)
listSubscriptionDeadLettersSession :: SubscriptionDeadLetterQuery -> Session SubscriptionDeadLetterPage
listSubscriptionDeadLettersSession query = do
let SubscriptionName name = query ^. #subscriptionName
pageSize = subscriptionDeadLetterLimitValue (query ^. #limit)
fetch = pageSize + 1
rows <- case (query ^. #consumerGroupMember, query ^. #after) of
(Nothing, Nothing) -> Session.statement (name, fetch) listSubscriptionDeadLettersFromStartStmt
(Just selectedMember, Nothing) -> Session.statement (name, selectedMember, fetch) listSubscriptionMemberDeadLettersFromStartStmt
(Nothing, Just (SubscriptionDeadLetterCursor (GlobalPosition position) ident)) ->
Session.statement (name, position, ident, fetch) listSubscriptionDeadLettersStmt
(Just selectedMember, Just (SubscriptionDeadLetterCursor (GlobalPosition position) ident)) ->
Session.statement (name, selectedMember, position, ident, fetch) listSubscriptionMemberDeadLettersStmt
let page = V.take (fromIntegral pageSize) rows
cursor = if V.length rows > fromIntegral pageSize then Just (subscriptionDeadLetterCursor (V.last page)) else Nothing
pure (SubscriptionDeadLetterPage page cursor)