kiroku-cli-0.1.0.0: src/Kiroku/Cli/Subscription/Status.hs
module Kiroku.Cli.Subscription.Status (
SubscriptionStatusRow (..),
renderSubscriptionStatusRows,
subscriptionStatusRows,
) where
import Data.Aeson qualified as Aeson
import Data.ByteString.Lazy qualified as LBS
import Data.Int (Int32, Int64)
import Data.List (sortOn)
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import Data.Text (Text)
import Data.Text qualified as T
import Data.Text.Encoding qualified as TE
import Kiroku.Cli.Command (OutputFormat (..))
import Kiroku.Store.Subscription (SubscriptionStateView (..))
import Kiroku.Store.Subscription.Types (SubscriptionName (..))
import Kiroku.Store.Types (GlobalPosition (..))
data SubscriptionStatusRow = SubscriptionStatusRow
{ rowSubscription :: !Text
, rowMember :: !Int32
, rowPhase :: !Text
, rowGlobalPosition :: !Int64
}
deriving stock (Eq, Show)
subscriptionStatusRows :: Map (SubscriptionName, Int32) SubscriptionStateView -> [SubscriptionStatusRow]
subscriptionStatusRows =
sortOn (\row -> (rowSubscription row, rowMember row))
. fmap toRow
. Map.elems
where
toRow view =
let SubscriptionName name = subscriptionName view
GlobalPosition position = cursor view
in SubscriptionStatusRow
{ rowSubscription = name
, rowMember = member view
, rowPhase = statePhase view
, rowGlobalPosition = position
}
renderSubscriptionStatusRows :: OutputFormat -> [SubscriptionStatusRow] -> Text
renderSubscriptionStatusRows OutputTable = renderTable
renderSubscriptionStatusRows OutputJson = renderJson
renderTable :: [SubscriptionStatusRow] -> Text
renderTable rows =
T.unlines (header : fmap renderRow rows)
where
header =
pad subWidth "SUBSCRIPTION"
<> " "
<> pad memberWidth "MEMBER"
<> " "
<> pad phaseWidth "PHASE"
<> " GLOBAL_POSITION"
subWidth = columnWidth "SUBSCRIPTION" (fmap rowSubscription rows)
memberWidth = columnWidth "MEMBER" (fmap (T.pack . show . rowMember) rows)
phaseWidth = columnWidth "PHASE" (fmap rowPhase rows)
renderRow row =
pad subWidth (rowSubscription row)
<> " "
<> pad memberWidth (T.pack (show (rowMember row)))
<> " "
<> pad phaseWidth (rowPhase row)
<> " "
<> T.pack (show (rowGlobalPosition row))
columnWidth :: Text -> [Text] -> Int
columnWidth label values =
maximum (T.length label : fmap T.length values)
pad :: Int -> Text -> Text
pad width value =
value <> T.replicate (width - T.length value) " "
renderJson :: [SubscriptionStatusRow] -> Text
renderJson =
TE.decodeUtf8
. LBS.toStrict
. Aeson.encode
. fmap rowJson
where
rowJson row =
Aeson.object
[ "subscription" Aeson..= rowSubscription row
, "member" Aeson..= rowMember row
, "phase" Aeson..= rowPhase row
, "global_position" Aeson..= rowGlobalPosition row
]