solana-staking-csvs-0.1.3.0: src/Console/SolanaStaking/Csv.hs
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE RecordWildCards #-}
-- | Types responsible for CSV generation.
module Console.SolanaStaking.Csv
( makeCsvContents
, ExportData (..)
, toExportData
) where
import Data.Csv
( DefaultOrdered (..)
, EncodeOptions (..)
, ToNamedRecord (..)
, defaultEncodeOptions
, encodeDefaultOrderedByNameWith
, namedRecord
, (.=)
)
import Data.Time (defaultTimeLocale, formatTime)
import Data.Time.Clock.POSIX (POSIXTime, posixSecondsToUTCTime)
import Console.SolanaStaking.Api
( StakeReward (..)
, StakingAccount (..)
, StakingPubKey (..)
, renderLamports
)
import Data.ByteString.Lazy qualified as LBS
import Data.Text qualified as T
-- | Represents a single row of CSV data.
data ExportData = ExportData
{ edTime :: T.Text
, edAmount :: T.Text
, edStakeAccount :: T.Text
, edEpoch :: Integer
}
deriving (Show, Read, Eq, Ord)
-- | Remove the @ed@ prefixes from the field names.
instance ToNamedRecord ExportData where
toNamedRecord ExportData {..} =
namedRecord
[ "time" .= edTime
, "amount" .= edAmount
, "stakeAccount" .= edStakeAccount
, "epoch" .= edEpoch
]
-- | Column order is @time, amount, stakeAccount, epoch@.
instance DefaultOrdered ExportData where
headerOrder _ = ["time", "amount", "stakeAccount", "epoch"]
-- | Convert an Account & Reward into a CSV row.
toExportData :: (StakingAccount, StakeReward) -> ExportData
toExportData (StakingAccount {..}, StakeReward {..}) =
ExportData
{ edTime = formatTimestamp srTimestamp
, edAmount = renderLamports srAmount
, edStakeAccount = fromStakingPubKey saPubKey
, edEpoch = srEpoch
}
where
formatTimestamp :: POSIXTime -> T.Text
formatTimestamp =
T.pack . formatTime defaultTimeLocale "%F %T%Z" . posixSecondsToUTCTime
-- | Build the CSV contents with a header row.
makeCsvContents :: [(StakingAccount, StakeReward)] -> LBS.ByteString
makeCsvContents =
encodeDefaultOrderedByNameWith defaultEncodeOptions {encUseCrLf = False}
. map toExportData