packages feed

solana-staking-csvs-0.1.0.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 qualified Data.ByteString.Lazy          as LBS
import qualified Data.Text                     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